From d743395c171a9a3913c7888996f1eb2b4b1ca438 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 10 Aug 2023 11:37:30 -0400 Subject: [PATCH 01/12] fix typos (#99) Co-authored-by: Dean Amiel --- .../InterchainTokenService.sol | 22 +- .../interchain-token/InterchainToken.sol | 8 +- contracts/interfaces/IInterchainToken.sol | 4 +- .../interfaces/IInterchainTokenExecutable.sol | 2 +- .../IInterchainTokenExpressExecutable.sol | 2 +- .../interfaces/IInterchainTokenService.sol | 2 + .../interfaces/IRemoteAddressValidator.sol | 4 +- contracts/interfaces/ITokenManager.sol | 10 +- contracts/proxies/TokenManagerProxy.sol | 8 +- contracts/test/utils/NakedProxy.sol | 4 +- contracts/token-manager/TokenManager.sol | 14 +- .../TokenManagerAddressStorage.sol | 6 +- contracts/utils/Distributable.sol | 2 +- contracts/utils/FlowLimit.sol | 1 + docs/index.md | 2069 ++++++++--------- 15 files changed, 1085 insertions(+), 1073 deletions(-) diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index 5a9eb904..e26a7403 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -71,7 +71,7 @@ contract InterchainTokenService is bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service'); /** - * @dev All of the varaibles passed here are stored as immutable variables. + * @dev All of the variables passed here are stored as immutable variables. * @param tokenManagerDeployer_ the address of the TokenManagerDeployer. * @param standardizedTokenDeployer_ the address of the StandardizedTokenDeployer. * @param gateway_ the address of the AxelarGateway. @@ -156,7 +156,7 @@ contract InterchainTokenService is /** * @notice Calculates the address of a TokenManager from a specific tokenId. The TokenManager does not need to exist already. * @param tokenId the tokenId. - * @return tokenManagerAddress deployement address of the TokenManager. + * @return tokenManagerAddress deployment address of the TokenManager. */ // TODO: Maybe copy the code of the create3Deployer to save gas, but would introduce duplicate code problems. function getTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) { @@ -373,7 +373,7 @@ contract InterchainTokenService is /** * @notice Used to deploy a standardized token alongside a TokenManager. If the `distributor` is the address of the TokenManager (which - * can be calculated ahead of time) then a mint/burn TokenManager is used. Otherwise a lock/unlcok TokenManager is used. + * can be calculated ahead of time) then a mint/burn TokenManager is used. Otherwise a lock/unlock TokenManager is used. * @param salt the salt to be used. * @param name the name of the token to be deployed. * @param symbol the symbol of the token to be deployed. @@ -397,12 +397,15 @@ contract InterchainTokenService is /** * @notice Used to deploy a standardized token alongside a TokenManager in another chain. If the `distributor` is empty - * bytes then a mint/burn TokenManager is used. Otherwise a lock/unlcok TokenManager is used. + * bytes then a mint/burn TokenManager is used. Otherwise a lock/unlock TokenManager is used. * @param salt the salt to be used. * @param name the name of the token to be deployed. * @param symbol the symbol of the token to be deployed. * @param decimals the decimals of the token to be deployed. * @param distributor the address that will be able to mint and burn the deployed token. + * @param mintTo The address where the minted tokens will be sent upon deployment + * @param mintAmount The amount of tokens to be minted upon deployment + * @param operator The operator data for standardized tokens * @param destinationChain the name of the destination chain to deploy to. * @param gasValue the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount * specified needs to be passed to the call @@ -495,11 +498,11 @@ contract InterchainTokenService is /** * @notice Transmit a sendTokenWithData for the given tokenId. Only callable by a token manager. * @param tokenId the tokenId of the TokenManager (which must be the msg.sender). - * @param sourceAddress the address where the token is coming from, which will also be used for reimburment of gas. + * @param sourceAddress the address where the token is coming from, which will also be used for reimbursement of gas. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the destinationAddress for the sendToken. * @param amount the amount of token to give. - * @param metadata the data to be passed to the destiantion. + * @param metadata the data to be passed to the destination. */ function transmitSendToken( bytes32 tokenId, @@ -559,10 +562,10 @@ contract InterchainTokenService is } function _sanitizeTokenManagerImplementation( - address[] memory implementaions, + address[] memory implementations, TokenManagerType tokenManagerType ) internal pure returns (address implementation) { - implementation = implementaions[uint256(tokenManagerType)]; + implementation = implementations[uint256(tokenManagerType)]; if (implementation == address(0)) revert ZeroAddress(); if (ITokenManager(implementation).implementationType() != uint256(tokenManagerType)) revert InvalidTokenManagerImplementation(); } @@ -768,6 +771,9 @@ contract InterchainTokenService is * @param symbol The symbol of the token * @param decimals The number of decimals of the token * @param distributor The distributor address for the token + * @param mintTo The address where the minted tokens will be sent upon deployment + * @param mintAmount The amount of tokens to be minted upon deployment + * @param operator The operator data for standardized tokens * @param destinationChain The destination chain where the token will be deployed * @param gasValue The amount of gas to be paid for the transaction */ diff --git a/contracts/interchain-token/InterchainToken.sol b/contracts/interchain-token/InterchainToken.sol index 3da7f8dd..9f668678 100644 --- a/contracts/interchain-token/InterchainToken.sol +++ b/contracts/interchain-token/InterchainToken.sol @@ -15,7 +15,7 @@ import { ERC20 } from '../token-implementations/ERC20.sol'; abstract contract InterchainToken is IInterchainToken, ERC20 { /** * @notice Getter for the tokenManager used for this token. - * @dev Needs to be overwitten. + * @dev Needs to be overwritten. * @return tokenManager_ the TokenManager called to facilitate cross chain transfers. */ function tokenManager() public view virtual returns (ITokenManager tokenManager_); @@ -26,7 +26,7 @@ abstract contract InterchainToken is IInterchainToken, ERC20 { * A different implementation could have `metadata` that tells this function which function to use or that it is used for anything else as well. * @param destinationChain The destination chain identifier. * @param recipient The bytes representation of the address of the recipient. - * @param amount The amount of token to be transfered. + * @param amount The amount of token to be transferred. * @param metadata Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. */ function interchainTransfer( @@ -50,7 +50,7 @@ abstract contract InterchainToken is IInterchainToken, ERC20 { * @param sender the sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain the string representation of the destination chain. * @param recipient the bytes representation of the address of the recipient. - * @param amount the amount of token to be transfered. + * @param amount the amount of token to be transferred. * @param metadata either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. */ function interchainTransferFrom( @@ -77,7 +77,7 @@ abstract contract InterchainToken is IInterchainToken, ERC20 { * @param from the sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain the string representation of the destination chain. * @param destinationAddress the bytes representation of the address of the recipient. - * @param amount the amount of token to be transfered. + * @param amount the amount of token to be transferred. * @param metadata either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. */ function _beforeInterchainTransfer( diff --git a/contracts/interfaces/IInterchainToken.sol b/contracts/interfaces/IInterchainToken.sol index 567519c4..c4456cd6 100644 --- a/contracts/interfaces/IInterchainToken.sol +++ b/contracts/interfaces/IInterchainToken.sol @@ -12,7 +12,7 @@ interface IInterchainToken { * A different implementation could have `metadata` that tells this function which function to use or that it is used for anything else as well. * @param destinationChain The destination chain identifier. * @param recipient The bytes representation of the address of the recipient. - * @param amount The amount of token to be transfered. + * @param amount The amount of token to be transferred. * @param metadata Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. */ function interchainTransfer( @@ -29,7 +29,7 @@ interface IInterchainToken { * @param sender the sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain the string representation of the destination chain. * @param recipient the bytes representation of the address of the recipient. - * @param amount the amount of token to be transfered. + * @param amount the amount of token to be transferred. * @param metadata either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. */ function interchainTransferFrom( diff --git a/contracts/interfaces/IInterchainTokenExecutable.sol b/contracts/interfaces/IInterchainTokenExecutable.sol index 0317ef9c..c5597708 100644 --- a/contracts/interfaces/IInterchainTokenExecutable.sol +++ b/contracts/interfaces/IInterchainTokenExecutable.sol @@ -13,7 +13,7 @@ interface IInterchainTokenExecutable { * @param sourceChain the name of the source chain * @param sourceAddress the address that sent the contract call * @param data the data to be proccessed - * @param tokenId the tokenId of the token manager managing the token. You can access it's address by querrying the service + * @param tokenId the tokenId of the token manager managing the token. You can access it's address by querying the service * @param amount the amount of token that was sent */ function executeWithInterchainToken( diff --git a/contracts/interfaces/IInterchainTokenExpressExecutable.sol b/contracts/interfaces/IInterchainTokenExpressExecutable.sol index 5d2ae96e..9475af22 100644 --- a/contracts/interfaces/IInterchainTokenExpressExecutable.sol +++ b/contracts/interfaces/IInterchainTokenExpressExecutable.sol @@ -15,7 +15,7 @@ interface IInterchainTokenExpressExecutable is IInterchainTokenExecutable { * @param sourceChain the name of the source chain * @param sourceAddress the address that sent the contract call * @param data the data to be proccessed - * @param tokenId the tokenId of the token manager managing the token. You can access it's address by querrying the service + * @param tokenId the tokenId of the token manager managing the token. You can access it's address by querying the service * @param amount the amount of token that was sent */ function expressExecuteWithInterchainToken( diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index a04fcaab..f39d1741 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -237,6 +237,8 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx * @param symbol The symbol of the standardized tokens. * @param decimals The number of decimals for the standardized tokens. * @param distributor The distributor data for mint/burn operations. + * @param mintTo The address where the minted tokens will be sent upon deployment. + * @param mintAmount The amount of tokens to be minted upon deployment. * @param operator The operator data for standardized tokens. * @param destinationChain The name of the destination chain. * @param gasValue The gas value for deployment. diff --git a/contracts/interfaces/IRemoteAddressValidator.sol b/contracts/interfaces/IRemoteAddressValidator.sol index 9f54bb13..c71b0361 100644 --- a/contracts/interfaces/IRemoteAddressValidator.sol +++ b/contracts/interfaces/IRemoteAddressValidator.sol @@ -11,8 +11,8 @@ interface IRemoteAddressValidator { error LengthMismatch(); error ZeroStringLength(); - event TrustedAddressAdded(string souceChain, string sourceAddress); - event TrustedAddressRemoved(string souceChain); + event TrustedAddressAdded(string sourceChain, string sourceAddress); + event TrustedAddressRemoved(string sourceChain); event GatewaySupportedChainAdded(string chain); event GatewaySupportedChainRemoved(string chain); diff --git a/contracts/interfaces/ITokenManager.sol b/contracts/interfaces/ITokenManager.sol index 832b1473..ac918101 100644 --- a/contracts/interfaces/ITokenManager.sol +++ b/contracts/interfaces/ITokenManager.sol @@ -36,10 +36,11 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen function implementationType() external pure returns (uint256); /** - * @notice Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. + * @notice Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. + * @param metadata any additional data to be sent with the transfer. */ function sendToken( string calldata destinationChain, @@ -49,7 +50,7 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen ) external payable; /** - * @notice Calls the service to initiate the a cross-chain transfer with data after taking the appropriate amount of tokens from the user. + * @notice Calls the service to initiate a cross-chain transfer with data after taking the appropriate amount of tokens from the user. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. @@ -63,11 +64,12 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen ) external payable; /** - * @notice Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. + * @notice Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. * @param sender the address of the user paying for the cross chain transfer. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. + * @param metadata any additional data to be sent with the transfer. */ function transmitInterchainTransfer( address sender, @@ -81,7 +83,7 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen * @notice This function gives token to a specified address. Can only be called by the service. * @param destinationAddress the address to give tokens to. * @param amount the amount of token to give. - * @return the amount of token actually given, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. + * @return the amount of token actually given, which will only be different than `amount` in cases where the token takes some on-transfer fee. */ function giveToken(address destinationAddress, uint256 amount) external returns (uint256); diff --git a/contracts/proxies/TokenManagerProxy.sol b/contracts/proxies/TokenManagerProxy.sol index 25163f31..d0445cc4 100644 --- a/contracts/proxies/TokenManagerProxy.sol +++ b/contracts/proxies/TokenManagerProxy.sol @@ -7,8 +7,8 @@ import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol'; /** * @title TokenManagerProxy - * @dev This contract is a proxy for token manager contracts. It implements ITokenManagerProxy and - * inherits from FixedProxy from the gmp sdk repo + * @notice This contract is a proxy for token manager contracts. + * @dev It implements ITokenManagerProxy. */ contract TokenManagerProxy is ITokenManagerProxy { IInterchainTokenService public immutable interchainTokenServiceAddress; @@ -64,12 +64,12 @@ contract TokenManagerProxy is ITokenManagerProxy { */ // solhint-disable-next-line no-complex-fallback fallback() external payable virtual { - address implementaion_ = implementation(); + address implementation_ = implementation(); assembly { calldatacopy(0, 0, calldatasize()) - let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0) + let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result diff --git a/contracts/test/utils/NakedProxy.sol b/contracts/test/utils/NakedProxy.sol index 33384aed..0c75fdaa 100644 --- a/contracts/test/utils/NakedProxy.sol +++ b/contracts/test/utils/NakedProxy.sol @@ -11,12 +11,12 @@ contract NakedProxy { // solhint-disable-next-line no-complex-fallback fallback() external payable virtual { - address implementaion_ = implementation; + address implementation_ = implementation; assembly { calldatacopy(0, 0, calldatasize()) - let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0) + let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result diff --git a/contracts/token-manager/TokenManager.sol b/contracts/token-manager/TokenManager.sol index 44788454..73926308 100644 --- a/contracts/token-manager/TokenManager.sol +++ b/contracts/token-manager/TokenManager.sol @@ -83,10 +83,11 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen } /** - * @notice Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. + * @notice Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. + * @param metadata any additional data to be sent with the transfer. */ function sendToken( string calldata destinationChain, @@ -108,7 +109,7 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen } /** - * @notice Calls the service to initiate the a cross-chain transfer with data after taking the appropriate amount of tokens from the user. + * @notice Calls the service to initiate a cross-chain transfer with data after taking the appropriate amount of tokens from the user. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. @@ -135,11 +136,12 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen } /** - * @notice Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. + * @notice Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. * @param sender the address of the user paying for the cross chain transfer. * @param destinationChain the name of the chain to send tokens to. * @param destinationAddress the address of the user to send tokens to. * @param amount the amount of tokens to take from msg.sender. + * @param metadata any additional data to be sent with the transfer */ function transmitInterchainTransfer( address sender, @@ -164,7 +166,7 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen * @notice This function gives token to a specified address. Can only be called by the service. * @param destinationAddress the address to give tokens to. * @param amount the amount of token to give. - * @return the amount of token actually given, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. + * @return the amount of token actually given, which will only be different than `amount` in cases where the token takes some on-transfer fee. */ function giveToken(address destinationAddress, uint256 amount) external onlyService returns (uint256) { amount = _giveToken(destinationAddress, amount); @@ -192,11 +194,11 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen /** * @notice Transfers tokens from this contract to a specific address. * Must be overridden in the inheriting contract. - * @param from The address to which the tokens will be sent + * @param receiver The address to which the tokens will be sent * @param amount The amount of tokens to send * @return uint amount of tokens sent */ - function _giveToken(address from, uint256 amount) internal virtual returns (uint256); + function _giveToken(address receiver, uint256 amount) internal virtual returns (uint256); /** * @dev Additional setup logic to perform diff --git a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol b/contracts/token-manager/implementations/TokenManagerAddressStorage.sol index ad78f9c7..a7a1d32f 100644 --- a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol +++ b/contracts/token-manager/implementations/TokenManagerAddressStorage.sol @@ -12,15 +12,15 @@ import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contract * the token address using a predetermined storage slot */ abstract contract TokenManagerAddressStorage is TokenManager { + // uint256(keccak256('token-address')) - 1 + uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; + /** * @dev Creates an instance of the TokenManagerAddressStorage contract. * @param interchainTokenService_ The address of the interchain token service contract */ constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} - // uint256(keccak256('token-address')) - 1 - uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; - /** * @dev Reads the stored token address from the predetermined storage slot * @return tokenAddress_ The address of the token diff --git a/contracts/utils/Distributable.sol b/contracts/utils/Distributable.sol index 4f930f29..e179a3f7 100644 --- a/contracts/utils/Distributable.sol +++ b/contracts/utils/Distributable.sol @@ -18,7 +18,7 @@ contract Distributable is IDistributable { uint256 internal constant PROPOSED_DISTRIBUTOR_SLOT = 0xbb1aa7d30971a97896e14e460c5ace030e39b624cf8f7c1ce200eeb378d7dcf1; /** - * @dev Throws a NotDistributor custom eror if called by any account other than the distributor. + * @dev Throws a NotDistributor custom error if called by any account other than the distributor. */ modifier onlyDistributor() { if (distributor() != msg.sender) revert NotDistributor(); diff --git a/contracts/utils/FlowLimit.sol b/contracts/utils/FlowLimit.sol index 27afade9..8caa7cea 100644 --- a/contracts/utils/FlowLimit.sol +++ b/contracts/utils/FlowLimit.sol @@ -82,6 +82,7 @@ contract FlowLimit is IFlowLimit { /** * @dev Adds a flow amount while ensuring it does not exceed the flow limit + * @param flowLimit The current flow limit value * @param slotToAdd The slot to add the flow to * @param slotToCompare The slot to compare the flow against * @param flowAmount The flow amount to add diff --git a/docs/index.md b/docs/index.md index 3131a399..8a2abb47 100644 --- a/docs/index.md +++ b/docs/index.md @@ -105,19 +105,19 @@ bytes32 PREFIX_STANDARDIZED_TOKEN_SALT constructor(address tokenManagerDeployer_, address standardizedTokenDeployer_, address gateway_, address gasService_, address remoteAddressValidator_, address[] tokenManagerImplementations, string chainName_) public ``` -_All of the varaibles passed here are stored as immutable variables._ +_All of the variables passed here are stored as immutable variables._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenManagerDeployer_ | address | the address of the TokenManagerDeployer. | -| standardizedTokenDeployer_ | address | the address of the StandardizedTokenDeployer. | -| gateway_ | address | the address of the AxelarGateway. | -| gasService_ | address | the address of the AxelarGasService. | -| remoteAddressValidator_ | address | the address of the RemoteAddressValidator. | +| Name | Type | Description | +| --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------- | +| tokenManagerDeployer\_ | address | the address of the TokenManagerDeployer. | +| standardizedTokenDeployer\_ | address | the address of the StandardizedTokenDeployer. | +| gateway\_ | address | the address of the AxelarGateway. | +| gasService\_ | address | the address of the AxelarGasService. | +| remoteAddressValidator\_ | address | the address of the RemoteAddressValidator. | | tokenManagerImplementations | address[] | this need to have exactly 3 implementations in the following order: Lock/Unlock, mint/burn and then liquidity pool. | -| chainName_ | string | the name of the current chain. | +| chainName\_ | string | the name of the current chain. | ### onlyRemoteService @@ -125,13 +125,13 @@ _All of the varaibles passed here are stored as immutable variables._ modifier onlyRemoteService(string sourceChain, string sourceAddress) ``` -This modifier is used to ensure that only a remote InterchainTokenService can _execute this one. +This modifier is used to ensure that only a remote InterchainTokenService can \_execute this one. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | the source of the contract call. | +| Name | Type | Description | +| ------------- | ------ | ------------------------------------ | +| sourceChain | string | the source of the contract call. | | sourceAddress | string | the address that the call came from. | ### onlyTokenManager @@ -144,8 +144,8 @@ This modifier is used to ensure certain functions can only be called by TokenMan #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------------------------- | | tokenId | bytes32 | the `tokenId` of the TokenManager trying to perform the call. | ### contractId @@ -166,8 +166,8 @@ Getter for the chain name. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------ | --------------------- | | name | string | the name of the chain | ### getTokenManagerAddress @@ -180,15 +180,15 @@ Calculates the address of a TokenManager from a specific tokenId. The TokenManag #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------ | | tokenId | bytes32 | the tokenId. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenManagerAddress | address | deployement address of the TokenManager. | +| Name | Type | Description | +| ------------------- | ------- | --------------------------------------- | +| tokenManagerAddress | address | deployment address of the TokenManager. | ### getValidTokenManagerAddress @@ -200,14 +200,14 @@ Returns the address of a TokenManager from a specific tokenId. The TokenManager #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------ | | tokenId | bytes32 | the tokenId. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------- | ------- | --------------------------------------- | | tokenManagerAddress | address | deployment address of the TokenManager. | ### getTokenAddress @@ -220,14 +220,14 @@ Returns the address of the token that an existing tokenManager points to. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------ | | tokenId | bytes32 | the tokenId. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | | tokenAddress | address | the address of the token. | ### getStandardizedTokenAddress @@ -241,14 +241,14 @@ The token does not need to exist. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------ | | tokenId | bytes32 | the tokenId. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | -------------------------------------- | | tokenAddress | address | the address of the standardized token. | ### getCanonicalTokenId @@ -262,14 +262,14 @@ This will depend on what chain it is called from, unlike custom tokenIds. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | | tokenAddress | address | the address of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------------------------------------------------ | | tokenId | bytes32 | the tokenId that the canonical TokenManager would get (or has gotten) for the token. | ### getCustomTokenId @@ -283,15 +283,15 @@ This will not depend on what chain it is called from, unlike canonical tokenIds. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sender | address | the address of the TokenManager deployer. | -| salt | bytes32 | the salt that the deployer uses for the deployment. | +| Name | Type | Description | +| ------ | ------- | --------------------------------------------------- | +| sender | address | the address of the TokenManager deployer. | +| salt | bytes32 | the salt that the deployer uses for the deployment. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------------------------------- | | tokenId | bytes32 | the tokenId that the custom TokenManager would get (or has gotten). | ### getImplementation @@ -305,14 +305,14 @@ to figure out their implementations #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------------- | ------- | ----------------------------- | | tokenManagerType | uint256 | the type of the TokenManager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------- | ------- | ---------------------------------------------- | | tokenManagerAddress | address | the address of the TokenManagerImplementation. | ### getParamsLockUnlock @@ -325,15 +325,15 @@ Getter function for the parameters of a lock/unlock TokenManager. Mainly to be u #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | the operator of the TokenManager. | -| tokenAddress | address | the token to be managed. | +| Name | Type | Description | +| ------------ | ------- | --------------------------------- | +| operator | bytes | the operator of the TokenManager. | +| tokenAddress | address | the token to be managed. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | --------------------------------------------------------------------- | | params | bytes | the resulting params to be passed to custom TokenManager deployments. | ### getParamsMintBurn @@ -346,15 +346,15 @@ Getter function for the parameters of a mint/burn TokenManager. Mainly to be use #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | the operator of the TokenManager. | -| tokenAddress | address | the token to be managed. | +| Name | Type | Description | +| ------------ | ------- | --------------------------------- | +| operator | bytes | the operator of the TokenManager. | +| tokenAddress | address | the token to be managed. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | --------------------------------------------------------------------- | | params | bytes | the resulting params to be passed to custom TokenManager deployments. | ### getParamsLiquidityPool @@ -367,16 +367,16 @@ Getter function for the parameters of a liquidity pool TokenManager. Mainly to b #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | the operator of the TokenManager. | -| tokenAddress | address | the token to be managed. | +| Name | Type | Description | +| -------------------- | ------- | ---------------------------------------------------------- | +| operator | bytes | the operator of the TokenManager. | +| tokenAddress | address | the token to be managed. | | liquidityPoolAddress | address | the liquidity pool to be used to store the bridged tokens. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | --------------------------------------------------------------------- | | params | bytes | the resulting params to be passed to custom TokenManager deployments. | ### getFlowLimit @@ -389,14 +389,14 @@ Getter function for the flow limit of an existing token manager with a give toke #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | the token ID of the TokenManager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | --------------- | | flowLimit | uint256 | the flow limit. | ### getFlowOutAmount @@ -409,14 +409,14 @@ Getter function for the flow out amount of an existing token manager with a give #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | the token ID of the TokenManager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | -------------------- | | flowOutAmount | uint256 | the flow out amount. | ### getFlowInAmount @@ -429,14 +429,14 @@ Getter function for the flow in amount of an existing token manager with a give #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | the token ID of the TokenManager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------- | | flowInAmount | uint256 | the flow in amount. | ### registerCanonicalToken @@ -449,14 +449,14 @@ Used to register canonical tokens. Caller does not matter. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------ | | tokenAddress | address | the token to be bridged. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------------------------- | | tokenId | bytes32 | the tokenId that was used for this canonical token. | ### deployRemoteCanonicalToken @@ -472,11 +472,11 @@ _`gasValue` exists because this function can be part of a multicall involving mu #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the canonical token. | -| destinationChain | string | the name of the chain to deploy the TokenManager and standardized token to. | -| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | +| Name | Type | Description | +| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| tokenId | bytes32 | the tokenId of the canonical token. | +| destinationChain | string | the name of the chain to deploy the TokenManager and standardized token to. | +| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | ### deployCustomTokenManager @@ -488,11 +488,11 @@ Used to deploy custom TokenManagers with the specified salt. Different callers w #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | the salt to be used. | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | the type of TokenManager to be deployed. | -| params | bytes | the params that will be used to initialize the TokenManager. | +| Name | Type | Description | +| ---------------- | --------------------------------------- | ------------------------------------------------------------ | +| salt | bytes32 | the salt to be used. | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | the type of TokenManager to be deployed. | +| params | bytes | the params that will be used to initialize the TokenManager. | ### deployRemoteCustomTokenManager @@ -507,13 +507,13 @@ that could make remote contract calls._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | the salt to be used. | -| destinationChain | string | the name of the chain to deploy the TokenManager and standardized token to. | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | the type of TokenManager to be deployed. | -| params | bytes | the params that will be used to initialize the TokenManager. | -| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | +| Name | Type | Description | +| ---------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| salt | bytes32 | the salt to be used. | +| destinationChain | string | the name of the chain to deploy the TokenManager and standardized token to. | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | the type of TokenManager to be deployed. | +| params | bytes | the params that will be used to initialize the TokenManager. | +| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | ### deployAndRegisterStandardizedToken @@ -522,17 +522,17 @@ function deployAndRegisterStandardizedToken(bytes32 salt, string name, string sy ``` Used to deploy a standardized token alongside a TokenManager. If the `distributor` is the address of the TokenManager (which -can be calculated ahead of time) then a mint/burn TokenManager is used. Otherwise a lock/unlcok TokenManager is used. +can be calculated ahead of time) then a mint/burn TokenManager is used. Otherwise a lock/unlock TokenManager is used. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | the salt to be used. | -| name | string | the name of the token to be deployed. | -| symbol | string | the symbol of the token to be deployed. | -| decimals | uint8 | the decimals of the token to be deployed. | -| mintAmount | uint256 | the amount of token to be mint during deployment to msg.sender. | +| Name | Type | Description | +| ----------- | ------- | ------------------------------------------------------------------ | +| salt | bytes32 | the salt to be used. | +| name | string | the name of the token to be deployed. | +| symbol | string | the symbol of the token to be deployed. | +| decimals | uint8 | the decimals of the token to be deployed. | +| mintAmount | uint256 | the amount of token to be mint during deployment to msg.sender. | | distributor | address | the address that will be able to mint and burn the deployed token. | ### deployAndRegisterRemoteStandardizedToken @@ -542,22 +542,22 @@ function deployAndRegisterRemoteStandardizedToken(bytes32 salt, string name, str ``` Used to deploy a standardized token alongside a TokenManager in another chain. If the `distributor` is empty -bytes then a mint/burn TokenManager is used. Otherwise a lock/unlcok TokenManager is used. +bytes then a mint/burn TokenManager is used. Otherwise a lock/unlock TokenManager is used. _`gasValue` exists because this function can be part of a multicall involving multiple functions that could make remote contract calls._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | the salt to be used. | -| name | string | the name of the token to be deployed. | -| symbol | string | the symbol of the token to be deployed. | -| decimals | uint8 | the decimals of the token to be deployed. | -| distributor | bytes | the address that will be able to mint and burn the deployed token. | -| operator | bytes | | -| destinationChain | string | the name of the destination chain to deploy to. | -| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | +| Name | Type | Description | +| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| salt | bytes32 | the salt to be used. | +| name | string | the name of the token to be deployed. | +| symbol | string | the symbol of the token to be deployed. | +| decimals | uint8 | the decimals of the token to be deployed. | +| distributor | bytes | the address that will be able to mint and burn the deployed token. | +| operator | bytes | | +| destinationChain | string | the name of the destination chain to deploy to. | +| gasValue | uint256 | the amount of native tokens to be used to pay for gas for the remote deployment. At least the amount specified needs to be passed to the call | ### expressReceiveToken @@ -570,12 +570,12 @@ sendToken that matches the parameters passed here. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the TokenManager used. | +| Name | Type | Description | +| ------------------ | ------- | ----------------------------------------- | +| tokenId | bytes32 | the tokenId of the TokenManager used. | | destinationAddress | address | the destinationAddress for the sendToken. | -| amount | uint256 | the amount of token to give. | -| commandId | bytes32 | the sendHash detected at the sourceChain. | +| amount | uint256 | the amount of token to give. | +| commandId | bytes32 | the sendHash detected at the sourceChain. | ### expressReceiveTokenWithData @@ -588,15 +588,15 @@ detected an outgoing sendToken that matches the parameters passed here. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the TokenManager used. | -| sourceChain | string | the name of the chain where the call came from. | -| sourceAddress | bytes | the caller of callContractWithInterchainToken. | -| destinationAddress | address | the destinationAddress for the sendToken. | -| amount | uint256 | the amount of token to give. | -| data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | -| commandId | bytes32 | the sendHash detected at the sourceChain. | +| Name | Type | Description | +| ------------------ | ------- | ----------------------------------------------------------------------------------- | +| tokenId | bytes32 | the tokenId of the TokenManager used. | +| sourceChain | string | the name of the chain where the call came from. | +| sourceAddress | bytes | the caller of callContractWithInterchainToken. | +| destinationAddress | address | the destinationAddress for the sendToken. | +| amount | uint256 | the amount of token to give. | +| data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | +| commandId | bytes32 | the sendHash detected at the sourceChain. | ### transmitSendToken @@ -608,14 +608,14 @@ Transmit a sendTokenWithData for the given tokenId. Only callable by a token man #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the TokenManager (which must be the msg.sender). | -| sourceAddress | address | the address where the token is coming from, which will also be used for reimburment of gas. | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the destinationAddress for the sendToken. | -| amount | uint256 | the amount of token to give. | -| metadata | bytes | the data to be passed to the destiantion. | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------------------------------------------------------------- | +| tokenId | bytes32 | the tokenId of the TokenManager (which must be the msg.sender). | +| sourceAddress | address | the address where the token is coming from, which will also be used for reimbursement of gas. | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the destinationAddress for the sendToken. | +| amount | uint256 | the amount of token to give. | +| metadata | bytes | the data to be passed to the destination. | ### setFlowLimit @@ -627,10 +627,10 @@ Used to set a flow limit for a token manager that has the service as its operato #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenIds | bytes32[] | an array of the token Ids of the tokenManagers to set the flow limit of. | -| flowLimits | uint256[] | the flowLimits to set | +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------------------------------------ | +| tokenIds | bytes32[] | an array of the token Ids of the tokenManagers to set the flow limit of. | +| flowLimits | uint256[] | the flowLimits to set | ### setPaused @@ -642,23 +642,23 @@ Used to pause the entire service. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ---- | ---------------------------- | | paused | bool | what value to set paused to. | -### _setup +### \_setup ```solidity function _setup(bytes params) internal ``` -### _sanitizeTokenManagerImplementation +### \_sanitizeTokenManagerImplementation ```solidity -function _sanitizeTokenManagerImplementation(address[] implementaions, enum ITokenManagerType.TokenManagerType tokenManagerType) internal pure returns (address implementation) +function _sanitizeTokenManagerImplementation(address[] implementations, enum ITokenManagerType.TokenManagerType tokenManagerType) internal pure returns (address implementation) ``` -### _execute +### \_execute ```solidity function _execute(string sourceChain, string sourceAddress, bytes payload) internal @@ -668,13 +668,13 @@ Executes operations based on the payload and selector. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | The chain where the transaction originates from | +| Name | Type | Description | +| ------------- | ------ | ------------------------------------------------- | +| sourceChain | string | The chain where the transaction originates from | | sourceAddress | string | The address where the transaction originates from | -| payload | bytes | The encoded data payload for the transaction | +| payload | bytes | The encoded data payload for the transaction | -### _processSendTokenPayload +### \_processSendTokenPayload ```solidity function _processSendTokenPayload(string sourceChain, bytes payload) internal @@ -684,12 +684,12 @@ Processes the payload data for a send token call #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------ | ----------------------------------------------- | | sourceChain | string | The chain where the transaction originates from | -| payload | bytes | The encoded data payload to be processed | +| payload | bytes | The encoded data payload to be processed | -### _processSendTokenWithDataPayload +### \_processSendTokenWithDataPayload ```solidity function _processSendTokenWithDataPayload(string sourceChain, bytes payload) internal @@ -699,12 +699,12 @@ Processes a send token with data payload. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------ | ----------------------------------------------- | | sourceChain | string | The chain where the transaction originates from | -| payload | bytes | The encoded data payload to be processed | +| payload | bytes | The encoded data payload to be processed | -### _processDeployTokenManagerPayload +### \_processDeployTokenManagerPayload ```solidity function _processDeployTokenManagerPayload(bytes payload) internal @@ -714,11 +714,11 @@ Processes a deploy token manager payload. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ----- | ---------------------------------------- | | payload | bytes | The encoded data payload to be processed | -### _processDeployStandardizedTokenAndManagerPayload +### \_processDeployStandardizedTokenAndManagerPayload ```solidity function _processDeployStandardizedTokenAndManagerPayload(bytes payload) internal @@ -728,11 +728,11 @@ Process a deploy standardized token and manager payload. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ----- | ---------------------------------------- | | payload | bytes | The encoded data payload to be processed | -### _callContract +### \_callContract ```solidity function _callContract(string destinationChain, bytes payload, uint256 gasValue, address refundTo) internal @@ -742,20 +742,20 @@ Calls a contract on a specific destination chain with the given payload #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | The target chain where the contract will be called | -| payload | bytes | The data payload for the transaction | -| gasValue | uint256 | The amount of gas to be paid for the transaction | -| refundTo | address | The address where the unused gas amount should be refunded to | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------------- | +| destinationChain | string | The target chain where the contract will be called | +| payload | bytes | The data payload for the transaction | +| gasValue | uint256 | The amount of gas to be paid for the transaction | +| refundTo | address | The address where the unused gas amount should be refunded to | -### _validateToken +### \_validateToken ```solidity function _validateToken(address tokenAddress) internal returns (string name, string symbol, uint8 decimals) ``` -### _deployRemoteTokenManager +### \_deployRemoteTokenManager ```solidity function _deployRemoteTokenManager(bytes32 tokenId, string destinationChain, uint256 gasValue, enum ITokenManagerType.TokenManagerType tokenManagerType, bytes params) internal @@ -765,15 +765,15 @@ Deploys a token manager on a destination chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token | -| destinationChain | string | The chain where the token manager will be deployed | -| gasValue | uint256 | The amount of gas to be paid for the transaction | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager to be deployed | -| params | bytes | Additional parameters for the token manager deployment | +| Name | Type | Description | +| ---------------- | --------------------------------------- | ------------------------------------------------------ | +| tokenId | bytes32 | The ID of the token | +| destinationChain | string | The chain where the token manager will be deployed | +| gasValue | uint256 | The amount of gas to be paid for the transaction | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager to be deployed | +| params | bytes | Additional parameters for the token manager deployment | -### _deployRemoteStandardizedToken +### \_deployRemoteStandardizedToken ```solidity function _deployRemoteStandardizedToken(bytes32 tokenId, string name, string symbol, uint8 decimals, bytes distributor, bytes operator, string destinationChain, uint256 gasValue) internal @@ -783,18 +783,18 @@ Deploys a standardized token on a destination chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token | -| name | string | The name of the token | -| symbol | string | The symbol of the token | -| decimals | uint8 | The number of decimals of the token | -| distributor | bytes | The distributor address for the token | -| operator | bytes | | -| destinationChain | string | The destination chain where the token will be deployed | -| gasValue | uint256 | The amount of gas to be paid for the transaction | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------ | +| tokenId | bytes32 | The ID of the token | +| name | string | The name of the token | +| symbol | string | The symbol of the token | +| decimals | uint8 | The number of decimals of the token | +| distributor | bytes | The distributor address for the token | +| operator | bytes | | +| destinationChain | string | The destination chain where the token will be deployed | +| gasValue | uint256 | The amount of gas to be paid for the transaction | -### _deployTokenManager +### \_deployTokenManager ```solidity function _deployTokenManager(bytes32 tokenId, enum ITokenManagerType.TokenManagerType tokenManagerType, bytes params) internal @@ -804,13 +804,13 @@ Deploys a token manager #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of the token manager to be deployed | -| params | bytes | Additional parameters for the token manager deployment | +| Name | Type | Description | +| ---------------- | --------------------------------------- | ------------------------------------------------------ | +| tokenId | bytes32 | The ID of the token | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of the token manager to be deployed | +| params | bytes | Additional parameters for the token manager deployment | -### _getStandardizedTokenSalt +### \_getStandardizedTokenSalt ```solidity function _getStandardizedTokenSalt(bytes32 tokenId) internal pure returns (bytes32 salt) @@ -820,17 +820,17 @@ Compute the salt for a standardized token deployment. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------- | | tokenId | bytes32 | The ID of the token | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ------------------------------------------ | | salt | bytes32 | The computed salt for the token deployment | -### _deployStandardizedToken +### \_deployStandardizedToken ```solidity function _deployStandardizedToken(bytes32 tokenId, address distributor, string name, string symbol, uint8 decimals, uint256 mintAmount, address mintTo) internal @@ -840,23 +840,23 @@ Deploys a standardized token. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token | -| distributor | address | The distributor address for the token | -| name | string | The name of the token | -| symbol | string | The symbol of the token | -| decimals | uint8 | The number of decimals of the token | -| mintAmount | uint256 | The amount of tokens to be minted upon deployment | -| mintTo | address | The address where the minted tokens will be sent upon deployment | +| Name | Type | Description | +| ----------- | ------- | ---------------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token | +| distributor | address | The distributor address for the token | +| name | string | The name of the token | +| symbol | string | The symbol of the token | +| decimals | uint8 | The number of decimals of the token | +| mintAmount | uint256 | The amount of tokens to be minted upon deployment | +| mintTo | address | The address where the minted tokens will be sent upon deployment | -### _decodeMetadata +### \_decodeMetadata ```solidity function _decodeMetadata(bytes metadata) internal pure returns (uint32 version, bytes data) ``` -### _expressExecuteWithInterchainTokenToken +### \_expressExecuteWithInterchainTokenToken ```solidity function _expressExecuteWithInterchainTokenToken(bytes32 tokenId, address destinationAddress, string sourceChain, bytes sourceAddress, bytes data, uint256 amount) internal @@ -938,17 +938,17 @@ Gets the address of the express caller for a specific token transfer #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| destinationAddress | address | The address of the recipient | -| amount | uint256 | The amount of tokens to be sent | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| destinationAddress | address | The address of the recipient | +| amount | uint256 | The amount of tokens to be sent | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | ### getExpressReceiveTokenWithData @@ -961,20 +961,20 @@ Gets the address of the express caller for a specific token transfer with data #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| sourceChain | string | The chain from which the token will be sent | -| sourceAddress | bytes | The originating address of the token on the source chain | -| destinationAddress | address | The address of the recipient on the destination chain | -| amount | uint256 | The amount of tokens to be sent | -| data | bytes | The data associated with the token transfer | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | -------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| sourceChain | string | The chain from which the token will be sent | +| sourceAddress | bytes | The originating address of the token on the source chain | +| destinationAddress | address | The address of the recipient on the destination chain | +| amount | uint256 | The amount of tokens to be sent | +| data | bytes | The data associated with the token transfer | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | ## IFlowLimit @@ -1001,8 +1001,8 @@ Returns the current flow limit #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | ---------------------------- | | flowLimit | uint256 | The current flow limit value | ### getFlowOutAmount @@ -1015,8 +1015,8 @@ Returns the current flow out amount #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------- | | flowOutAmount | uint256 | The current flow out amount | ### getFlowInAmount @@ -1029,8 +1029,8 @@ Returns the current flow in amount #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | -------------------------- | | flowInAmount | uint256 | The current flow in amount | ## IImplementation @@ -1057,13 +1057,13 @@ _You are revert unless the msg.sender is the InterchainTokenService_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | the name of the source chain | -| sourceAddress | bytes | the address that sent the contract call | -| data | bytes | the data to be proccessed | -| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querrying the service | -| amount | uint256 | the amount of token that was sent | +| Name | Type | Description | +| ------------- | ------- | -------------------------------------------------------------------------------------------------------- | +| sourceChain | string | the name of the source chain | +| sourceAddress | bytes | the address that sent the contract call | +| data | bytes | the data to be proccessed | +| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querying the service | +| amount | uint256 | the amount of token that was sent | ## IInterchainTokenExpressExecutable @@ -1081,13 +1081,13 @@ _You are revert unless the msg.sender is the InterchainTokenService_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | the name of the source chain | -| sourceAddress | bytes | the address that sent the contract call | -| data | bytes | the data to be proccessed | -| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querrying the service | -| amount | uint256 | the amount of token that was sent | +| Name | Type | Description | +| ------------- | ------- | -------------------------------------------------------------------------------------------------------- | +| sourceChain | string | the name of the source chain | +| sourceAddress | bytes | the address that sent the contract call | +| data | bytes | the data to be proccessed | +| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querying the service | +| amount | uint256 | the amount of token that was sent | ## IInterchainTokenService @@ -1245,8 +1245,8 @@ Returns the address of the token manager deployer contract. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------------------------- | ------- | --------------------------------------------------- | | tokenManagerDeployerAddress | address | The address of the token manager deployer contract. | ### standardizedTokenDeployer @@ -1259,8 +1259,8 @@ Returns the address of the standardized token deployer contract. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| -------------------------------- | ------- | -------------------------------------------------------- | | standardizedTokenDeployerAddress | address | The address of the standardized token deployer contract. | ### getChainName @@ -1273,8 +1273,8 @@ Returns the name of the current chain. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------ | ------------------------------ | | name | string | The name of the current chain. | ### getTokenManagerAddress @@ -1287,14 +1287,14 @@ Returns the address of the token manager associated with the given tokenId. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | The tokenId of the token manager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------- | ------- | --------------------------------- | | tokenManagerAddress | address | The address of the token manager. | ### getValidTokenManagerAddress @@ -1307,14 +1307,14 @@ Returns the address of the valid token manager associated with the given tokenId #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | The tokenId of the token manager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------- | ------- | --------------------------------------- | | tokenManagerAddress | address | The address of the valid token manager. | ### getTokenAddress @@ -1327,14 +1327,14 @@ Returns the address of the token associated with the given tokenId. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------- | | tokenId | bytes32 | The tokenId of the token manager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | | tokenAddress | address | The address of the token. | ### getStandardizedTokenAddress @@ -1347,14 +1347,14 @@ Returns the address of the standardized token associated with the given tokenId. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | -------------------------------------- | | tokenId | bytes32 | The tokenId of the standardized token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | -------------------------------------- | | tokenAddress | address | The address of the standardized token. | ### getCanonicalTokenId @@ -1367,14 +1367,14 @@ Returns the canonical tokenId associated with the given tokenAddress. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | | tokenAddress | address | The address of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------------------- | | tokenId | bytes32 | The canonical tokenId associated with the tokenAddress. | ### getCustomTokenId @@ -1387,15 +1387,15 @@ Returns the custom tokenId associated with the given operator and salt. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | address | The operator address. | -| salt | bytes32 | The salt used for token id calculation. | +| Name | Type | Description | +| -------- | ------- | --------------------------------------- | +| operator | address | The operator address. | +| salt | bytes32 | The salt used for token id calculation. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------------------------------- | | tokenId | bytes32 | The custom tokenId associated with the operator and salt. | ### getParamsLockUnlock @@ -1408,15 +1408,15 @@ Returns the parameters for the lock/unlock operation. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | The operator address. | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | +| operator | bytes | The operator address. | | tokenAddress | address | The address of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | --------------------------------------------- | | params | bytes | The parameters for the lock/unlock operation. | ### getParamsMintBurn @@ -1429,15 +1429,15 @@ Returns the parameters for the mint/burn operation. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | The operator address. | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | +| operator | bytes | The operator address. | | tokenAddress | address | The address of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------- | | params | bytes | The parameters for the mint/burn operation. | ### getParamsLiquidityPool @@ -1450,16 +1450,16 @@ Returns the parameters for the liquidity pool operation. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator | bytes | The operator address. | -| tokenAddress | address | The address of the token. | +| Name | Type | Description | +| -------------------- | ------- | ---------------------------------- | +| operator | bytes | The operator address. | +| tokenAddress | address | The address of the token. | | liquidityPoolAddress | address | The address of the liquidity pool. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------------ | | params | bytes | The parameters for the liquidity pool operation. | ### registerCanonicalToken @@ -1472,14 +1472,14 @@ Registers a canonical token and returns its associated tokenId. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ----------------------------------- | | tokenAddress | address | The address of the canonical token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ----------------------------------------------------------- | | tokenId | bytes32 | The tokenId associated with the registered canonical token. | ### deployRemoteCanonicalToken @@ -1492,11 +1492,11 @@ Deploys a standardized canonical token on a remote chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The tokenId of the canonical token. | -| destinationChain | string | The name of the destination chain. | -| gasValue | uint256 | The gas value for deployment. | +| Name | Type | Description | +| ---------------- | ------- | ----------------------------------- | +| tokenId | bytes32 | The tokenId of the canonical token. | +| destinationChain | string | The name of the destination chain. | +| gasValue | uint256 | The gas value for deployment. | ### deployCustomTokenManager @@ -1508,16 +1508,16 @@ Deploys a custom token manager contract. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used for token manager deployment. | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager. | -| params | bytes | The deployment parameters. | +| Name | Type | Description | +| ---------------- | --------------------------------------- | ------------------------------------------- | +| salt | bytes32 | The salt used for token manager deployment. | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager. | +| params | bytes | The deployment parameters. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------ | | tokenId | bytes32 | The tokenId of the deployed token manager. | ### deployRemoteCustomTokenManager @@ -1530,13 +1530,13 @@ Deploys a custom token manager contract on a remote chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used for token manager deployment. | -| destinationChain | string | The name of the destination chain. | -| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager. | -| params | bytes | The deployment parameters. | -| gasValue | uint256 | The gas value for deployment. | +| Name | Type | Description | +| ---------------- | --------------------------------------- | ------------------------------------------- | +| salt | bytes32 | The salt used for token manager deployment. | +| destinationChain | string | The name of the destination chain. | +| tokenManagerType | enum ITokenManagerType.TokenManagerType | The type of token manager. | +| params | bytes | The deployment parameters. | +| gasValue | uint256 | The gas value for deployment. | ### deployAndRegisterStandardizedToken @@ -1548,13 +1548,13 @@ Deploys a standardized token and registers it. The token manager type will be lo #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used for token deployment. | -| name | string | The name of the standardized token. | -| symbol | string | The symbol of the standardized token. | -| decimals | uint8 | The number of decimals for the standardized token. | -| mintAmount | uint256 | The amount of tokens to mint to the deployer. | +| Name | Type | Description | +| ----------- | ------- | -------------------------------------------------------- | +| salt | bytes32 | The salt used for token deployment. | +| name | string | The name of the standardized token. | +| symbol | string | The symbol of the standardized token. | +| decimals | uint8 | The number of decimals for the standardized token. | +| mintAmount | uint256 | The amount of tokens to mint to the deployer. | | distributor | address | The address of the distributor for mint/burn operations. | ### deployAndRegisterRemoteStandardizedToken @@ -1567,16 +1567,16 @@ Deploys and registers a standardized token on a remote chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used for token deployment. | -| name | string | The name of the standardized tokens. | -| symbol | string | The symbol of the standardized tokens. | -| decimals | uint8 | The number of decimals for the standardized tokens. | -| distributor | bytes | The distributor data for mint/burn operations. | -| operator | bytes | The operator data for standardized tokens. | -| destinationChain | string | The name of the destination chain. | -| gasValue | uint256 | The gas value for deployment. | +| Name | Type | Description | +| ---------------- | ------- | --------------------------------------------------- | +| salt | bytes32 | The salt used for token deployment. | +| name | string | The name of the standardized tokens. | +| symbol | string | The symbol of the standardized tokens. | +| decimals | uint8 | The number of decimals for the standardized tokens. | +| distributor | bytes | The distributor data for mint/burn operations. | +| operator | bytes | The operator data for standardized tokens. | +| destinationChain | string | The name of the destination chain. | +| gasValue | uint256 | The gas value for deployment. | ### getImplementation @@ -1588,14 +1588,14 @@ Returns the implementation address for a given token manager type. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------------- | ------- | -------------------------- | | tokenManagerType | uint256 | The type of token manager. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------- | ------- | ------------------------------------------------ | | tokenManagerAddress | address | The address of the token manager implementation. | ### transmitSendToken @@ -1608,14 +1608,14 @@ Initiates an interchain token transfer. Only callable by TokenManagers #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The tokenId of the token to be transmitted. | -| sourceAddress | address | The source address of the token. | -| destinationChain | string | The name of the destination chain. | -| destinationAddress | bytes | The destination address on the destination chain. | -| amount | uint256 | The amount of tokens to transmit. | -| metadata | bytes | The metadata associated with the transmission. | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------------------------- | +| tokenId | bytes32 | The tokenId of the token to be transmitted. | +| sourceAddress | address | The source address of the token. | +| destinationChain | string | The name of the destination chain. | +| destinationAddress | bytes | The destination address on the destination chain. | +| amount | uint256 | The amount of tokens to transmit. | +| metadata | bytes | The metadata associated with the transmission. | ### setFlowLimit @@ -1627,9 +1627,9 @@ Sets the flow limits for multiple tokens. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenIds | bytes32[] | An array of tokenIds. | +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------------------ | +| tokenIds | bytes32[] | An array of tokenIds. | | flowLimits | uint256[] | An array of flow limits corresponding to the tokenIds. | ### getFlowLimit @@ -1642,14 +1642,14 @@ Returns the flow limit for a specific token. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------- | | tokenId | bytes32 | The tokenId of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | ----------------------------- | | flowLimit | uint256 | The flow limit for the token. | ### getFlowOutAmount @@ -1662,14 +1662,14 @@ Returns the total amount of outgoing flow for a specific token. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------- | | tokenId | bytes32 | The tokenId of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | ------------------------------------------------ | | flowOutAmount | uint256 | The total amount of outgoing flow for the token. | ### getFlowInAmount @@ -1682,14 +1682,14 @@ Returns the total amount of incoming flow for a specific token. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------- | | tokenId | bytes32 | The tokenId of the token. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------------------------------ | | flowInAmount | uint256 | The total amount of incoming flow for the token. | ### setPaused @@ -1702,8 +1702,8 @@ Sets the paused state of the contract. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ---- | ------------------------------------------------------------------- | | paused | bool | The boolean value indicating whether the contract is paused or not. | ### expressReceiveToken @@ -1716,12 +1716,12 @@ Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the TokenManager used. | -| destinationAddress | address | the destinationAddress for the sendToken. | -| amount | uint256 | the amount of token to give. | -| commandId | bytes32 | the commandId calculated from the event at the sourceChain. | +| Name | Type | Description | +| ------------------ | ------- | ----------------------------------------------------------- | +| tokenId | bytes32 | the tokenId of the TokenManager used. | +| destinationAddress | address | the destinationAddress for the sendToken. | +| amount | uint256 | the amount of token to give. | +| commandId | bytes32 | the commandId calculated from the event at the sourceChain. | ### expressReceiveTokenWithData @@ -1733,15 +1733,15 @@ Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | the tokenId of the TokenManager used. | -| sourceChain | string | the name of the chain where the call came from. | -| sourceAddress | bytes | the caller of callContractWithInterchainToken. | -| destinationAddress | address | the destinationAddress for the sendToken. | -| amount | uint256 | the amount of token to give. | -| data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | -| commandId | bytes32 | the commandId calculated from the event at the sourceChain. | +| Name | Type | Description | +| ------------------ | ------- | ----------------------------------------------------------------------------------- | +| tokenId | bytes32 | the tokenId of the TokenManager used. | +| sourceChain | string | the name of the chain where the call came from. | +| sourceAddress | bytes | the caller of callContractWithInterchainToken. | +| destinationAddress | address | the destinationAddress for the sendToken. | +| amount | uint256 | the amount of token to give. | +| data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | +| commandId | bytes32 | the commandId calculated from the event at the sourceChain. | ## IMulticall @@ -1761,14 +1761,14 @@ If any of the calls fail, the function will revert with the failure message._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ---------------------------------- | | data | bytes[] | An array of encoded function calls | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------------------------------- | | results | bytes[] | An bytes array with the return data of each function call | ## IOperatable @@ -1795,9 +1795,9 @@ Get the address of the operator #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator_ | address | of the operator | +| Name | Type | Description | +| ---------- | ------- | --------------- | +| operator\_ | address | of the operator | ### transferOperatorship @@ -1811,9 +1811,9 @@ _Can only be called by the current operator_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator_ | address | The address of the new operator | +| Name | Type | Description | +| ---------- | ------- | ------------------------------- | +| operator\_ | address | The address of the new operator | ## IPausable @@ -1842,9 +1842,9 @@ Check if the contract is paused #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | paused A boolean representing the pause status. True if paused, false otherwise. | +| Name | Type | Description | +| ---- | ---- | -------------------------------------------------------------------------------- | +| [0] | bool | paused A boolean representing the pause status. True if paused, false otherwise. | ## IRemoteAddressValidator @@ -1871,13 +1871,13 @@ error ZeroStringLength() ### TrustedAddressAdded ```solidity -event TrustedAddressAdded(string souceChain, string sourceAddress) +event TrustedAddressAdded(string sourceChain, string sourceAddress) ``` ### TrustedAddressRemoved ```solidity -event TrustedAddressRemoved(string souceChain) +event TrustedAddressRemoved(string sourceChain) ``` ### GatewaySupportedChainAdded @@ -1902,16 +1902,16 @@ _Validates that the sender is a valid interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | Source chain of the transaction | +| Name | Type | Description | +| ------------- | ------ | --------------------------------- | +| sourceChain | string | Source chain of the transaction | | sourceAddress | string | Source address of the transaction | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | bool true if the sender is validated, false otherwise | +| Name | Type | Description | +| ---- | ---- | ----------------------------------------------------- | +| [0] | bool | bool true if the sender is validated, false otherwise | ### addTrustedAddress @@ -1923,9 +1923,9 @@ _Adds a trusted interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | Chain name of the interchain token service | +| Name | Type | Description | +| ------------- | ------ | -------------------------------------------- | +| sourceChain | string | Chain name of the interchain token service | | sourceAddress | string | Interchain token service address to be added | ### removeTrustedAddress @@ -1938,8 +1938,8 @@ _Removes a trusted interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------ | -------------------------------------------------------- | | sourceChain | string | Chain name of the interchain token service to be removed | ### getRemoteAddress @@ -1952,14 +1952,14 @@ _Fetches the interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------ | ----------------- | | chainName | string | Name of the chain | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------ | -------------------------------------------------------- | | remoteAddress | string | Interchain token service address for the specified chain | ### supportedByGateway @@ -1972,8 +1972,8 @@ Returns true if the gateway delivers token to this chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------ | ----------------- | | chainName | string | Name of the chain | ### addGatewaySupportedChains @@ -1986,8 +1986,8 @@ _Adds chains that are supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | -------------------------------------------- | | chainNames | string[] | List of chain names to be added as supported | ### removeGatewaySupportedChains @@ -2000,8 +2000,8 @@ _Removes chains that are no longer supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | ---------------------------------------------- | | chainNames | string[] | List of chain names to be removed as supported | ## IStandardizedTokenDeployer @@ -2038,16 +2038,16 @@ Deploys a new instance of the StandardizedTokenProxy contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used by Create3Deployer | -| tokenManager | address | Address of the token manager | -| distributor | address | Address of the distributor | -| name | string | Name of the token | -| symbol | string | Symbol of the token | -| decimals | uint8 | Decimals of the token | -| mintAmount | uint256 | Amount of tokens to mint initially | -| mintTo | address | Address to mint initial tokens to | +| Name | Type | Description | +| ------------ | ------- | ---------------------------------- | +| salt | bytes32 | The salt used by Create3Deployer | +| tokenManager | address | Address of the token manager | +| distributor | address | Address of the distributor | +| name | string | Name of the token | +| symbol | string | Symbol of the token | +| decimals | uint8 | Decimals of the token | +| mintAmount | uint256 | Amount of tokens to mint initially | +| mintTo | address | Address to mint initial tokens to | ## ITokenManager @@ -2094,9 +2094,9 @@ Must be overridden in the inheriting contract. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | address | address address of the token. | +| Name | Type | Description | +| ---- | ------- | ----------------------------- | +| [0] | address | address address of the token. | ### implementationType @@ -2112,16 +2112,16 @@ A function that should return the implementation type of the token manager. function sendToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable ``` -Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. +Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| metadata | bytes | | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------------- | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| metadata | bytes | | ### callContractWithInterchainToken @@ -2129,16 +2129,16 @@ Calls the service to initiate the a cross-chain transfer after taking the approp function callContractWithInterchainToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes data) external payable ``` -Calls the service to initiate the a cross-chain transfer with data after taking the appropriate amount of tokens from the user. +Calls the service to initiate a cross-chain transfer with data after taking the appropriate amount of tokens from the user. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| data | bytes | the data to pass to the destination contract. | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------------- | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| data | bytes | the data to pass to the destination contract. | ### transmitInterchainTransfer @@ -2146,17 +2146,17 @@ Calls the service to initiate the a cross-chain transfer with data after taking function transmitInterchainTransfer(address sender, string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable ``` -Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. +Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sender | address | the address of the user paying for the cross chain transfer. | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| metadata | bytes | | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------------------------------------ | +| sender | address | the address of the user paying for the cross chain transfer. | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| metadata | bytes | | ### giveToken @@ -2168,16 +2168,16 @@ This function gives token to a specified address. Can only be called by the serv #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------ | | destinationAddress | address | the address to give tokens to. | -| amount | uint256 | the amount of token to give. | +| amount | uint256 | the amount of token to give. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | the amount of token actually given, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. | +| Name | Type | Description | +| ---- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| [0] | uint256 | the amount of token actually given, which will only be different than `amount` in cases where the token takes some on-transfer fee. | ### setFlowLimit @@ -2189,8 +2189,8 @@ This function sets the flow limit for this TokenManager. Can only be called by t #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | -------------------------------------------------------------------------------------------------- | | flowLimit | uint256 | the maximum difference between the tokens flowing in and/or out at any given interval of time (6h) | ## ITokenManagerDeployer @@ -2227,11 +2227,11 @@ Deploys a new instance of the TokenManagerProxy contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The unique identifier for the token | -| implementationType | uint256 | Token manager implementation type | -| params | bytes | Additional parameters used in the setup of the token manager | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------------------------------------ | +| tokenId | bytes32 | The unique identifier for the token | +| implementationType | uint256 | Token manager implementation type | +| params | bytes | Additional parameters used in the setup of the token manager | ## ITokenManagerProxy @@ -2268,9 +2268,9 @@ Returns the address of the current implementation. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | address | impl The address of the current implementation | +| Name | Type | Description | +| ---- | ------- | ---------------------------------------------- | +| [0] | address | impl The address of the current implementation | ### tokenId @@ -2288,9 +2288,9 @@ A simple interface that defines all the token manager types ```solidity enum TokenManagerType { - LOCK_UNLOCK, - MINT_BURN, - LIQUIDITY_POOL + LOCK_UNLOCK, + MINT_BURN, + LIQUIDITY_POOL } ``` @@ -2314,14 +2314,14 @@ _Converts a bytes address to an address type._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ----- | -------------------------------------- | | bytesAddress | bytes | The bytes representation of an address | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | --------------------- | | addr | address | The converted address | ### toBytes @@ -2334,14 +2334,14 @@ _Converts an address to bytes._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | --------------------------- | | addr | address | The address to be converted | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ----- | --------------------------------------- | | bytesAddress | bytes | The bytes representation of the address | ## RemoteAddressValidator @@ -2395,9 +2395,9 @@ _Constructs the RemoteAddressValidator contract, both array parameters must be e #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| _interchainTokenServiceAddress | address | Address of the interchain token service | +| Name | Type | Description | +| ------------------------------- | ------- | --------------------------------------- | +| \_interchainTokenServiceAddress | address | Address of the interchain token service | ### contractId @@ -2407,13 +2407,13 @@ function contractId() external pure returns (bytes32) Getter for the contract id. -### _setup +### \_setup ```solidity function _setup(bytes params) internal ``` -### _lowerCase +### \_lowerCase ```solidity function _lowerCase(string s) internal pure returns (string) @@ -2423,15 +2423,15 @@ _Converts a string to lower case_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| s | string | Input string to be converted | +| Name | Type | Description | +| ---- | ------ | ---------------------------- | +| s | string | Input string to be converted | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | string | string lowercase version of the input string | +| Name | Type | Description | +| ---- | ------ | -------------------------------------------- | +| [0] | string | string lowercase version of the input string | ### validateSender @@ -2443,17 +2443,17 @@ _Validates that the sender is a valid interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | Source chain of the transaction | +| Name | Type | Description | +| ------------- | ------ | --------------------------------- | +| sourceChain | string | Source chain of the transaction | | sourceAddress | string | Source address of the transaction | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | bool true if the sender is validated, false otherwise | - +| Name | Type | Description | +| ---- | ---- | ----------------------------------------------------- | +| [0] | bool | bool true if the sender is validated, false otherwise | + ### addTrustedAddress ```solidity @@ -2464,10 +2464,10 @@ _Adds a trusted interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| chain | string | Chain name of the interchain token service | -| addr | string | Interchain token service address to be added | +| Name | Type | Description | +| ----- | ------ | -------------------------------------------- | +| chain | string | Chain name of the interchain token service | +| addr | string | Interchain token service address to be added | ### removeTrustedAddress @@ -2479,8 +2479,8 @@ _Removes a trusted interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----- | ------ | -------------------------------------------------------- | | chain | string | Chain name of the interchain token service to be removed | ### addGatewaySupportedChains @@ -2493,8 +2493,8 @@ _Adds chains that are supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | -------------------------------------------- | | chainNames | string[] | List of chain names to be added as supported | ### removeGatewaySupportedChains @@ -2507,8 +2507,8 @@ _Removes chains that are no longer supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | ---------------------------------------------- | | chainNames | string[] | List of chain names to be removed as supported | ### getRemoteAddress @@ -2521,14 +2521,14 @@ _Fetches the interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------ | ----------------- | | chainName | string | Name of the chain | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------ | -------------------------------------------------------- | | remoteAddress | string | Interchain token service address for the specified chain | ## RemoteAddressValidatorProxy @@ -2545,11 +2545,11 @@ _Constructs the RemoteAddressValidatorProxy contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| implementationAddress | address | Address of the RemoteAddressValidator implementation | -| owner | address | Address of the owner of the proxy | -| params | bytes | The params to be passed to the _setup function of the implementation. | +| Name | Type | Description | +| --------------------- | ------- | ---------------------------------------------------------------------- | +| implementationAddress | address | Address of the RemoteAddressValidator implementation | +| owner | address | Address of the owner of the proxy | +| params | bytes | The params to be passed to the \_setup function of the implementation. | ### contractId @@ -2561,9 +2561,9 @@ _Override for the `contractId` function in Proxy. Returns a unique identifier fo #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bytes32 | bytes32 Identifier for this contract. | +| Name | Type | Description | +| ---- | ------- | ------------------------------------- | +| [0] | bytes32 | bytes32 Identifier for this contract. | ## ExpressCallHandler @@ -2582,7 +2582,7 @@ uint256 PREFIX_EXPRESS_RECEIVE_TOKEN uint256 PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA ``` -### _getExpressReceiveTokenSlot +### \_getExpressReceiveTokenSlot ```solidity function _getExpressReceiveTokenSlot(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) internal pure returns (uint256 slot) @@ -2592,20 +2592,20 @@ Calculates the unique slot for a given express token transfer. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| destinationAddress | address | The address of the recipient | -| amount | uint256 | The amount of tokens to be sent | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| destinationAddress | address | The address of the recipient | +| amount | uint256 | The amount of tokens to be sent | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ------------------------------------------- | | slot | uint256 | The calculated slot for this token transfer | -### _getExpressReceiveTokenWithDataSlot +### \_getExpressReceiveTokenWithDataSlot ```solidity function _getExpressReceiveTokenWithDataSlot(bytes32 tokenId, string sourceChain, bytes sourceAddress, address destinationAddress, uint256 amount, bytes data, bytes32 commandId) internal pure returns (uint256 slot) @@ -2615,61 +2615,61 @@ Calculates the unique slot for a given token transfer with data #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| sourceChain | string | The chain from which the token will be sent | -| sourceAddress | bytes | The originating address of the token on the source chain | -| destinationAddress | address | The address of the recipient on the destination chain | -| amount | uint256 | The amount of tokens to be sent | -| data | bytes | The data associated with the token transfer | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | -------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| sourceChain | string | The chain from which the token will be sent | +| sourceAddress | bytes | The originating address of the token on the source chain | +| destinationAddress | address | The address of the recipient on the destination chain | +| amount | uint256 | The amount of tokens to be sent | +| data | bytes | The data associated with the token transfer | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ------------------------------------------- | | slot | uint256 | The calculated slot for this token transfer | -### _setExpressReceiveToken +### \_setExpressReceiveToken ```solidity function _setExpressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId, address expressCaller) internal ``` -Stores the address of the express caller at the storage slot determined by _getExpressSendTokenSlot +Stores the address of the express caller at the storage slot determined by \_getExpressSendTokenSlot #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| destinationAddress | address | The address of the recipient | -| amount | uint256 | The amount of tokens to be sent | -| commandId | bytes32 | The unique hash for this token transfer | -| expressCaller | address | The address of the express caller | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| destinationAddress | address | The address of the recipient | +| amount | uint256 | The amount of tokens to be sent | +| commandId | bytes32 | The unique hash for this token transfer | +| expressCaller | address | The address of the express caller | -### _setExpressReceiveTokenWithData +### \_setExpressReceiveTokenWithData ```solidity function _setExpressReceiveTokenWithData(bytes32 tokenId, string sourceChain, bytes sourceAddress, address destinationAddress, uint256 amount, bytes data, bytes32 commandId, address expressCaller) internal ``` Stores the address of the express caller for a given token transfer with data at -the storage slot determined by _getExpressSendTokenWithDataSlot +the storage slot determined by \_getExpressSendTokenWithDataSlot #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| sourceChain | string | The chain from which the token will be sent | -| sourceAddress | bytes | The originating address of the token on the source chain | -| destinationAddress | address | The address of the recipient on the destination chain | -| amount | uint256 | The amount of tokens to be sent | -| data | bytes | The data associated with the token transfer | -| commandId | bytes32 | The unique hash for this token transfer | -| expressCaller | address | The address of the express caller | +| Name | Type | Description | +| ------------------ | ------- | -------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| sourceChain | string | The chain from which the token will be sent | +| sourceAddress | bytes | The originating address of the token on the source chain | +| destinationAddress | address | The address of the recipient on the destination chain | +| amount | uint256 | The amount of tokens to be sent | +| data | bytes | The data associated with the token transfer | +| commandId | bytes32 | The unique hash for this token transfer | +| expressCaller | address | The address of the express caller | ### getExpressReceiveToken @@ -2681,17 +2681,17 @@ Gets the address of the express caller for a specific token transfer #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| destinationAddress | address | The address of the recipient | -| amount | uint256 | The amount of tokens to be sent | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| destinationAddress | address | The address of the recipient | +| amount | uint256 | The amount of tokens to be sent | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | ### getExpressReceiveTokenWithData @@ -2704,23 +2704,23 @@ Gets the address of the express caller for a specific token transfer with data #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| sourceChain | string | The chain from which the token will be sent | -| sourceAddress | bytes | The originating address of the token on the source chain | -| destinationAddress | address | The address of the recipient on the destination chain | -| amount | uint256 | The amount of tokens to be sent | -| data | bytes | The data associated with the token transfer | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | -------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| sourceChain | string | The chain from which the token will be sent | +| sourceAddress | bytes | The originating address of the token on the source chain | +| destinationAddress | address | The address of the recipient on the destination chain | +| amount | uint256 | The amount of tokens to be sent | +| data | bytes | The data associated with the token transfer | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | -### _popExpressReceiveToken +### \_popExpressReceiveToken ```solidity function _popExpressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) internal returns (address expressCaller) @@ -2730,20 +2730,20 @@ Removes the express caller from storage for a specific token transfer, if it exi #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| destinationAddress | address | The address of the recipient | -| amount | uint256 | The amount of tokens to be sent | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| destinationAddress | address | The address of the recipient | +| amount | uint256 | The amount of tokens to be sent | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | -### _popExpressReceiveTokenWithData +### \_popExpressReceiveTokenWithData ```solidity function _popExpressReceiveTokenWithData(bytes32 tokenId, string sourceChain, bytes sourceAddress, address destinationAddress, uint256 amount, bytes data, bytes32 commandId) internal returns (address expressCaller) @@ -2753,20 +2753,20 @@ Removes the express caller from storage for a specific token transfer with data, #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The ID of the token being sent | -| sourceChain | string | The chain from which the token will be sent | -| sourceAddress | bytes | The originating address of the token on the source chain | -| destinationAddress | address | The address of the recipient on the destination chain | -| amount | uint256 | The amount of tokens to be sent | -| data | bytes | The data associated with the token transfer | -| commandId | bytes32 | The unique hash for this token transfer | +| Name | Type | Description | +| ------------------ | ------- | -------------------------------------------------------- | +| tokenId | bytes32 | The ID of the token being sent | +| sourceChain | string | The chain from which the token will be sent | +| sourceAddress | bytes | The originating address of the token on the source chain | +| destinationAddress | address | The address of the recipient on the destination chain | +| amount | uint256 | The amount of tokens to be sent | +| data | bytes | The data associated with the token transfer | +| commandId | bytes32 | The unique hash for this token transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------------------------------------- | | expressCaller | address | The address of the express caller for this token transfer | ## Multicall @@ -2793,14 +2793,14 @@ If any of the calls fail, the function will revert with the failure message._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ---------------------------------- | | data | bytes[] | An array of encoded function calls | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | --------------------------------------------------------- | | results | bytes[] | An bytes array with the return data of each function call | ## Operatable @@ -2833,11 +2833,11 @@ Get the address of the operator #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator_ | address | of the operator | +| Name | Type | Description | +| ---------- | ------- | --------------- | +| operator\_ | address | of the operator | -### _setOperator +### \_setOperator ```solidity function _setOperator(address operator_) internal @@ -2847,9 +2847,9 @@ _Internal function that stores the new operator address in the operator storage #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator_ | address | The address of the new operator | +| Name | Type | Description | +| ---------- | ------- | ------------------------------- | +| operator\_ | address | The address of the new operator | ### transferOperatorship @@ -2863,9 +2863,9 @@ _Can only be called by the current operator_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| operator_ | address | The address of the new operator | +| Name | Type | Description | +| ---------- | ------- | ------------------------------- | +| operator\_ | address | The address of the new operator | ## Pausable @@ -2898,11 +2898,11 @@ Check if the contract is paused #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ---- | ------------------------------------------------------------------------- | | paused | bool | A boolean representing the pause status. True if paused, false otherwise. | -### _setPaused +### \_setPaused ```solidity function _setPaused(bool paused) internal @@ -2915,8 +2915,8 @@ or from derived contracts._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ---- | -------------------- | | paused | bool | The new pause status | ## InterchainTokenExecutable @@ -2957,15 +2957,15 @@ _You are revert unless the msg.sender is the InterchainTokenService_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | the name of the source chain | -| sourceAddress | bytes | the address that sent the contract call | -| data | bytes | the data to be proccessed | -| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querrying the service | -| amount | uint256 | the amount of token that was sent | +| Name | Type | Description | +| ------------- | ------- | -------------------------------------------------------------------------------------------------------- | +| sourceChain | string | the name of the source chain | +| sourceAddress | bytes | the address that sent the contract call | +| data | bytes | the data to be proccessed | +| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querying the service | +| amount | uint256 | the amount of token that was sent | -### _executeWithInterchainToken +### \_executeWithInterchainToken ```solidity function _executeWithInterchainToken(string sourceChain, bytes sourceAddress, bytes data, bytes32 tokenId, uint256 amount) internal virtual @@ -2991,17 +2991,17 @@ _You are revert unless the msg.sender is the InterchainTokenService_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | the name of the source chain | -| sourceAddress | bytes | the address that sent the contract call | -| data | bytes | the data to be proccessed | -| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querrying the service | -| amount | uint256 | the amount of token that was sent | +| Name | Type | Description | +| ------------- | ------- | -------------------------------------------------------------------------------------------------------- | +| sourceChain | string | the name of the source chain | +| sourceAddress | bytes | the address that sent the contract call | +| data | bytes | the data to be proccessed | +| tokenId | bytes32 | the tokenId of the token manager managing the token. You can access it's address by querying the service | +| amount | uint256 | the amount of token that was sent | ## InterchainToken -The implementation ERC20 can be done in any way, however this example assumes that an _approve internal function exists +The implementation ERC20 can be done in any way, however this example assumes that an \_approve internal function exists that can be used to create approvals, and that `allowance` is a mapping. _You can skip the `tokenManagerRequiresApproval()` function altogether if you know what it should return for your token._ @@ -3018,8 +3018,8 @@ _Needs to be overwitten._ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ---------------------- | ------------------------------------------------------------ | | tokenManager | contract ITokenManager | the TokenManager called to facilitate cross chain transfers. | ### tokenManagerRequiresApproval @@ -3028,19 +3028,19 @@ _Needs to be overwitten._ function tokenManagerRequiresApproval() public view virtual returns (bool) ``` -Getter function specifiying if the tokenManager requires approval to facilitate cross-chain transfers. +Getter function specifying if the tokenManager requires approval to facilitate cross-chain transfers. Usually, only mint/burn tokenManagers do not need approval. _The return value depends on the implementation of ERC20. In case of lock/unlock and liquidity pool TokenManagers it is possible to implement transferFrom to allow the -TokenManager specifically to do it permissionlesly. +TokenManager specifically to do it permissionlessly. On the other hand you can implement burn in a way that requires approval for a mint/burn TokenManager_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | +| Name | Type | Description | +| ---- | ---- | ------------------------------------------------------------------------- | +| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | ### interchainTransfer @@ -3055,12 +3055,12 @@ A different implementation could have `metadata` that tells this function which #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | The destination chain identifier. | -| recipient | bytes | The bytes representation of the address of the recipient. | -| amount | uint256 | The amount of token to be transfered. | -| metadata | bytes | Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| destinationChain | string | The destination chain identifier. | +| recipient | bytes | The bytes representation of the address of the recipient. | +| amount | uint256 | The amount of token to be transferred. | +| metadata | bytes | Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. | ### interchainTransferFrom @@ -3075,13 +3075,13 @@ A different implementation could have `metadata` that tells this function which #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sender | address | the sender of the tokens. They need to have approved `msg.sender` before this is called. | -| destinationChain | string | the string representation of the destination chain. | -| recipient | bytes | the bytes representation of the address of the recipient. | -| amount | uint256 | the amount of token to be transfered. | -| metadata | bytes | either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| sender | address | the sender of the tokens. They need to have approved `msg.sender` before this is called. | +| destinationChain | string | the string representation of the destination chain. | +| recipient | bytes | the bytes representation of the address of the recipient. | +| amount | uint256 | the amount of token to be transferred. | +| metadata | bytes | either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. | ## IDistributable @@ -3107,8 +3107,8 @@ Get the address of the distributor #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------- | ------------------ | | distributor | address | of the distributor | ### transferDistributorship @@ -3123,8 +3123,8 @@ _Can only be called by the current distributor_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------- | ---------------------------------- | | distributor | address | The address of the new distributor | ## IERC20BurnableMintable @@ -3142,10 +3142,10 @@ Can only be called by the distributor address. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| to | address | The address that will receive the minted tokens | -| amount | uint256 | The amount of tokens to mint | +| Name | Type | Description | +| ------ | ------- | ----------------------------------------------- | +| to | address | The address that will receive the minted tokens | +| amount | uint256 | The amount of tokens to mint | ### burn @@ -3158,10 +3158,10 @@ Can only be called by the distributor address. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | The address that will have its tokens burnt | -| amount | uint256 | The amount of tokens to burn | +| Name | Type | Description | +| ------ | ------- | ------------------------------------------- | +| from | address | The address that will have its tokens burnt | +| amount | uint256 | The amount of tokens to burn | ## IInterchainToken @@ -3180,12 +3180,12 @@ A different implementation could have `metadata` that tells this function which #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | The destination chain identifier. | -| recipient | bytes | The bytes representation of the address of the recipient. | -| amount | uint256 | The amount of token to be transfered. | -| metadata | bytes | Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| destinationChain | string | The destination chain identifier. | +| recipient | bytes | The bytes representation of the address of the recipient. | +| amount | uint256 | The amount of token to be transferred. | +| metadata | bytes | Either empty, to just facilitate an interchain transfer, or the data can be passed for an interchain contract call with transfer as per semantics defined by the token service. | ### interchainTransferFrom @@ -3200,13 +3200,13 @@ A different implementation could have `metadata` that tells this function which #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sender | address | the sender of the tokens. They need to have approved `msg.sender` before this is called. | -| destinationChain | string | the string representation of the destination chain. | -| recipient | bytes | the bytes representation of the address of the recipient. | -| amount | uint256 | the amount of token to be transfered. | -| metadata | bytes | either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| sender | address | the sender of the tokens. They need to have approved `msg.sender` before this is called. | +| destinationChain | string | the string representation of the destination chain. | +| recipient | bytes | the bytes representation of the address of the recipient. | +| amount | uint256 | the amount of token to be transferred. | +| metadata | bytes | either empty, to just facilitate a cross-chain transfer, or the data to be passed to a cross-chain contract call and transfer. | ## ILinkerRouter @@ -3233,13 +3233,13 @@ error ZeroStringLength() ### TrustedAddressAdded ```solidity -event TrustedAddressAdded(string souceChain, string sourceAddress) +event TrustedAddressAdded(string sourceChain, string sourceAddress) ``` ### TrustedAddressRemoved ```solidity -event TrustedAddressRemoved(string souceChain) +event TrustedAddressRemoved(string sourceChain) ``` ### GatewaySupportedChainAdded @@ -3264,16 +3264,16 @@ _Validates that the sender is a valid interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | Source chain of the transaction | +| Name | Type | Description | +| ------------- | ------ | --------------------------------- | +| sourceChain | string | Source chain of the transaction | | sourceAddress | string | Source address of the transaction | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | bool true if the sender is validated, false otherwise | +| Name | Type | Description | +| ---- | ---- | ----------------------------------------------------- | +| [0] | bool | bool true if the sender is validated, false otherwise | ### addTrustedAddress @@ -3285,9 +3285,9 @@ _Adds a trusted interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sourceChain | string | Chain name of the interchain token service | +| Name | Type | Description | +| ------------- | ------ | -------------------------------------------- | +| sourceChain | string | Chain name of the interchain token service | | sourceAddress | string | Interchain token service address to be added | ### removeTrustedAddress @@ -3300,8 +3300,8 @@ _Removes a trusted interchain token service address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ------ | -------------------------------------------------------- | | sourceChain | string | Chain name of the interchain token service to be removed | ### getRemoteAddress @@ -3314,14 +3314,14 @@ _Fetches the interchain token service address for the specified chain_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------ | ----------------- | | chainName | string | Name of the chain | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------ | -------------------------------------------------------- | | remoteAddress | string | Interchain token service address for the specified chain | ### supportedByGateway @@ -3334,8 +3334,8 @@ Returns true if the gateway delivers token to this chain. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------ | ----------------- | | chainName | string | Name of the chain | ### addGatewaySupportedChains @@ -3348,8 +3348,8 @@ _Adds chains that are supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | -------------------------------------------- | | chainNames | string[] | List of chain names to be added as supported | ### removeGatewaySupportedChains @@ -3362,8 +3362,8 @@ _Removes chains that are no longer supported by the Axelar gateway_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------- | -------- | ---------------------------------------------- | | chainNames | string[] | List of chain names to be removed as supported | ## InterchainTokenServiceProxy @@ -3380,11 +3380,11 @@ _Constructs the InterchainTokenServiceProxy contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------------------- | ------- | ------------------------------------------------------ | | implementationAddress | address | Address of the interchain token service implementation | -| owner | address | Address of the owner of the proxy | -| operator | address | | +| owner | address | Address of the owner of the proxy | +| operator | address | | ### contractId @@ -3396,9 +3396,9 @@ _Override for the 'contractId' function in FinalProxy. Returns a unique identifi #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bytes32 | bytes32 identifier for this contract | +| Name | Type | Description | +| ---- | ------- | ------------------------------------ | +| [0] | bytes32 | bytes32 identifier for this contract | ## TokenManagerProxy @@ -3437,12 +3437,12 @@ _Constructs the TokenManagerProxy contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenServiceAddress_ | address | The address of the interchain token service | -| implementationType_ | uint256 | The token manager type | -| tokenId_ | bytes32 | The identifier for the token | -| params | bytes | The initialization parameters for the token manager contract | +| Name | Type | Description | +| ------------------------------- | ------- | ------------------------------------------------------------ | +| interchainTokenServiceAddress\_ | address | The address of the interchain token service | +| implementationType\_ | uint256 | The token manager type | +| tokenId\_ | bytes32 | The identifier for the token | +| params | bytes | The initialization parameters for the token manager contract | ### implementation @@ -3454,11 +3454,11 @@ _Returns the address of the current implementation._ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ----------------------------------------- | | impl | address | The address of the current implementation | -### _getImplementation +### \_getImplementation ```solidity function _getImplementation(contract IInterchainTokenService interchainTokenServiceAddress_, uint256 implementationType_) internal view returns (address impl) @@ -3468,15 +3468,15 @@ _Returns the implementation address from the interchain token service for the pr #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenServiceAddress_ | contract IInterchainTokenService | The address of the interchain token service | -| implementationType_ | uint256 | The token manager type | +| Name | Type | Description | +| ------------------------------- | -------------------------------- | ------------------------------------------- | +| interchainTokenServiceAddress\_ | contract IInterchainTokenService | The address of the interchain token service | +| implementationType\_ | uint256 | The token manager type | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | --------------------------------- | | impl | address | The address of the implementation | ### setup @@ -3489,8 +3489,8 @@ _Setup function. Empty in this contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----------- | ----- | ------------------------- | | setupParams | bytes | Initialization parameters | ### fallback @@ -3529,7 +3529,7 @@ constructor(address interchainTokenService_) public string lastMessage ``` -### _executeWithInterchainToken +### \_executeWithInterchainToken ```solidity function _executeWithInterchainToken(string sourceChain, bytes sourceAddress, bytes data, bytes32 tokenId, uint256 amount) internal @@ -3543,7 +3543,7 @@ function _executeWithInterchainToken(string sourceChain, bytes sourceAddress, by contract ITokenManager tokenManager ``` -### tokenManagerRequiresApproval_ +### tokenManagerRequiresApproval\_ ```solidity bool tokenManagerRequiresApproval_ @@ -3585,9 +3585,9 @@ _Needs to be overwitten._ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | contract ITokenManager | | +| Name | Type | Description | +| ---- | ---------------------- | ----------- | +| [0] | contract ITokenManager | | ### tokenManagerRequiresApproval @@ -3595,19 +3595,19 @@ _Needs to be overwitten._ function tokenManagerRequiresApproval() public view returns (bool) ``` -Getter function specifiying if the tokenManager requires approval to facilitate cross-chain transfers. +Getter function specifying if the tokenManager requires approval to facilitate cross-chain transfers. Usually, only mint/burn tokenManagers do not need approval. _The return value depends on the implementation of ERC20. In case of lock/unlock and liquidity pool TokenManagers it is possible to implement transferFrom to allow the -TokenManager specifically to do it permissionlesly. +TokenManager specifically to do it permissionlessly. On the other hand you can implement burn in a way that requires approval for a mint/burn TokenManager_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | +| Name | Type | Description | +| ---- | ---- | ------------------------------------------------------------------------- | +| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | ### setTokenManagerRequiresApproval @@ -3655,10 +3655,10 @@ function testOperatorable() external ## ERC20 -_Implementation of the {IERC20} interface. +\_Implementation of the {IERC20} interface. This implementation is agnostic to the way tokens are created. This means -that a supply mechanism has to be added in a derived contract using {_mint}. +that a supply mechanism has to be added in a derived contract using {\_mint}. For a generic mechanism see {ERC20PresetMinterPauser}. TIP: For a detailed writeup see our guide @@ -3676,7 +3676,7 @@ these events, as it isn't required by the specification. Finally, the non-standard {decreaseAllowance} and {increaseAllowance} functions have been added to mitigate the well-known issues around setting -allowances. See {IERC20-approve}._ +allowances. See {IERC20-approve}.\_ ### balanceOf @@ -3692,11 +3692,11 @@ _Returns the amount of tokens owned by `account`._ mapping(address => mapping(address => uint256)) allowance ``` -_Returns the remaining number of tokens that `spender` will be +\_Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. -This value changes when {approve} or {transferFrom} are called._ +This value changes when {approve} or {transferFrom} are called.\_ ### totalSupply @@ -3712,12 +3712,12 @@ _Returns the amount of tokens in existence._ function transfer(address recipient, uint256 amount) external virtual returns (bool) ``` -_See {IERC20-transfer}. +\_See {IERC20-transfer}. Requirements: -- `recipient` cannot be the zero address. -- the caller must have a balance of at least `amount`._ +- `recipient` cannot be the zero address. +- the caller must have a balance of at least `amount`.\_ ### approve @@ -3725,14 +3725,14 @@ Requirements: function approve(address spender, uint256 amount) external virtual returns (bool) ``` -_See {IERC20-approve}. +\_See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: -- `spender` cannot be the zero address._ +- `spender` cannot be the zero address.\_ ### transferFrom @@ -3740,17 +3740,17 @@ Requirements: function transferFrom(address sender, address recipient, uint256 amount) external virtual returns (bool) ``` -_See {IERC20-transferFrom}. +\_See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. Requirements: -- `sender` and `recipient` cannot be the zero address. -- `sender` must have a balance of at least `amount`. -- the caller must have allowance for ``sender``'s tokens of at least -`amount`._ +- `sender` and `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. +- the caller must have allowance for `sender`'s tokens of at least + `amount`.\_ ### increaseAllowance @@ -3758,7 +3758,7 @@ Requirements: function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool) ``` -_Atomically increases the allowance granted to `spender` by the caller. +\_Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. @@ -3767,7 +3767,7 @@ Emits an {Approval} event indicating the updated allowance. Requirements: -- `spender` cannot be the zero address._ +- `spender` cannot be the zero address.\_ ### decreaseAllowance @@ -3775,7 +3775,7 @@ Requirements: function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool) ``` -_Atomically decreases the allowance granted to `spender` by the caller. +\_Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. @@ -3784,17 +3784,17 @@ Emits an {Approval} event indicating the updated allowance. Requirements: -- `spender` cannot be the zero address. -- `spender` must have allowance for the caller of at least -`subtractedValue`._ +- `spender` cannot be the zero address. +- `spender` must have allowance for the caller of at least + `subtractedValue`.\_ -### _transfer +### \_transfer ```solidity function _transfer(address sender, address recipient, uint256 amount) internal virtual ``` -_Moves tokens `amount` from `sender` to `recipient`. +\_Moves tokens `amount` from `sender` to `recipient`. This is internal function is equivalent to {transfer}, and can be used to e.g. implement automatic token fees, slashing mechanisms, etc. @@ -3803,48 +3803,48 @@ Emits a {Transfer} event. Requirements: -- `sender` cannot be the zero address. -- `recipient` cannot be the zero address. -- `sender` must have a balance of at least `amount`._ +- `sender` cannot be the zero address. +- `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`.\_ -### _mint +### \_mint ```solidity function _mint(address account, uint256 amount) internal virtual ``` -_Creates `amount` tokens and assigns them to `account`, increasing +\_Creates `amount` tokens and assigns them to `account`, increasing the total supply. Emits a {Transfer} event with `from` set to the zero address. Requirements: -- `to` cannot be the zero address._ +- `to` cannot be the zero address.\_ -### _burn +### \_burn ```solidity function _burn(address account, uint256 amount) internal virtual ``` -_Destroys `amount` tokens from `account`, reducing the +\_Destroys `amount` tokens from `account`, reducing the total supply. Emits a {Transfer} event with `to` set to the zero address. Requirements: -- `account` cannot be the zero address. -- `account` must have at least `amount` tokens._ +- `account` cannot be the zero address. +- `account` must have at least `amount` tokens.\_ -### _approve +### \_approve ```solidity function _approve(address owner, address spender, uint256 amount) internal virtual ``` -_Sets `amount` as the allowance of `spender` over the `owner` s tokens. +\_Sets `amount` as the allowance of `spender` over the `owner` s tokens. This internal function is equivalent to `approve`, and can be used to e.g. set automatic allowances for certain subsystems, etc. @@ -3853,8 +3853,8 @@ Emits an {Approval} event. Requirements: -- `owner` cannot be the zero address. -- `spender` cannot be the zero address._ +- `owner` cannot be the zero address. +- `spender` cannot be the zero address.\_ ## ERC20Permit @@ -3901,7 +3901,7 @@ mapping(address => uint256) nonces _Mapping of nonces for each address._ -### _setDomainTypeSignatureHash +### \_setDomainTypeSignatureHash ```solidity function _setDomainTypeSignatureHash(string name) internal @@ -3911,8 +3911,8 @@ Internal function to set the domain type signature hash #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------ | -------------- | | name | string | The token name | ### permit @@ -3928,15 +3928,15 @@ to spend tokens on their behalf via a signed message._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| issuer | address | The address of the token holder | -| spender | address | The address of the designated spender | -| value | uint256 | The number of tokens to be spent | +| Name | Type | Description | +| -------- | ------- | ------------------------------------------------- | +| issuer | address | The address of the token holder | +| spender | address | The address of the designated spender | +| value | uint256 | The number of tokens to be spent | | deadline | uint256 | The time at which the permission to spend expires | -| v | uint8 | The recovery id of the signature | -| r | bytes32 | Half of the ECDSA signature pair | -| s | bytes32 | Half of the ECDSA signature pair | +| v | uint8 | The recovery id of the signature | +| r | bytes32 | Half of the ECDSA signature pair | +| s | bytes32 | Half of the ECDSA signature pair | ## StandardizedToken @@ -3991,9 +3991,9 @@ Returns the token manager for this token #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | contract ITokenManager | ITokenManager The token manager contract | +| Name | Type | Description | +| ---- | ---------------------- | ---------------------------------------- | +| [0] | contract ITokenManager | ITokenManager The token manager contract | ### setup @@ -4005,8 +4005,8 @@ Setup function to initialize contract parameters #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------ | | params | bytes | The setup parameters in bytes The setup params include tokenManager, distributor, tokenName, symbol, decimals, mintAmount and mintTo | ### mint @@ -4020,10 +4020,10 @@ Can only be called by the distributor address. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ----------------------------------------------- | | account | address | The address that will receive the minted tokens | -| amount | uint256 | The amount of tokens to mint | +| amount | uint256 | The amount of tokens to mint | ### burn @@ -4036,10 +4036,10 @@ Can only be called by the distributor address. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------------------------------- | | account | address | The address that will have its tokens burnt | -| amount | uint256 | The amount of tokens to burn | +| amount | uint256 | The amount of tokens to burn | ## StandardizedTokenLockUnlock @@ -4049,19 +4049,19 @@ Can only be called by the distributor address. function tokenManagerRequiresApproval() public pure returns (bool) ``` -Getter function specifiying if the tokenManager requires approval to facilitate cross-chain transfers. +Getter function specifying if the tokenManager requires approval to facilitate cross-chain transfers. Usually, only mint/burn tokenManagers do not need approval. _The return value depends on the implementation of ERC20. In case of lock/unlock and liquidity pool TokenManagers it is possible to implement transferFrom to allow the -TokenManager specifically to do it permissionlesly. +TokenManager specifically to do it permissionlessly. On the other hand you can implement burn in a way that requires approval for a mint/burn TokenManager_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | +| Name | Type | Description | +| ---- | ---- | ------------------------------------------------------------------------- | +| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | ## StandardizedTokenMintBurn @@ -4071,19 +4071,19 @@ On the other hand you can implement burn in a way that requires approval for a m function tokenManagerRequiresApproval() public pure returns (bool) ``` -Getter function specifiying if the tokenManager requires approval to facilitate cross-chain transfers. +Getter function specifying if the tokenManager requires approval to facilitate cross-chain transfers. Usually, only mint/burn tokenManagers do not need approval. _The return value depends on the implementation of ERC20. In case of lock/unlock and liquidity pool TokenManagers it is possible to implement transferFrom to allow the -TokenManager specifically to do it permissionlesly. +TokenManager specifically to do it permissionlessly. On the other hand you can implement burn in a way that requires approval for a mint/burn TokenManager_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | +| Name | Type | Description | +| ---- | ---- | ------------------------------------------------------------------------- | +| [0] | bool | tokenManager the TokenManager called to facilitate cross chain transfers. | ## TokenManager @@ -4105,9 +4105,9 @@ Constructs the TokenManager contract. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenService_ | address | The address of the interchain token service | +| Name | Type | Description | +| ------------------------ | ------- | ------------------------------------------- | +| interchainTokenService\_ | address | The address of the interchain token service | ### onlyService @@ -4136,9 +4136,9 @@ Must be overridden in the inheriting contract. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | address | address address of the token. | +| Name | Type | Description | +| ---- | ------- | ----------------------------- | +| [0] | address | address address of the token. | ### setup @@ -4150,8 +4150,8 @@ _This function should only be called by the proxy, and only once from the proxy #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | params | bytes | the parameters to be used to initialize the TokenManager. The exact format depends on the type of TokenManager used but the first 32 bytes are reserved for the address of the operator, stored as bytes (to be compatible with non-EVM chains) | ### sendToken @@ -4160,16 +4160,16 @@ _This function should only be called by the proxy, and only once from the proxy function sendToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable virtual ``` -Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. +Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| metadata | bytes | | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------------- | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| metadata | bytes | | ### callContractWithInterchainToken @@ -4177,16 +4177,16 @@ Calls the service to initiate the a cross-chain transfer after taking the approp function callContractWithInterchainToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes data) external payable virtual ``` -Calls the service to initiate the a cross-chain transfer with data after taking the appropriate amount of tokens from the user. +Calls the service to initiate a cross-chain transfer with data after taking the appropriate amount of tokens from the user. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| data | bytes | the data to pass to the destination contract. | +| Name | Type | Description | +| ------------------ | ------- | --------------------------------------------- | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| data | bytes | the data to pass to the destination contract. | ### transmitInterchainTransfer @@ -4194,17 +4194,17 @@ Calls the service to initiate the a cross-chain transfer with data after taking function transmitInterchainTransfer(address sender, string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable virtual ``` -Calls the service to initiate the a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. +Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. This can only be called by the token itself. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| sender | address | the address of the user paying for the cross chain transfer. | -| destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the address of the user to send tokens to. | -| amount | uint256 | the amount of tokens to take from msg.sender. | -| metadata | bytes | | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------------------------------------ | +| sender | address | the address of the user paying for the cross chain transfer. | +| destinationChain | string | the name of the chain to send tokens to. | +| destinationAddress | bytes | the address of the user to send tokens to. | +| amount | uint256 | the amount of tokens to take from msg.sender. | +| metadata | bytes | | ### giveToken @@ -4216,16 +4216,16 @@ This function gives token to a specified address. Can only be called by the serv #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------ | | destinationAddress | address | the address to give tokens to. | -| amount | uint256 | the amount of token to give. | +| amount | uint256 | the amount of token to give. | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | the amount of token actually given, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. | +| Name | Type | Description | +| ---- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| [0] | uint256 | the amount of token actually given, which will only be different than `amount` in cases where the token takes some on-transfer fee. | ### setFlowLimit @@ -4237,11 +4237,11 @@ This function sets the flow limit for this TokenManager. Can only be called by t #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | -------------------------------------------------------------------------------------------------- | | flowLimit | uint256 | the maximum difference between the tokens flowing in and/or out at any given interval of time (6h) | -### _takeToken +### \_takeToken ```solidity function _takeToken(address from, uint256 amount) internal virtual returns (uint256) @@ -4252,21 +4252,21 @@ Must be overridden in the inheriting contract. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | The address from which the tokens will be sent | -| amount | uint256 | The amount of tokens to receive | +| Name | Type | Description | +| ------ | ------- | ---------------------------------------------- | +| from | address | The address from which the tokens will be sent | +| amount | uint256 | The amount of tokens to receive | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint amount of tokens received | +| Name | Type | Description | +| ---- | ------- | ------------------------------ | +| [0] | uint256 | uint amount of tokens received | -### _giveToken +### \_giveToken ```solidity -function _giveToken(address from, uint256 amount) internal virtual returns (uint256) +function _giveToken(address receiver, uint256 amount) internal virtual returns (uint256) ``` Transfers tokens from this contract to a specific address. @@ -4274,18 +4274,18 @@ Must be overridden in the inheriting contract. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | The address to which the tokens will be sent | -| amount | uint256 | The amount of tokens to send | +| Name | Type | Description | +| ------ | ------- | -------------------------------------------- | +| from | address | The address to which the tokens will be sent | +| amount | uint256 | The amount of tokens to send | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint amount of tokens sent | +| Name | Type | Description | +| ---- | ------- | -------------------------- | +| [0] | uint256 | uint amount of tokens sent | -### _setup +### \_setup ```solidity function _setup(bytes params) internal virtual @@ -4296,11 +4296,11 @@ Must be overridden in the inheriting contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | -------------------- | | params | bytes | The setup parameters | -### _getTokenId +### \_getTokenId ```solidity function _getTokenId() internal view returns (bytes32 tokenId) @@ -4310,8 +4310,8 @@ Gets the token ID from the token manager proxy. #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------- | ------- | ------------------- | | tokenId | bytes32 | The ID of the token | ## TokenManagerAddressStorage @@ -4329,9 +4329,9 @@ _Creates an instance of the TokenManagerAddressStorage contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenService_ | address | The address of the interchain token service contract | +| Name | Type | Description | +| ------------------------ | ------- | ---------------------------------------------------- | +| interchainTokenService\_ | address | The address of the interchain token service contract | ### TOKEN_ADDRESS_SLOT @@ -4349,11 +4349,11 @@ _Reads the stored token address from the predetermined storage slot_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenAddress_ | address | The address of the token | +| Name | Type | Description | +| -------------- | ------- | ------------------------ | +| tokenAddress\_ | address | The address of the token | -### _setTokenAddress +### \_setTokenAddress ```solidity function _setTokenAddress(address tokenAddress_) internal @@ -4363,9 +4363,9 @@ _Stores the token address in the predetermined storage slot_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenAddress_ | address | The address of the token to store | +| Name | Type | Description | +| -------------- | ------- | --------------------------------- | +| tokenAddress\_ | address | The address of the token to store | ## TokenManagerLiquidityPool @@ -4392,9 +4392,9 @@ of TokenManagerAddressStorage which calls the constructor of TokenManager._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenService_ | address | The address of the interchain token service contract | +| Name | Type | Description | +| ------------------------ | ------- | ---------------------------------------------------- | +| interchainTokenService\_ | address | The address of the interchain token service contract | ### implementationType @@ -4404,7 +4404,7 @@ function implementationType() external pure returns (uint256) A function that should return the implementation type of the token manager. -### _setup +### \_setup ```solidity function _setup(bytes params) internal @@ -4414,11 +4414,11 @@ _Sets up the token address and liquidity pool address._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------------------------------------------------------------------- | | params | bytes | The setup parameters in bytes. Should be encoded with the token address and the liquidity pool address. | -### _setLiquidityPool +### \_setLiquidityPool ```solidity function _setLiquidityPool(address liquidityPool_) internal @@ -4428,9 +4428,9 @@ _Stores the liquidity pool address at a specific storage slot_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| liquidityPool_ | address | The address of the liquidity pool | +| Name | Type | Description | +| --------------- | ------- | --------------------------------- | +| liquidityPool\_ | address | The address of the liquidity pool | ### liquidityPool @@ -4442,9 +4442,9 @@ _Reads the stored liquidity pool address from the specified storage slot_ #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| liquidityPool_ | address | The address of the liquidity pool | +| Name | Type | Description | +| --------------- | ------- | --------------------------------- | +| liquidityPool\_ | address | The address of the liquidity pool | ### setLiquidityPool @@ -4456,11 +4456,11 @@ _Updates the address of the liquidity pool. Can only be called by the operator._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---------------- | ------- | ------------------------------------- | | newLiquidityPool | address | The new address of the liquidity pool | -### _takeToken +### \_takeToken ```solidity function _takeToken(address from, uint256 amount) internal returns (uint256) @@ -4470,18 +4470,18 @@ _Transfers a specified amount of tokens from a specified address to the liquidit #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | The address to transfer tokens from | -| amount | uint256 | The amount of tokens to transfer | +| Name | Type | Description | +| ------ | ------- | ----------------------------------- | +| from | address | The address to transfer tokens from | +| amount | uint256 | The amount of tokens to transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. | +| Name | Type | Description | +| ---- | ------- | --------------------------------------------------------------------------------------------- | +| [0] | uint256 | uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. | -### _giveToken +### \_giveToken ```solidity function _giveToken(address to, uint256 amount) internal returns (uint256) @@ -4491,16 +4491,16 @@ _Transfers a specified amount of tokens from the liquidity pool to a specified a #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| to | address | The address to transfer tokens to | -| amount | uint256 | The amount of tokens to transfer | +| Name | Type | Description | +| ------ | ------- | --------------------------------- | +| to | address | The address to transfer tokens to | +| amount | uint256 | The amount of tokens to transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint The actual amount of tokens transferred | +| Name | Type | Description | +| ---- | ------- | -------------------------------------------- | +| [0] | uint256 | uint The actual amount of tokens transferred | ## TokenManagerLockUnlock @@ -4520,9 +4520,9 @@ of TokenManagerAddressStorage which calls the constructor of TokenManager._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenService_ | address | The address of the interchain token service contract | +| Name | Type | Description | +| ------------------------ | ------- | ---------------------------------------------------- | +| interchainTokenService\_ | address | The address of the interchain token service contract | ### implementationType @@ -4532,7 +4532,7 @@ function implementationType() external pure returns (uint256) A function that should return the implementation type of the token manager. -### _setup +### \_setup ```solidity function _setup(bytes params) internal @@ -4542,11 +4542,11 @@ _Sets up the token address._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------------------------------------ | | params | bytes | The setup parameters in bytes. Should be encoded with the token address. | -### _takeToken +### \_takeToken ```solidity function _takeToken(address from, uint256 amount) internal returns (uint256) @@ -4556,18 +4556,18 @@ _Transfers a specified amount of tokens from a specified address to this contrac #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | The address to transfer tokens from | -| amount | uint256 | The amount of tokens to transfer | +| Name | Type | Description | +| ------ | ------- | ----------------------------------- | +| from | address | The address to transfer tokens from | +| amount | uint256 | The amount of tokens to transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. | +| Name | Type | Description | +| ---- | ------- | --------------------------------------------------------------------------------------------- | +| [0] | uint256 | uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. | -### _giveToken +### \_giveToken ```solidity function _giveToken(address to, uint256 amount) internal returns (uint256) @@ -4577,16 +4577,16 @@ _Transfers a specified amount of tokens from this contract to a specified addres #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| to | address | The address to transfer tokens to | -| amount | uint256 | The amount of tokens to transfer | +| Name | Type | Description | +| ------ | ------- | --------------------------------- | +| to | address | The address to transfer tokens to | +| amount | uint256 | The amount of tokens to transfer | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint The actual amount of tokens transferred | +| Name | Type | Description | +| ---- | ------- | -------------------------------------------- | +| [0] | uint256 | uint The actual amount of tokens transferred | ## TokenManagerMintBurn @@ -4606,9 +4606,9 @@ of TokenManagerAddressStorage which calls the constructor of TokenManager._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| interchainTokenService_ | address | The address of the interchain token service contract | +| Name | Type | Description | +| ------------------------ | ------- | ---------------------------------------------------- | +| interchainTokenService\_ | address | The address of the interchain token service contract | ### implementationType @@ -4618,7 +4618,7 @@ function implementationType() external pure returns (uint256) A function that should return the implementation type of the token manager. -### _setup +### \_setup ```solidity function _setup(bytes params) internal @@ -4628,11 +4628,11 @@ _Sets up the token address._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------------------------------------ | | params | bytes | The setup parameters in bytes. Should be encoded with the token address. | -### _takeToken +### \_takeToken ```solidity function _takeToken(address from, uint256 amount) internal returns (uint256) @@ -4642,18 +4642,18 @@ _Burns the specified amount of tokens from a particular address._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| from | address | Address to burn tokens from | -| amount | uint256 | Amount of tokens to burn | +| Name | Type | Description | +| ------ | ------- | --------------------------- | +| from | address | Address to burn tokens from | +| amount | uint256 | Amount of tokens to burn | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint Amount of tokens burned | +| Name | Type | Description | +| ---- | ------- | ---------------------------- | +| [0] | uint256 | uint Amount of tokens burned | -### _giveToken +### \_giveToken ```solidity function _giveToken(address to, uint256 amount) internal returns (uint256) @@ -4663,16 +4663,16 @@ _Mints the specified amount of tokens to a particular address_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| to | address | Address to mint tokens to | -| amount | uint256 | Amount of tokens to mint | +| Name | Type | Description | +| ------ | ------- | ------------------------- | +| to | address | Address to mint tokens to | +| amount | uint256 | Amount of tokens to mint | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| [0] | uint256 | uint Amount of tokens minted | +| Name | Type | Description | +| ---- | ------- | ---------------------------- | +| [0] | uint256 | uint Amount of tokens minted | ## Distributable @@ -4692,7 +4692,7 @@ uint256 DISTRIBUTOR_SLOT modifier onlyDistributor() ``` -_Throws a NotDistributor custom eror if called by any account other than the distributor._ +_Throws a NotDistributor custom error if called by any account other than the distributor._ ### distributor @@ -4704,11 +4704,11 @@ Get the address of the distributor #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | -| distributor_ | address | of the distributor | +| Name | Type | Description | +| ------------- | ------- | ------------------ | +| distributor\_ | address | of the distributor | -### _setDistributor +### \_setDistributor ```solidity function _setDistributor(address distributor_) internal @@ -4718,9 +4718,9 @@ _Internal function that stores the new distributor address in the correct storag #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| distributor_ | address | The address of the new distributor | +| Name | Type | Description | +| ------------- | ------- | ---------------------------------- | +| distributor\_ | address | The address of the new distributor | ### transferDistributorship @@ -4734,9 +4734,9 @@ _Can only be called by the current distributor_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| distributor_ | address | The address of the new distributor | +| Name | Type | Description | +| ------------- | ------- | ---------------------------------- | +| distributor\_ | address | The address of the new distributor | ## FlowLimit @@ -4778,11 +4778,11 @@ Returns the current flow limit #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | ---------------------------- | | flowLimit | uint256 | The current flow limit value | -### _setFlowLimit +### \_setFlowLimit ```solidity function _setFlowLimit(uint256 flowLimit) internal @@ -4792,11 +4792,11 @@ _Internal function to set the flow limit_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| --------- | ------- | ---------------------------------- | | flowLimit | uint256 | The value to set the flow limit to | -### _getFlowOutSlot +### \_getFlowOutSlot ```solidity function _getFlowOutSlot(uint256 epoch) internal pure returns (uint256 slot) @@ -4806,17 +4806,17 @@ _Returns the slot which is used to get the flow out amount for a specific epoch_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----- | ------- | ---------------------------------------- | | epoch | uint256 | The epoch to get the flow out amount for | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | ---------------------------------------- | | slot | uint256 | The slot to get the flow out amount from | -### _getFlowInSlot +### \_getFlowInSlot ```solidity function _getFlowInSlot(uint256 epoch) internal pure returns (uint256 slot) @@ -4826,14 +4826,14 @@ _Returns the slot which is used to get the flow in amount for a specific epoch_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ----- | ------- | --------------------------------------- | | epoch | uint256 | The epoch to get the flow in amount for | #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ---- | ------- | --------------------------------------- | | slot | uint256 | The slot to get the flow in amount from | ### getFlowOutAmount @@ -4846,8 +4846,8 @@ Returns the current flow out amount #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | --------------------------- | | flowOutAmount | uint256 | The current flow out amount | ### getFlowInAmount @@ -4860,11 +4860,11 @@ Returns the current flow in amount #### Return Values -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | -------------------------- | | flowInAmount | uint256 | The current flow in amount | -### _addFlow +### \_addFlow ```solidity function _addFlow(uint256 flowLimit, uint256 slotToAdd, uint256 slotToCompare, uint256 flowAmount) internal @@ -4874,14 +4874,14 @@ _Adds a flow amount while ensuring it does not exceed the flow limit_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| flowLimit | uint256 | | -| slotToAdd | uint256 | The slot to add the flow to | +| Name | Type | Description | +| ------------- | ------- | ------------------------------------ | +| flowLimit | uint256 | | +| slotToAdd | uint256 | The slot to add the flow to | | slotToCompare | uint256 | The slot to compare the flow against | -| flowAmount | uint256 | The flow amount to add | +| flowAmount | uint256 | The flow amount to add | -### _addFlowOut +### \_addFlowOut ```solidity function _addFlowOut(uint256 flowOutAmount) internal @@ -4891,11 +4891,11 @@ _Adds a flow out amount_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------- | ------- | -------------------------- | | flowOutAmount | uint256 | The flow out amount to add | -### _addFlowIn +### \_addFlowIn ```solidity function _addFlowIn(uint256 flowInAmount) internal @@ -4905,8 +4905,8 @@ _Adds a flow in amount_ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------------ | ------- | ------------------------- | | flowInAmount | uint256 | The flow in amount to add | ## Implementation @@ -4944,8 +4944,8 @@ The overriding function must have the onlyProxy modifier. #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | -------------------------------------------- | | params | bytes | The parameters to be used for initialization | ## TokenManagerDeployer @@ -4970,9 +4970,9 @@ Constructor for the TokenManagerDeployer contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| deployer_ | address | Address of the Create3Deployer contract | +| Name | Type | Description | +| ---------- | ------- | --------------------------------------- | +| deployer\_ | address | Address of the Create3Deployer contract | ### deployTokenManager @@ -4984,11 +4984,11 @@ Deploys a new instance of the TokenManagerProxy contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| tokenId | bytes32 | The unique identifier for the token | -| implementationType | uint256 | Token manager implementation type | -| params | bytes | Additional parameters used in the setup of the token manager | +| Name | Type | Description | +| ------------------ | ------- | ------------------------------------------------------------ | +| tokenId | bytes32 | The unique identifier for the token | +| implementationType | uint256 | Token manager implementation type | +| params | bytes | Additional parameters used in the setup of the token manager | ## IStandardizedToken @@ -5015,8 +5015,8 @@ _This should be hidden by the proxy._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | +| Name | Type | Description | +| ------ | ----- | ------------------------------------------- | | params | bytes | the data to be used for the initialization. | ## IStandardizedTokenProxy @@ -5059,10 +5059,10 @@ _Constructs the StandardizedTokenProxy contract._ #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| implementationAddress | address | Address of the StandardizedToken implementation | -| params | bytes | Initialization parameters for the StandardizedToken contract | +| Name | Type | Description | +| --------------------- | ------- | ------------------------------------------------------------ | +| implementationAddress | address | Address of the StandardizedToken implementation | +| params | bytes | Initialization parameters for the StandardizedToken contract | ## StandardizedTokenDeployer @@ -5098,11 +5098,11 @@ Constructor for the StandardizedTokenDeployer contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| deployer_ | address | Address of the Create3Deployer contract | -| implementationLockUnlockAddress_ | address | Address of the StandardizedTokenLockUnlock contract | -| implementationMintBurnAddress_ | address | Address of the StandardizedTokenMintBurn contract | +| Name | Type | Description | +| --------------------------------- | ------- | --------------------------------------------------- | +| deployer\_ | address | Address of the Create3Deployer contract | +| implementationLockUnlockAddress\_ | address | Address of the StandardizedTokenLockUnlock contract | +| implementationMintBurnAddress\_ | address | Address of the StandardizedTokenMintBurn contract | ### deployStandardizedToken @@ -5114,14 +5114,13 @@ Deploys a new instance of the StandardizedTokenProxy contract #### Parameters -| Name | Type | Description | -| ---- | ---- | ----------- | -| salt | bytes32 | The salt used by Create3Deployer | -| tokenManager | address | Address of the token manager | -| distributor | address | Address of the distributor | -| name | string | Name of the token | -| symbol | string | Symbol of the token | -| decimals | uint8 | Decimals of the token | -| mintAmount | uint256 | Amount of tokens to mint initially | -| mintTo | address | Address to mint initial tokens to | - +| Name | Type | Description | +| ------------ | ------- | ---------------------------------- | +| salt | bytes32 | The salt used by Create3Deployer | +| tokenManager | address | Address of the token manager | +| distributor | address | Address of the distributor | +| name | string | Name of the token | +| symbol | string | Symbol of the token | +| decimals | uint8 | Decimals of the token | +| mintAmount | uint256 | Amount of tokens to mint initially | +| mintTo | address | Address to mint initial tokens to | From c04aaa3942e3d99d25ab5618b5ede44aa45fa019 Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 30 Aug 2023 18:06:53 +0300 Subject: [PATCH 02/12] feat: use create3 lib instead of using the Create3Deployer to save some gas. (#93) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * fix a duplication bug * lint --------- Co-authored-by: Milap Sheth --- .../InterchainTokenService.sol | 8 ++--- .../interfaces/IStandardizedTokenDeployer.sol | 10 ++++-- .../interfaces/ITokenManagerDeployer.sol | 5 --- contracts/utils/StandardizedTokenDeployer.sol | 15 ++++---- contracts/utils/TokenManagerDeployer.sol | 15 ++------ hardhat.config.js | 1 - scripts/deploy.js | 7 ++-- test/tokenServiceFullFlow.js | 34 +++---------------- test/utils.js | 12 +++---- 9 files changed, 32 insertions(+), 75 deletions(-) diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index e26a7403..fc9070da 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -21,7 +21,7 @@ import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; import { StringToBytes32, Bytes32ToString } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/Bytes32String.sol'; import { Upgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol'; -import { Create3Deployer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3Deployer.sol'; +import { Create3 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3.sol'; import { ExpressCallHandler } from '../utils/ExpressCallHandler.sol'; import { Pausable } from '../utils/Pausable.sol'; @@ -55,7 +55,6 @@ contract InterchainTokenService is IRemoteAddressValidator public immutable remoteAddressValidator; address public immutable tokenManagerDeployer; address public immutable standardizedTokenDeployer; - Create3Deployer internal immutable deployer; bytes32 internal immutable chainNameHash; bytes32 internal immutable chainName; @@ -99,7 +98,6 @@ contract InterchainTokenService is gasService = IAxelarGasService(gasService_); tokenManagerDeployer = tokenManagerDeployer_; standardizedTokenDeployer = standardizedTokenDeployer_; - deployer = ITokenManagerDeployer(tokenManagerDeployer_).deployer(); if (tokenManagerImplementations.length != uint256(type(TokenManagerType).max) + 1) revert LengthMismatch(); @@ -160,7 +158,7 @@ contract InterchainTokenService is */ // TODO: Maybe copy the code of the create3Deployer to save gas, but would introduce duplicate code problems. function getTokenManagerAddress(bytes32 tokenId) public view returns (address tokenManagerAddress) { - tokenManagerAddress = deployer.deployedAddress(address(this), tokenId); + tokenManagerAddress = Create3.deployedAddress(address(this), tokenId); } /** @@ -191,7 +189,7 @@ contract InterchainTokenService is */ function getStandardizedTokenAddress(bytes32 tokenId) public view returns (address tokenAddress) { tokenId = _getStandardizedTokenSalt(tokenId); - tokenAddress = deployer.deployedAddress(address(this), tokenId); + tokenAddress = Create3.deployedAddress(address(this), tokenId); } /** diff --git a/contracts/interfaces/IStandardizedTokenDeployer.sol b/contracts/interfaces/IStandardizedTokenDeployer.sol index 3444b892..147c01c9 100644 --- a/contracts/interfaces/IStandardizedTokenDeployer.sol +++ b/contracts/interfaces/IStandardizedTokenDeployer.sol @@ -13,9 +13,15 @@ interface IStandardizedTokenDeployer { error TokenDeploymentFailed(); /** - * @notice Getter for the Create3Deployer. + * @notice Returns the standardized token implementation address */ - function deployer() external view returns (Create3Deployer); + function implementationAddress() external view returns (address); + + /** + * @notice Returns the standardized token deployment address. + * @return tokenAddress the token address. + */ + function deployedAddress(bytes32 salt) external view returns (address tokenAddress); /** * @notice Deploys a new instance of the StandardizedTokenProxy contract diff --git a/contracts/interfaces/ITokenManagerDeployer.sol b/contracts/interfaces/ITokenManagerDeployer.sol index ceae052e..c3e8cbf8 100644 --- a/contracts/interfaces/ITokenManagerDeployer.sol +++ b/contracts/interfaces/ITokenManagerDeployer.sol @@ -12,11 +12,6 @@ interface ITokenManagerDeployer { error AddressZero(); error TokenManagerDeploymentFailed(); - /** - * @notice Getter for the Create3Deployer. - */ - function deployer() external view returns (Create3Deployer); - /** * @notice Deploys a new instance of the TokenManagerProxy contract * @param tokenId The unique identifier for the token diff --git a/contracts/utils/StandardizedTokenDeployer.sol b/contracts/utils/StandardizedTokenDeployer.sol index 5c2a2ca8..b7af5c8d 100644 --- a/contracts/utils/StandardizedTokenDeployer.sol +++ b/contracts/utils/StandardizedTokenDeployer.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { Create3Deployer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3Deployer.sol'; +import { Create3 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3.sol'; import { IStandardizedTokenDeployer } from '../interfaces/IStandardizedTokenDeployer.sol'; @@ -13,17 +13,14 @@ import { StandardizedTokenProxy } from '../proxies/StandardizedTokenProxy.sol'; * @notice This contract is used to deploy new instances of the StandardizedTokenProxy contract. */ contract StandardizedTokenDeployer is IStandardizedTokenDeployer { - Create3Deployer public immutable deployer; address public immutable implementationAddress; /** * @notice Constructor for the StandardizedTokenDeployer contract - * @param deployer_ Address of the Create3Deployer contract * @param implementationAddress_ Address of the StandardizedToken contract */ - constructor(address deployer_, address implementationAddress_) { - if (deployer_ == address(0) || implementationAddress_ == address(0)) revert AddressZero(); - deployer = Create3Deployer(deployer_); + constructor(address implementationAddress_) { + if (implementationAddress_ == address(0)) revert AddressZero(); implementationAddress = implementationAddress_; } @@ -53,7 +50,11 @@ contract StandardizedTokenDeployer is IStandardizedTokenDeployer { bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo); bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); } - address tokenAddress = deployer.deploy(bytecode, salt); + address tokenAddress = Create3.deploy(salt, bytecode); if (tokenAddress.code.length == 0) revert TokenDeploymentFailed(); } + + function deployedAddress(bytes32 salt) external view returns (address tokenAddress) { + return Create3.deployedAddress(address(this), salt); + } } diff --git a/contracts/utils/TokenManagerDeployer.sol b/contracts/utils/TokenManagerDeployer.sol index 8c552d80..14040795 100644 --- a/contracts/utils/TokenManagerDeployer.sol +++ b/contracts/utils/TokenManagerDeployer.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { Create3Deployer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3Deployer.sol'; +import { Create3 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3.sol'; import { ITokenManagerDeployer } from '../interfaces/ITokenManagerDeployer.sol'; @@ -13,17 +13,6 @@ import { TokenManagerProxy } from '../proxies/TokenManagerProxy.sol'; * @notice This contract is used to deploy new instances of the TokenManagerProxy contract. */ contract TokenManagerDeployer is ITokenManagerDeployer { - Create3Deployer public immutable deployer; - - /** - * @notice Constructor for the TokenManagerDeployer contract - * @param deployer_ Address of the Create3Deployer contract - */ - constructor(address deployer_) { - if (deployer_ == address(0)) revert AddressZero(); - deployer = Create3Deployer(deployer_); - } - /** * @notice Deploys a new instance of the TokenManagerProxy contract * @param tokenId The unique identifier for the token @@ -33,7 +22,7 @@ contract TokenManagerDeployer is ITokenManagerDeployer { function deployTokenManager(bytes32 tokenId, uint256 implementationType, bytes calldata params) external payable { bytes memory args = abi.encode(address(this), implementationType, tokenId, params); bytes memory bytecode = abi.encodePacked(type(TokenManagerProxy).creationCode, args); - address tokenManagerAddress = deployer.deploy(bytecode, tokenId); + address tokenManagerAddress = Create3.deploy(tokenId, bytecode); if (tokenManagerAddress.code.length == 0) revert TokenManagerDeploymentFailed(); } } diff --git a/hardhat.config.js b/hardhat.config.js index ef6ece08..b4a3f6ad 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -8,7 +8,6 @@ const { importNetworks, readJSON } = require('@axelar-network/axelar-contract-de const chains = require(`@axelar-network/axelar-contract-deployments/info/${env}.json`); const keys = readJSON(`${__dirname}/info/keys.json`); const { networks, etherscan } = importNetworks(chains, keys); - /** * @type import('hardhat/config').HardhatUserConfig */ diff --git a/scripts/deploy.js b/scripts/deploy.js index d23320a4..cb153979 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -80,12 +80,9 @@ async function deployAll(wallet, chainName, deploymentKey = 'interchainTokenServ const create3Deployer = await deployContract(wallet, 'Create3Deployer'); const gateway = await deployMockGateway(wallet); const gasService = await deployGasService(wallet); - const tokenManagerDeployer = await deployContract(wallet, 'TokenManagerDeployer', [create3Deployer.address]); + const tokenManagerDeployer = await deployContract(wallet, 'TokenManagerDeployer', []); const standardizedToken = await deployContract(wallet, 'StandardizedToken'); - const standardizedTokenDeployer = await deployContract(wallet, 'StandardizedTokenDeployer', [ - create3Deployer.address, - standardizedToken.address, - ]); + const standardizedTokenDeployer = await deployContract(wallet, 'StandardizedTokenDeployer', [standardizedToken.address]); const interchainTokenServiceAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey); const remoteAddressValidator = await deployRemoteAddressValidator(wallet, interchainTokenServiceAddress); const tokenManagerImplementations = await deployTokenManagerImplementations(wallet, interchainTokenServiceAddress); diff --git a/test/tokenServiceFullFlow.js b/test/tokenServiceFullFlow.js index 23376953..89bcf31c 100644 --- a/test/tokenServiceFullFlow.js +++ b/test/tokenServiceFullFlow.js @@ -8,13 +8,11 @@ const { AddressZero } = ethers.constants; const { defaultAbiCoder, keccak256 } = ethers.utils; const { Contract, Wallet } = ethers; -const IStandardizedTokenDeployer = require('../artifacts/contracts/interfaces/IStandardizedTokenDeployer.sol/IStandardizedTokenDeployer.json'); const IStandardizedToken = require('../artifacts/contracts/interfaces/IStandardizedToken.sol/IStandardizedToken.json'); const ITokenManager = require('../artifacts/contracts/interfaces/ITokenManager.sol/ITokenManager.json'); -const Create3Deployer = require('../artifacts/@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'); const { getRandomBytes32 } = require('../scripts/utils'); -const { deployAll } = require('../scripts/deploy'); +const { deployAll, deployContract } = require('../scripts/deploy'); const SELECTOR_SEND_TOKEN = 1; // const SELECTOR_SEND_TOKEN_WITH_DATA = 2; @@ -40,40 +38,18 @@ describe('Interchain Token Service', () => { describe('Full canonical token registration, remote deployment and token send', async () => { let token; - const salt = getRandomBytes32(); const otherChains = ['chain 1', 'chain 2']; const gasValues = [1234, 5678]; const tokenCap = BigInt(1e18); before(async () => { // The below is used to deploy a token, but any ERC20 can be used instead. - const tokenDeployerAddress = await service.standardizedTokenDeployer(); - const tokenDeployer = new Contract(tokenDeployerAddress, IStandardizedTokenDeployer.abi, wallet); - const create3DeployerAddress = await tokenDeployer.deployer(); - const create3Deployer = new Contract(create3DeployerAddress, Create3Deployer.abi, wallet); - const tokenAddress = await create3Deployer.deployedAddress(tokenDeployer.address, salt); - token = new Contract(tokenAddress, IStandardizedToken.abi, wallet); - - tokenId = await service.getCanonicalTokenId(tokenAddress); + token = await deployContract(wallet, 'InterchainTokenTest', [name, symbol, decimals, wallet.address]); + tokenId = await service.getCanonicalTokenId(token.address); const tokenManagerAddress = await service.getTokenManagerAddress(tokenId); + await (await token.mint(wallet.address, tokenCap)).wait(); + await (await token.setTokenManager(tokenManagerAddress)).wait(); tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet); - - await expect( - tokenDeployer.deployStandardizedToken( - salt, - tokenManagerAddress, - wallet.address, - name, - symbol, - decimals, - tokenCap, - wallet.address, - ), - ) - .to.emit(token, 'DistributorshipTransferred') - .withArgs(wallet.address) - .and.to.emit(token, 'Transfer') - .withArgs(AddressZero, wallet.address, tokenCap); }); it('Should register the token and initiate its deployment on other chains', async () => { diff --git a/test/utils.js b/test/utils.js index 16a90746..6d0e4f73 100644 --- a/test/utils.js +++ b/test/utils.js @@ -344,7 +344,7 @@ describe('Pausable', () => { }); describe('StandardizedTokenDeployer', () => { - let create3Deployer, standardizedToken, standardizedTokenDeployer; + let standardizedToken, standardizedTokenDeployer; const tokenManager = new Wallet(getRandomBytes32()).address; const mintTo = new Wallet(getRandomBytes32()).address; const name = 'tokenName'; @@ -353,18 +353,14 @@ describe('StandardizedTokenDeployer', () => { const mintAmount = 123; before(async () => { - create3Deployer = await deployContract(ownerWallet, 'Create3Deployer'); standardizedToken = await deployContract(ownerWallet, 'StandardizedToken'); - standardizedTokenDeployer = await deployContract(ownerWallet, 'StandardizedTokenDeployer', [ - create3Deployer.address, - standardizedToken.address, - ]); + standardizedTokenDeployer = await deployContract(ownerWallet, 'StandardizedTokenDeployer', [standardizedToken.address]); }); it('Should deploy a mint burn token only once', async () => { const salt = getRandomBytes32(); - const tokenAddress = await create3Deployer.deployedAddress(standardizedTokenDeployer.address, salt); + const tokenAddress = await standardizedTokenDeployer.deployedAddress(salt); const token = new Contract(tokenAddress, StandardizedToken.abi, ownerWallet); const tokenProxy = new Contract(tokenAddress, StandardizedTokenProxy.abi, ownerWallet); @@ -386,6 +382,6 @@ describe('StandardizedTokenDeployer', () => { expect(await token.tokenManager()).to.equal(tokenManager); await expect( standardizedTokenDeployer.deployStandardizedToken(salt, tokenManager, tokenManager, name, symbol, decimals, mintAmount, mintTo), - ).to.be.revertedWithCustomError(create3Deployer, 'AlreadyDeployed'); + ).to.be.revertedWithCustomError(standardizedTokenDeployer, 'AlreadyDeployed'); }); }); From 8d66c0b4d42fa7c3918ee9e2ccb9d80b7a4e3b1b Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 4 Sep 2023 17:19:12 +0300 Subject: [PATCH 03/12] feat: fee on transfer as a separate token manager (#96) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. --------- Co-authored-by: Milap Sheth --- .../InterchainTokenService.sol | 32 ++-- .../interfaces/IInterchainTokenService.sol | 6 - contracts/interfaces/INoReEntrancy.sol | 12 ++ contracts/interfaces/ITokenManagerType.sol | 1 + .../RemoteAddressValidator.sol | 15 +- contracts/test/FeeOnTransferTokenTest.sol | 72 ++++++++ .../TokenManagerLiquidityPool.sol | 9 +- .../TokenManagerLockUnlock.sol | 7 +- .../TokenManagerLockUnlockFeeOnTransfer.sol | 72 ++++++++ contracts/utils/Multicall.sol | 4 +- contracts/utils/NoReEntrancy.sol | 46 +++++ scripts/deploy.js | 2 +- test/tokenService.js | 167 ++++++++++++++++-- 13 files changed, 387 insertions(+), 58 deletions(-) create mode 100644 contracts/interfaces/INoReEntrancy.sol create mode 100644 contracts/test/FeeOnTransferTokenTest.sol create mode 100644 contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol create mode 100644 contracts/utils/NoReEntrancy.sol diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index fc9070da..e4fc3cc1 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -50,6 +50,7 @@ contract InterchainTokenService is address internal immutable implementationLockUnlock; address internal immutable implementationMintBurn; + address internal immutable implementationLockUnlockFee; address internal immutable implementationLiquidityPool; IAxelarGasService public immutable gasService; IRemoteAddressValidator public immutable remoteAddressValidator; @@ -103,6 +104,10 @@ contract InterchainTokenService is implementationLockUnlock = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LOCK_UNLOCK); implementationMintBurn = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.MINT_BURN); + implementationLockUnlockFee = _sanitizeTokenManagerImplementation( + tokenManagerImplementations, + TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER + ); implementationLiquidityPool = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LIQUIDITY_POOL); chainName = chainName_.toBytes32(); @@ -143,14 +148,6 @@ contract InterchainTokenService is return CONTRACT_ID; } - /** - * @notice Getter for the chain name. - * @return name the name of the chain - */ - function getChainName() public view returns (string memory name) { - name = chainName.toTrimmedString(); - } - /** * @notice Calculates the address of a TokenManager from a specific tokenId. The TokenManager does not need to exist already. * @param tokenId the tokenId. @@ -225,6 +222,8 @@ contract InterchainTokenService is return implementationLockUnlock; } else if (TokenManagerType(tokenManagerType) == TokenManagerType.MINT_BURN) { return implementationMintBurn; + } else if (TokenManagerType(tokenManagerType) == TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER) { + return implementationLockUnlockFee; } else if (TokenManagerType(tokenManagerType) == TokenManagerType.LIQUIDITY_POOL) { return implementationLiquidityPool; } @@ -439,6 +438,7 @@ contract InterchainTokenService is /** * @notice Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing * sendToken that matches the parameters passed here. + * @dev This is not to be used with fee on transfer tokens as it will incur losses for the express caller. * @param tokenId the tokenId of the TokenManager used. * @param destinationAddress the destinationAddress for the sendToken. * @param amount the amount of token to give. @@ -459,6 +459,7 @@ contract InterchainTokenService is /** * @notice Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have * detected an outgoing sendToken that matches the parameters passed here. + * @dev This is not to be used with fee on transfer tokens as it will incur losses for the express caller and it will pass an incorrect amount to the contract. * @param tokenId the tokenId of the TokenManager used. * @param sourceChain the name of the chain where the call came from. * @param sourceAddress the caller of callContractWithInterchainToken. @@ -513,7 +514,7 @@ contract InterchainTokenService is bytes memory payload; if (metadata.length < 4) { payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount); - _callContract(destinationChain, payload, msg.value, sourceAddress); + _callContract(destinationChain, payload, msg.value); emit TokenSent(tokenId, destinationChain, destinationAddress, amount); return; } @@ -521,7 +522,7 @@ contract InterchainTokenService is (version, metadata) = _decodeMetadata(metadata); if (version > 0) revert InvalidMetadataVersion(version); payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata); - _callContract(destinationChain, payload, msg.value, sourceAddress); + _callContract(destinationChain, payload, msg.value); emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata); } @@ -719,17 +720,16 @@ contract InterchainTokenService is * @param destinationChain The target chain where the contract will be called * @param payload The data payload for the transaction * @param gasValue The amount of gas to be paid for the transaction - * @param refundTo The address where the unused gas amount should be refunded to */ - function _callContract(string calldata destinationChain, bytes memory payload, uint256 gasValue, address refundTo) internal { + function _callContract(string calldata destinationChain, bytes memory payload, uint256 gasValue) internal { string memory destinationAddress = remoteAddressValidator.getRemoteAddress(destinationChain); if (gasValue > 0) { gasService.payNativeGasForContractCall{ value: gasValue }( address(this), destinationChain, destinationAddress, - payload, - refundTo + payload, // solhint-disable-next-line avoid-tx-origin + tx.origin ); } gateway.callContract(destinationChain, destinationAddress, payload); @@ -758,7 +758,7 @@ contract InterchainTokenService is bytes memory params ) internal { bytes memory payload = abi.encode(SELECTOR_DEPLOY_TOKEN_MANAGER, tokenId, tokenManagerType, params); - _callContract(destinationChain, payload, gasValue, msg.sender); + _callContract(destinationChain, payload, gasValue); emit RemoteTokenManagerDeploymentInitialized(tokenId, destinationChain, gasValue, tokenManagerType, params); } @@ -798,7 +798,7 @@ contract InterchainTokenService is mintAmount, operator ); - _callContract(destinationChain, payload, gasValue, msg.sender); + _callContract(destinationChain, payload, gasValue); emit RemoteStandardizedTokenAndManagerDeploymentInitialized( tokenId, name, diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index f39d1741..e5c3d2cb 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -90,12 +90,6 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx */ function standardizedTokenDeployer() external view returns (address standardizedTokenDeployerAddress); - /** - * @notice Returns the name of the current chain. - * @return name The name of the current chain. - */ - function getChainName() external view returns (string memory name); - /** * @notice Returns the address of the token manager associated with the given tokenId. * @param tokenId The tokenId of the token manager. diff --git a/contracts/interfaces/INoReEntrancy.sol b/contracts/interfaces/INoReEntrancy.sol new file mode 100644 index 00000000..9e0dd68d --- /dev/null +++ b/contracts/interfaces/INoReEntrancy.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Pausable + * @notice This contract provides a mechanism to halt the execution of specific functions + * if a pause condition is activated. + */ +interface INoReEntrancy { + error ReEntrancy(); +} diff --git a/contracts/interfaces/ITokenManagerType.sol b/contracts/interfaces/ITokenManagerType.sol index 9da7ec99..b9a42ade 100644 --- a/contracts/interfaces/ITokenManagerType.sol +++ b/contracts/interfaces/ITokenManagerType.sol @@ -10,6 +10,7 @@ interface ITokenManagerType { enum TokenManagerType { LOCK_UNLOCK, MINT_BURN, + LOCK_UNLOCK_FEE_ON_TRANSFER, LIQUIDITY_POOL } } diff --git a/contracts/remote-address-validator/RemoteAddressValidator.sol b/contracts/remote-address-validator/RemoteAddressValidator.sol index dfa760c6..08507209 100644 --- a/contracts/remote-address-validator/RemoteAddressValidator.sol +++ b/contracts/remote-address-validator/RemoteAddressValidator.sol @@ -77,10 +77,10 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { */ function _lowerCase(string memory s) internal pure returns (string memory) { uint256 length = bytes(s).length; - - for (uint256 i; i < length; i++) { - uint8 b = uint8(bytes(s)[i]); - if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32)); + uint8 b; + for (uint256 i; i < length; ++i) { + b = uint8(bytes(s)[i]); + if ((b >= 65) && (b <= 90)) bytes(s)[i] = bytes1(b + uint8(32)); } return s; @@ -152,9 +152,9 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { */ function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { uint256 length = chainNames.length; - + string calldata chainName; for (uint256 i; i < length; ++i) { - string calldata chainName = chainNames[i]; + chainName = chainNames[i]; supportedByGateway[chainName] = true; emit GatewaySupportedChainAdded(chainName); @@ -167,9 +167,10 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { */ function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { uint256 length = chainNames.length; + string calldata chainName; for (uint256 i; i < length; ++i) { - string calldata chainName = chainNames[i]; + chainName = chainNames[i]; supportedByGateway[chainName] = false; emit GatewaySupportedChainRemoved(chainName); diff --git a/contracts/test/FeeOnTransferTokenTest.sol b/contracts/test/FeeOnTransferTokenTest.sol new file mode 100644 index 00000000..a5163a1f --- /dev/null +++ b/contracts/test/FeeOnTransferTokenTest.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { InterchainToken } from '../interchain-token/InterchainToken.sol'; +import { Distributable } from '../utils/Distributable.sol'; +import { ITokenManager } from '../interfaces/ITokenManager.sol'; +import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; + +contract FeeOnTransferTokenTest is InterchainToken, Distributable, IERC20BurnableMintable { + ITokenManager public tokenManager_; + bool internal tokenManagerRequiresApproval_ = true; + string public name; + string public symbol; + uint8 public decimals; + + constructor(string memory name_, string memory symbol_, uint8 decimals_, address tokenManagerAddress) { + name = name_; + symbol = symbol_; + decimals = decimals_; + _setDistributor(msg.sender); + tokenManager_ = ITokenManager(tokenManagerAddress); + } + + function tokenManager() public view override returns (ITokenManager) { + return tokenManager_; + } + + function _beforeInterchainTransfer( + address sender, + string calldata /*destinationChain*/, + bytes calldata /*destinationAddress*/, + uint256 amount, + bytes calldata /*metadata*/ + ) internal override { + if (!tokenManagerRequiresApproval_) return; + address tokenManagerAddress = address(tokenManager_); + uint256 allowance_ = allowance[sender][tokenManagerAddress]; + if (allowance_ != type(uint256).max) { + if (allowance_ > type(uint256).max - amount) { + allowance_ = type(uint256).max - amount; + } + + _approve(sender, tokenManagerAddress, allowance_ + amount); + } + } + + function setTokenManagerRequiresApproval(bool requiresApproval) public { + tokenManagerRequiresApproval_ = requiresApproval; + } + + function mint(address account, uint256 amount) external onlyDistributor { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external onlyDistributor { + _burn(account, amount); + } + + function setTokenManager(ITokenManager tokenManagerAddress) external { + tokenManager_ = tokenManagerAddress; + } + + // Always transfer 10 less base tokens. + function _transfer(address sender, address recipient, uint256 amount) internal override { + if (sender == address(0) || recipient == address(0)) revert InvalidAccount(); + + balanceOf[sender] -= amount; + balanceOf[recipient] += amount - 10; + emit Transfer(sender, recipient, amount); + } +} diff --git a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol index d1497425..a3468599 100644 --- a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol +++ b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; +import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; @@ -14,7 +15,7 @@ import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/c * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerLiquidityPool is TokenManagerAddressStorage { +contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { // uint256(keccak256('liquidity-pool-slot')) - 1 uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807; @@ -26,7 +27,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage { constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} function implementationType() external pure returns (uint256) { - return 2; + return 3; } /** @@ -74,7 +75,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage { * @param amount The amount of tokens to transfer * @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. */ - function _takeToken(address from, uint256 amount) internal override returns (uint256) { + function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); address liquidityPool_ = liquidityPool(); uint256 balance = token.balanceOf(liquidityPool_); @@ -91,7 +92,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage { * @param amount The amount of tokens to transfer * @return uint The actual amount of tokens transferred */ - function _giveToken(address to, uint256 amount) internal override returns (uint256) { + function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); uint256 balance = IERC20(token).balanceOf(to); diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol index 2de125de..06e858a7 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol @@ -43,12 +43,10 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage { */ function _takeToken(address from, uint256 amount) internal override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = token.balanceOf(address(this)); SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); - // Note: This allows support for fee-on-transfer tokens - return IERC20(token).balanceOf(address(this)) - balance; + return amount; } /** @@ -59,10 +57,9 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage { */ function _giveToken(address to, uint256 amount) internal override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = IERC20(token).balanceOf(to); SafeTokenTransfer.safeTransfer(token, to, amount); - return IERC20(token).balanceOf(to) - balance; + return amount; } } diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol new file mode 100644 index 00000000..4cf3c5dc --- /dev/null +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; +import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; +import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; + +import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; + +/** + * @title TokenManagerLockUnlock + * @notice This contract is an implementation of TokenManager that locks and unlocks a specific token on behalf of the interchain token service. + * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. + * It uses the Axelar SDK to safely transfer tokens. + */ +contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { + /** + * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor + * of TokenManagerAddressStorage which calls the constructor of TokenManager. + * @param interchainTokenService_ The address of the interchain token service contract + */ + constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} + + function implementationType() external pure returns (uint256) { + return 2; + } + + /** + * @dev Sets up the token address. + * @param params The setup parameters in bytes. Should be encoded with the token address. + */ + function _setup(bytes calldata params) internal override { + // The first argument is reserved for the operator. + (, address tokenAddress) = abi.decode(params, (bytes, address)); + _setTokenAddress(tokenAddress); + } + + /** + * @dev Transfers a specified amount of tokens from a specified address to this contract. + * @param from The address to transfer tokens from + * @param amount The amount of tokens to transfer + * @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. + */ + function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) { + IERC20 token = IERC20(tokenAddress()); + uint256 balance = token.balanceOf(address(this)); + + SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); + + uint256 diff = token.balanceOf(address(this)) - balance; + if (diff < amount) { + amount = diff; + } + return amount; + } + + /** + * @dev Transfers a specified amount of tokens from this contract to a specified address. + * @param to The address to transfer tokens to + * @param amount The amount of tokens to transfer + * @return uint The actual amount of tokens transferred + */ + function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { + IERC20 token = IERC20(tokenAddress()); + uint256 balance = IERC20(token).balanceOf(to); + + SafeTokenTransfer.safeTransfer(token, to, amount); + + return IERC20(token).balanceOf(to) - balance; + } +} diff --git a/contracts/utils/Multicall.sol b/contracts/utils/Multicall.sol index 4c94e407..50914d39 100644 --- a/contracts/utils/Multicall.sol +++ b/contracts/utils/Multicall.sol @@ -21,8 +21,10 @@ contract Multicall is IMulticall { */ function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) { results = new bytes[](data.length); + bool success; + bytes memory result; for (uint256 i = 0; i < data.length; ++i) { - (bool success, bytes memory result) = address(this).delegatecall(data[i]); + (success, result) = address(this).delegatecall(data[i]); if (!success) { revert(string(result)); diff --git a/contracts/utils/NoReEntrancy.sol b/contracts/utils/NoReEntrancy.sol new file mode 100644 index 00000000..0a1e1225 --- /dev/null +++ b/contracts/utils/NoReEntrancy.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { INoReEntrancy } from '../interfaces/INoReEntrancy.sol'; + +/** + * @title Pausable + * @notice This contract provides a mechanism to halt the execution of specific functions + * if a pause condition is activated. + */ +contract NoReEntrancy is INoReEntrancy { + // uint256(keccak256('entered')) - 1 + uint256 internal constant ENTERED_SLOT = 0x01f33dd720a8dea3c4220dc5074a2239fb442c4c775306a696f97a7c54f785fc; + + /** + * @notice A modifier that throws a Paused custom error if the contract is paused + * @dev This modifier should be used with functions that can be paused + */ + modifier noReEntrancy() { + if (_hasEntered()) revert ReEntrancy(); + _setEntered(true); + _; + _setEntered(false); + } + + /** + * @notice Check if the contract is already executing. + * @return entered A boolean representing the entered status. True if already executing, false otherwise. + */ + function _hasEntered() internal view returns (bool entered) { + assembly { + entered := sload(ENTERED_SLOT) + } + } + + /** + * @notice Sets the entered status of the contract + * @param entered A boolean representing the entered status. True if already executing, false otherwise. + */ + function _setEntered(bool entered) internal { + assembly { + sstore(ENTERED_SLOT, entered) + } + } +} diff --git a/scripts/deploy.js b/scripts/deploy.js index cb153979..0d66964b 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -68,7 +68,7 @@ async function deployInterchainTokenService( async function deployTokenManagerImplementations(wallet, interchainTokenServiceAddress) { const implementations = []; - for (const type of ['LockUnlock', 'MintBurn', 'LiquidityPool']) { + for (const type of ['LockUnlock', 'MintBurn', 'LockUnlockFee', 'LiquidityPool']) { const impl = await deployContract(wallet, `TokenManager${type}`, [interchainTokenServiceAddress]); implementations.push(impl); } diff --git a/test/tokenService.js b/test/tokenService.js index ec201748..9b856885 100644 --- a/test/tokenService.js +++ b/test/tokenService.js @@ -21,7 +21,8 @@ const SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN = 4; const LOCK_UNLOCK = 0; const MINT_BURN = 1; -const LIQUIDITY_POOL = 2; +const LOCK_UNLOCK_FEE_ON_TRANSFER = 2; +const LIQUIDITY_POOL = 3; describe('Interchain Token Service', () => { let wallet, liquidityPool; @@ -53,6 +54,30 @@ describe('Interchain Token Service', () => { return [token, tokenManager, tokenId]; }; + deployFunctions.lockUnlockFee = async function deployNewLockUnlock( + tokenName, + tokenSymbol, + tokenDecimals, + mintAmount = 0, + skipApprove = false, + ) { + const salt = getRandomBytes32(); + const tokenId = await service.getCustomTokenId(wallet.address, salt); + const tokenManager = new Contract(await service.getTokenManagerAddress(tokenId), TokenManager.abi, wallet); + + const token = await deployContract(wallet, 'FeeOnTransferTokenTest', [tokenName, tokenSymbol, tokenDecimals, tokenManager.address]); + const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + + await (await service.deployCustomTokenManager(salt, LOCK_UNLOCK_FEE_ON_TRANSFER, params)).wait(); + + if (mintAmount > 0) { + await (await token.mint(wallet.address, mintAmount)).wait(); + if (!skipApprove) await (await token.approve(tokenManager.address, mintAmount)).wait(); + } + + return [token, tokenManager, tokenId]; + }; + deployFunctions.mintBurn = async function deployNewMintBurn(tokenName, tokenSymbol, tokenDecimals, mintAmount = 0) { const salt = getRandomBytes32(); const tokenId = await service.getCustomTokenId(wallet.address, salt); @@ -562,6 +587,30 @@ describe('Interchain Token Service', () => { expect(await tokenManager.operator()).to.equal(wallet.address); }); + it('Should deploy a lock/unlock with fee on transfer token manager', async () => { + const tokenName = 'Token Name'; + const tokenSymbol = 'TN'; + const tokenDecimals = 13; + const salt = getRandomBytes32(); + const tokenId = await service.getCustomTokenId(wallet.address, salt); + const tokenManagerAddress = await service.getTokenManagerAddress(tokenId); + const token = await deployContract(wallet, 'FeeOnTransferTokenTest', [ + tokenName, + tokenSymbol, + tokenDecimals, + tokenManagerAddress, + ]); + const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + + const tx = service.deployCustomTokenManager(salt, LOCK_UNLOCK_FEE_ON_TRANSFER, params); + await expect(tx).to.emit(service, 'TokenManagerDeployed').withArgs(tokenId, LOCK_UNLOCK_FEE_ON_TRANSFER, params); + + expect(tokenManagerAddress).to.not.equal(AddressZero); + const tokenManager = new Contract(tokenManagerAddress, TokenManager.abi, wallet); + + expect(await tokenManager.operator()).to.equal(wallet.address); + }); + it('Should deploy a liquidity pool token manager', async () => { const tokenName = 'Token Name'; const tokenSymbol = 'TN'; @@ -798,18 +847,19 @@ describe('Interchain Token Service', () => { const destAddress = '0x5678'; const gasValue = 90; - for (const type of ['lockUnlock', 'mintBurn', 'liquidityPool']) { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'liquidityPool']) { it(`Should be able to initiate an interchain token transfer [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount); + const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'uint256'], - [SELECTOR_SEND_TOKEN, tokenId, destAddress, amount], + [SELECTOR_SEND_TOKEN, tokenId, destAddress, sendAmount], ); const payloadHash = keccak256(payload); let transferToAddress = AddressZero; - if (type === 'lockUnlock') { + if (type === 'lockUnlock' || type === 'lockUnlockFee') { transferToAddress = tokenManager.address; } else if (type === 'liquidityPool') { transferToAddress = liquidityPool.address; @@ -823,7 +873,7 @@ describe('Interchain Token Service', () => { .and.to.emit(gasService, 'NativeGasPaidForContractCall') .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, gasValue, wallet.address) .to.emit(service, 'TokenSent') - .withArgs(tokenId, destChain, destAddress, amount); + .withArgs(tokenId, destChain, destAddress, sendAmount); }); } }); @@ -871,6 +921,23 @@ describe('Interchain Token Service', () => { .withArgs(tokenId, sourceChain, destAddress, amount); }); + it('Should be able to receive lock/unlock with fee on transfer token', async () => { + const [token, tokenManager, tokenId] = await deployFunctions.lockUnlockFee(`Test Token Lock Unlock`, 'TT', 12, amount + 10); + (await await token.transfer(tokenManager.address, amount + 10)).wait(); + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256'], + [SELECTOR_SEND_TOKEN, tokenId, destAddress, amount], + ); + const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + + await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) + .to.emit(token, 'Transfer') + .withArgs(tokenManager.address, destAddress, amount) + .and.to.emit(service, 'TokenReceived') + .withArgs(tokenId, sourceChain, destAddress, amount - 10); + }); + it('Should be able to receive liquidity pool token', async () => { const [token, , tokenId] = await deployFunctions.liquidityPool(`Test Token Liquidity Pool`, 'TTLP', 12, amount); (await await token.transfer(liquidityPool.address, amount)).wait(); @@ -900,18 +967,19 @@ describe('Interchain Token Service', () => { sourceAddress = wallet.address; }); - for (const type of ['lockUnlock', 'mintBurn', 'liquidityPool']) { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'liquidityPool']) { it(`Should be able to initiate an interchain token transfer [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount); + const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'uint256', 'bytes', 'bytes'], - [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, amount, sourceAddress, data], + [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, sendAmount, sourceAddress, data], ); const payloadHash = keccak256(payload); let transferToAddress = AddressZero; - if (type === 'lockUnlock') { + if (type === 'lockUnlock' || type === 'lockUnlockFee') { transferToAddress = tokenManager.address; } else if (type === 'liquidityPool') { transferToAddress = liquidityPool.address; @@ -925,7 +993,7 @@ describe('Interchain Token Service', () => { .and.to.emit(gasService, 'NativeGasPaidForContractCall') .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, gasValue, wallet.address) .to.emit(service, 'TokenSentWithData') - .withArgs(tokenId, destChain, destAddress, amount, sourceAddress, data); + .withArgs(tokenId, destChain, destAddress, sendAmount, sourceAddress, data); }); } }); @@ -992,6 +1060,30 @@ describe('Interchain Token Service', () => { expect(await executable.lastMessage()).to.equal(msg); }); + it('Should be able to receive lock/unlock with fee on transfer token', async () => { + const [token, tokenManager, tokenId] = await deployFunctions.lockUnlockFee(`Test Token Lock Unlock`, 'TT', 12, amount + 10); + (await await token.transfer(tokenManager.address, amount + 10)).wait(); + const msg = `lock/unlock`; + const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256', 'bytes', 'bytes'], + [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, amount, sourceAddressForService, data], + ); + const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + + await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) + .to.emit(token, 'Transfer') + .withArgs(tokenManager.address, destAddress, amount) + .to.emit(token, 'Transfer') + .withArgs(destAddress, wallet.address, amount - 10) + .and.to.emit(service, 'TokenReceivedWithData') + .withArgs(tokenId, sourceChain, destAddress, amount - 10, sourceAddressForService, data) + .and.to.emit(executable, 'MessageReceived') + .withArgs(sourceChain, sourceAddressForService, wallet.address, msg, tokenId, amount - 10); + + expect(await executable.lastMessage()).to.equal(msg); + }); + it('Should be able to receive liquidity pool token', async () => { const [token, , tokenId] = await deployFunctions.liquidityPool(`Test Token Liquidity Pool`, 'TTLP', 12, amount); (await await token.transfer(liquidityPool.address, amount)).wait(); @@ -1024,19 +1116,19 @@ describe('Interchain Token Service', () => { const gasValue = 90; const metadata = '0x'; - for (const type of ['lockUnlock', 'mintBurn', 'liquidityPool']) { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'liquidityPool']) { it(`Should be able to initiate an interchain token transfer [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount, true); - + const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'uint256'], - [SELECTOR_SEND_TOKEN, tokenId, destAddress, amount], + [SELECTOR_SEND_TOKEN, tokenId, destAddress, sendAmount], ); const payloadHash = keccak256(payload); let transferToAddress = AddressZero; - if (type === 'lockUnlock') { + if (type === 'lockUnlock' || type === 'lockUnlockFee') { transferToAddress = tokenManager.address; } else if (type === 'liquidityPool') { transferToAddress = liquidityPool.address; @@ -1050,7 +1142,7 @@ describe('Interchain Token Service', () => { .and.to.emit(gasService, 'NativeGasPaidForContractCall') .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, gasValue, wallet.address) .to.emit(service, 'TokenSent') - .withArgs(tokenId, destChain, destAddress, amount); + .withArgs(tokenId, destChain, destAddress, sendAmount); }); } }); @@ -1067,19 +1159,20 @@ describe('Interchain Token Service', () => { sourceAddress = wallet.address; }); - for (const type of ['lockUnlock', 'mintBurn', 'liquidityPool']) { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'liquidityPool']) { it(`Should be able to initiate an interchain token transfer [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount, false); + const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'uint256', 'bytes', 'bytes'], - [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, amount, sourceAddress, data], + [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, sendAmount, sourceAddress, data], ); const payloadHash = keccak256(payload); let transferToAddress = AddressZero; - if (type === 'lockUnlock') { + if (type === 'lockUnlock' || type === 'lockUnlockFee') { transferToAddress = tokenManager.address; } else if (type === 'liquidityPool') { transferToAddress = liquidityPool.address; @@ -1094,7 +1187,7 @@ describe('Interchain Token Service', () => { .and.to.emit(gasService, 'NativeGasPaidForContractCall') .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, gasValue, wallet.address) .to.emit(service, 'TokenSentWithData') - .withArgs(tokenId, destChain, destAddress, amount, sourceAddress, data); + .withArgs(tokenId, destChain, destAddress, sendAmount, sourceAddress, data); }); } }); @@ -1193,6 +1286,26 @@ describe('Interchain Token Service', () => { .withArgs(tokenId, destAddress, amount, commandId, wallet.address); }); + it('Should be able to receive lock/unlock with fee on transfer token', async () => { + const [token, tokenManager, tokenId] = await deployFunctions.lockUnlockFee(`Test Token Lock Unlock`, 'TT', 12, 2 * amount + 10); + await (await token.transfer(tokenManager.address, amount + 10)).wait(); + await (await token.approve(service.address, amount)).wait(); + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256'], + [SELECTOR_SEND_TOKEN, tokenId, destAddress, amount], + ); + const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + + await (await service.expressReceiveToken(tokenId, destAddress, amount, commandId)).wait(); + + await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) + .to.emit(token, 'Transfer') + .withArgs(tokenManager.address, wallet.address, amount) + .and.to.emit(service, 'ExpressExecutionFulfilled') + .withArgs(tokenId, destAddress, amount, commandId, wallet.address); + }); + it('Should be able to receive liquidity pool token', async () => { const [token, , tokenId] = await deployFunctions.liquidityPool(`Test Token Liquidity Pool`, 'TTLP', 12, amount * 2); await (await token.transfer(liquidityPool.address, amount)).wait(); @@ -1296,6 +1409,24 @@ describe('Interchain Token Service', () => { expect(await executable.lastMessage()).to.equal(msg); }); + it('Should be able to receive lock/unlock with fee on transfer token', async () => { + const [token, tokenManager, tokenId] = await deployFunctions.lockUnlockFee(`Test Token Lock Unlock`, 'TT', 12, amount * 2 + 10); + await (await token.transfer(tokenManager.address, amount + 10)).wait(); + await (await token.approve(service.address, amount)).wait(); + + const msg = `lock/unlock`; + const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256', 'bytes', 'bytes'], + [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destAddress, amount, sourceAddressForService, data], + ); + const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + + await expect( + service.expressReceiveTokenWithData(tokenId, sourceChain, sourceAddressForService, destAddress, amount, data, commandId), + ).to.be.reverted; + }); + it('Should be able to receive liquidity pool token', async () => { const [token, , tokenId] = await deployFunctions.liquidityPool(`Test Token Liquidity Pool`, 'TTLP', 12, amount * 2); (await await token.transfer(liquidityPool.address, amount)).wait(); From 950fc9eff5e20deae974ed7ac4e980a97bce37c0 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Wed, 27 Sep 2023 14:20:55 -0400 Subject: [PATCH 04/12] fix: flow limit should have a tighter check (#97) Co-authored-by: Foivos --- contracts/token-manager/TokenManager.sol | 3 +++ contracts/utils/ExpressCallHandler.sol | 10 ++++++++++ contracts/utils/FlowLimit.sol | 15 +++++++++++++-- contracts/utils/StandardizedTokenDeployer.sol | 9 ++++----- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/contracts/token-manager/TokenManager.sol b/contracts/token-manager/TokenManager.sol index 73926308..5e7fb798 100644 --- a/contracts/token-manager/TokenManager.sol +++ b/contracts/token-manager/TokenManager.sol @@ -78,6 +78,7 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen } else { operator_ = operatorBytes.toAddress(); } + _setOperator(operator_); _setup(params); } @@ -96,8 +97,10 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen bytes calldata metadata ) external payable virtual { address sender = msg.sender; + amount = _takeToken(sender, amount); _addFlowOut(amount); + interchainTokenService.transmitSendToken{ value: msg.value }( this.tokenId(), sender, diff --git a/contracts/utils/ExpressCallHandler.sol b/contracts/utils/ExpressCallHandler.sol index 496cc617..d2612d93 100644 --- a/contracts/utils/ExpressCallHandler.sol +++ b/contracts/utils/ExpressCallHandler.sol @@ -88,10 +88,13 @@ contract ExpressCallHandler is IExpressCallHandler { assembly { prevExpressCaller := sload(slot) } + if (prevExpressCaller != address(0)) revert AlreadyExpressCalled(); + assembly { sstore(slot, expressCaller) } + emit ExpressReceive(tokenId, destinationAddress, amount, commandId, expressCaller); } @@ -130,10 +133,13 @@ contract ExpressCallHandler is IExpressCallHandler { assembly { prevExpressCaller := sload(slot) } + if (prevExpressCaller != address(0)) revert AlreadyExpressCalled(); + assembly { sstore(slot, expressCaller) } + emit ExpressReceiveWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); } @@ -209,10 +215,12 @@ contract ExpressCallHandler is IExpressCallHandler { assembly { expressCaller := sload(slot) } + if (expressCaller != address(0)) { assembly { sstore(slot, 0) } + emit ExpressExecutionFulfilled(tokenId, destinationAddress, amount, commandId, expressCaller); } } @@ -249,10 +257,12 @@ contract ExpressCallHandler is IExpressCallHandler { assembly { expressCaller := sload(slot) } + if (expressCaller != address(0)) { assembly { sstore(slot, 0) } + emit ExpressExecutionWithDataFulfilled( tokenId, sourceChain, diff --git a/contracts/utils/FlowLimit.sol b/contracts/utils/FlowLimit.sol index 8caa7cea..94acdc79 100644 --- a/contracts/utils/FlowLimit.sol +++ b/contracts/utils/FlowLimit.sol @@ -12,8 +12,8 @@ import { IFlowLimit } from '../interfaces/IFlowLimit.sol'; contract FlowLimit is IFlowLimit { // uint256(keccak256('flow-limit')) - 1 uint256 internal constant FLOW_LIMIT_SLOT = 0x201b7a0b7c19aaddc4ce9579b7df8d2db123805861bc7763627f13e04d8af42f; - uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount')); - uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount')); + uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('flow-out-amount')); + uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('flow-in-amount')); uint256 internal constant EPOCH_TIME = 6 hours; @@ -35,6 +35,7 @@ contract FlowLimit is IFlowLimit { assembly { sstore(FLOW_LIMIT_SLOT, flowLimit) } + emit FlowLimitSet(flowLimit); } @@ -63,6 +64,7 @@ contract FlowLimit is IFlowLimit { function getFlowOutAmount() external view returns (uint256 flowOutAmount) { uint256 epoch = block.timestamp / EPOCH_TIME; uint256 slot = _getFlowOutSlot(epoch); + assembly { flowOutAmount := sload(slot) } @@ -75,6 +77,7 @@ contract FlowLimit is IFlowLimit { function getFlowInAmount() external view returns (uint256 flowInAmount) { uint256 epoch = block.timestamp / EPOCH_TIME; uint256 slot = _getFlowInSlot(epoch); + assembly { flowInAmount := sload(slot) } @@ -90,11 +93,15 @@ contract FlowLimit is IFlowLimit { function _addFlow(uint256 flowLimit, uint256 slotToAdd, uint256 slotToCompare, uint256 flowAmount) internal { uint256 flowToAdd; uint256 flowToCompare; + assembly { flowToAdd := sload(slotToAdd) flowToCompare := sload(slotToCompare) } + if (flowToAdd + flowAmount > flowToCompare + flowLimit) revert FlowLimitExceeded(); + if (flowAmount > flowLimit) revert FlowLimitExceeded(); + assembly { sstore(slotToAdd, add(flowToAdd, flowAmount)) } @@ -107,9 +114,11 @@ contract FlowLimit is IFlowLimit { function _addFlowOut(uint256 flowOutAmount) internal { uint256 flowLimit = getFlowLimit(); if (flowLimit == 0) return; + uint256 epoch = block.timestamp / EPOCH_TIME; uint256 slotToAdd = _getFlowOutSlot(epoch); uint256 slotToCompare = _getFlowInSlot(epoch); + _addFlow(flowLimit, slotToAdd, slotToCompare, flowOutAmount); } @@ -120,9 +129,11 @@ contract FlowLimit is IFlowLimit { function _addFlowIn(uint256 flowInAmount) internal { uint256 flowLimit = getFlowLimit(); if (flowLimit == 0) return; + uint256 epoch = block.timestamp / EPOCH_TIME; uint256 slotToAdd = _getFlowInSlot(epoch); uint256 slotToCompare = _getFlowOutSlot(epoch); + _addFlow(flowLimit, slotToAdd, slotToCompare, flowInAmount); } } diff --git a/contracts/utils/StandardizedTokenDeployer.sol b/contracts/utils/StandardizedTokenDeployer.sol index b7af5c8d..dd74d8d2 100644 --- a/contracts/utils/StandardizedTokenDeployer.sol +++ b/contracts/utils/StandardizedTokenDeployer.sol @@ -45,12 +45,11 @@ contract StandardizedTokenDeployer is IStandardizedTokenDeployer { uint256 mintAmount, address mintTo ) external payable { - bytes memory bytecode; - { - bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo); - bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); - } + bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo); + bytes memory bytecode = bytes.concat(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); + address tokenAddress = Create3.deploy(salt, bytecode); + if (tokenAddress.code.length == 0) revert TokenDeploymentFailed(); } From dc5dc8f4fbe4a7b915632a8f90b8216fa3e1014d Mon Sep 17 00:00:00 2001 From: Foivos Date: Fri, 29 Sep 2023 16:58:05 +0300 Subject: [PATCH 05/12] feat: move views out of serivce (#98) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * fix(RemoteAddressValidator): merge conflicts --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- .../InterchainTokenService.sol | 45 ++----------------- .../interfaces/IInterchainTokenService.sol | 29 ------------ .../interfaces/IRemoteAddressValidator.sol | 5 +++ .../interfaces/ITokenManagerLiquidityPool.sol | 31 +++++++++++++ .../interfaces/ITokenManagerLockUnlock.sol | 19 ++++++++ .../interfaces/ITokenManagerLockUnlockFee.sol | 19 ++++++++ .../interfaces/ITokenManagerMintBurn.sol | 19 ++++++++ contracts/proxies/TokenManagerProxy.sol | 6 +-- .../RemoteAddressValidator.sol | 28 +++++++----- .../TokenManagerLiquidityPool.sol | 16 +++++++ .../TokenManagerLockUnlock.sol | 13 +++++- .../TokenManagerLockUnlockFeeOnTransfer.sol | 10 +++++ .../implementations/TokenManagerMintBurn.sol | 13 +++++- contracts/utils/StandardizedTokenDeployer.sol | 1 - scripts/deploy.js | 9 ++-- test/RemoteAddressValidator.js | 18 ++++++-- 16 files changed, 183 insertions(+), 98 deletions(-) create mode 100644 contracts/interfaces/ITokenManagerLiquidityPool.sol create mode 100644 contracts/interfaces/ITokenManagerLockUnlock.sol create mode 100644 contracts/interfaces/ITokenManagerLockUnlockFee.sol create mode 100644 contracts/interfaces/ITokenManagerMintBurn.sol diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index e4fc3cc1..127cc5e1 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -56,8 +56,7 @@ contract InterchainTokenService is IRemoteAddressValidator public immutable remoteAddressValidator; address public immutable tokenManagerDeployer; address public immutable standardizedTokenDeployer; - bytes32 internal immutable chainNameHash; - bytes32 internal immutable chainName; + bytes32 public immutable chainNameHash; bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id'); bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id'); @@ -78,7 +77,6 @@ contract InterchainTokenService is * @param gasService_ the address of the AxelarGasService. * @param remoteAddressValidator_ the address of the RemoteAddressValidator. * @param tokenManagerImplementations this need to have exactly 3 implementations in the following order: Lock/Unlock, mint/burn and then liquidity pool. - * @param chainName_ the name of the current chain. */ constructor( address tokenManagerDeployer_, @@ -86,8 +84,7 @@ contract InterchainTokenService is address gateway_, address gasService_, address remoteAddressValidator_, - address[] memory tokenManagerImplementations, - string memory chainName_ + address[] memory tokenManagerImplementations ) AxelarExecutable(gateway_) { if ( remoteAddressValidator_ == address(0) || @@ -109,8 +106,7 @@ contract InterchainTokenService is TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER ); implementationLiquidityPool = _sanitizeTokenManagerImplementation(tokenManagerImplementations, TokenManagerType.LIQUIDITY_POOL); - - chainName = chainName_.toBytes32(); + string memory chainName_ = remoteAddressValidator.chainName(); chainNameHash = keccak256(bytes(chainName_)); } @@ -229,41 +225,6 @@ contract InterchainTokenService is } } - /** - * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. - * @param operator the operator of the TokenManager. - * @param tokenAddress the token to be managed. - * @return params the resulting params to be passed to custom TokenManager deployments. - */ - function getParamsLockUnlock(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { - params = abi.encode(operator, tokenAddress); - } - - /** - * @notice Getter function for the parameters of a mint/burn TokenManager. Mainly to be used by frontends. - * @param operator the operator of the TokenManager. - * @param tokenAddress the token to be managed. - * @return params the resulting params to be passed to custom TokenManager deployments. - */ - function getParamsMintBurn(bytes memory operator, address tokenAddress) public pure returns (bytes memory params) { - params = abi.encode(operator, tokenAddress); - } - - /** - * @notice Getter function for the parameters of a liquidity pool TokenManager. Mainly to be used by frontends. - * @param operator the operator of the TokenManager. - * @param tokenAddress the token to be managed. - * @param liquidityPoolAddress the liquidity pool to be used to store the bridged tokens. - * @return params the resulting params to be passed to custom TokenManager deployments. - */ - function getParamsLiquidityPool( - bytes memory operator, - address tokenAddress, - address liquidityPoolAddress - ) public pure returns (bytes memory params) { - params = abi.encode(operator, tokenAddress, liquidityPoolAddress); - } - /** * @notice Getter function for the flow limit of an existing token manager with a give token ID. * @param tokenId the token ID of the TokenManager. diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index e5c3d2cb..04771b8f 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -133,35 +133,6 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx */ function getCustomTokenId(address operator, bytes32 salt) external view returns (bytes32 tokenId); - /** - * @notice Returns the parameters for the lock/unlock operation. - * @param operator The operator address. - * @param tokenAddress The address of the token. - * @return params The parameters for the lock/unlock operation. - */ - function getParamsLockUnlock(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); - - /** - * @notice Returns the parameters for the mint/burn operation. - * @param operator The operator address. - * @param tokenAddress The address of the token. - * @return params The parameters for the mint/burn operation. - */ - function getParamsMintBurn(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); - - /** - * @notice Returns the parameters for the liquidity pool operation. - * @param operator The operator address. - * @param tokenAddress The address of the token. - * @param liquidityPoolAddress The address of the liquidity pool. - * @return params The parameters for the liquidity pool operation. - */ - function getParamsLiquidityPool( - bytes memory operator, - address tokenAddress, - address liquidityPoolAddress - ) external pure returns (bytes memory params); - /** * @notice Registers a canonical token and returns its associated tokenId. * @param tokenAddress The address of the canonical token. diff --git a/contracts/interfaces/IRemoteAddressValidator.sol b/contracts/interfaces/IRemoteAddressValidator.sol index c71b0361..49b23a66 100644 --- a/contracts/interfaces/IRemoteAddressValidator.sol +++ b/contracts/interfaces/IRemoteAddressValidator.sol @@ -16,6 +16,11 @@ interface IRemoteAddressValidator { event GatewaySupportedChainAdded(string chain); event GatewaySupportedChainRemoved(string chain); + /** + * @notice Returns the interchain token address + */ + function chainName() external view returns (string memory); + /** * @notice Returns the interchain token address */ diff --git a/contracts/interfaces/ITokenManagerLiquidityPool.sol b/contracts/interfaces/ITokenManagerLiquidityPool.sol new file mode 100644 index 00000000..902a0d1f --- /dev/null +++ b/contracts/interfaces/ITokenManagerLiquidityPool.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { ITokenManager } from './ITokenManager.sol'; + +/** + * @title ITokenManager + * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one. + */ +interface ITokenManagerLiquidityPool is ITokenManager { + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress, address liquidityPool) external pure returns (bytes memory params); + + /** + * @dev Reads the stored liquidity pool address from the specified storage slot + * @return liquidityPool_ The address of the liquidity pool + */ + function liquidityPool() external view returns (address liquidityPool_); + + /** + * @dev Updates the address of the liquidity pool. Can only be called by the operator. + * @param newLiquidityPool The new address of the liquidity pool + */ + function setLiquidityPool(address newLiquidityPool) external; +} diff --git a/contracts/interfaces/ITokenManagerLockUnlock.sol b/contracts/interfaces/ITokenManagerLockUnlock.sol new file mode 100644 index 00000000..5c009ae8 --- /dev/null +++ b/contracts/interfaces/ITokenManagerLockUnlock.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { ITokenManager } from './ITokenManager.sol'; + +/** + * @title ITokenManager + * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one. + */ +interface ITokenManagerLockUnlock is ITokenManager { + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); +} diff --git a/contracts/interfaces/ITokenManagerLockUnlockFee.sol b/contracts/interfaces/ITokenManagerLockUnlockFee.sol new file mode 100644 index 00000000..686b01d3 --- /dev/null +++ b/contracts/interfaces/ITokenManagerLockUnlockFee.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { ITokenManager } from './ITokenManager.sol'; + +/** + * @title ITokenManager + * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one. + */ +interface ITokenManagerLockUnlockFee is ITokenManager { + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); +} diff --git a/contracts/interfaces/ITokenManagerMintBurn.sol b/contracts/interfaces/ITokenManagerMintBurn.sol new file mode 100644 index 00000000..b9e1f4d1 --- /dev/null +++ b/contracts/interfaces/ITokenManagerMintBurn.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { ITokenManager } from './ITokenManager.sol'; + +/** + * @title ITokenManager + * @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one. + */ +interface ITokenManagerMintBurn is ITokenManager { + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params); +} diff --git a/contracts/proxies/TokenManagerProxy.sol b/contracts/proxies/TokenManagerProxy.sol index d0445cc4..3f3dfa92 100644 --- a/contracts/proxies/TokenManagerProxy.sol +++ b/contracts/proxies/TokenManagerProxy.sol @@ -11,7 +11,7 @@ import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol'; * @dev It implements ITokenManagerProxy. */ contract TokenManagerProxy is ITokenManagerProxy { - IInterchainTokenService public immutable interchainTokenServiceAddress; + IInterchainTokenService public immutable interchainTokenService; uint256 public immutable implementationType; bytes32 public immutable tokenId; @@ -23,7 +23,7 @@ contract TokenManagerProxy is ITokenManagerProxy { * @param params The initialization parameters for the token manager contract */ constructor(address interchainTokenServiceAddress_, uint256 implementationType_, bytes32 tokenId_, bytes memory params) { - interchainTokenServiceAddress = IInterchainTokenService(interchainTokenServiceAddress_); + interchainTokenService = IInterchainTokenService(interchainTokenServiceAddress_); implementationType = implementationType_; tokenId = tokenId_; address impl = _getImplementation(IInterchainTokenService(interchainTokenServiceAddress_), implementationType_); @@ -37,7 +37,7 @@ contract TokenManagerProxy is ITokenManagerProxy { * @return impl The address of the current implementation */ function implementation() public view returns (address impl) { - impl = _getImplementation(interchainTokenServiceAddress, implementationType); + impl = _getImplementation(interchainTokenService, implementationType); } /** diff --git a/contracts/remote-address-validator/RemoteAddressValidator.sol b/contracts/remote-address-validator/RemoteAddressValidator.sol index 08507209..d3ce7648 100644 --- a/contracts/remote-address-validator/RemoteAddressValidator.sol +++ b/contracts/remote-address-validator/RemoteAddressValidator.sol @@ -16,6 +16,7 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { mapping(string => bytes32) public remoteAddressHashes; mapping(string => string) public remoteAddresses; mapping(string => bool) public supportedByGateway; + string public chainName; address public immutable interchainTokenServiceAddress; bytes32 public immutable interchainTokenServiceAddressHash; @@ -32,7 +33,7 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { * @dev Constructs the RemoteAddressValidator contract, both array parameters must be equal in length * @param _interchainTokenServiceAddress Address of the interchain token service */ - constructor(address _interchainTokenServiceAddress) { + constructor(address _interchainTokenServiceAddress, string memory chainName_) { if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress(); interchainTokenServiceAddress = _interchainTokenServiceAddress; @@ -50,6 +51,9 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { interchainTokenServiceAddress1 = p1; interchainTokenServiceAddress2 = p2; + + if (bytes(chainName_).length == 0) revert ZeroStringLength(); + chainName = chainName_; } /** @@ -152,12 +156,12 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { */ function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { uint256 length = chainNames.length; - string calldata chainName; + string calldata chainName_; for (uint256 i; i < length; ++i) { - chainName = chainNames[i]; - supportedByGateway[chainName] = true; + chainName_ = chainNames[i]; + supportedByGateway[chainName_] = true; - emit GatewaySupportedChainAdded(chainName); + emit GatewaySupportedChainAdded(chainName_); } } @@ -167,23 +171,23 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { */ function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { uint256 length = chainNames.length; - string calldata chainName; + string calldata chainName_; for (uint256 i; i < length; ++i) { - chainName = chainNames[i]; - supportedByGateway[chainName] = false; + chainName_ = chainNames[i]; + supportedByGateway[chainName_] = false; - emit GatewaySupportedChainRemoved(chainName); + emit GatewaySupportedChainRemoved(chainName_); } } /** * @dev Fetches the interchain token service address for the specified chain - * @param chainName Name of the chain + * @param chainName_ Name of the chain * @return remoteAddress Interchain token service address for the specified chain */ - function getRemoteAddress(string calldata chainName) external view returns (string memory remoteAddress) { - remoteAddress = remoteAddresses[chainName]; + function getRemoteAddress(string calldata chainName_) external view returns (string memory remoteAddress) { + remoteAddress = remoteAddresses[chainName_]; if (bytes(remoteAddress).length == 0) { remoteAddress = _interchainTokenServiceAddressString(); diff --git a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol index a3468599..4275337f 100644 --- a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol +++ b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.0; import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; +import { ITokenManagerLiquidityPool } from '../../interfaces/ITokenManagerLiquidityPool.sol'; import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; @@ -100,4 +101,19 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { return IERC20(token).balanceOf(to) - balance; } + + /** + * @notice Getter function for the parameters of a liquidity pool TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @param liquidityPoolAddress the liquidity pool to be used to store the bridged tokens. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams( + bytes memory operator, + address tokenAddress, + address liquidityPoolAddress + ) external pure returns (bytes memory params) { + params = abi.encode(operator, tokenAddress, liquidityPoolAddress); + } } diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol index 06e858a7..22e673fa 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; +import { ITokenManagerLockUnlock } from '../../interfaces/ITokenManagerLockUnlock.sol'; import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; @@ -13,7 +14,7 @@ import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerLockUnlock is TokenManagerAddressStorage { +contract TokenManagerLockUnlock is TokenManagerAddressStorage, ITokenManagerLockUnlock { /** * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor * of TokenManagerAddressStorage which calls the constructor of TokenManager. @@ -62,4 +63,14 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage { return amount; } + + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params) { + params = abi.encode(operator, tokenAddress); + } } diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol index 4cf3c5dc..eb147d16 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol @@ -69,4 +69,14 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { return IERC20(token).balanceOf(to) - balance; } + + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params) { + params = abi.encode(operator, tokenAddress); + } } diff --git a/contracts/token-manager/implementations/TokenManagerMintBurn.sol b/contracts/token-manager/implementations/TokenManagerMintBurn.sol index 70031b00..3bdb155c 100644 --- a/contracts/token-manager/implementations/TokenManagerMintBurn.sol +++ b/contracts/token-manager/implementations/TokenManagerMintBurn.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; import { IERC20BurnableMintable } from '../../interfaces/IERC20BurnableMintable.sol'; +import { ITokenManagerMintBurn } from '../../interfaces/ITokenManagerMintBurn.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; @@ -14,7 +15,7 @@ import { SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerMintBurn is TokenManagerAddressStorage { +contract TokenManagerMintBurn is TokenManagerAddressStorage, ITokenManagerMintBurn { /** * @dev Constructs an instance of TokenManagerMintBurn. Calls the constructor * of TokenManagerAddressStorage which calls the constructor of TokenManager. @@ -63,4 +64,14 @@ contract TokenManagerMintBurn is TokenManagerAddressStorage { return amount; } + + /** + * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. + * @param operator the operator of the TokenManager. + * @param tokenAddress the token to be managed. + * @return params the resulting params to be passed to custom TokenManager deployments. + */ + function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params) { + params = abi.encode(operator, tokenAddress); + } } diff --git a/contracts/utils/StandardizedTokenDeployer.sol b/contracts/utils/StandardizedTokenDeployer.sol index dd74d8d2..77536f3f 100644 --- a/contracts/utils/StandardizedTokenDeployer.sol +++ b/contracts/utils/StandardizedTokenDeployer.sol @@ -49,7 +49,6 @@ contract StandardizedTokenDeployer is IStandardizedTokenDeployer { bytes memory bytecode = bytes.concat(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params)); address tokenAddress = Create3.deploy(salt, bytecode); - if (tokenAddress.code.length == 0) revert TokenDeploymentFailed(); } diff --git a/scripts/deploy.js b/scripts/deploy.js index 0d66964b..be3f5752 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -11,8 +11,8 @@ async function deployContract(wallet, contractName, args = []) { return contract; } -async function deployRemoteAddressValidator(wallet, interchainTokenServiceAddress) { - const remoteAddressValidatorImpl = await deployContract(wallet, 'RemoteAddressValidator', [interchainTokenServiceAddress]); +async function deployRemoteAddressValidator(wallet, interchainTokenServiceAddress, chainName) { + const remoteAddressValidatorImpl = await deployContract(wallet, 'RemoteAddressValidator', [interchainTokenServiceAddress, chainName]); const params = defaultAbiCoder.encode(['string[]', 'string[]'], [[], []]); const remoteAddressValidatorProxy = await deployContract(wallet, 'RemoteAddressValidatorProxy', [ @@ -43,7 +43,6 @@ async function deployInterchainTokenService( gasServiceAddress, remoteAddressValidatorAddress, tokenManagerImplementations, - chainName, deploymentKey, operatorAddress = wallet.address, ) { @@ -54,7 +53,6 @@ async function deployInterchainTokenService( gasServiceAddress, remoteAddressValidatorAddress, tokenManagerImplementations, - chainName, ]); const proxy = await deployCreate3Contract(create3DeployerAddress, wallet, InterchainTokenServiceProxy, deploymentKey, [ implementation.address, @@ -84,7 +82,7 @@ async function deployAll(wallet, chainName, deploymentKey = 'interchainTokenServ const standardizedToken = await deployContract(wallet, 'StandardizedToken'); const standardizedTokenDeployer = await deployContract(wallet, 'StandardizedTokenDeployer', [standardizedToken.address]); const interchainTokenServiceAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey); - const remoteAddressValidator = await deployRemoteAddressValidator(wallet, interchainTokenServiceAddress); + const remoteAddressValidator = await deployRemoteAddressValidator(wallet, interchainTokenServiceAddress, chainName); const tokenManagerImplementations = await deployTokenManagerImplementations(wallet, interchainTokenServiceAddress); const service = await deployInterchainTokenService( @@ -96,7 +94,6 @@ async function deployAll(wallet, chainName, deploymentKey = 'interchainTokenServ gasService.address, remoteAddressValidator.address, tokenManagerImplementations.map((impl) => impl.address), - chainName, deploymentKey, ); return [service, gateway, gasService]; diff --git a/test/RemoteAddressValidator.js b/test/RemoteAddressValidator.js index 209f8732..a0b1c04a 100644 --- a/test/RemoteAddressValidator.js +++ b/test/RemoteAddressValidator.js @@ -15,24 +15,36 @@ describe('RemoteAddressValidator', () => { const otherRemoteAddress = 'any string as an address'; const otherChain = 'Chain Name'; + const chainName = 'Chain Name'; before(async () => { const wallets = await ethers.getSigners(); ownerWallet = wallets[0]; otherWallet = wallets[1]; interchainTokenServiceAddress = wallets[2].address; - remoteAddressValidator = await deployRemoteAddressValidator(ownerWallet, interchainTokenServiceAddress); + remoteAddressValidator = await deployRemoteAddressValidator(ownerWallet, interchainTokenServiceAddress, chainName); }); it('Should revert on RemoteAddressValidator deployment with invalid interchain token service address', async () => { const remoteAddressValidatorFactory = await ethers.getContractFactory('RemoteAddressValidator'); - await expect(remoteAddressValidatorFactory.deploy(AddressZero)).to.be.revertedWithCustomError( + await expect(remoteAddressValidatorFactory.deploy(AddressZero, chainName)).to.be.revertedWithCustomError( remoteAddressValidator, 'ZeroAddress', ); }); + it('Should revert on RemoteAddressValidator deployment with invalid chain name', async () => { + const remoteAddressValidatorFactory = await ethers.getContractFactory('RemoteAddressValidator'); + await expect(remoteAddressValidatorFactory.deploy(interchainTokenServiceAddress, '')).to.be.revertedWithCustomError( + remoteAddressValidator, + 'ZeroStringLength', + ); + }); + it('Should revert on RemoteAddressValidator deployment with length mismatch between chains and trusted addresses arrays', async () => { - const remoteAddressValidatorImpl = await deployContract(ownerWallet, 'RemoteAddressValidator', [interchainTokenServiceAddress]); + const remoteAddressValidatorImpl = await deployContract(ownerWallet, 'RemoteAddressValidator', [ + interchainTokenServiceAddress, + chainName, + ]); const remoteAddressValidatorProxyFactory = await ethers.getContractFactory('RemoteAddressValidatorProxy'); const params = defaultAbiCoder.encode(['string[]', 'string[]'], [['Chain A'], []]); await expect( From 463facc71378f955181e18d4938da0397b514997 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 2 Oct 2023 16:07:16 +0300 Subject: [PATCH 06/12] feat: addressed ackeeblockchains's 3.0 report (#102) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * fix(RemoteAddressValidator): merge conflicts * Removed some duplicate definitions --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- .../InterchainTokenService.sol | 7 ++-- .../interchain-token/InterchainToken.sol | 3 +- contracts/interfaces/INoReEntrancy.sol | 6 ++++ .../interfaces/IRemoteAddressValidator.sol | 20 ------------ .../RemoteAddressValidator.sol | 32 ------------------- contracts/token-manager/TokenManager.sol | 2 +- .../TokenManagerLiquidityPool.sol | 15 ++++++--- .../TokenManagerLockUnlock.sol | 2 +- .../TokenManagerLockUnlockFeeOnTransfer.sol | 8 +++-- .../implementations/TokenManagerMintBurn.sol | 2 +- contracts/utils/Distributable.sol | 1 + contracts/utils/ExpressCallHandler.sol | 2 +- contracts/utils/NoReEntrancy.sol | 8 ++--- contracts/utils/Operatable.sol | 3 +- test/RemoteAddressValidator.js | 32 ------------------- 15 files changed, 38 insertions(+), 105 deletions(-) diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index 127cc5e1..86413d23 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -330,8 +330,7 @@ contract InterchainTokenService is } /** - * @notice Used to deploy a standardized token alongside a TokenManager. If the `distributor` is the address of the TokenManager (which - * can be calculated ahead of time) then a mint/burn TokenManager is used. Otherwise a lock/unlock TokenManager is used. + * @notice Used to deploy a standardized token alongside a TokenManager. * @param salt the salt to be used. * @param name the name of the token to be deployed. * @param symbol the symbol of the token to be deployed. @@ -446,9 +445,9 @@ contract InterchainTokenService is SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); - _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount); - _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller); + + _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount); } /*********************\ diff --git a/contracts/interchain-token/InterchainToken.sol b/contracts/interchain-token/InterchainToken.sol index 9f668678..edd81eb7 100644 --- a/contracts/interchain-token/InterchainToken.sol +++ b/contracts/interchain-token/InterchainToken.sol @@ -10,7 +10,6 @@ import { ERC20 } from '../token-implementations/ERC20.sol'; * @title An example implementation of the IInterchainToken. * @notice The implementation ERC20 can be done in any way, however this example assumes that an _approve internal function exists * that can be used to create approvals, and that `allowance` is a mapping. - * @dev You can skip the `tokenManagerRequiresApproval()` function altogether if you know what it should return for your token. */ abstract contract InterchainToken is IInterchainToken, ERC20 { /** @@ -66,7 +65,7 @@ abstract contract InterchainToken is IInterchainToken, ERC20 { _approve(sender, msg.sender, _allowance - amount); } - _beforeInterchainTransfer(msg.sender, destinationChain, recipient, amount, metadata); + _beforeInterchainTransfer(sender, destinationChain, recipient, amount, metadata); ITokenManager tokenManager_ = tokenManager(); tokenManager_.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata); diff --git a/contracts/interfaces/INoReEntrancy.sol b/contracts/interfaces/INoReEntrancy.sol index 9e0dd68d..6b2414d6 100644 --- a/contracts/interfaces/INoReEntrancy.sol +++ b/contracts/interfaces/INoReEntrancy.sol @@ -9,4 +9,10 @@ pragma solidity ^0.8.0; */ interface INoReEntrancy { error ReEntrancy(); + + /** + * @notice Check if the contract is already executing. + * @return entered A boolean representing the entered status. True if already executing, false otherwise. + */ + function hasEntered() external view returns (bool entered); } diff --git a/contracts/interfaces/IRemoteAddressValidator.sol b/contracts/interfaces/IRemoteAddressValidator.sol index 49b23a66..93d6eda7 100644 --- a/contracts/interfaces/IRemoteAddressValidator.sol +++ b/contracts/interfaces/IRemoteAddressValidator.sol @@ -13,8 +13,6 @@ interface IRemoteAddressValidator { event TrustedAddressAdded(string sourceChain, string sourceAddress); event TrustedAddressRemoved(string sourceChain); - event GatewaySupportedChainAdded(string chain); - event GatewaySupportedChainRemoved(string chain); /** * @notice Returns the interchain token address @@ -58,22 +56,4 @@ interface IRemoteAddressValidator { * @return remoteAddress Interchain token service address for the specified chain */ function getRemoteAddress(string calldata chainName) external view returns (string memory remoteAddress); - - /** - * @notice Returns true if the gateway delivers token to this chain. - * @param chainName Name of the chain - */ - function supportedByGateway(string calldata chainName) external view returns (bool); - - /** - * @dev Adds chains that are supported by the Axelar gateway - * @param chainNames List of chain names to be added as supported - */ - function addGatewaySupportedChains(string[] calldata chainNames) external; - - /** - * @dev Removes chains that are no longer supported by the Axelar gateway - * @param chainNames List of chain names to be removed as supported - */ - function removeGatewaySupportedChains(string[] calldata chainNames) external; } diff --git a/contracts/remote-address-validator/RemoteAddressValidator.sol b/contracts/remote-address-validator/RemoteAddressValidator.sol index d3ce7648..75881d9e 100644 --- a/contracts/remote-address-validator/RemoteAddressValidator.sol +++ b/contracts/remote-address-validator/RemoteAddressValidator.sol @@ -15,7 +15,6 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { mapping(string => bytes32) public remoteAddressHashes; mapping(string => string) public remoteAddresses; - mapping(string => bool) public supportedByGateway; string public chainName; address public immutable interchainTokenServiceAddress; @@ -150,37 +149,6 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { emit TrustedAddressRemoved(sourceChain); } - /** - * @dev Adds chains that are supported by the Axelar gateway - * @param chainNames List of chain names to be added as supported - */ - function addGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { - uint256 length = chainNames.length; - string calldata chainName_; - for (uint256 i; i < length; ++i) { - chainName_ = chainNames[i]; - supportedByGateway[chainName_] = true; - - emit GatewaySupportedChainAdded(chainName_); - } - } - - /** - * @dev Removes chains that are no longer supported by the Axelar gateway - * @param chainNames List of chain names to be removed as supported - */ - function removeGatewaySupportedChains(string[] calldata chainNames) external onlyOwner { - uint256 length = chainNames.length; - string calldata chainName_; - - for (uint256 i; i < length; ++i) { - chainName_ = chainNames[i]; - supportedByGateway[chainName_] = false; - - emit GatewaySupportedChainRemoved(chainName_); - } - } - /** * @dev Fetches the interchain token service address for the specified chain * @param chainName_ Name of the chain diff --git a/contracts/token-manager/TokenManager.sol b/contracts/token-manager/TokenManager.sol index 5e7fb798..d4c06c8a 100644 --- a/contracts/token-manager/TokenManager.sol +++ b/contracts/token-manager/TokenManager.sol @@ -172,8 +172,8 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen * @return the amount of token actually given, which will only be different than `amount` in cases where the token takes some on-transfer fee. */ function giveToken(address destinationAddress, uint256 amount) external onlyService returns (uint256) { - amount = _giveToken(destinationAddress, amount); _addFlowIn(amount); + amount = _giveToken(destinationAddress, amount); return amount; } diff --git a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol index 4275337f..4f552462 100644 --- a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol +++ b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol @@ -28,7 +28,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} function implementationType() external pure returns (uint256) { - return 3; + return uint256(TokenManagerType.LIQUIDITY_POOL); } /** @@ -83,8 +83,11 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { SafeTokenTransferFrom.safeTransferFrom(token, from, liquidityPool_, amount); - // Note: This allows support for fee-on-transfer tokens - return IERC20(token).balanceOf(liquidityPool_) - balance; + uint256 diff = token.balanceOf(liquidityPool_) - balance; + if (diff < amount) { + amount = diff; + } + return amount; } /** @@ -99,7 +102,11 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { SafeTokenTransferFrom.safeTransferFrom(token, liquidityPool(), to, amount); - return IERC20(token).balanceOf(to) - balance; + uint256 diff = token.balanceOf(to) - balance; + if (diff < amount) { + amount = diff; + } + return amount; } /** diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol index 22e673fa..e9d9fb0f 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol @@ -23,7 +23,7 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage, ITokenManagerLock constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} function implementationType() external pure returns (uint256) { - return 0; + return uint256(TokenManagerType.LOCK_UNLOCK); } /** diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol index eb147d16..b1db1cd9 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol @@ -23,7 +23,7 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} function implementationType() external pure returns (uint256) { - return 2; + return uint256(TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER); } /** @@ -67,7 +67,11 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { SafeTokenTransfer.safeTransfer(token, to, amount); - return IERC20(token).balanceOf(to) - balance; + uint256 diff = token.balanceOf(to) - balance; + if (diff < amount) { + amount = diff; + } + return amount; } /** diff --git a/contracts/token-manager/implementations/TokenManagerMintBurn.sol b/contracts/token-manager/implementations/TokenManagerMintBurn.sol index 3bdb155c..f226b4b7 100644 --- a/contracts/token-manager/implementations/TokenManagerMintBurn.sol +++ b/contracts/token-manager/implementations/TokenManagerMintBurn.sol @@ -24,7 +24,7 @@ contract TokenManagerMintBurn is TokenManagerAddressStorage, ITokenManagerMintBu constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} function implementationType() external pure returns (uint256) { - return 1; + return uint256(TokenManagerType.MINT_BURN); } /** diff --git a/contracts/utils/Distributable.sol b/contracts/utils/Distributable.sol index e179a3f7..efdeda77 100644 --- a/contracts/utils/Distributable.sol +++ b/contracts/utils/Distributable.sol @@ -75,6 +75,7 @@ contract Distributable is IDistributable { address proposedDistributor; assembly { proposedDistributor := sload(PROPOSED_DISTRIBUTOR_SLOT) + sstore(PROPOSED_DISTRIBUTOR_SLOT, 0) } if (msg.sender != proposedDistributor) revert NotProposedDistributor(); _setDistributor(proposedDistributor); diff --git a/contracts/utils/ExpressCallHandler.sol b/contracts/utils/ExpressCallHandler.sol index d2612d93..fbac6a7a 100644 --- a/contracts/utils/ExpressCallHandler.sol +++ b/contracts/utils/ExpressCallHandler.sol @@ -13,7 +13,7 @@ contract ExpressCallHandler is IExpressCallHandler { // uint256(keccak256('prefix-express-give-token')); uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN = 0x67c7b41c1cb0375e36084c4ec399d005168e83425fa471b9224f6115af865619; // uint256(keccak256('prefix-express-give-token-with-data')); - uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaad; + uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaaf; /** * @notice Calculates the unique slot for a given express token transfer. diff --git a/contracts/utils/NoReEntrancy.sol b/contracts/utils/NoReEntrancy.sol index 0a1e1225..16d81bbc 100644 --- a/contracts/utils/NoReEntrancy.sol +++ b/contracts/utils/NoReEntrancy.sol @@ -14,11 +14,11 @@ contract NoReEntrancy is INoReEntrancy { uint256 internal constant ENTERED_SLOT = 0x01f33dd720a8dea3c4220dc5074a2239fb442c4c775306a696f97a7c54f785fc; /** - * @notice A modifier that throws a Paused custom error if the contract is paused - * @dev This modifier should be used with functions that can be paused + * @notice A modifier that throws a ReEntrancy custom error if the contract is entered + * @dev This modifier should be used with functions that can be entered twice */ modifier noReEntrancy() { - if (_hasEntered()) revert ReEntrancy(); + if (hasEntered()) revert ReEntrancy(); _setEntered(true); _; _setEntered(false); @@ -28,7 +28,7 @@ contract NoReEntrancy is INoReEntrancy { * @notice Check if the contract is already executing. * @return entered A boolean representing the entered status. True if already executing, false otherwise. */ - function _hasEntered() internal view returns (bool entered) { + function hasEntered() public view returns (bool entered) { assembly { entered := sload(ENTERED_SLOT) } diff --git a/contracts/utils/Operatable.sol b/contracts/utils/Operatable.sol index 5ca7537e..203b9957 100644 --- a/contracts/utils/Operatable.sol +++ b/contracts/utils/Operatable.sol @@ -12,7 +12,7 @@ import { IOperatable } from '../interfaces/IOperatable.sol'; */ contract Operatable is IOperatable { // uint256(keccak256('operator')) - 1 - uint256 internal constant OPERATOR_SLOT = 0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d7; + uint256 internal constant OPERATOR_SLOT = 0x46a52cf33029de9f84853745a87af28464c80bf0346df1b32e205fc73319f621; // uint256(keccak256('proposed-operator')) - 1 uint256 internal constant PROPOSED_OPERATOR_SLOT = 0x18dd7104fe20f6107b1523000995e8f87ac02b734a65cf0a45fafa7635a2c526; @@ -74,6 +74,7 @@ contract Operatable is IOperatable { address proposedOperator; assembly { proposedOperator := sload(PROPOSED_OPERATOR_SLOT) + sstore(PROPOSED_OPERATOR_SLOT, 0) } if (msg.sender != proposedOperator) revert NotProposedOperator(); _setOperator(proposedOperator); diff --git a/test/RemoteAddressValidator.js b/test/RemoteAddressValidator.js index a0b1c04a..6415bc77 100644 --- a/test/RemoteAddressValidator.js +++ b/test/RemoteAddressValidator.js @@ -126,36 +126,4 @@ describe('RemoteAddressValidator', () => { expect(await remoteAddressValidator.validateSender(otherChain, otherRemoteAddress)).to.equal(false); expect(await remoteAddressValidator.validateSender(otherChain, interchainTokenServiceAddress)).to.equal(true); }); - - it('Should have chains as not gateway supported by default', async () => { - expect(await remoteAddressValidator.supportedByGateway(otherChain)).to.equal(false); - }); - - it('Should not be able to add a chain as gateway supported as not the onwer', async () => { - await expect(remoteAddressValidator.connect(otherWallet).addGatewaySupportedChains([otherChain])).to.be.revertedWithCustomError( - remoteAddressValidator, - 'NotOwner', - ); - }); - - it('Should be able to add a chain as gateway supported as the onwer', async () => { - await expect(remoteAddressValidator.addGatewaySupportedChains([otherChain])) - .to.emit(remoteAddressValidator, 'GatewaySupportedChainAdded') - .withArgs(otherChain); - expect(await remoteAddressValidator.supportedByGateway(otherChain)).to.equal(true); - }); - - it('Should not be able to remove a chain as gateway supported as not the onwer', async () => { - await expect(remoteAddressValidator.connect(otherWallet).removeGatewaySupportedChains([otherChain])).to.be.revertedWithCustomError( - remoteAddressValidator, - 'NotOwner', - ); - }); - - it('Should be able to remove a chain as gateway supported as the onwer', async () => { - await expect(remoteAddressValidator.removeGatewaySupportedChains([otherChain])) - .to.emit(remoteAddressValidator, 'GatewaySupportedChainRemoved') - .withArgs(otherChain); - expect(await remoteAddressValidator.supportedByGateway(otherChain)).to.equal(false); - }); }); From 403e3bd7f5335791524e9112e37a10d2409bd272 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 2 Oct 2023 16:18:12 +0300 Subject: [PATCH 07/12] feat: interchain transfer everywhere (#104) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * remove duplictes from merge --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- .../InterchainTokenService.sol | 216 +++++++++-------- contracts/interfaces/IExpressCallHandler.sol | 69 +----- .../interfaces/IInterchainTokenService.sol | 45 ++-- contracts/interfaces/ITokenManager.sol | 10 +- contracts/proxies/TokenManagerProxy.sol | 5 - contracts/test/InterchainExecutableTest.sol | 2 +- .../test/utils/ExpressCallHandlerTest.sol | 47 +--- contracts/token-manager/TokenManager.sol | 14 +- contracts/utils/ExpressCallHandler.sol | 225 ++---------------- docs/index.md | 26 +- test/tokenService.js | 102 +++----- test/tokenServiceFullFlow.js | 4 +- test/utils.js | 121 ++-------- 13 files changed, 246 insertions(+), 640 deletions(-) diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index 86413d23..d005a47c 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -397,57 +397,65 @@ contract InterchainTokenService is /** * @notice Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing - * sendToken that matches the parameters passed here. + * interchainTransfer that matches the parameters passed here. * @dev This is not to be used with fee on transfer tokens as it will incur losses for the express caller. - * @param tokenId the tokenId of the TokenManager used. - * @param destinationAddress the destinationAddress for the sendToken. - * @param amount the amount of token to give. + * @param payload the payload of the receive token * @param commandId the sendHash detected at the sourceChain. */ - function expressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) external { + function expressReceiveToken(bytes calldata payload, bytes32 commandId, string calldata sourceChain) external { if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId); address caller = msg.sender; + _setExpressReceiveToken(payload, commandId, caller); + + (uint256 selector, bytes32 tokenId, bytes memory destinationAddressBytes, uint256 amount) = abi.decode( + payload, + (uint256, bytes32, bytes, uint256) + ); + address destinationAddress = destinationAddressBytes.toAddress(); + ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId)); IERC20 token = IERC20(tokenManager.tokenAddress()); SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); - _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, caller); + if (selector == SELECTOR_SEND_TOKEN_WITH_DATA) { + (, , , , bytes memory sourceAddress, bytes memory data) = abi.decode(payload, (uint256, bytes32, bytes, uint256, bytes, bytes)); + IInterchainTokenExpressExecutable(destinationAddress).executeWithInterchainToken( + sourceChain, + sourceAddress, + data, + tokenId, + amount + ); + } else if (selector != SELECTOR_SEND_TOKEN) { + revert InvalidExpressSelector(); + } } - /** - * @notice Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have - * detected an outgoing sendToken that matches the parameters passed here. - * @dev This is not to be used with fee on transfer tokens as it will incur losses for the express caller and it will pass an incorrect amount to the contract. - * @param tokenId the tokenId of the TokenManager used. - * @param sourceChain the name of the chain where the call came from. - * @param sourceAddress the caller of callContractWithInterchainToken. - * @param destinationAddress the destinationAddress for the sendToken. - * @param amount the amount of token to give. - * @param data the data to be passed to destinationAddress after giving them the tokens specified. - * @param commandId the sendHash detected at the sourceChain. - */ - function expressReceiveTokenWithData( + function interchainTransfer( bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, + string calldata destinationChain, + bytes calldata destinationAddress, uint256 amount, - bytes calldata data, - bytes32 commandId + bytes calldata metadata ) external { - if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted(commandId); - - address caller = msg.sender; - ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId)); - IERC20 token = IERC20(tokenManager.tokenAddress()); - - SafeTokenTransferFrom.safeTransferFrom(token, caller, destinationAddress, amount); - - _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, caller); + ITokenManager tokenManager = ITokenManager(getTokenManagerAddress(tokenId)); + amount = tokenManager.takeToken(msg.sender, amount); + _transmitSendToken(tokenId, msg.sender, destinationChain, destinationAddress, amount, metadata); + } - _expressExecuteWithInterchainTokenToken(tokenId, destinationAddress, sourceChain, sourceAddress, data, amount); + function sendTokenWithData( + bytes32 tokenId, + string calldata destinationChain, + bytes calldata destinationAddress, + uint256 amount, + bytes calldata data + ) external { + ITokenManager tokenManager = ITokenManager(getTokenManagerAddress(tokenId)); + amount = tokenManager.takeToken(msg.sender, amount); + uint32 prefix = 0; + _transmitSendToken(tokenId, msg.sender, destinationChain, destinationAddress, amount, abi.encodePacked(prefix, data)); } /*********************\ @@ -459,7 +467,7 @@ contract InterchainTokenService is * @param tokenId the tokenId of the TokenManager (which must be the msg.sender). * @param sourceAddress the address where the token is coming from, which will also be used for reimbursement of gas. * @param destinationChain the name of the chain to send tokens to. - * @param destinationAddress the destinationAddress for the sendToken. + * @param destinationAddress the destinationAddress for the interchainTransfer. * @param amount the amount of token to give. * @param metadata the data to be passed to the destination. */ @@ -471,19 +479,7 @@ contract InterchainTokenService is uint256 amount, bytes calldata metadata ) external payable onlyTokenManager(tokenId) notPaused { - bytes memory payload; - if (metadata.length < 4) { - payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount); - _callContract(destinationChain, payload, msg.value); - emit TokenSent(tokenId, destinationChain, destinationAddress, amount); - return; - } - uint32 version; - (version, metadata) = _decodeMetadata(metadata); - if (version > 0) revert InvalidMetadataVersion(version); - payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata); - _callContract(destinationChain, payload, msg.value); - emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata); + _transmitSendToken(tokenId, sourceAddress, destinationChain, destinationAddress, amount, metadata); } /*************\ @@ -541,10 +537,8 @@ contract InterchainTokenService is bytes calldata payload ) internal override onlyRemoteService(sourceChain, sourceAddress) notPaused { uint256 selector = abi.decode(payload, (uint256)); - if (selector == SELECTOR_SEND_TOKEN) { - _processSendTokenPayload(sourceChain, payload); - } else if (selector == SELECTOR_SEND_TOKEN_WITH_DATA) { - _processSendTokenWithDataPayload(sourceChain, payload); + if (selector == SELECTOR_SEND_TOKEN || selector == SELECTOR_SEND_TOKEN_WITH_DATA) { + _processSendTokenPayload(sourceChain, payload, selector); } else if (selector == SELECTOR_DEPLOY_TOKEN_MANAGER) { _processDeployTokenManagerPayload(payload); } else if (selector == SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN) { @@ -559,67 +553,45 @@ contract InterchainTokenService is * @param sourceChain The chain where the transaction originates from * @param payload The encoded data payload to be processed */ - function _processSendTokenPayload(string calldata sourceChain, bytes calldata payload) internal { - (, bytes32 tokenId, bytes memory destinationAddressBytes, uint256 amount) = abi.decode(payload, (uint256, bytes32, bytes, uint256)); - bytes32 commandId; - - assembly { - commandId := calldataload(4) - } - address destinationAddress = destinationAddressBytes.toAddress(); - ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId)); - address expressCaller = _popExpressReceiveToken(tokenId, destinationAddress, amount, commandId); - if (expressCaller == address(0)) { - amount = tokenManager.giveToken(destinationAddress, amount); - emit TokenReceived(tokenId, sourceChain, destinationAddress, amount); - } else { - amount = tokenManager.giveToken(expressCaller, amount); - } - } - - /** - * @notice Processes a send token with data payload. - * @param sourceChain The chain where the transaction originates from - * @param payload The encoded data payload to be processed - */ - function _processSendTokenWithDataPayload(string calldata sourceChain, bytes calldata payload) internal { + function _processSendTokenPayload(string calldata sourceChain, bytes calldata payload, uint256 selector) internal { bytes32 tokenId; - uint256 amount; - bytes memory sourceAddress; - bytes memory data; address destinationAddress; + uint256 amount; + { + bytes memory destinationAddressBytes; + (, tokenId, destinationAddressBytes, amount) = abi.decode(payload, (uint256, bytes32, bytes, uint256)); + destinationAddress = destinationAddressBytes.toAddress(); + } bytes32 commandId; assembly { commandId := calldataload(4) } + ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenId)); { - bytes memory destinationAddressBytes; - (, tokenId, destinationAddressBytes, amount, sourceAddress, data) = abi.decode( - payload, - (uint256, bytes32, bytes, uint256, bytes, bytes) - ); - destinationAddress = destinationAddressBytes.toAddress(); - } - ITokenManager tokenManager = ITokenManager(getTokenManagerAddress(tokenId)); - { - address expressCaller = _popExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ); + address expressCaller = _popExpressReceiveToken(payload, commandId); if (expressCaller != address(0)) { amount = tokenManager.giveToken(expressCaller, amount); return; } } amount = tokenManager.giveToken(destinationAddress, amount); - IInterchainTokenExpressExecutable(destinationAddress).executeWithInterchainToken(sourceChain, sourceAddress, data, tokenId, amount); - emit TokenReceivedWithData(tokenId, sourceChain, destinationAddress, amount, sourceAddress, data); + if (selector == SELECTOR_SEND_TOKEN_WITH_DATA) { + bytes memory sourceAddress; + bytes memory data; + (, , , , sourceAddress, data) = abi.decode(payload, (uint256, bytes32, bytes, uint256, bytes, bytes)); + + IInterchainTokenExpressExecutable(destinationAddress).executeWithInterchainToken( + sourceChain, + sourceAddress, + data, + tokenId, + amount + ); + emit TokenReceivedWithData(tokenId, sourceChain, destinationAddress, amount, sourceAddress, data); + } else { + emit TokenReceived(tokenId, sourceChain, destinationAddress, amount); + } } /** @@ -839,11 +811,17 @@ contract InterchainTokenService is emit StandardizedTokenDeployed(tokenId, distributor, name, symbol, decimals, mintAmount, mintTo); } - function _decodeMetadata(bytes calldata metadata) internal pure returns (uint32 version, bytes calldata data) { + function _decodeMetadata(bytes memory metadata) internal pure returns (uint32 version, bytes memory data) { + data = new bytes(metadata.length - 4); assembly { - data.length := sub(metadata.length, 4) - data.offset := add(metadata.offset, 4) - version := calldataload(sub(metadata.offset, 28)) + version := shr(224, mload(data)) + } + if (data.length == 0) return (version, data); + uint256 n = (data.length - 1) / 32; + for (uint256 i = 0; i <= n; ++i) { + assembly { + mstore(add(data, add(32, mul(32, i))), mload(add(metadata, add(36, mul(32, i))))) + } } } @@ -863,4 +841,36 @@ contract InterchainTokenService is amount ); } + + /** + * @notice Transmit a sendTokenWithData for the given tokenId. Only callable by a token manager. + * @param tokenId the tokenId of the TokenManager (which must be the msg.sender). + * @param sourceAddress the address where the token is coming from, which will also be used for reimburment of gas. + * @param destinationChain the name of the chain to send tokens to. + * @param destinationAddress the destinationAddress for the interchainTransfer. + * @param amount the amount of token to give. + * @param metadata the data to be passed to the destiantion. + */ + function _transmitSendToken( + bytes32 tokenId, + address sourceAddress, + string calldata destinationChain, + bytes memory destinationAddress, + uint256 amount, + bytes memory metadata + ) internal { + bytes memory payload; + if (metadata.length < 4) { + payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount); + _callContract(destinationChain, payload, msg.value); + emit TokenSent(tokenId, destinationChain, destinationAddress, amount); + return; + } + uint32 version; + (version, metadata) = _decodeMetadata(metadata); + if (version > 0) revert InvalidMetadataVersion(version); + payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata); + _callContract(destinationChain, payload, msg.value); + emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata); + } } diff --git a/contracts/interfaces/IExpressCallHandler.sol b/contracts/interfaces/IExpressCallHandler.sol index 8a4ae602..601fdb6e 100644 --- a/contracts/interfaces/IExpressCallHandler.sol +++ b/contracts/interfaces/IExpressCallHandler.sol @@ -6,75 +6,14 @@ interface IExpressCallHandler { error AlreadyExpressCalled(); error SameDestinationAsCaller(); - event ExpressReceive( - bytes32 indexed tokenId, - address indexed destinationAddress, - uint256 amount, - bytes32 indexed sendHash, - address expressCaller - ); - event ExpressExecutionFulfilled( - bytes32 indexed tokenId, - address indexed destinationAddress, - uint256 amount, - bytes32 indexed sendHash, - address expressCaller - ); - - event ExpressReceiveWithData( - bytes32 indexed tokenId, - string sourceChain, - bytes sourceAddress, - address indexed destinationAddress, - uint256 amount, - bytes data, - bytes32 indexed sendHash, - address expressCaller - ); - event ExpressExecutionWithDataFulfilled( - bytes32 indexed tokenId, - string sourceChain, - bytes sourceAddress, - address indexed destinationAddress, - uint256 amount, - bytes data, - bytes32 indexed sendHash, - address expressCaller - ); + event ExpressReceive(bytes payload, bytes32 indexed sendHash, address indexed expressCaller); + event ExpressExecutionFulfilled(bytes payload, bytes32 indexed sendHash, address indexed expressCaller); /** * @notice Gets the address of the express caller for a specific token transfer - * @param tokenId The ID of the token being sent - * @param destinationAddress The address of the recipient - * @param amount The amount of tokens to be sent - * @param commandId The unique hash for this token transfer - * @return expressCaller The address of the express caller for this token transfer - */ - function getExpressReceiveToken( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId - ) external view returns (address expressCaller); - - /** - * @notice Gets the address of the express caller for a specific token transfer with data - * @param tokenId The ID of the token being sent - * @param sourceChain The chain from which the token will be sent - * @param sourceAddress The originating address of the token on the source chain - * @param destinationAddress The address of the recipient on the destination chain - * @param amount The amount of tokens to be sent - * @param data The data associated with the token transfer + * @param payload the payload for the receive token * @param commandId The unique hash for this token transfer * @return expressCaller The address of the express caller for this token transfer */ - function getExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes calldata data, - bytes32 commandId - ) external view returns (address expressCaller); + function getExpressReceiveToken(bytes calldata payload, bytes32 commandId) external view returns (address expressCaller); } diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index 04771b8f..82201e79 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -28,6 +28,7 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx error SelectorUnknown(); error InvalidMetadataVersion(uint32 version); error AlreadyExecuted(bytes32 commandId); + error InvalidExpressSelector(); event TokenSent(bytes32 tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount); event TokenSentWithData( @@ -228,6 +229,22 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx */ function getImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress); + function interchainTransfer( + bytes32 tokenId, + string calldata destinationChain, + bytes calldata destinationAddress, + uint256 amount, + bytes calldata metadata + ) external; + + function sendTokenWithData( + bytes32 tokenId, + string calldata destinationChain, + bytes calldata destinationAddress, + uint256 amount, + bytes calldata data + ) external; + /** * @notice Initiates an interchain token transfer. Only callable by TokenManagers * @param tokenId The tokenId of the token to be transmitted. @@ -281,31 +298,9 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx function setPaused(bool paused) external; /** - * @notice Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing sendToken that matches the parameters passed here. - * @param tokenId the tokenId of the TokenManager used. - * @param destinationAddress the destinationAddress for the sendToken. - * @param amount the amount of token to give. + * @notice Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing interchainTransfer that matches the parameters passed here. + * @param payload the payload of the receive token * @param commandId the commandId calculated from the event at the sourceChain. */ - function expressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) external; - - /** - * @notice Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have detected an outgoing sendToken that matches the parameters passed here. - * @param tokenId the tokenId of the TokenManager used. - * @param sourceChain the name of the chain where the call came from. - * @param sourceAddress the caller of callContractWithInterchainToken. - * @param destinationAddress the destinationAddress for the sendToken. - * @param amount the amount of token to give. - * @param data the data to be passed to destinationAddress after giving them the tokens specified. - * @param commandId the commandId calculated from the event at the sourceChain. - */ - function expressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes calldata data, - bytes32 commandId - ) external; + function expressReceiveToken(bytes calldata payload, bytes32 commandId, string calldata sourceChain) external; } diff --git a/contracts/interfaces/ITokenManager.sol b/contracts/interfaces/ITokenManager.sol index ac918101..37fc5ed0 100644 --- a/contracts/interfaces/ITokenManager.sol +++ b/contracts/interfaces/ITokenManager.sol @@ -42,7 +42,7 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen * @param amount the amount of tokens to take from msg.sender. * @param metadata any additional data to be sent with the transfer. */ - function sendToken( + function interchainTransfer( string calldata destinationChain, bytes calldata destinationAddress, uint256 amount, @@ -87,6 +87,14 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen */ function giveToken(address destinationAddress, uint256 amount) external returns (uint256); + /** + * @notice This function takes token to from a specified address. Can only be called by the service. + * @param sourceAddress the address to take tokens from. + * @param amount the amount of token to take. + * @return the amount of token actually taken, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. + */ + function takeToken(address sourceAddress, uint256 amount) external returns (uint256); + /** * @notice This function sets the flow limit for this TokenManager. Can only be called by the operator. * @param flowLimit the maximum difference between the tokens flowing in and/or out at any given interval of time (6h) diff --git a/contracts/proxies/TokenManagerProxy.sol b/contracts/proxies/TokenManagerProxy.sol index 3f3dfa92..33a3c2d9 100644 --- a/contracts/proxies/TokenManagerProxy.sol +++ b/contracts/proxies/TokenManagerProxy.sol @@ -81,9 +81,4 @@ contract TokenManagerProxy is ITokenManagerProxy { } } } - - /** - * @dev Receive function which allows this contract to receive ether. - */ - receive() external payable virtual {} } diff --git a/contracts/test/InterchainExecutableTest.sol b/contracts/test/InterchainExecutableTest.sol index 1f7ac97d..bf952cb0 100644 --- a/contracts/test/InterchainExecutableTest.sol +++ b/contracts/test/InterchainExecutableTest.sol @@ -23,7 +23,7 @@ contract InterchainExecutableTest is InterchainTokenExpressExecutable { (address receiver, string memory message) = abi.decode(data, (address, string)); lastMessage = message; address tokenAddress = IInterchainTokenService(msg.sender).getTokenAddress(tokenId); - IERC20(tokenAddress).transfer(receiver, amount); emit MessageReceived(sourceChain, sourceAddress, receiver, message, tokenId, amount); + IERC20(tokenAddress).transfer(receiver, amount); } } diff --git a/contracts/test/utils/ExpressCallHandlerTest.sol b/contracts/test/utils/ExpressCallHandlerTest.sol index d8c101d8..92cb8b12 100644 --- a/contracts/test/utils/ExpressCallHandlerTest.sol +++ b/contracts/test/utils/ExpressCallHandlerTest.sol @@ -7,50 +7,11 @@ import { ExpressCallHandler } from '../../utils/ExpressCallHandler.sol'; contract ExpressCallHandlerTest is ExpressCallHandler { address public lastPoppedExpressCaller; - function setExpressReceiveToken( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId, - address expressCaller - ) external { - _setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, expressCaller); + function setExpressReceiveToken(bytes calldata payload, bytes32 commandId, address expressCaller) external { + _setExpressReceiveToken(payload, commandId, expressCaller); } - function setExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes calldata data, - bytes32 commandId, - address expressCaller - ) external { - _setExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); - } - - function popExpressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) external { - lastPoppedExpressCaller = _popExpressReceiveToken(tokenId, destinationAddress, amount, commandId); - } - - function popExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes memory data, - bytes32 commandId - ) external { - lastPoppedExpressCaller = _popExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ); + function popExpressReceiveToken(bytes calldata payload, bytes32 commandId) external { + lastPoppedExpressCaller = _popExpressReceiveToken(payload, commandId); } } diff --git a/contracts/token-manager/TokenManager.sol b/contracts/token-manager/TokenManager.sol index d4c06c8a..c0e58663 100644 --- a/contracts/token-manager/TokenManager.sol +++ b/contracts/token-manager/TokenManager.sol @@ -90,7 +90,7 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen * @param amount the amount of tokens to take from msg.sender. * @param metadata any additional data to be sent with the transfer. */ - function sendToken( + function interchainTransfer( string calldata destinationChain, bytes calldata destinationAddress, uint256 amount, @@ -177,6 +177,18 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen return amount; } + /** + * @notice This function gives token to a specified address. Can only be called by the service. + * @param sourceAddress the address to give tokens to. + * @param amount the amount of token to give. + * @return the amount of token actually given, which will onle be differen than `amount` in cases where the token takes some on-transfer fee. + */ + function takeToken(address sourceAddress, uint256 amount) external onlyService returns (uint256) { + _addFlowOut(amount); + amount = _takeToken(sourceAddress, amount); + return amount; + } + /** * @notice This function sets the flow limit for this TokenManager. Can only be called by the operator. * @param flowLimit the maximum difference between the tokens flowing in and/or out at any given interval of time (6h) diff --git a/contracts/utils/ExpressCallHandler.sol b/contracts/utils/ExpressCallHandler.sol index fbac6a7a..baab3951 100644 --- a/contracts/utils/ExpressCallHandler.sol +++ b/contracts/utils/ExpressCallHandler.sol @@ -12,123 +12,25 @@ import { IExpressCallHandler } from '../interfaces/IExpressCallHandler.sol'; contract ExpressCallHandler is IExpressCallHandler { // uint256(keccak256('prefix-express-give-token')); uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN = 0x67c7b41c1cb0375e36084c4ec399d005168e83425fa471b9224f6115af865619; - // uint256(keccak256('prefix-express-give-token-with-data')); - uint256 internal constant PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA = 0x3e607cc12a253b1d9f677a03d298ad869a90a8ba4bd0fb5739e7d79db7cdeaaf; /** * @notice Calculates the unique slot for a given express token transfer. - * @param tokenId The ID of the token being sent - * @param destinationAddress The address of the recipient - * @param amount The amount of tokens to be sent + * @param payload the payload of the receive token * @param commandId The unique hash for this token transfer * @return slot The calculated slot for this token transfer */ - function _getExpressReceiveTokenSlot( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId - ) internal pure returns (uint256 slot) { - slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, tokenId, destinationAddress, amount, commandId))); - } - - /** - * @notice Calculates the unique slot for a given token transfer with data - * @param tokenId The ID of the token being sent - * @param sourceChain The chain from which the token will be sent - * @param sourceAddress The originating address of the token on the source chain - * @param destinationAddress The address of the recipient on the destination chain - * @param amount The amount of tokens to be sent - * @param data The data associated with the token transfer - * @param commandId The unique hash for this token transfer - * @return slot The calculated slot for this token transfer - */ - function _getExpressReceiveTokenWithDataSlot( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes memory data, - bytes32 commandId - ) internal pure returns (uint256 slot) { - slot = uint256( - keccak256( - abi.encode( - PREFIX_EXPRESS_RECEIVE_TOKEN_WITH_DATA, - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ) - ) - ); + function _getExpressReceiveTokenSlot(bytes calldata payload, bytes32 commandId) internal pure returns (uint256 slot) { + slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, payload, commandId))); } /** * @notice Stores the address of the express caller at the storage slot determined by _getExpressSendTokenSlot - * @param tokenId The ID of the token being sent - * @param destinationAddress The address of the recipient - * @param amount The amount of tokens to be sent - * @param commandId The unique hash for this token transfer - * @param expressCaller The address of the express caller - */ - function _setExpressReceiveToken( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId, - address expressCaller - ) internal { - uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId); - address prevExpressCaller; - assembly { - prevExpressCaller := sload(slot) - } - - if (prevExpressCaller != address(0)) revert AlreadyExpressCalled(); - - assembly { - sstore(slot, expressCaller) - } - - emit ExpressReceive(tokenId, destinationAddress, amount, commandId, expressCaller); - } - - /** - * @notice Stores the address of the express caller for a given token transfer with data at - * the storage slot determined by _getExpressSendTokenWithDataSlot - * @param tokenId The ID of the token being sent - * @param sourceChain The chain from which the token will be sent - * @param sourceAddress The originating address of the token on the source chain - * @param destinationAddress The address of the recipient on the destination chain - * @param amount The amount of tokens to be sent - * @param data The data associated with the token transfer + * @param payload The payload for the receive token * @param commandId The unique hash for this token transfer * @param expressCaller The address of the express caller */ - function _setExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes calldata data, - bytes32 commandId, - address expressCaller - ) internal { - uint256 slot = _getExpressReceiveTokenWithDataSlot( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ); + function _setExpressReceiveToken(bytes calldata payload, bytes32 commandId, address expressCaller) internal { + uint256 slot = _getExpressReceiveTokenSlot(payload, commandId); address prevExpressCaller; assembly { prevExpressCaller := sload(slot) @@ -140,58 +42,17 @@ contract ExpressCallHandler is IExpressCallHandler { sstore(slot, expressCaller) } - emit ExpressReceiveWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); + emit ExpressReceive(payload, commandId, expressCaller); } /** * @notice Gets the address of the express caller for a specific token transfer - * @param tokenId The ID of the token being sent - * @param destinationAddress The address of the recipient - * @param amount The amount of tokens to be sent - * @param commandId The unique hash for this token transfer - * @return expressCaller The address of the express caller for this token transfer - */ - function getExpressReceiveToken( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId - ) public view returns (address expressCaller) { - uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId); - assembly { - expressCaller := sload(slot) - } - } - - /** - * @notice Gets the address of the express caller for a specific token transfer with data - * @param tokenId The ID of the token being sent - * @param sourceChain The chain from which the token will be sent - * @param sourceAddress The originating address of the token on the source chain - * @param destinationAddress The address of the recipient on the destination chain - * @param amount The amount of tokens to be sent - * @param data The data associated with the token transfer + * @param payload The payload for the receive token * @param commandId The unique hash for this token transfer * @return expressCaller The address of the express caller for this token transfer */ - function getExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes calldata data, - bytes32 commandId - ) public view returns (address expressCaller) { - uint256 slot = _getExpressReceiveTokenWithDataSlot( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ); + function getExpressReceiveToken(bytes calldata payload, bytes32 commandId) public view returns (address expressCaller) { + uint256 slot = _getExpressReceiveTokenSlot(payload, commandId); assembly { expressCaller := sload(slot) } @@ -199,61 +60,12 @@ contract ExpressCallHandler is IExpressCallHandler { /** * @notice Removes the express caller from storage for a specific token transfer, if it exists. - * @param tokenId The ID of the token being sent - * @param destinationAddress The address of the recipient - * @param amount The amount of tokens to be sent - * @param commandId The unique hash for this token transfer - * @return expressCaller The address of the express caller for this token transfer - */ - function _popExpressReceiveToken( - bytes32 tokenId, - address destinationAddress, - uint256 amount, - bytes32 commandId - ) internal returns (address expressCaller) { - uint256 slot = _getExpressReceiveTokenSlot(tokenId, destinationAddress, amount, commandId); - assembly { - expressCaller := sload(slot) - } - - if (expressCaller != address(0)) { - assembly { - sstore(slot, 0) - } - - emit ExpressExecutionFulfilled(tokenId, destinationAddress, amount, commandId, expressCaller); - } - } - - /** - * @notice Removes the express caller from storage for a specific token transfer with data, if it exists. - * @param tokenId The ID of the token being sent - * @param sourceChain The chain from which the token will be sent - * @param sourceAddress The originating address of the token on the source chain - * @param destinationAddress The address of the recipient on the destination chain - * @param amount The amount of tokens to be sent - * @param data The data associated with the token transfer + * @param payload the payload for the receive token * @param commandId The unique hash for this token transfer * @return expressCaller The address of the express caller for this token transfer */ - function _popExpressReceiveTokenWithData( - bytes32 tokenId, - string memory sourceChain, - bytes memory sourceAddress, - address destinationAddress, - uint256 amount, - bytes memory data, - bytes32 commandId - ) internal returns (address expressCaller) { - uint256 slot = _getExpressReceiveTokenWithDataSlot( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId - ); + function _popExpressReceiveToken(bytes calldata payload, bytes32 commandId) internal returns (address expressCaller) { + uint256 slot = _getExpressReceiveTokenSlot(payload, commandId); assembly { expressCaller := sload(slot) } @@ -263,16 +75,7 @@ contract ExpressCallHandler is IExpressCallHandler { sstore(slot, 0) } - emit ExpressExecutionWithDataFulfilled( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId, - expressCaller - ); + emit ExpressExecutionFulfilled(payload, commandId, expressCaller); } } } diff --git a/docs/index.md b/docs/index.md index 8a2abb47..430eaa02 100644 --- a/docs/index.md +++ b/docs/index.md @@ -566,14 +566,14 @@ function expressReceiveToken(bytes32 tokenId, address destinationAddress, uint25 ``` Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing -sendToken that matches the parameters passed here. +interchainTransfer that matches the parameters passed here. #### Parameters | Name | Type | Description | | ------------------ | ------- | ----------------------------------------- | | tokenId | bytes32 | the tokenId of the TokenManager used. | -| destinationAddress | address | the destinationAddress for the sendToken. | +| destinationAddress | address | the destinationAddress for the interchainTransfer. | | amount | uint256 | the amount of token to give. | | commandId | bytes32 | the sendHash detected at the sourceChain. | @@ -584,7 +584,7 @@ function expressReceiveTokenWithData(bytes32 tokenId, string sourceChain, bytes ``` Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have -detected an outgoing sendToken that matches the parameters passed here. +detected an outgoing interchainTransfer that matches the parameters passed here. #### Parameters @@ -593,7 +593,7 @@ detected an outgoing sendToken that matches the parameters passed here. | tokenId | bytes32 | the tokenId of the TokenManager used. | | sourceChain | string | the name of the chain where the call came from. | | sourceAddress | bytes | the caller of callContractWithInterchainToken. | -| destinationAddress | address | the destinationAddress for the sendToken. | +| destinationAddress | address | the destinationAddress for the interchainTransfer. | | amount | uint256 | the amount of token to give. | | data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | | commandId | bytes32 | the sendHash detected at the sourceChain. | @@ -613,7 +613,7 @@ Transmit a sendTokenWithData for the given tokenId. Only callable by a token man | tokenId | bytes32 | the tokenId of the TokenManager (which must be the msg.sender). | | sourceAddress | address | the address where the token is coming from, which will also be used for reimbursement of gas. | | destinationChain | string | the name of the chain to send tokens to. | -| destinationAddress | bytes | the destinationAddress for the sendToken. | +| destinationAddress | bytes | the destinationAddress for the interchainTransfer. | | amount | uint256 | the amount of token to give. | | metadata | bytes | the data to be passed to the destination. | @@ -1712,14 +1712,14 @@ Sets the paused state of the contract. function expressReceiveToken(bytes32 tokenId, address destinationAddress, uint256 amount, bytes32 commandId) external ``` -Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing sendToken that matches the parameters passed here. +Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if you have detected an outgoing interchainTransfer that matches the parameters passed here. #### Parameters | Name | Type | Description | | ------------------ | ------- | ----------------------------------------------------------- | | tokenId | bytes32 | the tokenId of the TokenManager used. | -| destinationAddress | address | the destinationAddress for the sendToken. | +| destinationAddress | address | the destinationAddress for the interchainTransfer. | | amount | uint256 | the amount of token to give. | | commandId | bytes32 | the commandId calculated from the event at the sourceChain. | @@ -1729,7 +1729,7 @@ Uses the caller's tokens to fullfill a sendCall ahead of time. Use this only if function expressReceiveTokenWithData(bytes32 tokenId, string sourceChain, bytes sourceAddress, address destinationAddress, uint256 amount, bytes data, bytes32 commandId) external ``` -Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have detected an outgoing sendToken that matches the parameters passed here. +Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of time. Use this only if you have detected an outgoing interchainTransfer that matches the parameters passed here. #### Parameters @@ -1738,7 +1738,7 @@ Uses the caller's tokens to fullfill a callContractWithInterchainToken ahead of | tokenId | bytes32 | the tokenId of the TokenManager used. | | sourceChain | string | the name of the chain where the call came from. | | sourceAddress | bytes | the caller of callContractWithInterchainToken. | -| destinationAddress | address | the destinationAddress for the sendToken. | +| destinationAddress | address | the destinationAddress for the interchainTransfer. | | amount | uint256 | the amount of token to give. | | data | bytes | the data to be passed to destinationAddress after giving them the tokens specified. | | commandId | bytes32 | the commandId calculated from the event at the sourceChain. | @@ -2106,10 +2106,10 @@ function implementationType() external pure returns (uint256) A function that should return the implementation type of the token manager. -### sendToken +### interchainTransfer ```solidity -function sendToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable +function interchainTransfer(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable ``` Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. @@ -4154,10 +4154,10 @@ _This function should only be called by the proxy, and only once from the proxy | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | params | bytes | the parameters to be used to initialize the TokenManager. The exact format depends on the type of TokenManager used but the first 32 bytes are reserved for the address of the operator, stored as bytes (to be compatible with non-EVM chains) | -### sendToken +### interchainTransfer ```solidity -function sendToken(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable virtual +function interchainTransfer(string destinationChain, bytes destinationAddress, uint256 amount, bytes metadata) external payable virtual ``` Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user. diff --git a/test/tokenService.js b/test/tokenService.js index 9b856885..582c908c 100644 --- a/test/tokenService.js +++ b/test/tokenService.js @@ -865,7 +865,7 @@ describe('Interchain Token Service', () => { transferToAddress = liquidityPool.address; } - await expect(tokenManager.sendToken(destChain, destAddress, amount, '0x', { value: gasValue })) + await expect(tokenManager.interchainTransfer(destChain, destAddress, amount, '0x', { value: gasValue })) .and.to.emit(token, 'Transfer') .withArgs(wallet.address, transferToAddress, amount) .and.to.emit(gateway, 'ContractCall') @@ -1215,19 +1215,25 @@ describe('Interchain Token Service', () => { }); it('Should express execute', async () => { - await expect(service.expressReceiveToken(tokenId, destinationAddress, amount, commandId)) + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256'], + [SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount], + ); + await expect(service.expressReceiveToken(payload, commandId, sourceChain)) .to.emit(service, 'ExpressReceive') - .withArgs(tokenId, destinationAddress, amount, commandId, wallet.address) + .withArgs(payload, commandId, wallet.address) .and.to.emit(token, 'Transfer') .withArgs(wallet.address, destinationAddress, amount); }); it('Should express execute with token', async () => { - await expect( - service.expressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, executable.address, amount, data, commandId), - ) - .to.emit(service, 'ExpressReceiveWithData') - .withArgs(tokenId, sourceChain, sourceAddress, executable.address, amount, data, commandId, wallet.address) + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256', 'bytes', ' bytes'], + [SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, executable.address, amount, sourceAddress, data], + ); + await expect(service.expressReceiveToken(payload, commandId, sourceChain)) + .to.emit(service, 'ExpressReceive') + .withArgs(payload, commandId, wallet.address) .and.to.emit(token, 'Transfer') .withArgs(wallet.address, executable.address, amount) .and.to.emit(token, 'Transfer') @@ -1257,13 +1263,13 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await (await service.expressReceiveToken(tokenId, destAddress, amount, commandId)).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(tokenManager.address, wallet.address, amount) .and.to.emit(service, 'ExpressExecutionFulfilled') - .withArgs(tokenId, destAddress, amount, commandId, wallet.address); + .withArgs(payload, commandId, wallet.address); }); it('Should be able to receive mint/burn token', async () => { @@ -1277,13 +1283,13 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await (await service.expressReceiveToken(tokenId, destAddress, amount, commandId)).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(AddressZero, wallet.address, amount) .and.to.emit(service, 'ExpressExecutionFulfilled') - .withArgs(tokenId, destAddress, amount, commandId, wallet.address); + .withArgs(payload, commandId, wallet.address); }); it('Should be able to receive lock/unlock with fee on transfer token', async () => { @@ -1297,13 +1303,13 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await (await service.expressReceiveToken(tokenId, destAddress, amount, commandId)).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(tokenManager.address, wallet.address, amount) .and.to.emit(service, 'ExpressExecutionFulfilled') - .withArgs(tokenId, destAddress, amount, commandId, wallet.address); + .withArgs(payload, commandId, wallet.address); }); it('Should be able to receive liquidity pool token', async () => { @@ -1317,13 +1323,13 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await (await service.expressReceiveToken(tokenId, destAddress, amount, commandId)).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(liquidityPool.address, wallet.address, amount) .and.to.emit(service, 'ExpressExecutionFulfilled') - .withArgs(tokenId, destAddress, amount, commandId, wallet.address); + .withArgs(payload, commandId, wallet.address); }); }); @@ -1354,23 +1360,14 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await ( - await service.expressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddressForService, - destAddress, - amount, - data, - commandId, - ) - ).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); - await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) + const tx = service.execute(commandId, sourceChain, sourceAddress, payload); + await expect(tx) .to.emit(token, 'Transfer') .withArgs(tokenManager.address, wallet.address, amount) - .and.to.emit(service, 'ExpressExecutionWithDataFulfilled') - .withArgs(tokenId, sourceChain, sourceAddressForService, destAddress, amount, data, commandId, wallet.address); + .and.to.emit(service, 'ExpressExecutionFulfilled') + .withArgs(payload, commandId, wallet.address); expect(await executable.lastMessage()).to.equal(msg); }); @@ -1388,23 +1385,13 @@ describe('Interchain Token Service', () => { const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await ( - await service.expressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddressForService, - destAddress, - amount, - data, - commandId, - ) - ).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(AddressZero, wallet.address, amount) - .and.to.emit(service, 'ExpressExecutionWithDataFulfilled') - .withArgs(tokenId, sourceChain, sourceAddressForService, destAddress, amount, data, commandId, wallet.address); + .and.to.emit(service, 'ExpressExecutionFulfilled') + .withArgs(payload, commandId, wallet.address); expect(await executable.lastMessage()).to.equal(msg); }); @@ -1422,9 +1409,7 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await expect( - service.expressReceiveTokenWithData(tokenId, sourceChain, sourceAddressForService, destAddress, amount, data, commandId), - ).to.be.reverted; + await expect(service.expressReceiveToken(payload, commandId, sourceChain)).to.be.reverted; }); it('Should be able to receive liquidity pool token', async () => { @@ -1440,23 +1425,13 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await ( - await service.expressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddressForService, - destAddress, - amount, - data, - commandId, - ) - ).wait(); + await (await service.expressReceiveToken(payload, commandId, sourceChain)).wait(); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') .withArgs(liquidityPool.address, wallet.address, amount) - .and.to.emit(service, 'ExpressExecutionWithDataFulfilled') - .withArgs(tokenId, sourceChain, sourceAddressForService, destAddress, amount, data, commandId, wallet.address); + .and.to.emit(service, 'ExpressExecutionFulfilled') + .withArgs(payload, commandId, wallet.address); expect(await executable.lastMessage()).to.equal(msg); }); @@ -1477,11 +1452,10 @@ describe('Interchain Token Service', () => { // These tests will fail every once in a while since the two transactions will happen in different epochs. // LMK of any fixes to this that do not involve writing a new contract to facilitate a multicall. it('Should be able to send token only if it does not trigger the mint limit', async () => { - await (await tokenManager.sendToken(destinationChain, destinationAddress, sendAmount, '0x')).wait(); - await expect(tokenManager.sendToken(destinationChain, destinationAddress, sendAmount, '0x')).to.be.revertedWithCustomError( - tokenManager, - 'FlowLimitExceeded', - ); + await (await tokenManager.interchainTransfer(destinationChain, destinationAddress, sendAmount, '0x')).wait(); + await expect( + tokenManager.interchainTransfer(destinationChain, destinationAddress, sendAmount, '0x'), + ).to.be.revertedWithCustomError(tokenManager, 'FlowLimitExceeded'); }); it('Should be able to receive token only if it does not trigger the mint limit', async () => { diff --git a/test/tokenServiceFullFlow.js b/test/tokenServiceFullFlow.js index 89bcf31c..8dd2c420 100644 --- a/test/tokenServiceFullFlow.js +++ b/test/tokenServiceFullFlow.js @@ -101,7 +101,7 @@ describe('Interchain Token Service', () => { .to.emit(token, 'Approval') .withArgs(wallet.address, tokenManager.address, amount); - await expect(tokenManager.sendToken(destChain, destAddress, amount, '0x', { value: gasValue })) + await expect(tokenManager.interchainTransfer(destChain, destAddress, amount, '0x', { value: gasValue })) .and.to.emit(token, 'Transfer') .withArgs(wallet.address, tokenManager.address, amount) .and.to.emit(gateway, 'ContractCall') @@ -210,7 +210,7 @@ describe('Interchain Token Service', () => { ); const payloadHash = keccak256(payload); - await expect(tokenManager.sendToken(destChain, destAddress, amount, '0x', { value: gasValue })) + await expect(tokenManager.interchainTransfer(destChain, destAddress, amount, '0x', { value: gasValue })) .and.to.emit(token, 'Transfer') .withArgs(wallet.address, AddressZero, amount) .and.to.emit(gateway, 'ContractCall') diff --git a/test/utils.js b/test/utils.js index 6d0e4f73..17030fc2 100644 --- a/test/utils.js +++ b/test/utils.js @@ -72,13 +72,8 @@ describe('Distributable', () => { describe('ExpressCallHandler', () => { let handler; - const tokenId = getRandomBytes32(); - const destinationAddress = new Wallet(getRandomBytes32()).address; - const amount = 123; const expressCaller = new Wallet(getRandomBytes32()).address; - const sourceChain = 'sourceChain'; - const sourceAddress = '0x1234'; - const data = '0x5678'; + const payload = '0x5678'; before(async () => { handler = await deployContract(ownerWallet, 'ExpressCallHandlerTest'); @@ -86,122 +81,36 @@ describe('ExpressCallHandler', () => { it('Should be able to set an express receive token', async () => { const commandId = getRandomBytes32(); - await expect(handler.setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, expressCaller)) + await expect(handler.setExpressReceiveToken(payload, commandId, expressCaller)) .to.emit(handler, 'ExpressReceive') - .withArgs(tokenId, destinationAddress, amount, commandId, expressCaller); - expect(await handler.getExpressReceiveToken(tokenId, destinationAddress, amount, commandId)).to.equal(expressCaller); + .withArgs(payload, commandId, expressCaller); + expect(await handler.getExpressReceiveToken(payload, commandId)).to.equal(expressCaller); }); it('Should not be able to set an express receive token if it is already set', async () => { const commandId = getRandomBytes32(); - await expect(handler.setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, expressCaller)) + await expect(handler.setExpressReceiveToken(payload, commandId, expressCaller)) .to.emit(handler, 'ExpressReceive') - .withArgs(tokenId, destinationAddress, amount, commandId, expressCaller); - expect(await handler.getExpressReceiveToken(tokenId, destinationAddress, amount, commandId)).to.equal(expressCaller); + .withArgs(payload, commandId, expressCaller); + expect(await handler.getExpressReceiveToken(payload, commandId)).to.equal(expressCaller); const newExpressCaller = new Wallet(getRandomBytes32()).address; - await expect( - handler.setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, newExpressCaller), - ).to.be.revertedWithCustomError(handler, 'AlreadyExpressCalled'); - }); - - it('Should be able to set an express receive token', async () => { - const commandId = getRandomBytes32(); - await expect( - handler.setExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId, - expressCaller, - ), - ) - .to.emit(handler, 'ExpressReceiveWithData') - .withArgs(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); - expect( - await handler.getExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId), - ).to.equal(expressCaller); - }); - - it('Should be able to set an express receive token', async () => { - const commandId = getRandomBytes32(); - await expect( - handler.setExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId, - expressCaller, - ), - ) - .to.emit(handler, 'ExpressReceiveWithData') - .withArgs(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); - expect( - await handler.getExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId), - ).to.equal(expressCaller); - - const newExpressCaller = new Wallet(getRandomBytes32()).address; - await expect( - handler.setExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId, - newExpressCaller, - ), - ).to.be.revertedWithCustomError(handler, 'AlreadyExpressCalled'); - }); - - it('Should properly pop an express receive token', async () => { - const commandId = getRandomBytes32(); - await expect(handler.popExpressReceiveToken(tokenId, destinationAddress, amount, commandId)).to.not.emit( + await expect(handler.setExpressReceiveToken(payload, commandId, newExpressCaller)).to.be.revertedWithCustomError( handler, - 'ExpressExecutionFulfilled', + 'AlreadyExpressCalled', ); - expect(await handler.lastPoppedExpressCaller()).to.equal(AddressZero); - - await (await handler.setExpressReceiveToken(tokenId, destinationAddress, amount, commandId, expressCaller)).wait(); - - await expect(handler.popExpressReceiveToken(tokenId, destinationAddress, amount, commandId)) - .to.emit(handler, 'ExpressExecutionFulfilled') - .withArgs(tokenId, destinationAddress, amount, commandId, expressCaller); - expect(await handler.lastPoppedExpressCaller()).to.equal(expressCaller); }); - it('Should properly pop an express receive token with data', async () => { + it('Should properly pop an express receive token', async () => { const commandId = getRandomBytes32(); - await expect( - handler.popExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId), - ).to.not.emit(handler, 'ExpressExecutionWithDataFulfilled'); + await expect(handler.popExpressReceiveToken(payload, commandId)).to.not.emit(handler, 'ExpressExecutionFulfilled'); expect(await handler.lastPoppedExpressCaller()).to.equal(AddressZero); - await ( - await handler.setExpressReceiveTokenWithData( - tokenId, - sourceChain, - sourceAddress, - destinationAddress, - amount, - data, - commandId, - expressCaller, - ) - ).wait(); + await (await handler.setExpressReceiveToken(payload, commandId, expressCaller)).wait(); - await expect( - handler.popExpressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId), - ) - .to.emit(handler, 'ExpressExecutionWithDataFulfilled') - .withArgs(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller); + await expect(handler.popExpressReceiveToken(payload, commandId)) + .to.emit(handler, 'ExpressExecutionFulfilled') + .withArgs(payload, commandId, expressCaller); expect(await handler.lastPoppedExpressCaller()).to.equal(expressCaller); }); }); From 926e0254b3ba236ceafe99e4382e907803dc8223 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 2 Oct 2023 18:09:54 +0300 Subject: [PATCH 08/12] feat: code4rena gas opts (#105) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * changed from uint256.max to a const * change setting to zero to delete for storage slots. * rearange storage variables to save a bit of gas. * Removed unecesairy casts * made as many event params inexed as possible * Removed unused imports --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- .../InterchainTokenService.sol | 1 - contracts/interchain-token/InterchainToken.sol | 2 +- contracts/interfaces/IInterchainTokenService.sol | 12 +++++------- contracts/interfaces/IPausable.sol | 2 +- .../RemoteAddressValidator.sol | 4 ++-- contracts/test/FeeOnTransferTokenTest.sol | 7 ++++--- contracts/test/InterchainTokenTest.sol | 6 +++--- contracts/token-implementations/ERC20.sol | 3 ++- .../token-implementations/StandardizedToken.sol | 2 +- .../implementations/TokenManagerAddressStorage.sol | 2 -- .../implementations/TokenManagerLiquidityPool.sol | 2 +- .../TokenManagerLockUnlockFeeOnTransfer.sol | 2 +- 12 files changed, 21 insertions(+), 24 deletions(-) diff --git a/contracts/interchain-token-service/InterchainTokenService.sol b/contracts/interchain-token-service/InterchainTokenService.sol index d005a47c..4ba539c6 100644 --- a/contracts/interchain-token-service/InterchainTokenService.sol +++ b/contracts/interchain-token-service/InterchainTokenService.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; -import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol'; import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol'; import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; diff --git a/contracts/interchain-token/InterchainToken.sol b/contracts/interchain-token/InterchainToken.sol index edd81eb7..3d7c29f8 100644 --- a/contracts/interchain-token/InterchainToken.sol +++ b/contracts/interchain-token/InterchainToken.sol @@ -61,7 +61,7 @@ abstract contract InterchainToken is IInterchainToken, ERC20 { ) external payable { uint256 _allowance = allowance[sender][msg.sender]; - if (_allowance != type(uint256).max) { + if (_allowance != UINT256_MAX) { _approve(sender, msg.sender, _allowance - amount); } diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index 82201e79..a46bcfd2 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -2,11 +2,9 @@ pragma solidity ^0.8.0; -import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; import { IAxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarExecutable.sol'; import { IExpressCallHandler } from './IExpressCallHandler.sol'; -import { ITokenManagerDeployer } from './ITokenManagerDeployer.sol'; import { ITokenManagerType } from './ITokenManagerType.sol'; import { IPausable } from './IPausable.sol'; import { IMulticall } from './IMulticall.sol'; @@ -30,9 +28,9 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx error AlreadyExecuted(bytes32 commandId); error InvalidExpressSelector(); - event TokenSent(bytes32 tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount); + event TokenSent(bytes32 indexed tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount); event TokenSentWithData( - bytes32 tokenId, + bytes32 indexed tokenId, string destinationChain, bytes destinationAddress, uint256 indexed amount, @@ -62,7 +60,7 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx uint8 tokenDecimals, bytes distributor, bytes mintTo, - uint256 mintAmount, + uint256 indexed mintAmount, bytes operator, string destinationChain, uint256 indexed gasValue @@ -70,11 +68,11 @@ interface IInterchainTokenService is ITokenManagerType, IExpressCallHandler, IAx event TokenManagerDeployed(bytes32 indexed tokenId, TokenManagerType indexed tokenManagerType, bytes params); event StandardizedTokenDeployed( bytes32 indexed tokenId, - address distributor, + address indexed distributor, string name, string symbol, uint8 decimals, - uint256 mintAmount, + uint256 indexed mintAmount, address mintTo ); event CustomTokenIdClaimed(bytes32 indexed tokenId, address indexed deployer, bytes32 indexed salt); diff --git a/contracts/interfaces/IPausable.sol b/contracts/interfaces/IPausable.sol index f58eecf6..c5adbd7f 100644 --- a/contracts/interfaces/IPausable.sol +++ b/contracts/interfaces/IPausable.sol @@ -8,7 +8,7 @@ pragma solidity ^0.8.0; * if a pause condition is activated. */ interface IPausable { - event PausedSet(bool paused); + event PausedSet(bool indexed paused); error Paused(); diff --git a/contracts/remote-address-validator/RemoteAddressValidator.sol b/contracts/remote-address-validator/RemoteAddressValidator.sol index 75881d9e..89d7d40c 100644 --- a/contracts/remote-address-validator/RemoteAddressValidator.sol +++ b/contracts/remote-address-validator/RemoteAddressValidator.sol @@ -143,8 +143,8 @@ contract RemoteAddressValidator is IRemoteAddressValidator, Upgradable { function removeTrustedAddress(string calldata sourceChain) external onlyOwner { if (bytes(sourceChain).length == 0) revert ZeroStringLength(); - remoteAddressHashes[sourceChain] = bytes32(0); - remoteAddresses[sourceChain] = ''; + delete remoteAddressHashes[sourceChain]; + delete remoteAddresses[sourceChain]; emit TrustedAddressRemoved(sourceChain); } diff --git a/contracts/test/FeeOnTransferTokenTest.sol b/contracts/test/FeeOnTransferTokenTest.sol index a5163a1f..d0816dd1 100644 --- a/contracts/test/FeeOnTransferTokenTest.sol +++ b/contracts/test/FeeOnTransferTokenTest.sol @@ -10,6 +10,7 @@ import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol contract FeeOnTransferTokenTest is InterchainToken, Distributable, IERC20BurnableMintable { ITokenManager public tokenManager_; bool internal tokenManagerRequiresApproval_ = true; + string public name; string public symbol; uint8 public decimals; @@ -36,9 +37,9 @@ contract FeeOnTransferTokenTest is InterchainToken, Distributable, IERC20Burnabl if (!tokenManagerRequiresApproval_) return; address tokenManagerAddress = address(tokenManager_); uint256 allowance_ = allowance[sender][tokenManagerAddress]; - if (allowance_ != type(uint256).max) { - if (allowance_ > type(uint256).max - amount) { - allowance_ = type(uint256).max - amount; + if (allowance_ != UINT256_MAX) { + if (allowance_ > UINT256_MAX - amount) { + allowance_ = UINT256_MAX - amount; } _approve(sender, tokenManagerAddress, allowance_ + amount); diff --git a/contracts/test/InterchainTokenTest.sol b/contracts/test/InterchainTokenTest.sol index 53c369c2..96fa8cbb 100644 --- a/contracts/test/InterchainTokenTest.sol +++ b/contracts/test/InterchainTokenTest.sol @@ -36,9 +36,9 @@ contract InterchainTokenTest is InterchainToken, Distributable, IERC20BurnableMi if (!tokenManagerRequiresApproval_) return; address tokenManagerAddress = address(tokenManager_); uint256 allowance_ = allowance[sender][tokenManagerAddress]; - if (allowance_ != type(uint256).max) { - if (allowance_ > type(uint256).max - amount) { - allowance_ = type(uint256).max - amount; + if (allowance_ != UINT256_MAX) { + if (allowance_ > UINT256_MAX - amount) { + allowance_ = UINT256_MAX - amount; } _approve(sender, tokenManagerAddress, allowance_ + amount); diff --git a/contracts/token-implementations/ERC20.sol b/contracts/token-implementations/ERC20.sol index 66be0690..71b7f10d 100644 --- a/contracts/token-implementations/ERC20.sol +++ b/contracts/token-implementations/ERC20.sol @@ -34,6 +34,7 @@ contract ERC20 is IERC20 { mapping(address => mapping(address => uint256)) public override allowance; uint256 public override totalSupply; + uint256 internal constant UINT256_MAX = 2 ** 256 - 1; /** * @dev See {IERC20-transfer}. @@ -79,7 +80,7 @@ contract ERC20 is IERC20 { function transferFrom(address sender, address recipient, uint256 amount) external virtual override returns (bool) { uint256 _allowance = allowance[sender][msg.sender]; - if (_allowance != type(uint256).max) { + if (_allowance != UINT256_MAX) { _approve(sender, msg.sender, _allowance - amount); } diff --git a/contracts/token-implementations/StandardizedToken.sol b/contracts/token-implementations/StandardizedToken.sol index 8d291a00..f1fe4951 100644 --- a/contracts/token-implementations/StandardizedToken.sol +++ b/contracts/token-implementations/StandardizedToken.sol @@ -19,10 +19,10 @@ import { Distributable } from '../utils/Distributable.sol'; contract StandardizedToken is IERC20BurnableMintable, InterchainToken, ERC20Permit, Implementation, Distributable { using AddressBytesUtils for bytes; - address internal tokenManager_; string public name; string public symbol; uint8 public decimals; + address internal tokenManager_; bytes32 private constant CONTRACT_ID = keccak256('standardized-token'); diff --git a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol b/contracts/token-manager/implementations/TokenManagerAddressStorage.sol index a7a1d32f..23a1559f 100644 --- a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol +++ b/contracts/token-manager/implementations/TokenManagerAddressStorage.sol @@ -3,8 +3,6 @@ pragma solidity ^0.8.0; import { TokenManager } from '../TokenManager.sol'; -import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; -import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; /** * @title TokenManagerAddressStorage diff --git a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol index 4f552462..1539fa9f 100644 --- a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol +++ b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol @@ -98,7 +98,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { */ function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = IERC20(token).balanceOf(to); + uint256 balance = token.balanceOf(to); SafeTokenTransferFrom.safeTransferFrom(token, liquidityPool(), to, amount); diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol index b1db1cd9..01b21ab5 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol @@ -63,7 +63,7 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { */ function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = IERC20(token).balanceOf(to); + uint256 balance = token.balanceOf(to); SafeTokenTransfer.safeTransfer(token, to, amount); From 4ca3dd6bda97bd89349314e2a0426b4d45443c07 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 3 Oct 2023 12:48:34 +0300 Subject: [PATCH 09/12] feat: do not cache chain id for permit (#106) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * changed from uint256.max to a const * change setting to zero to delete for storage slots. * rearange storage variables to save a bit of gas. * Removed unecesairy casts * made as many event params inexed as possible * Removed unused imports * domain separator is calculated each time. * added some natspec --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- .../token-implementations/ERC20Permit.sol | 21 ++++++++++++------- .../StandardizedToken.sol | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/contracts/token-implementations/ERC20Permit.sol b/contracts/token-implementations/ERC20Permit.sol index 022edb76..349bd7de 100644 --- a/contracts/token-implementations/ERC20Permit.sol +++ b/contracts/token-implementations/ERC20Permit.sol @@ -22,7 +22,7 @@ abstract contract ERC20Permit is IERC20, IERC20Permit, ERC20 { * @dev Represents hash of the EIP-712 Domain Separator. */ // solhint-disable-next-line var-name-mixedcase - bytes32 public DOMAIN_SEPARATOR; + bytes32 public nameHash; string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = '\x19\x01'; @@ -38,13 +38,20 @@ abstract contract ERC20Permit is IERC20, IERC20Permit, ERC20 { mapping(address => uint256) public nonces; /** - * @notice Internal function to set the domain type signature hash + * @notice Internal function to set the token name hash * @param name The token name */ - function _setDomainTypeSignatureHash(string memory name) internal { - DOMAIN_SEPARATOR = keccak256( - abi.encode(DOMAIN_TYPE_SIGNATURE_HASH, keccak256(bytes(name)), keccak256(bytes('1')), block.chainid, address(this)) - ); + function _setNameHash(string memory name) internal { + nameHash = keccak256(bytes(name)); + } + + /** + * @notice Calculates the DOMAIN_SEPARATOR. + * @dev This is not cached because chainid can change on chain forks. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() public view returns (bytes32 domainSeparator) { + domainSeparator = keccak256(abi.encode(DOMAIN_TYPE_SIGNATURE_HASH, nameHash, keccak256(bytes('1')), block.chainid, address(this))); } /** @@ -69,7 +76,7 @@ abstract contract ERC20Permit is IERC20, IERC20Permit, ERC20 { bytes32 digest = keccak256( abi.encodePacked( EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, - DOMAIN_SEPARATOR, + DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_SIGNATURE_HASH, issuer, spender, value, nonces[issuer]++, deadline)) ) ); diff --git a/contracts/token-implementations/StandardizedToken.sol b/contracts/token-implementations/StandardizedToken.sol index f1fe4951..e4e150a8 100644 --- a/contracts/token-implementations/StandardizedToken.sol +++ b/contracts/token-implementations/StandardizedToken.sol @@ -68,7 +68,7 @@ contract StandardizedToken is IERC20BurnableMintable, InterchainToken, ERC20Perm name = tokenName; _setDistributor(distributor_); - _setDomainTypeSignatureHash(tokenName); + _setNameHash(tokenName); } { uint256 mintAmount; From 73119518ff27c19471f97053d7fa1307697dc22a Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 3 Oct 2023 12:55:08 +0300 Subject: [PATCH 10/12] feat: another example (#107) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * changed from uint256.max to a const * change setting to zero to delete for storage slots. * rearange storage variables to save a bit of gas. * Removed unecesairy casts * made as many event params inexed as possible * Removed unused imports * domain separator is calculated each time. * added some natspec * added an example for using pre-existing custom tokens. * added a comment * feat(TokenManager): added MintBurnFrom and MintBurnFromAddress (#108) * feat(TokenManager): MintBurnFrom and MintBurnFromAddress * fix(TokenManager): removed MintBurnFromAddress as deprecated * Update contracts/interfaces/IERC20BurnableFrom.sol --------- Co-authored-by: Milap Sheth --------- Co-authored-by: Milap Sheth Co-authored-by: Kiryl Yermakou --- contracts/interfaces/IERC20BurnableFrom.sol | 25 ++++ ...intable.sol => IERC20MintableBurnable.sol} | 6 +- contracts/interfaces/IStandardizedToken.sol | 4 +- contracts/interfaces/ITokenManagerType.sol | 3 +- contracts/test/FeeOnTransferTokenTest.sol | 4 +- contracts/test/InterchainTokenTest.sol | 4 +- .../StandardizedToken.sol | 4 +- contracts/token-manager/TokenManager.sol | 24 +++- .../TokenManagerAddressStorage.sol | 41 ------- .../TokenManagerLiquidityPool.sol | 12 +- .../TokenManagerLockUnlock.sol | 15 ++- .../TokenManagerLockUnlockFeeOnTransfer.sol | 13 +- .../implementations/TokenManagerMintBurn.sol | 22 ++-- .../TokenManagerMintBurnFrom.sol | 44 +++++++ contracts/utils/NoReEntrancy.sol | 10 +- scripts/deploy.js | 2 +- test/tokenService.js | 41 ++++--- test/tokenServiceFullFlow.js | 113 +++++++++++++++++- 18 files changed, 276 insertions(+), 111 deletions(-) create mode 100644 contracts/interfaces/IERC20BurnableFrom.sol rename contracts/interfaces/{IERC20BurnableMintable.sol => IERC20MintableBurnable.sol} (79%) delete mode 100644 contracts/token-manager/implementations/TokenManagerAddressStorage.sol create mode 100644 contracts/token-manager/implementations/TokenManagerMintBurnFrom.sol diff --git a/contracts/interfaces/IERC20BurnableFrom.sol b/contracts/interfaces/IERC20BurnableFrom.sol new file mode 100644 index 00000000..5c086542 --- /dev/null +++ b/contracts/interfaces/IERC20BurnableFrom.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20BurnableFrom { + /** + * @notice Function to burn tokens from a burn deposit address + * @notice It is needed to support legacy Axelar Gateway tokens + * @dev Can only be called after token is transferred to a deposit address. + * @param salt The address that will have its tokens burnt + */ + function burn(bytes32 salt) external; + + /** + * @notice Function to burn tokens + * @notice Requires the caller to have allowance for `amount` on `from` + * @dev Can only be called by the distributor address. + * @param from The address that will have its tokens burnt + * @param amount The amount of tokens to burn + */ + function burnFrom(address from, uint256 amount) external; +} diff --git a/contracts/interfaces/IERC20BurnableMintable.sol b/contracts/interfaces/IERC20MintableBurnable.sol similarity index 79% rename from contracts/interfaces/IERC20BurnableMintable.sol rename to contracts/interfaces/IERC20MintableBurnable.sol index 12925185..f6fe5049 100644 --- a/contracts/interfaces/IERC20BurnableMintable.sol +++ b/contracts/interfaces/IERC20MintableBurnable.sol @@ -5,10 +5,10 @@ pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ -interface IERC20BurnableMintable { +interface IERC20MintableBurnable { /** * @notice Function to mint new tokens - * Can only be called by the distributor address. + * @dev Can only be called by the distributor address. * @param to The address that will receive the minted tokens * @param amount The amount of tokens to mint */ @@ -16,7 +16,7 @@ interface IERC20BurnableMintable { /** * @notice Function to burn tokens - * Can only be called by the distributor address. + * @dev Can only be called by the distributor address. * @param from The address that will have its tokens burnt * @param amount The amount of tokens to burn */ diff --git a/contracts/interfaces/IStandardizedToken.sol b/contracts/interfaces/IStandardizedToken.sol index 79b61315..9763a2ff 100644 --- a/contracts/interfaces/IStandardizedToken.sol +++ b/contracts/interfaces/IStandardizedToken.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { IInterchainToken } from './IInterchainToken.sol'; import { IDistributable } from './IDistributable.sol'; -import { IERC20BurnableMintable } from './IERC20BurnableMintable.sol'; +import { IERC20MintableBurnable } from './IERC20MintableBurnable.sol'; import { ITokenManager } from './ITokenManager.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; @@ -13,7 +13,7 @@ import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interf * @notice This contract implements a standardized token which extends InterchainToken functionality. * This contract also inherits Distributable and Implementation logic. */ -interface IStandardizedToken is IInterchainToken, IDistributable, IERC20BurnableMintable, IERC20 { +interface IStandardizedToken is IInterchainToken, IDistributable, IERC20MintableBurnable, IERC20 { /** * @notice Returns the contract id, which a proxy can check to ensure no false implementation was used. */ diff --git a/contracts/interfaces/ITokenManagerType.sol b/contracts/interfaces/ITokenManagerType.sol index b9a42ade..925bff8c 100644 --- a/contracts/interfaces/ITokenManagerType.sol +++ b/contracts/interfaces/ITokenManagerType.sol @@ -8,8 +8,9 @@ pragma solidity ^0.8.0; */ interface ITokenManagerType { enum TokenManagerType { - LOCK_UNLOCK, MINT_BURN, + MINT_BURN_FROM, + LOCK_UNLOCK, LOCK_UNLOCK_FEE_ON_TRANSFER, LIQUIDITY_POOL } diff --git a/contracts/test/FeeOnTransferTokenTest.sol b/contracts/test/FeeOnTransferTokenTest.sol index d0816dd1..05664232 100644 --- a/contracts/test/FeeOnTransferTokenTest.sol +++ b/contracts/test/FeeOnTransferTokenTest.sol @@ -5,9 +5,9 @@ pragma solidity ^0.8.0; import { InterchainToken } from '../interchain-token/InterchainToken.sol'; import { Distributable } from '../utils/Distributable.sol'; import { ITokenManager } from '../interfaces/ITokenManager.sol'; -import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; +import { IERC20MintableBurnable } from '../interfaces/IERC20MintableBurnable.sol'; -contract FeeOnTransferTokenTest is InterchainToken, Distributable, IERC20BurnableMintable { +contract FeeOnTransferTokenTest is InterchainToken, Distributable, IERC20MintableBurnable { ITokenManager public tokenManager_; bool internal tokenManagerRequiresApproval_ = true; diff --git a/contracts/test/InterchainTokenTest.sol b/contracts/test/InterchainTokenTest.sol index 96fa8cbb..8a44f732 100644 --- a/contracts/test/InterchainTokenTest.sol +++ b/contracts/test/InterchainTokenTest.sol @@ -5,9 +5,9 @@ pragma solidity ^0.8.0; import { InterchainToken } from '../interchain-token/InterchainToken.sol'; import { Distributable } from '../utils/Distributable.sol'; import { ITokenManager } from '../interfaces/ITokenManager.sol'; -import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; +import { IERC20MintableBurnable } from '../interfaces/IERC20MintableBurnable.sol'; -contract InterchainTokenTest is InterchainToken, Distributable, IERC20BurnableMintable { +contract InterchainTokenTest is InterchainToken, Distributable, IERC20MintableBurnable { ITokenManager public tokenManager_; bool internal tokenManagerRequiresApproval_ = true; string public name; diff --git a/contracts/token-implementations/StandardizedToken.sol b/contracts/token-implementations/StandardizedToken.sol index e4e150a8..769fa53e 100644 --- a/contracts/token-implementations/StandardizedToken.sol +++ b/contracts/token-implementations/StandardizedToken.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; +import { IERC20MintableBurnable } from '../interfaces/IERC20MintableBurnable.sol'; import { ITokenManager } from '../interfaces/ITokenManager.sol'; import { InterchainToken } from '../interchain-token/InterchainToken.sol'; @@ -16,7 +16,7 @@ import { Distributable } from '../utils/Distributable.sol'; * @notice This contract implements a standardized token which extends InterchainToken functionality. * This contract also inherits Distributable and Implementation logic. */ -contract StandardizedToken is IERC20BurnableMintable, InterchainToken, ERC20Permit, Implementation, Distributable { +contract StandardizedToken is IERC20MintableBurnable, InterchainToken, ERC20Permit, Implementation, Distributable { using AddressBytesUtils for bytes; string public name; diff --git a/contracts/token-manager/TokenManager.sol b/contracts/token-manager/TokenManager.sol index c0e58663..516baea5 100644 --- a/contracts/token-manager/TokenManager.sol +++ b/contracts/token-manager/TokenManager.sol @@ -20,6 +20,9 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen IInterchainTokenService public immutable interchainTokenService; + // uint256(keccak256('token-address')) - 1 + uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; + /** * @notice Constructs the TokenManager contract. * @param interchainTokenService_ The address of the interchain token service @@ -46,11 +49,14 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen } /** - * @notice A function that should return the address of the token. - * Must be overridden in the inheriting contract. - * @return address address of the token. + * @dev Reads the stored token address from the predetermined storage slot + * @return tokenAddress_ The address of the token */ - function tokenAddress() public view virtual returns (address); + function tokenAddress() public view virtual returns (address tokenAddress_) { + assembly { + tokenAddress_ := sload(TOKEN_ADDRESS_SLOT) + } + } /** * @notice A function that returns the token id. @@ -197,6 +203,16 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen _setFlowLimit(flowLimit); } + /** + * @dev Stores the token address in the predetermined storage slot + * @param tokenAddress_ The address of the token to store + */ + function _setTokenAddress(address tokenAddress_) internal { + assembly { + sstore(TOKEN_ADDRESS_SLOT, tokenAddress_) + } + } + /** * @notice Transfers tokens from a specific address to this contract. * Must be overridden in the inheriting contract. diff --git a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol b/contracts/token-manager/implementations/TokenManagerAddressStorage.sol deleted file mode 100644 index 23a1559f..00000000 --- a/contracts/token-manager/implementations/TokenManagerAddressStorage.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import { TokenManager } from '../TokenManager.sol'; - -/** - * @title TokenManagerAddressStorage - * @notice This contract extends the TokenManager contract and provides additional functionality to store and retrieve - * the token address using a predetermined storage slot - */ -abstract contract TokenManagerAddressStorage is TokenManager { - // uint256(keccak256('token-address')) - 1 - uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba; - - /** - * @dev Creates an instance of the TokenManagerAddressStorage contract. - * @param interchainTokenService_ The address of the interchain token service contract - */ - constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} - - /** - * @dev Reads the stored token address from the predetermined storage slot - * @return tokenAddress_ The address of the token - */ - function tokenAddress() public view override returns (address tokenAddress_) { - assembly { - tokenAddress_ := sload(TOKEN_ADDRESS_SLOT) - } - } - - /** - * @dev Stores the token address in the predetermined storage slot - * @param tokenAddress_ The address of the token to store - */ - function _setTokenAddress(address tokenAddress_) internal { - assembly { - sstore(TOKEN_ADDRESS_SLOT, tokenAddress_) - } - } -} diff --git a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol index 1539fa9f..5089a444 100644 --- a/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol +++ b/contracts/token-manager/implementations/TokenManagerLiquidityPool.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; +import { TokenManager } from '../TokenManager.sol'; import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { ITokenManagerLiquidityPool } from '../../interfaces/ITokenManagerLiquidityPool.sol'; @@ -16,7 +16,9 @@ import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/c * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { +contract TokenManagerLiquidityPool is TokenManager, NoReEntrancy { + using SafeTokenTransferFrom for IERC20; + // uint256(keccak256('liquidity-pool-slot')) - 1 uint256 internal constant LIQUIDITY_POOL_SLOT = 0x8e02741a3381812d092c5689c9fc701c5185c1742fdf7954c4c4472be4cc4807; @@ -25,7 +27,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { * of TokenManagerAddressStorage which calls the constructor of TokenManager. * @param interchainTokenService_ The address of the interchain token service contract */ - constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} + constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} function implementationType() external pure returns (uint256) { return uint256(TokenManagerType.LIQUIDITY_POOL); @@ -81,7 +83,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { address liquidityPool_ = liquidityPool(); uint256 balance = token.balanceOf(liquidityPool_); - SafeTokenTransferFrom.safeTransferFrom(token, from, liquidityPool_, amount); + token.safeTransferFrom(from, liquidityPool_, amount); uint256 diff = token.balanceOf(liquidityPool_) - balance; if (diff < amount) { @@ -100,7 +102,7 @@ contract TokenManagerLiquidityPool is TokenManagerAddressStorage, NoReEntrancy { IERC20 token = IERC20(tokenAddress()); uint256 balance = token.balanceOf(to); - SafeTokenTransferFrom.safeTransferFrom(token, liquidityPool(), to, amount); + token.safeTransferFrom(liquidityPool(), to, amount); uint256 diff = token.balanceOf(to) - balance; if (diff < amount) { diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol index e9d9fb0f..96ebce7e 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlock.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlock.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; -import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; +import { TokenManager } from '../TokenManager.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { ITokenManagerLockUnlock } from '../../interfaces/ITokenManagerLockUnlock.sol'; -import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; +import { SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; /** * @title TokenManagerLockUnlock @@ -14,13 +14,16 @@ import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerLockUnlock is TokenManagerAddressStorage, ITokenManagerLockUnlock { +contract TokenManagerLockUnlock is TokenManager, ITokenManagerLockUnlock { + using SafeTokenTransfer for IERC20; + using SafeTokenTransferFrom for IERC20; + /** * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor * of TokenManagerAddressStorage which calls the constructor of TokenManager. * @param interchainTokenService_ The address of the interchain token service contract */ - constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} + constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} function implementationType() external pure returns (uint256) { return uint256(TokenManagerType.LOCK_UNLOCK); @@ -45,7 +48,7 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage, ITokenManagerLock function _takeToken(address from, uint256 amount) internal override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); + token.safeTransferFrom(from, address(this), amount); return amount; } @@ -59,7 +62,7 @@ contract TokenManagerLockUnlock is TokenManagerAddressStorage, ITokenManagerLock function _giveToken(address to, uint256 amount) internal override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - SafeTokenTransfer.safeTransfer(token, to, amount); + token.safeTransfer(to, amount); return amount; } diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol index 01b21ab5..733ec6aa 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; +import { TokenManager } from '../TokenManager.sol'; import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; @@ -14,13 +14,16 @@ import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { +contract TokenManagerLockUnlockFee is TokenManager, NoReEntrancy { + using SafeTokenTransfer for IERC20; + using SafeTokenTransferFrom for IERC20; + /** * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor * of TokenManagerAddressStorage which calls the constructor of TokenManager. * @param interchainTokenService_ The address of the interchain token service contract */ - constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} + constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} function implementationType() external pure returns (uint256) { return uint256(TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER); @@ -46,7 +49,7 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { IERC20 token = IERC20(tokenAddress()); uint256 balance = token.balanceOf(address(this)); - SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); + token.safeTransferFrom(from, address(this), amount); uint256 diff = token.balanceOf(address(this)) - balance; if (diff < amount) { @@ -65,7 +68,7 @@ contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy { IERC20 token = IERC20(tokenAddress()); uint256 balance = token.balanceOf(to); - SafeTokenTransfer.safeTransfer(token, to, amount); + token.safeTransfer(to, amount); uint256 diff = token.balanceOf(to) - balance; if (diff < amount) { diff --git a/contracts/token-manager/implementations/TokenManagerMintBurn.sol b/contracts/token-manager/implementations/TokenManagerMintBurn.sol index f226b4b7..779fd80f 100644 --- a/contracts/token-manager/implementations/TokenManagerMintBurn.sol +++ b/contracts/token-manager/implementations/TokenManagerMintBurn.sol @@ -2,28 +2,30 @@ pragma solidity ^0.8.0; -import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; -import { IERC20BurnableMintable } from '../../interfaces/IERC20BurnableMintable.sol'; -import { ITokenManagerMintBurn } from '../../interfaces/ITokenManagerMintBurn.sol'; - import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; +import { TokenManager } from '../TokenManager.sol'; +import { IERC20MintableBurnable } from '../../interfaces/IERC20MintableBurnable.sol'; +import { ITokenManagerMintBurn } from '../../interfaces/ITokenManagerMintBurn.sol'; + /** * @title TokenManagerMintBurn * @notice This contract is an implementation of TokenManager that mints and burns a specific token on behalf of the interchain token service. * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. * It uses the Axelar SDK to safely transfer tokens. */ -contract TokenManagerMintBurn is TokenManagerAddressStorage, ITokenManagerMintBurn { +contract TokenManagerMintBurn is TokenManager, ITokenManagerMintBurn { + using SafeTokenCall for IERC20; + /** * @dev Constructs an instance of TokenManagerMintBurn. Calls the constructor * of TokenManagerAddressStorage which calls the constructor of TokenManager. * @param interchainTokenService_ The address of the interchain token service contract */ - constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} + constructor(address interchainTokenService_) TokenManager(interchainTokenService_) {} - function implementationType() external pure returns (uint256) { + function implementationType() external pure virtual returns (uint256) { return uint256(TokenManagerType.MINT_BURN); } @@ -43,10 +45,10 @@ contract TokenManagerMintBurn is TokenManagerAddressStorage, ITokenManagerMintBu * @param amount Amount of tokens to burn * @return uint Amount of tokens burned */ - function _takeToken(address from, uint256 amount) internal override returns (uint256) { + function _takeToken(address from, uint256 amount) internal virtual override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.burn.selector, from, amount)); + token.safeCall(abi.encodeWithSelector(IERC20MintableBurnable.burn.selector, from, amount)); return amount; } @@ -60,7 +62,7 @@ contract TokenManagerMintBurn is TokenManagerAddressStorage, ITokenManagerMintBu function _giveToken(address to, uint256 amount) internal override returns (uint256) { IERC20 token = IERC20(tokenAddress()); - SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20BurnableMintable.mint.selector, to, amount)); + token.safeCall(abi.encodeWithSelector(IERC20MintableBurnable.mint.selector, to, amount)); return amount; } diff --git a/contracts/token-manager/implementations/TokenManagerMintBurnFrom.sol b/contracts/token-manager/implementations/TokenManagerMintBurnFrom.sol new file mode 100644 index 00000000..0ef1e552 --- /dev/null +++ b/contracts/token-manager/implementations/TokenManagerMintBurnFrom.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; +import { SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; + +import { IERC20BurnableFrom } from '../../interfaces/IERC20BurnableFrom.sol'; +import { TokenManagerMintBurn } from './TokenManagerMintBurn.sol'; + +/** + * @title TokenManagerMintBurn + * @notice This contract is an implementation of TokenManager that mints and burns a specific token on behalf of the interchain token service. + * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. + * It uses the Axelar SDK to safely transfer tokens. + */ +contract TokenManagerMintBurnFrom is TokenManagerMintBurn { + using SafeTokenCall for IERC20; + + /** + * @dev Constructs an instance of TokenManagerMintBurn. Calls the constructor + * of TokenManagerAddressStorage which calls the constructor of TokenManager. + * @param interchainTokenService_ The address of the interchain token service contract + */ + constructor(address interchainTokenService_) TokenManagerMintBurn(interchainTokenService_) {} + + function implementationType() external pure override returns (uint256) { + return uint256(TokenManagerType.MINT_BURN_FROM); + } + + /** + * @dev Burns the specified amount of tokens from a particular address. + * @param from Address to burn tokens from + * @param amount Amount of tokens to burn + * @return uint Amount of tokens burned + */ + function _takeToken(address from, uint256 amount) internal override returns (uint256) { + IERC20 token = IERC20(tokenAddress()); + + token.safeCall(abi.encodeWithSelector(IERC20BurnableFrom.burnFrom.selector, from, amount)); + + return amount; + } +} diff --git a/contracts/utils/NoReEntrancy.sol b/contracts/utils/NoReEntrancy.sol index 16d81bbc..5fe91829 100644 --- a/contracts/utils/NoReEntrancy.sol +++ b/contracts/utils/NoReEntrancy.sol @@ -12,6 +12,8 @@ import { INoReEntrancy } from '../interfaces/INoReEntrancy.sol'; contract NoReEntrancy is INoReEntrancy { // uint256(keccak256('entered')) - 1 uint256 internal constant ENTERED_SLOT = 0x01f33dd720a8dea3c4220dc5074a2239fb442c4c775306a696f97a7c54f785fc; + uint256 internal constant NOT_ENTERED = 1; + uint256 internal constant HAS_ENTERED = 2; /** * @notice A modifier that throws a ReEntrancy custom error if the contract is entered @@ -19,9 +21,9 @@ contract NoReEntrancy is INoReEntrancy { */ modifier noReEntrancy() { if (hasEntered()) revert ReEntrancy(); - _setEntered(true); + _setEntered(HAS_ENTERED); _; - _setEntered(false); + _setEntered(NOT_ENTERED); } /** @@ -30,7 +32,7 @@ contract NoReEntrancy is INoReEntrancy { */ function hasEntered() public view returns (bool entered) { assembly { - entered := sload(ENTERED_SLOT) + entered := eq(sload(ENTERED_SLOT), HAS_ENTERED) } } @@ -38,7 +40,7 @@ contract NoReEntrancy is INoReEntrancy { * @notice Sets the entered status of the contract * @param entered A boolean representing the entered status. True if already executing, false otherwise. */ - function _setEntered(bool entered) internal { + function _setEntered(uint256 entered) internal { assembly { sstore(ENTERED_SLOT, entered) } diff --git a/scripts/deploy.js b/scripts/deploy.js index be3f5752..87da2b26 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -66,7 +66,7 @@ async function deployInterchainTokenService( async function deployTokenManagerImplementations(wallet, interchainTokenServiceAddress) { const implementations = []; - for (const type of ['LockUnlock', 'MintBurn', 'LockUnlockFee', 'LiquidityPool']) { + for (const type of ['MintBurn', 'MintBurnFrom', 'LockUnlock', 'LockUnlockFee', 'LiquidityPool']) { const impl = await deployContract(wallet, `TokenManager${type}`, [interchainTokenServiceAddress]); implementations.push(impl); } diff --git a/test/tokenService.js b/test/tokenService.js index 582c908c..f2e2a39c 100644 --- a/test/tokenService.js +++ b/test/tokenService.js @@ -19,10 +19,11 @@ const SELECTOR_SEND_TOKEN_WITH_DATA = 2; const SELECTOR_DEPLOY_TOKEN_MANAGER = 3; const SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN = 4; -const LOCK_UNLOCK = 0; -const MINT_BURN = 1; -const LOCK_UNLOCK_FEE_ON_TRANSFER = 2; -const LIQUIDITY_POOL = 3; +const MINT_BURN = 0; +const MINT_BURN_FROM = 1; +const LOCK_UNLOCK = 2; +const LOCK_UNLOCK_FEE_ON_TRANSFER = 3; +const LIQUIDITY_POOL = 4; describe('Interchain Token Service', () => { let wallet, liquidityPool; @@ -78,25 +79,29 @@ describe('Interchain Token Service', () => { return [token, tokenManager, tokenId]; }; - deployFunctions.mintBurn = async function deployNewMintBurn(tokenName, tokenSymbol, tokenDecimals, mintAmount = 0) { - const salt = getRandomBytes32(); - const tokenId = await service.getCustomTokenId(wallet.address, salt); - const tokenManagerAddress = await service.getTokenManagerAddress(tokenId); - const token = await deployContract(wallet, 'InterchainTokenTest', [tokenName, tokenSymbol, tokenDecimals, tokenManagerAddress]); + const makeDeployNewMintBurn = (type) => + async function deployNewMintBurn(tokenName, tokenSymbol, tokenDecimals, mintAmount = 0) { + const salt = getRandomBytes32(); + const tokenId = await service.getCustomTokenId(wallet.address, salt); + const tokenManagerAddress = await service.getTokenManagerAddress(tokenId); + const token = await deployContract(wallet, 'InterchainTokenTest', [tokenName, tokenSymbol, tokenDecimals, tokenManagerAddress]); - const tokenManager = new Contract(await service.getTokenManagerAddress(tokenId), TokenManager.abi, wallet); + const tokenManager = new Contract(await service.getTokenManagerAddress(tokenId), TokenManager.abi, wallet); - if (mintAmount > 0) { - await (await token.mint(wallet.address, mintAmount)).wait(); - } + if (mintAmount > 0) { + await (await token.mint(wallet.address, mintAmount)).wait(); + } - await (await token.transferDistributorship(tokenManagerAddress)).wait(); + await (await token.transferDistributorship(tokenManagerAddress)).wait(); - const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - await (await service.deployCustomTokenManager(salt, MINT_BURN, params)).wait(); + const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + await (await service.deployCustomTokenManager(salt, type, params)).wait(); - return [token, tokenManager, tokenId]; - }; + return [token, tokenManager, tokenId]; + }; + + deployFunctions.mintBurn = makeDeployNewMintBurn(MINT_BURN); + deployFunctions.mintBurnFrom = makeDeployNewMintBurn(MINT_BURN_FROM); deployFunctions.liquidityPool = async function deployNewLiquidityPool( tokenName, diff --git a/test/tokenServiceFullFlow.js b/test/tokenServiceFullFlow.js index 8dd2c420..1fa94921 100644 --- a/test/tokenServiceFullFlow.js +++ b/test/tokenServiceFullFlow.js @@ -10,20 +10,23 @@ const { Contract, Wallet } = ethers; const IStandardizedToken = require('../artifacts/contracts/interfaces/IStandardizedToken.sol/IStandardizedToken.json'); const ITokenManager = require('../artifacts/contracts/interfaces/ITokenManager.sol/ITokenManager.json'); +const ITokenManagerMintBurn = require('../artifacts/contracts/interfaces/ITokenManagerMintBurn.sol/ITokenManagerMintBurn.json'); const { getRandomBytes32 } = require('../scripts/utils'); const { deployAll, deployContract } = require('../scripts/deploy'); const SELECTOR_SEND_TOKEN = 1; // const SELECTOR_SEND_TOKEN_WITH_DATA = 2; -// const SELECTOR_DEPLOY_TOKEN_MANAGER = 3; +const SELECTOR_DEPLOY_TOKEN_MANAGER = 3; const SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN = 4; -const LOCK_UNLOCK = 0; -const MINT_BURN = 1; -// const LIQUIDITY_POOL = 2; +const MINT_BURN = 0; +// const MINT_BURN_FROM = 1; +const LOCK_UNLOCK = 2; +// const LOCK_UNLOCK_FEE_ON_TRANSFER = 3; +// const LIQUIDITY_POOL = 4; -describe('Interchain Token Service', () => { +describe('Interchain Token Service Flow', () => { let wallet; let service, gateway, gasService, tokenManager, tokenId; const name = 'tokenName'; @@ -235,4 +238,104 @@ describe('Interchain Token Service', () => { await expect(token.burn(newAddress, amount)).to.be.revertedWithCustomError(token, 'NotDistributor'); }); }); + + describe('Full pre-existing token registration and token send', async () => { + let token; + const otherChains = ['chain 1', 'chain 2']; + const gasValues = [1234, 5678]; + const tokenCap = BigInt(1e18); + const salt = keccak256('0x697858'); + + before(async () => { + // The below is used to deploy a token, but any ERC20 that has a mint capability can be used instead. + token = await deployContract(wallet, 'InterchainTokenTest', [name, symbol, decimals, wallet.address]); + + tokenId = await service.getCustomTokenId(wallet.address, salt); + const tokenManagerAddress = await service.getTokenManagerAddress(tokenId); + await (await token.mint(wallet.address, tokenCap)).wait(); + await (await token.setTokenManager(tokenManagerAddress)).wait(); + tokenManager = new Contract(tokenManagerAddress, ITokenManager.abi, wallet); + }); + + it('Should register the token and initiate its deployment on other chains', async () => { + const implAddress = await service.getImplementation(MINT_BURN); + const impl = new Contract(implAddress, ITokenManagerMintBurn.abi, wallet); + const params = await impl.getParams(wallet.address, token.address); + const tx1 = await service.populateTransaction.deployCustomTokenManager(salt, MINT_BURN, params); + const data = [tx1.data]; + let value = 0; + + for (const i in otherChains) { + const tx = await service.populateTransaction.deployRemoteCustomTokenManager( + salt, + otherChains[i], + MINT_BURN, + params, + gasValues[i], + ); + data.push(tx.data); + value += gasValues[i]; + } + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'uint256', 'bytes'], + [SELECTOR_DEPLOY_TOKEN_MANAGER, tokenId, MINT_BURN, params], + ); + await expect(service.multicall(data, { value })) + .to.emit(service, 'TokenManagerDeployed') + .withArgs(tokenId, MINT_BURN, params) + .and.to.emit(service, 'RemoteTokenManagerDeploymentInitialized') + .withArgs(tokenId, otherChains[0], gasValues[0], MINT_BURN, params) + .and.to.emit(gasService, 'NativeGasPaidForContractCall') + .withArgs(service.address, otherChains[0], service.address.toLowerCase(), keccak256(payload), gasValues[0], wallet.address) + .and.to.emit(gateway, 'ContractCall') + .withArgs(service.address, otherChains[0], service.address.toLowerCase(), keccak256(payload), payload) + .and.to.emit(service, 'RemoteTokenManagerDeploymentInitialized') + .withArgs(tokenId, otherChains[1], gasValues[1], MINT_BURN, params) + .and.to.emit(gasService, 'NativeGasPaidForContractCall') + .withArgs(service.address, otherChains[1], service.address.toLowerCase(), keccak256(payload), gasValues[1], wallet.address) + .and.to.emit(gateway, 'ContractCall') + .withArgs(service.address, otherChains[1], service.address.toLowerCase(), keccak256(payload), payload); + }); + + // For this test the token must be a standardized token (or a distributable token in general) + it('Should be able to change the token distributor', async () => { + const newAddress = new Wallet(getRandomBytes32()).address; + const amount = 1234; + + await expect(token.mint(newAddress, amount)).to.emit(token, 'Transfer').withArgs(AddressZero, newAddress, amount); + await expect(token.burn(newAddress, amount)).to.emit(token, 'Transfer').withArgs(newAddress, AddressZero, amount); + + await expect(token.transferDistributorship(tokenManager.address)) + .to.emit(token, 'DistributorshipTransferred') + .withArgs(tokenManager.address); + + await expect(token.mint(newAddress, amount)).to.be.revertedWithCustomError(token, 'NotDistributor'); + await expect(token.burn(newAddress, amount)).to.be.revertedWithCustomError(token, 'NotDistributor'); + }); + + // In order to be able to receive tokens the distributorship should be changed on other chains as well. + it('Should send some token to another chain', async () => { + const amount = 1234; + const destAddress = '0x1234'; + const destChain = otherChains[0]; + const gasValue = 6789; + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'uint256'], + [SELECTOR_SEND_TOKEN, tokenId, destAddress, amount], + ); + const payloadHash = keccak256(payload); + + await expect(tokenManager.interchainTransfer(destChain, destAddress, amount, '0x', { value: gasValue })) + .and.to.emit(token, 'Transfer') + .withArgs(wallet.address, AddressZero, amount) + .and.to.emit(gateway, 'ContractCall') + .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, payload) + .and.to.emit(gasService, 'NativeGasPaidForContractCall') + .withArgs(service.address, destChain, service.address.toLowerCase(), payloadHash, gasValue, wallet.address) + .to.emit(service, 'TokenSent') + .withArgs(tokenId, destChain, destAddress, amount); + }); + }); }); From 67ec36a1db99e5d6abf566cdcc6757b0d30674d0 Mon Sep 17 00:00:00 2001 From: Kiryl Yermakou Date: Tue, 3 Oct 2023 12:48:56 -0400 Subject: [PATCH 11/12] fix(LockUnlockFee): always return adjusted amount (#110) * renamed folder and changed version * npmignore * npmignore * change version * using include pattern instead. * Fixed most of the things least auhority suggested. * made lint happy * Apply suggestions from code review * fixed some bugs * added events * rename set to transfer for distributor and operator * changed standardized token to always allow token managers to mint/burn it. * using immutable storage for remoteAddressValidator address to save gas * Added some recommended changes * added milap's suggested changes * Fixed some names and some minor gas optimizations * prettier and lint * stash * import .env in hardhat.config * trying to fix .env.example * Added some getters in IRemoteAddressValidator and removed useless check for distributor in the InterchainTokenService. * removed ternary operators * made lint happy * made lint happy * Added a new token manager to handle fee on transfer and added some tests for it as well * fixed the liquidity pool check. * fix a duplication bug * lint * added some more tests * Added more tests * Added proper re-entrancy protection for fee on transfer token managers. * change to tx.origin for refunds * Added support for more kinds of addresses. * some minor gas opts * some more gas optimizations. * Added a getter for chain name to the remote address validator. * moved the tokenManager getter functionality to a separate contract which saves almost a kilobyte of codesize. * made lint happy * Removed tokenManagerGetter and put params into tokenManagers * Added separate tokenManager interfaces * addressed ackeeblockchains's 3.0 report * prettier * added interchain transfer methods to the service and unified receiving tokens a bit. * made lint happy * rename sendToken to interchainTransfer * changed sendToken everywhere * changed from uint256.max to a const * change setting to zero to delete for storage slots. * rearange storage variables to save a bit of gas. * Removed unecesairy casts * made as many event params inexed as possible * Removed unused imports * domain separator is calculated each time. * added some natspec * added an example for using pre-existing custom tokens. * added a comment * feat(TokenManager): MintBurnFrom and MintBurnFromAddress * fix(TokenManager): removed MintBurnFromAddress as deprecated * fix(LockUnlockFee): always return adjusted amount --------- Co-authored-by: Foivos Co-authored-by: Milap Sheth --- ...ransfer.sol => TokenManagerLockUnlockFee.sol} | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) rename contracts/token-manager/implementations/{TokenManagerLockUnlockFeeOnTransfer.sol => TokenManagerLockUnlockFee.sol} (89%) diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFee.sol similarity index 89% rename from contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol rename to contracts/token-manager/implementations/TokenManagerLockUnlockFee.sol index 733ec6aa..b3b95f01 100644 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ b/contracts/token-manager/implementations/TokenManagerLockUnlockFee.sol @@ -47,15 +47,11 @@ contract TokenManagerLockUnlockFee is TokenManager, NoReEntrancy { */ function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = token.balanceOf(address(this)); + uint256 balanceBefore = token.balanceOf(address(this)); token.safeTransferFrom(from, address(this), amount); - uint256 diff = token.balanceOf(address(this)) - balance; - if (diff < amount) { - amount = diff; - } - return amount; + return token.balanceOf(address(this)) - balanceBefore; } /** @@ -66,15 +62,11 @@ contract TokenManagerLockUnlockFee is TokenManager, NoReEntrancy { */ function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { IERC20 token = IERC20(tokenAddress()); - uint256 balance = token.balanceOf(to); + uint256 balanceBefore = token.balanceOf(to); token.safeTransfer(to, amount); - uint256 diff = token.balanceOf(to) - balance; - if (diff < amount) { - amount = diff; - } - return amount; + return token.balanceOf(to) - balanceBefore; } /** From a5fe90154be314077167552783d739a4a35810ac Mon Sep 17 00:00:00 2001 From: Kiryl Yermakou Date: Tue, 3 Oct 2023 14:03:45 -0400 Subject: [PATCH 12/12] fix(InvalidStandardizedToken): imports --- contracts/test/InvalidStandardizedToken.sol | 4 +- .../TokenManagerLockUnlockFeeOnTransfer.sol | 87 ------------------- 2 files changed, 2 insertions(+), 89 deletions(-) delete mode 100644 contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol diff --git a/contracts/test/InvalidStandardizedToken.sol b/contracts/test/InvalidStandardizedToken.sol index 21dccfcf..088a3ddf 100644 --- a/contracts/test/InvalidStandardizedToken.sol +++ b/contracts/test/InvalidStandardizedToken.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { IERC20BurnableMintable } from '../interfaces/IERC20BurnableMintable.sol'; +import { IERC20MintableBurnable } from '../interfaces/IERC20MintableBurnable.sol'; import { ITokenManager } from '../interfaces/ITokenManager.sol'; import { InterchainToken } from '../interchain-token/InterchainToken.sol'; @@ -11,7 +11,7 @@ import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol'; import { Implementation } from '../utils/Implementation.sol'; import { Distributable } from '../utils/Distributable.sol'; -contract InvalidStandardizedToken is IERC20BurnableMintable, InterchainToken, ERC20Permit, Implementation, Distributable { +contract InvalidStandardizedToken is IERC20MintableBurnable, InterchainToken, ERC20Permit, Implementation, Distributable { using AddressBytesUtils for bytes; string public name; diff --git a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol b/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol deleted file mode 100644 index 820e269a..00000000 --- a/contracts/token-manager/implementations/TokenManagerLockUnlockFeeOnTransfer.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import { TokenManagerAddressStorage } from './TokenManagerAddressStorage.sol'; -import { NoReEntrancy } from '../../utils/NoReEntrancy.sol'; -import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; -import { ITokenManagerLockUnlockFee } from '../../interfaces/ITokenManagerLockUnlockFee.sol'; - -import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/SafeTransfer.sol'; - -/** - * @title TokenManagerLockUnlock - * @notice This contract is an implementation of TokenManager that locks and unlocks a specific token on behalf of the interchain token service. - * @dev This contract extends TokenManagerAddressStorage and provides implementation for its abstract methods. - * It uses the Axelar SDK to safely transfer tokens. - */ -contract TokenManagerLockUnlockFee is TokenManagerAddressStorage, NoReEntrancy, ITokenManagerLockUnlockFee { - /** - * @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor - * of TokenManagerAddressStorage which calls the constructor of TokenManager. - * @param interchainTokenService_ The address of the interchain token service contract - */ - constructor(address interchainTokenService_) TokenManagerAddressStorage(interchainTokenService_) {} - - function implementationType() external pure returns (uint256) { - return uint256(TokenManagerType.LOCK_UNLOCK_FEE_ON_TRANSFER); - } - - /** - * @dev Sets up the token address. - * @param params The setup parameters in bytes. Should be encoded with the token address. - */ - function _setup(bytes calldata params) internal override { - // The first argument is reserved for the operator. - (, address tokenAddress) = abi.decode(params, (bytes, address)); - _setTokenAddress(tokenAddress); - } - - /** - * @dev Transfers a specified amount of tokens from a specified address to this contract. - * @param from The address to transfer tokens from - * @param amount The amount of tokens to transfer - * @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens. - */ - function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) { - IERC20 token = IERC20(tokenAddress()); - uint256 balance = token.balanceOf(address(this)); - - SafeTokenTransferFrom.safeTransferFrom(token, from, address(this), amount); - - uint256 diff = token.balanceOf(address(this)) - balance; - if (diff < amount) { - amount = diff; - } - return amount; - } - - /** - * @dev Transfers a specified amount of tokens from this contract to a specified address. - * @param to The address to transfer tokens to - * @param amount The amount of tokens to transfer - * @return uint The actual amount of tokens transferred - */ - function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) { - IERC20 token = IERC20(tokenAddress()); - uint256 balance = token.balanceOf(to); - - SafeTokenTransfer.safeTransfer(token, to, amount); - - uint256 diff = token.balanceOf(to) - balance; - if (diff < amount) { - amount = diff; - } - return amount; - } - - /** - * @notice Getter function for the parameters of a lock/unlock TokenManager. Mainly to be used by frontends. - * @param operator the operator of the TokenManager. - * @param tokenAddress the token to be managed. - * @return params the resulting params to be passed to custom TokenManager deployments. - */ - function getParams(bytes memory operator, address tokenAddress) external pure returns (bytes memory params) { - params = abi.encode(operator, tokenAddress); - } -}