// pragma solidity 0.6.4;
pragma experimental ABIEncoderV2;
import "../interfaces/IDepositExecute.sol";
import "../interfaces/IERC20.sol";
import "./HandlerHelpers.sol";
import "../ERC20Safe.sol";
import "../ExampleToken.sol";
import "../utils/UpgradableOwnable.sol";
@title Handles ERC20 deposits and deposit executions.
@notice This contract is intended to be used with the Bridge contract.
bytes8 _destinationChainID;
address _destinationRecipientAddress;
// depositNonce => Deposit Record
mapping(bytes8 => mapping(uint64 => DepositRecord)) public _depositRecords;
@param bridgeAddress Contract address of previously deployed Bridge.
function initialize(address bridgeAddress) public {
_bridgeAddress = bridgeAddress;
function adminChangeBridgeAddress(address newBridgeAddress)
_bridgeAddress = newBridgeAddress;
@param depositNonce This ID will have been generated by the Bridge contract.
@param destId ID of chain deposit will be bridged to.
@return DepositRecord which consists of:
- _tokenAddress Address used when {deposit} was executed.
- _destinationChainID ChainID deposited tokens are intended to end up on.
- _resourceID ResourceID used when {deposit} was executed.
- _destinationRecipientAddress Address tokens are intended to be deposited to on desitnation chain.
- _depositer Address that initially called {deposit} in the Bridge contract.
- _amount Amount of tokens that were deposited.
function getDepositRecord(uint64 depositNonce, bytes8 destId)
returns (DepositRecord memory)
return _depositRecords[destId][depositNonce];
@notice A deposit is initiatied by making a deposit in the Bridge contract.
@param destinationChainID Chain ID of chain tokens are expected to be bridged to.
@param depositNonce This value is generated as an ID by the Bridge contract.
@param depositer Address of account making the deposit in the Bridge contract.
@notice Data passed into the function should be constructed as follows:
amount uint256 bytes 0 - 32
recipientAddress length uint256 bytes 32 - 64
recipientAddress bytes bytes 64 - END
@dev Depending if the corresponding {tokenAddress} for the parsed {resourceID} is
marked true in {_burnList}, deposited tokens will be burned, if not, they will be locked.
bytes8 destinationChainID,
address recipientAddress,
) external override onlyBridge isInitisalised returns (address) {
// bytes memory recipientAddress;
// uint256 lenRecipientAddress;
// amount := calldataload(0xC4)
// recipientAddress := mload(0x40)
// lenRecipientAddress := calldataload(0xE4)
// mstore(0x40, add(0x20, add(recipientAddress, lenRecipientAddress)))
// recipientAddress, // copy to destinationRecipientAddress
// 0xE4, // copy from calldata @ 0x104
// sub(calldatasize(), 0xE) // copy size (calldatasize - 0x104)
address tokenAddress = _resourceIDToTokenContractAddress[resourceID];
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
if (_burnList[tokenAddress]) {
burnERC20(tokenAddress, depositer, amount);
lockERC20(tokenAddress, depositer, address(this), amount);
_depositRecords[destinationChainID][depositNonce] = DepositRecord(
@notice Proposal execution should be initiated when a proposal is finalized in the Bridge contract.
by a relayer on the deposit's destination chain.
@notice Data passed into the function should be constructed as follows:
amount uint256 bytes 0 - 32
destinationRecipientAddress length uint256 bytes 32 - 64
destinationRecipientAddress bytes bytes 64 - END
function executeProposal(
address recipientAddress,
) external override onlyBridge isInitisalised {
// bytes memory destinationRecipientAddress;
// amount := calldataload(0x64)
// destinationRecipientAddress := mload(0x40)
// let lenDestinationRecipientAddress := calldataload(0x84)
// destinationRecipientAddress,
// lenDestinationRecipientAddress
// // in the calldata the destinationRecipientAddress is stored at 0xC4 after accounting for the function signature and length declaration
// destinationRecipientAddress, // copy to destinationRecipientAddress
// 0x84, // copy from calldata @ 0x84
// sub(calldatasize(), 0x84) // copy size to the end of calldata
// bytes20 recipientAddress;
address tokenAddress = _resourceIDToTokenContractAddress[resourceID];
// recipientAddress := mload(add(destinationRecipientAddress, 0x20))
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
if (_burnList[tokenAddress]) {
mintERC20(tokenAddress, recipientAddress, amount);
releaseERC20(tokenAddress, recipientAddress, amount);
@notice Used to manually release ERC20 tokens from ERC20Safe.
@param tokenAddress Address of token contract to release.
@param recipient Address to release tokens to.
@param amount The amount of ERC20 tokens to release.
) external override onlyBridge isInitisalised {
releaseERC20(tokenAddress, recipient, amount);
function getAddressFromResourceId(bytes32 resourceID)
return _resourceIDToTokenContractAddress[resourceID];
@notice Used to approve spending tokens.
@param resourceID ResourceID to be used for approval.
@param spender Spender address.
@param amount Amount to approve.
) external override onlyBridge isInitisalised {
address tokenAddress = _resourceIDToTokenContractAddress[resourceID];
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
approveERC20(tokenAddress, spender, amount);