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); }); });