Lachain ERC20 handler
Contract
// 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.
*/
contract ERC20Handler is
IDepositExecute,
HandlerHelpers,
UpgradableOwnable,
ERC20Safe
{
struct DepositRecord {
address _tokenAddress;
bytes8 _destinationChainID;
bytes32 _resourceID;
address _destinationRecipientAddress;
address _depositer;
uint256 _amount;
}
// 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;
ownableInit(msg.sender);
}
function adminChangeBridgeAddress(address newBridgeAddress)
external
onlyOwner
isInitisalised
{
_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)
external
view
isInitisalised
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.
*/
function deposit(
bytes32 resourceID,
bytes8 destinationChainID,
uint64 depositNonce,
address depositer,
address recipientAddress,
uint256 amount,
bytes calldata params
) external override onlyBridge isInitisalised returns (address) {
// bytes memory recipientAddress;
// uint256 amount;
// uint256 lenRecipientAddress;
// assembly {
// amount := calldataload(0xC4)
// recipientAddress := mload(0x40)
// lenRecipientAddress := calldataload(0xE4)
// mstore(0x40, add(0x20, add(recipientAddress, lenRecipientAddress)))
// calldatacopy(
// recipientAddress, // copy to destinationRecipientAddress
// 0xE4, // copy from calldata @ 0x104
// sub(calldatasize(), 0xE) // copy size (calldatasize - 0x104)
// )
// }
address tokenAddress = _resourceIDToTokenContractAddress[resourceID];
require(
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
);
if (_burnList[tokenAddress]) {
burnERC20(tokenAddress, depositer, amount);
} else {
lockERC20(tokenAddress, depositer, address(this), amount);
}
_depositRecords[destinationChainID][depositNonce] = DepositRecord(
tokenAddress,
destinationChainID,
resourceID,
recipientAddress,
depositer,
amount
);
return (tokenAddress);
}
/**
@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(
bytes32 resourceID,
address recipientAddress,
uint256 amount,
bytes calldata params
) external override onlyBridge isInitisalised {
// uint256 amount;
// bytes memory destinationRecipientAddress;
// assembly {
// amount := calldataload(0x64)
// destinationRecipientAddress := mload(0x40)
// let lenDestinationRecipientAddress := calldataload(0x84)
// mstore(
// 0x40,
// add(
// 0x20,
// add(
// destinationRecipientAddress,
// lenDestinationRecipientAddress
// )
// )
// )
// // in the calldata the destinationRecipientAddress is stored at 0xC4 after accounting for the function signature and length declaration
// calldatacopy(
// 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];
// assembly {
// recipientAddress := mload(add(destinationRecipientAddress, 0x20))
// }
require(
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
);
if (_burnList[tokenAddress]) {
mintERC20(tokenAddress, recipientAddress, amount);
} else {
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.
*/
function withdraw(
address tokenAddress,
address recipient,
uint256 amount
) external override onlyBridge isInitisalised {
releaseERC20(tokenAddress, recipient, amount);
}
function getAddressFromResourceId(bytes32 resourceID)
external
view
override
returns (address)
{
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.
*/
function approve(
bytes32 resourceID,
address spender,
uint256 amount
) external override onlyBridge isInitisalised {
address tokenAddress = _resourceIDToTokenContractAddress[resourceID];
require(
_contractWhitelist[tokenAddress],
"provided tokenAddress is not whitelisted"
);
approveERC20(tokenAddress, spender, amount);
}
}
Last updated