Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions contracts/anchors/bridged/Anchor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,34 @@ contract Anchor is LinkableAnchor {
token = address(_token);
}

function wrap(address tokenAddress, uint256 amount) public {
function wrapToken(address tokenAddress, uint256 amount) public {
ITokenWrapper(token).wrapFor(msg.sender, tokenAddress, amount);
}

function unwrap(address tokenAddress, uint256 amount) public {
function unwrapIntoToken(address tokenAddress, uint256 amount) public {
ITokenWrapper(token).unwrapFor(msg.sender, tokenAddress, amount);
}

function wrapNative() payable public {
ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0);
}

function unwrapIntoNative(address tokenAddress, uint256 amount) public {
ITokenWrapper(token).unwrapFor(msg.sender, tokenAddress, amount);
}

function wrapAndDeposit(
address tokenAddress,
bytes32 _commitment
) public {
) payable public {
require(!commitments[_commitment], "The commitment has been submitted");
// wrap the token and send directly to this contract
ITokenWrapper(token).wrapForAndSendTo(msg.sender, tokenAddress, denomination, address(this));
// wrap into the token and send directly to this contract
ITokenWrapper(token).wrapForAndSendTo{value: msg.value}(
msg.sender,
tokenAddress,
denomination,
address(this)
);
// insert a new commitment to the tree
uint32 insertedIndex = _insert(_commitment);
commitments[_commitment] = true;
Expand Down
6 changes: 3 additions & 3 deletions contracts/interfaces/ITokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ pragma solidity ^0.8.0;
@author Webb Technologies.
*/
interface ITokenWrapper {
function wrap(address tokenAddress, uint256 amount) external;
function wrap(address tokenAddress, uint256 amount) payable external;
function unwrap(address tokenAddress, uint256 amount) external;
function wrapFor(address sender, address tokenAddress, uint256 amount) external;
function wrapForAndSendTo(address sender, address tokenAddress, uint256 amount, address mintRecipient) external;
function wrapFor(address sender, address tokenAddress, uint256 amount) payable external;
function wrapForAndSendTo(address sender, address tokenAddress, uint256 amount, address mintRecipient) payable external;
function unwrapFor(address sender, address tokenAddress, uint256 amount) external;
}
2 changes: 1 addition & 1 deletion contracts/mocks/GTokenWrapperMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ contract GTokenWrapperMock is GovernedTokenWrapper {
* @notice Construct a new Comp token
*/
constructor(string memory name, string memory symbol, address governor, uint256 limit)
GovernedTokenWrapper(name, symbol, governor, limit) {}
GovernedTokenWrapper(name, symbol, governor, limit, true) {}
}
24 changes: 17 additions & 7 deletions contracts/tokens/GovernedTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,21 @@ contract GovernedTokenWrapper is TokenWrapper {
address[] public tokens;
mapping (address => bool) valid;

bool isNativeAllowed;
uint256 public wrappingLimit;

constructor(string memory name, string memory symbol, address _governor, uint256 _limit) TokenWrapper(name, symbol) {
constructor(string memory name, string memory symbol, address _governor, uint256 _limit, bool _isNativeAllowed) TokenWrapper(name, symbol) {
governor = _governor;
wrappingLimit = _limit;
isNativeAllowed = _isNativeAllowed;
}

function setGovernor(address _governor) public onlyGovernor {
governor = _governor;
}

function _isValidAddress(address tokenAddress) override internal virtual returns (bool) {
return valid[tokenAddress];
}

function _isValidAmount(uint256 amount) override internal virtual returns (bool) {
return amount + this.totalSupply() <= wrappingLimit;
function setNativeAllowed(bool _isNativeAllowed) public onlyGovernor {
isNativeAllowed = _isNativeAllowed;
}

function add(address tokenAddress) public onlyGovernor {
Expand All @@ -46,6 +44,18 @@ contract GovernedTokenWrapper is TokenWrapper {
wrappingLimit = limit;
}

function _isValidAddress(address tokenAddress) override internal virtual returns (bool) {
return valid[tokenAddress];
}

function _isValidAmount(uint256 amount) override internal virtual returns (bool) {
return amount + this.totalSupply() <= wrappingLimit;
}

function _isNativeValid() override internal virtual returns (bool) {
return isNativeAllowed;
}

function getTokens() external view returns (address[] memory) {
return tokens;
}
Expand Down
139 changes: 104 additions & 35 deletions contracts/tokens/TokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,73 +28,142 @@ abstract contract TokenWrapper is ERC20PresetMinterPauser, ITokenWrapper {
@param tokenAddress Address of ERC20 to transfer.
@param amount Amount of tokens to transfer.
*/
function wrap(address tokenAddress, uint256 amount) override public {
require(_isValidAddress(tokenAddress), "Invalid token address");
require(_isValidAmount(amount), "Invalid token amount");
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(_msgSender(), address(this), amount);
// mint the wrapped token for the sender
_mint(_msgSender(), amount);
function wrap(
address tokenAddress,
uint256 amount
) override payable public isValidWrapping(tokenAddress, amount) {
if (tokenAddress == address(0)) {
// mint the native value sent to the contract
_mint(_msgSender(), msg.value);
} else {
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(_msgSender(), address(this), amount);
// mint the wrapped token for the sender
_mint(_msgSender(), amount);
}
}

/**
@notice Used to unwrap/burn the wrapper token on behalf of a sender.
@param tokenAddress Address of ERC20 to unwrap into.
@param amount Amount of tokens to burn.
*/
function unwrap(address tokenAddress, uint256 amount) override public {
require(_isValidAddress(tokenAddress), "Invalid token address");
require(_isValidAmount(amount), "Invalid token amount");
function unwrap(
address tokenAddress,
uint256 amount
) override public isValidUnwrapping(tokenAddress, amount) {
// burn wrapped token from sender
_burn(_msgSender(), amount);
// transfer liquidity from the token wrapper to the sender
IERC20(tokenAddress).transfer(_msgSender(), amount);
// unwrap liquidity and send to the sender
if (tokenAddress == address(0)) {
// transfer native liquidity from the token wrapper to the sender
payable(msg.sender).transfer(amount);
} else {
// transfer ERC20 liquidity from the token wrapper to the sender
IERC20(tokenAddress).transfer(_msgSender(), amount);
}
}

/**
@notice Used to wrap tokens on behalf of a sender
@param sender Address of sender where assets are sent from.
@param tokenAddress Address of ERC20 to transfer.
@param amount Amount of tokens to transfer.
*/
function wrapFor(address sender, address tokenAddress, uint256 amount) override public {
require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role");
require(_isValidAddress(tokenAddress), "Invalid token address");
require(_isValidAmount(amount), "Invalid token amount");
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(sender, address(this), amount);
// mint the wrapped token for the sender
mint(sender, amount);
function wrapFor(
address sender,
address tokenAddress,
uint256 amount
) override payable public isMinter() isValidWrapping(tokenAddress, amount) {
if (tokenAddress == address(0)) {
mint(sender, msg.value);
} else {
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(sender, address(this), amount);
// mint the wrapped token for the sender
mint(sender, amount);
}
}

/**
@notice Used to wrap tokens and mint the wrapped tokens to a potentially different recipient
@notice Used to wrap tokens on behalf of a sender and mint to a potentially different address
@param sender Address of sender where assets are sent from.
@param tokenAddress Address of ERC20 to transfer.
@param amount Amount of tokens to transfer.
@param recipient Recipient of the wrapped tokens.
*/
function wrapForAndSendTo(address sender, address tokenAddress, uint256 amount, address recipient) override public {
require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role");
require(_isValidAddress(tokenAddress), "Invalid token address");
require(_isValidAmount(amount), "Invalid token amount");
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(sender, address(this), amount);
// mint the wrapped token for the sender
mint(recipient, amount);
function wrapForAndSendTo(
address sender,
address tokenAddress,
uint256 amount,
address recipient
) override payable public isMinter() isValidWrapping(tokenAddress, amount) {
if (tokenAddress == address(0)) {
mint(recipient, msg.value);
} else {
// transfer liquidity to the token wrapper
IERC20(tokenAddress).transferFrom(sender, address(this), amount);
// mint the wrapped token for the recipient
mint(recipient, amount);
}
}

/**
@notice Used to unwrap/burn the wrapper token.
@param tokenAddress Address of ERC20 to unwrap into.
@param amount Amount of tokens to burn.
*/
function unwrapFor(address sender, address tokenAddress, uint256 amount) override public {
require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role");
require(_isValidAddress(tokenAddress), "Invalid token address");
require(_isValidAmount(amount), "Invalid token amount");
function unwrapFor(
address sender,
address tokenAddress,
uint256 amount
) override public isMinter() isValidUnwrapping(tokenAddress, amount) {
// burn wrapped token from sender
_burn(sender, amount);
// transfer liquidity from the token wrapper to the sender
IERC20(tokenAddress).transfer(sender, amount);
if (tokenAddress == address(0)) {
payable(sender).transfer(amount);
} else {
// transfer liquidity from the token wrapper to the sender
IERC20(tokenAddress).transfer(sender, amount);
}
}

/** @dev this function is defined in a child contract */
function _isValidAddress(address tokenAddress) internal virtual returns (bool);

/** @dev this function is defined in a child contract */
function _isNativeValid() internal virtual returns (bool);

/** @dev this function is defined in a child contract */
function _isValidAmount(uint256 amount) internal virtual returns (bool);

modifier isMinter() {
require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role");
_;
}

modifier isValidWrapping(address tokenAddress, uint256 amount) {
if (tokenAddress == address(0)) {
require(amount == 0, "Invalid amount provided for native wrapping");
require(_isNativeValid(), "Native wrapping is not allowed for this token wrapper");
} else {
require(msg.value == 0, "Invalid value sent for wrapping");
require(_isValidAddress(tokenAddress), "Invalid token address");
}

require(_isValidAmount(amount), "Invalid token amount");
_;
}

modifier isValidUnwrapping(address tokenAddress, uint256 amount) {
if (tokenAddress == address(0)) {
require(address(this).balance >= amount, "Insufficient native balance");
require(_isNativeValid(), "Native unwrapping is not allowed for this token wrapper");
} else {
require(IERC20(tokenAddress).balanceOf(address(this)) >= amount, "Insufficient ERC20 balance");
require(_isValidAddress(tokenAddress), "Invalid token address");
}

_;
}
}
31 changes: 31 additions & 0 deletions lib/darkwebb/ERC20.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ethers } from "ethers";
import { ERC20 as ERC20Contract} from '../../typechain/ERC20';
import { ERC20__factory } from "../../typechain/factories/ERC20__factory";

class ERC20 {
contract: ERC20Contract;

constructor(
contract: ERC20Contract
) {
this.contract = contract;
}

public static async createERC20(
name: string,
symbol: string,
deployer: ethers.Signer
): Promise<ERC20> {
const factory = new ERC20__factory(deployer);
const contract = await factory.deploy(
name,
symbol,
);
await contract.deployed();

const handler = new ERC20(contract);
return handler;
}
}

export default ERC20;
37 changes: 37 additions & 0 deletions lib/darkwebb/GovernedTokenWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ethers } from "ethers";
import { GovernedTokenWrapper as GovernedTokenWrapperContract} from '../../typechain/GovernedTokenWrapper';
import { GovernedTokenWrapper__factory } from "../../typechain/factories/GovernedTokenWrapper__factory";

class GovernedTokenWrapper {
contract: GovernedTokenWrapperContract;

constructor(
contract: GovernedTokenWrapperContract
) {
this.contract = contract;
}

public static async createGovernedTokenWrapper(
name: string,
symbol: string,
governor: string,
limit: string,
isNativeAllowed: boolean,
deployer: ethers.Signer
) {
const factory = new GovernedTokenWrapper__factory(deployer);
const contract = await factory.deploy(
name,
symbol,
governor,
limit,
isNativeAllowed
);
await contract.deployed();

const handler = new GovernedTokenWrapper(contract);
return handler;
}
}

export default GovernedTokenWrapper;
24 changes: 12 additions & 12 deletions scripts/bash/compile_circom.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ mkdir -p artifacts/circuits/bridge
# --sym artifacts/circuits/bridge/poseidon_bridge_2.sym
# echo "Done!\n"

# echo "Compiling Webb style Poseidon bridge 3 withdrawal circuit..."
# circom circuits/test/poseidon_bridge_3.circom \
# --r1cs artifacts/circuits/bridge/poseidon_bridge_3.r1cs \
# --wasm artifacts/circuits/bridge/poseidon_bridge_3.wasm \
# --sym artifacts/circuits/bridge/poseidon_bridge_3.sym
# echo "Done!\n"
echo "Compiling Webb style Poseidon bridge 3 withdrawal circuit..."
circom circuits/test/poseidon_bridge_3.circom \
--r1cs artifacts/circuits/bridge/poseidon_bridge_3.r1cs \
--wasm artifacts/circuits/bridge/poseidon_bridge_3.wasm \
--sym artifacts/circuits/bridge/poseidon_bridge_3.sym
echo "Done!\n"

# echo "Compiling Webb style Poseidon bridge 4 withdrawal circuit..."
# circom circuits/test/poseidon_bridge_4.circom \
Expand Down Expand Up @@ -59,9 +59,9 @@ mkdir -p artifacts/circuits/bridge
# --sym artifacts/circuits/poseidon_preimage_3.sym
# echo "Done!"

echo "Compiling Set membership of length 5 circuit..."
circom circuits/test/set_membership_5.circom \
--r1cs artifacts/circuits/bridge/set_membership_5.r1cs \
--wasm artifacts/circuits/bridge/set_membership_5.wasm \
--sym artifacts/circuits/bridge/set_membership_5.sym
echo "Done!\n"
# echo "Compiling Set membership of length 5 circuit..."
# circom circuits/test/set_membership_5.circom \
# --r1cs artifacts/circuits/bridge/set_membership_5.r1cs \
# --wasm artifacts/circuits/bridge/set_membership_5.wasm \
# --sym artifacts/circuits/bridge/set_membership_5.sym
# echo "Done!\n"
Loading