From 8209e67d18f5e238a7bda7fb75d00afd2c5bd31f Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 4 Jan 2024 18:27:57 +0200 Subject: [PATCH 01/18] added support for gateway tokens --- contracts/InterchainTokenService.sol | 102 ++++++++++++++++----- contracts/TokenHandler.sol | 19 +++- contracts/interfaces/ITokenHandler.sol | 1 + contracts/interfaces/ITokenManagerType.sol | 3 +- 4 files changed, 99 insertions(+), 26 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 4890ff16..41d35c8b 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -23,6 +23,7 @@ import { IInterchainTokenDeployer } from './interfaces/IInterchainTokenDeployer. import { IInterchainTokenExecutable } from './interfaces/IInterchainTokenExecutable.sol'; import { IInterchainTokenExpressExecutable } from './interfaces/IInterchainTokenExpressExecutable.sol'; import { ITokenManager } from './interfaces/ITokenManager.sol'; +import { IERC20Named } from './interfaces/IERC20Named.sol'; import { Operator } from './utils/Operator.sol'; @@ -368,7 +369,7 @@ contract InterchainTokenService is string calldata sourceChain, string calldata sourceAddress, bytes calldata payload - ) external payable whenNotPaused { + ) public payable whenNotPaused { uint256 messageType = abi.decode(payload, (uint256)); if (messageType != MESSAGE_TYPE_INTERCHAIN_TRANSFER) { revert InvalidExpressMessageType(messageType); @@ -460,11 +461,12 @@ contract InterchainTokenService is bytes calldata metadata, uint256 gasValue ) external payable whenNotPaused { - amount = _takeToken(tokenId, msg.sender, amount, false); + string memory symbol; + (amount, symbol) = _takeToken(tokenId, msg.sender, amount, false); (MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata); - _transmitInterchainTransfer(tokenId, msg.sender, destinationChain, destinationAddress, amount, metadataVersion, data, gasValue); + _transmitInterchainTransfer(tokenId, msg.sender, destinationChain, destinationAddress, amount, metadataVersion, data, symbol, gasValue); } /** @@ -484,8 +486,8 @@ contract InterchainTokenService is uint256 gasValue ) external payable whenNotPaused { if (data.length == 0) revert EmptyData(); - - amount = _takeToken(tokenId, msg.sender, amount, false); + string memory symbol; + (amount, symbol) = _takeToken(tokenId, msg.sender, amount, false); _transmitInterchainTransfer( tokenId, @@ -495,6 +497,7 @@ contract InterchainTokenService is amount, MetadataVersion.CONTRACT_CALL, data, + symbol, gasValue ); } @@ -521,11 +524,12 @@ contract InterchainTokenService is uint256 amount, bytes calldata metadata ) external payable whenNotPaused { - amount = _takeToken(tokenId, sourceAddress, amount, true); + string memory symbol; + (amount, symbol) = _takeToken(tokenId, sourceAddress, amount, true); (MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata); - _transmitInterchainTransfer(tokenId, sourceAddress, destinationChain, destinationAddress, amount, metadataVersion, data, msg.value); + _transmitInterchainTransfer(tokenId, sourceAddress, destinationChain, destinationAddress, amount, metadataVersion, data, symbol, msg.value); } /*************\ @@ -612,7 +616,7 @@ contract InterchainTokenService is string calldata sourceChain, string calldata sourceAddress, bytes calldata payload - ) external onlyRemoteService(sourceChain, sourceAddress) whenNotPaused { + ) public onlyRemoteService(sourceChain, sourceAddress) whenNotPaused { bytes32 payloadHash = keccak256(payload); if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash)) revert NotApprovedByGateway(); @@ -646,25 +650,25 @@ contract InterchainTokenService is } function expressExecuteWithToken( - bytes32 /*commandId*/, - string calldata /*sourceChain*/, - string calldata /*sourceAddress*/, - bytes calldata /*payload*/, + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + bytes calldata payload, string calldata /*tokenSymbol*/, uint256 /*amount*/ ) external payable { - revert ExecuteWithTokenNotSupported(); + expressExecute(commandId, sourceChain, sourceAddress, payload); } function executeWithToken( - bytes32 /*commandId*/, - string calldata /*sourceChain*/, - string calldata /*sourceAddress*/, - bytes calldata /*payload*/, + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + bytes calldata payload, string calldata /*tokenSymbol*/, uint256 /*amount*/ - ) external pure { - revert ExecuteWithTokenNotSupported(); + ) external { + execute(commandId, sourceChain, sourceAddress, payload); } /** @@ -800,6 +804,52 @@ contract InterchainTokenService is gateway.callContract(destinationChain, destinationAddress, payload); } + /** + * @notice Calls a contract on a specific destination chain with the given payload + * @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. + */ + function _callContractWithToken( + string calldata destinationChain, + bytes memory payload, + string memory symbol, + uint256 amount, + MetadataVersion metadataVersion, + uint256 gasValue + ) internal { + string memory destinationAddress = trustedAddress(destinationChain); + if (bytes(destinationAddress).length == 0) revert UntrustedChain(); + + if (gasValue > 0) { + if (metadataVersion == MetadataVersion.CONTRACT_CALL) { + gasService.payNativeGasForContractCallWithToken{ value: gasValue }( + address(this), + destinationChain, + destinationAddress, + payload, // solhint-disable-next-line avoid-tx-origin + symbol, + amount, + tx.origin + ); + } else if (metadataVersion == MetadataVersion.EXPRESS_CALL) { + gasService.payNativeGasForExpressCallWithToken{ value: gasValue }( + address(this), + destinationChain, + destinationAddress, + payload, // solhint-disable-next-line avoid-tx-origin + symbol, + amount, + tx.origin + ); + } else { + revert InvalidMetadataVersion(uint32(metadataVersion)); + } + } + + gateway.callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount); + } + /** * @notice Deploys a token manager on a destination chain. * @param tokenId The ID of the token. @@ -962,6 +1012,7 @@ contract InterchainTokenService is uint256 amount, MetadataVersion metadataVersion, bytes memory data, + string memory symbol, uint256 gasValue ) internal { // slither-disable-next-line reentrancy-events @@ -982,14 +1033,17 @@ contract InterchainTokenService is amount, data ); - - _callContract(destinationChain, payload, metadataVersion, gasValue); + if(bytes(symbol).length > 0) { + _callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); + } else { + _callContract(destinationChain, payload, metadataVersion, gasValue); + } } /** * @dev Takes token from a sender via the token service. `tokenOnly` indicates if the caller should be restricted to the token only. */ - function _takeToken(bytes32 tokenId, address from, uint256 amount, bool tokenOnly) internal returns (uint256) { + function _takeToken(bytes32 tokenId, address from, uint256 amount, bool tokenOnly) internal returns (uint256, string memory symbol) { address tokenManager_ = tokenManagerAddress(tokenId); uint256 tokenManagerType; address tokenAddress; @@ -1006,8 +1060,8 @@ contract InterchainTokenService is /// @dev Track the flow amount being sent out as a message ITokenManager(tokenManager_).addFlowOut(amount); - - return amount; + if(tokenManagerType == uint256(TokenManagerType.GATEWAY)) symbol = IERC20Named(tokenAddress).symbol(); + return (amount, symbol); } /** diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 0eee208f..b018e1f2 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -19,6 +19,13 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { using SafeTokenTransferFrom for IERC20; using SafeTokenCall for IERC20; + address immutable gateway; + + constructor(address gateway_) { + if(gateway_ == address(0)) revert AddressZero(); + gateway = gateway_; + } + /** * @notice This function gives token to a specified address from the token manager. * @param tokenManagerType The token manager type. @@ -41,7 +48,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { return amount; } - if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) { + if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) || tokenManagerType == uint256(TokenManagerType.GATEWAY)) { _transferTokenFrom(tokenAddress, tokenManager, to, amount); return amount; } @@ -91,6 +98,12 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { return amount; } + if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + _transferTokenFrom(tokenAddress, from, tokenManager, amount); + _approveGateway(tokenAddress, amount); + return amount; + } + revert UnsupportedTokenManagerType(tokenManagerType); } @@ -162,4 +175,8 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { function _takeTokenMintBurnFrom(address tokenAddress, address from, uint256 amount) internal { IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20BurnableFrom.burnFrom.selector, from, amount)); } + + function _approveGateway(address tokenAddress, uint256 amount) internal { + IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20.approve.selector, gateway, amount)); + } } diff --git a/contracts/interfaces/ITokenHandler.sol b/contracts/interfaces/ITokenHandler.sol index 2db6d981..7f304b51 100644 --- a/contracts/interfaces/ITokenHandler.sol +++ b/contracts/interfaces/ITokenHandler.sol @@ -8,6 +8,7 @@ pragma solidity ^0.8.0; */ interface ITokenHandler { error UnsupportedTokenManagerType(uint256 tokenManagerType); + error AddressZero(); /** * @notice This function gives token to a specified address from the token manager. diff --git a/contracts/interfaces/ITokenManagerType.sol b/contracts/interfaces/ITokenManagerType.sol index 2d5a3a7d..889a7334 100644 --- a/contracts/interfaces/ITokenManagerType.sol +++ b/contracts/interfaces/ITokenManagerType.sol @@ -11,6 +11,7 @@ interface ITokenManagerType { MINT_BURN, MINT_BURN_FROM, LOCK_UNLOCK, - LOCK_UNLOCK_FEE + LOCK_UNLOCK_FEE, + GATEWAY } } From b04d039514abf0b767bc22e054b01d648a4a5827 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 8 Jan 2024 20:08:28 +0200 Subject: [PATCH 02/18] fixed tests --- scripts/deploy.js | 2 +- test/InterchainTokenService.js | 18 +----------------- test/InterchainTokenServiceUpgradeFlow.js | 2 +- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/scripts/deploy.js b/scripts/deploy.js index 0067040c..b9708a4b 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -93,7 +93,7 @@ async function deployAll( const interchainToken = await deployContract(wallet, 'InterchainToken', [interchainTokenServiceAddress]); const interchainTokenDeployer = await deployContract(wallet, 'InterchainTokenDeployer', [interchainToken.address]); const tokenManager = await deployContract(wallet, 'TokenManager', [interchainTokenServiceAddress]); - const tokenHandler = await deployContract(wallet, 'TokenHandler', []); + const tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address]); const interchainTokenFactoryAddress = await getCreate3Address(create3Deployer.address, wallet, factoryDeploymentKey); diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 8a2a4e7e..19c68919 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -508,7 +508,7 @@ describe('Interchain Token Service', () => { }); describe('Token Handler', () => { - const tokenManagerType = 4; + const tokenManagerType = 5; const amount = 1234; it('Should revert on give token with unsupported token type', async () => { @@ -2452,22 +2452,6 @@ describe('Interchain Token Service', () => { 'ExecuteWithTokenNotSupported', ); }); - - it('Should revert on expressExecuteWithToken', async () => { - await expectRevert( - (gasOptions) => service.expressExecuteWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount, gasOptions), - service, - 'ExecuteWithTokenNotSupported', - ); - }); - - it('Should revert on executeWithToken', async () => { - await expectRevert( - (gasOptions) => service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount, gasOptions), - service, - 'ExecuteWithTokenNotSupported', - ); - }); }); describe('Bytecode checks [ @skip-on-coverage ]', () => { diff --git a/test/InterchainTokenServiceUpgradeFlow.js b/test/InterchainTokenServiceUpgradeFlow.js index c66a5c16..a0c6214e 100644 --- a/test/InterchainTokenServiceUpgradeFlow.js +++ b/test/InterchainTokenServiceUpgradeFlow.js @@ -73,7 +73,7 @@ describe('Interchain Token Service Upgrade Flow', () => { tokenManagerDeployer = await deployContract(wallet, 'TokenManagerDeployer', []); interchainTokenDeployer = await deployContract(wallet, 'InterchainTokenDeployer', [interchainToken.address]); tokenManager = await deployContract(wallet, 'TokenManager', [interchainTokenServiceAddress]); - tokenHandler = await deployContract(wallet, 'TokenHandler', []); + tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address]); interchainTokenFactoryAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey + 'Factory'); axelarServiceGovernanceFactory = await ethers.getContractFactory( From bf9ab529a79e99d6907177ccb3bdc25664a3f770 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 8 Jan 2024 20:25:31 +0200 Subject: [PATCH 03/18] stash --- contracts/InterchainTokenService.sol | 2 +- test/InterchainTokenService.js | 38 ++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 41d35c8b..40a89f12 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -1034,7 +1034,7 @@ contract InterchainTokenService is data ); if(bytes(symbol).length > 0) { - _callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); + //_callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); } else { _callContract(destinationChain, payload, metadataVersion, gasValue); } diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 19c68919..d35fbdfe 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -23,6 +23,7 @@ const MINT_BURN = 0; const MINT_BURN_FROM = 1; const LOCK_UNLOCK = 2; const LOCK_UNLOCK_FEE_ON_TRANSFER = 3; +const GATEWAY = 4; const OPERATOR_ROLE = 1; const FLOW_LIMITER_ROLE = 2; @@ -81,6 +82,39 @@ describe('Interchain Token Service', () => { return [token, tokenManager, tokenId]; }; + deployFunctions.gateway = async function deployNewLockUnlock( + tokenName, + tokenSymbol, + tokenDecimals, + mintAmount = 0, + skipApprove = false, + ) { + const salt = getRandomBytes32(); + const tokenId = await service.interchainTokenId(wallet.address, salt); + const tokenManager = await getContractAt('TokenManager', await service.tokenManagerAddress(tokenId), wallet); + + const token = await deployContract(wallet, 'TestInterchainTokenStandard', [ + tokenName, + tokenSymbol, + tokenDecimals, + service.address, + tokenId, + ]); + let params = defaultAbiCoder.encode(['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], [tokenName, tokenSymbol, tokenDecimals, 0, token.address, 0]); + await (await gateway.deployToken(params, getRandomBytes32())).wait(); + + params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + + await (await service.deployTokenManager(salt, '', GATEWAY, params, 0)).wait(); + + if (mintAmount > 0) { + await (await token.mint(wallet.address, mintAmount)).wait(); + if (!skipApprove) await (await token.approve(service.address, mintAmount)).wait(); + } + + return [token, tokenManager, tokenId]; + }; + deployFunctions.lockUnlockFee = async function deployNewLockUnlock( tokenName, tokenSymbol, @@ -1372,8 +1406,8 @@ describe('Interchain Token Service', () => { await service.setPauseStatus(false).then((tx) => tx.wait()); }); - for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'mintBurnFrom']) { - it(`Should initiate an interchain token transfer via the interchainTransfer standard contract call & express call [${type}]`, async () => { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'mintBurnFrom', 'gateway']) { + it.only(`Should initiate an interchain token transfer via the interchainTransfer standard contract call & express call [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount * 2); const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const metadata = '0x00000000'; From 4198d10fc9131c8ec50249c02c4766ee84afab23 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 9 Jan 2024 18:12:10 +0200 Subject: [PATCH 04/18] fixed most tests --- contracts/InterchainTokenService.sol | 55 +++++---- contracts/TokenHandler.sol | 20 +++- scripts/utils.js | 22 ++++ test/InterchainTokenService.js | 172 ++++++++++++++++++++++++++- 4 files changed, 241 insertions(+), 28 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 40a89f12..b8b70ab0 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -621,22 +621,7 @@ contract InterchainTokenService is if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash)) revert NotApprovedByGateway(); - uint256 messageType = abi.decode(payload, (uint256)); - if (messageType == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { - address expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash); - - _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); - - if (expressExecutor != address(0)) { - emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor); - } - } else if (messageType == MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER) { - _processDeployTokenManagerPayload(payload); - } else if (messageType == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) { - _processDeployInterchainTokenPayload(payload); - } else { - revert InvalidMessageType(messageType); - } + _execute(commandId, sourceChain, sourceAddress, payload, payloadHash); } function contractCallWithTokenValue( @@ -665,10 +650,14 @@ contract InterchainTokenService is string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, - string calldata /*tokenSymbol*/, - uint256 /*amount*/ - ) external { - execute(commandId, sourceChain, sourceAddress, payload); + string calldata tokenSymbol, + uint256 amount + ) external { + bytes32 payloadHash = keccak256(payload); + + if (!gateway.validateContractCallAndMint(commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount)) revert NotApprovedByGateway(); + + _execute(commandId, sourceChain, sourceAddress, payload, payloadHash); } /** @@ -849,7 +838,31 @@ contract InterchainTokenService is gateway.callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount); } + + function _execute( + bytes32 commandId, + string calldata sourceChain, + string calldata sourceAddress, + bytes calldata payload, + bytes32 payloadHash + ) internal { + uint256 messageType = abi.decode(payload, (uint256)); + if (messageType == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { + address expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash); + _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); + + if (expressExecutor != address(0)) { + emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor); + } + } else if (messageType == MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER) { + _processDeployTokenManagerPayload(payload); + } else if (messageType == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) { + _processDeployInterchainTokenPayload(payload); + } else { + revert InvalidMessageType(messageType); + } + } /** * @notice Deploys a token manager on a destination chain. * @param tokenId The ID of the token. @@ -1034,7 +1047,7 @@ contract InterchainTokenService is data ); if(bytes(symbol).length > 0) { - //_callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); + _callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); } else { _callContract(destinationChain, payload, metadataVersion, gasValue); } diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index b018e1f2..66a653a7 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { ITokenHandler } from './interfaces/ITokenHandler.sol'; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; -import { SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol'; +import { SafeTokenTransfer, SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol'; import { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol'; import { ITokenManagerType } from './interfaces/ITokenManagerType.sol'; @@ -18,6 +18,7 @@ import { IERC20BurnableFrom } from './interfaces/IERC20BurnableFrom.sol'; contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { using SafeTokenTransferFrom for IERC20; using SafeTokenCall for IERC20; + using SafeTokenTransfer for IERC20; address immutable gateway; @@ -48,7 +49,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { return amount; } - if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) || tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) { _transferTokenFrom(tokenAddress, tokenManager, to, amount); return amount; } @@ -58,6 +59,11 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { return amount; } + if(tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + _transferToken(tokenAddress, to, amount); + return amount; + } + revert UnsupportedTokenManagerType(tokenManagerType); } @@ -99,7 +105,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { } if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { - _transferTokenFrom(tokenAddress, from, tokenManager, amount); + _transferTokenFrom(tokenAddress, from, address(this), amount); _approveGateway(tokenAddress, amount); return amount; } @@ -127,7 +133,8 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { if ( tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) || tokenManagerType == uint256(TokenManagerType.MINT_BURN) || - tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM) + tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM) || + tokenManagerType == uint256(TokenManagerType.GATEWAY) ) { _transferTokenFrom(tokenAddress, from, to, amount); return amount; @@ -146,6 +153,11 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { IERC20(tokenAddress).safeTransferFrom(from, to, amount); } + function _transferToken(address tokenAddress, address to, uint256 amount) internal { + // slither-disable-next-line arbitrary-send-erc20 + IERC20(tokenAddress).safeTransfer(to, amount); + } + function _transferTokenFromWithFee( address tokenAddress, address from, diff --git a/scripts/utils.js b/scripts/utils.js index 172044cc..eb2d2e34 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -26,6 +26,27 @@ async function approveContractCall( return commandId; } +async function approveContractCallWithMint( + gateway, + sourceChain, + sourceAddress, + contractAddress, + payload, + symbol, + amount, + sourceTxHash = getRandomBytes32(), + sourceEventIndex = 0, + commandId = getRandomBytes32(), +) { + const params = defaultAbiCoder.encode( + ['string', 'string', 'address', 'bytes32', 'string', 'uint256', 'bytes32', 'uint256'], + [sourceChain, sourceAddress, contractAddress, keccak256(payload), symbol, amount, sourceTxHash, sourceEventIndex], + ); + await (await gateway.approveContractCallWithMint(params, commandId)).wait(); + + return commandId; +} + async function deployGatewayToken(gateway, tokenName, tokenSymbol, tokenDecimals, walletForExternal) { let tokenAddress = AddressZero; @@ -45,5 +66,6 @@ async function deployGatewayToken(gateway, tokenName, tokenSymbol, tokenDecimals module.exports = { getRandomBytes32, approveContractCall, + approveContractCallWithMint, deployGatewayToken, }; diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index d35fbdfe..16a453b5 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -10,7 +10,7 @@ const { getContractAt, } = ethers; const { getCreate3Address } = require('@axelar-network/axelar-gmp-sdk-solidity'); -const { approveContractCall } = require('../scripts/utils'); +const { approveContractCall, approveContractCallWithMint } = require('../scripts/utils'); const { getRandomBytes32, getRandomInt, expectRevert, gasReporter, getEVMVersion } = require('./utils'); const { deployAll, deployContract, deployInterchainTokenService } = require('../scripts/deploy'); @@ -1377,6 +1377,29 @@ describe('Interchain Token Service', () => { .and.to.emit(service, 'InterchainTransferReceived') .withArgs(commandId, tokenId, sourceChain, hexlify(wallet.address), destAddress, amount, HashZero); }); + + + it('Should be able to receive gateway token', async () => { + const symbol = 'TT5'; + const [token, , tokenId] = await deployFunctions.gateway(`Test Token Lock Unlock`, symbol, 12, amount); + (await token.transfer(gateway.address, amount)).wait(); + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], + [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, hexlify(wallet.address), destAddress, amount, '0x'], + ); + const commandId = await approveContractCallWithMint(gateway, sourceChain, sourceAddress, service.address, payload, symbol, amount); + + await expect( + reportGas(service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount), 'Receive GMP INTERCHAIN_TRANSFER lock/unlock'), + ) + .to.emit(token, 'Transfer') + .withArgs(service.address, destAddress, amount) + .to.emit(token, 'Transfer') + .withArgs(gateway.address, service.address, amount) + .and.to.emit(service, 'InterchainTransferReceived') + .withArgs(commandId, tokenId, sourceChain, hexlify(wallet.address), destAddress, amount, HashZero); + }); }); describe('Send Token With Data', () => { @@ -1406,8 +1429,8 @@ describe('Interchain Token Service', () => { await service.setPauseStatus(false).then((tx) => tx.wait()); }); - for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'mintBurnFrom', 'gateway']) { - it.only(`Should initiate an interchain token transfer via the interchainTransfer standard contract call & express call [${type}]`, async () => { + for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'mintBurnFrom']) { + it(`Should initiate an interchain token transfer via the interchainTransfer standard contract call & express call [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount * 2); const sendAmount = type === 'lockUnlockFee' ? amount - 10 : amount; const metadata = '0x00000000'; @@ -1464,6 +1487,54 @@ describe('Interchain Token Service', () => { }); } + it(`Should initiate an interchain token transfer via the interchainTransfer standard contract call & express call [gateway]`, async () => { + const symbol = 'TT1'; + const [token, , tokenId] = await deployFunctions.gateway(`Test Token gateway`, symbol, 12, amount * 2); + const sendAmount = amount; + const metadata = '0x00000000'; + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], + [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, sourceAddress, destAddress, sendAmount, '0x'], + ); + const payloadHash = keccak256(payload); + + const metadataExpress = '0x00000001'; + + let transferToAddress = service.address; + + await expect( + reportGas( + service.interchainTransfer(tokenId, destinationChain, destAddress, amount, metadata, gasValue, { value: gasValue }), + `Call service.interchainTransfer with metadata gateway`, + ), + ) + .to.emit(token, 'Transfer') + .withArgs(wallet.address, transferToAddress, amount) + .and.to.emit(gateway, 'ContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, payload, symbol, amount) + .and.to.emit(gasService, 'NativeGasPaidForContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, symbol, amount, gasValue, wallet.address) + .to.emit(service, 'InterchainTransfer') + .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, HashZero); + + await expect( + reportGas( + service.interchainTransfer(tokenId, destinationChain, destAddress, amount, metadataExpress, gasValue, { + value: gasValue, + }), + `Call service.interchainTransfer with metadata gateway (express call)`, + ), + ) + .to.emit(token, 'Transfer') + .withArgs(wallet.address, transferToAddress, amount) + .and.to.emit(gateway, 'ContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, payload, symbol, amount) + .and.to.emit(gasService, 'NativeGasPaidForExpressCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, symbol, amount, gasValue, wallet.address) + .to.emit(service, 'InterchainTransfer') + .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, HashZero); + }); + for (const type of ['lockUnlock', 'lockUnlockFee']) { it(`Should be able to initiate an interchain token transfer via the interchainTransfer function on the service when the service is approved as well [${type}]`, async () => { const [token, tokenManager, tokenId] = await deployFunctions[type](`Test Token ${type}`, 'TT', 12, amount); @@ -1855,6 +1926,51 @@ describe('Interchain Token Service', () => { .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, sender.address, destinationChain, destAddress, sendAmount, HashZero); }); + + it(`Should be able to initiate an interchain token transfer via interchainTransfer & interchainTransferFrom [gateway]`, async () => { + const symbol = 'TT2'; + [token, tokenManager, tokenId] = await deployFunctions.gateway(`Test Token gateway`, symbol, 12, amount * 3, true); + const sendAmount = amount; + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], + [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, hexlify(wallet.address), destAddress, sendAmount, '0x'], + ); + const payloadHash = keccak256(payload); + + let transferToAddress = service.address; + + await expect( + reportGas( + token.connect(wallet).interchainTransfer(destinationChain, destAddress, amount, metadata, { value: gasValue }), + `Call token.interchainTransfer gateway`, + ), + ) + .and.to.emit(token, 'Transfer') + .withArgs(wallet.address, transferToAddress, amount) + .and.to.emit(gateway, 'ContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, payload, symbol, amount) + .and.to.emit(gasService, 'NativeGasPaidForContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, symbol, amount, gasValue, wallet.address) + .to.emit(service, 'InterchainTransfer') + .withArgs(tokenId, wallet.address, destinationChain, destAddress, sendAmount, HashZero); + + await token.approve(otherWallet.address, amount).then((tx) => tx.wait()); + + await expect( + token + .connect(otherWallet) + .interchainTransferFrom(wallet.address, destinationChain, destAddress, amount, metadata, { value: gasValue }), + ) + .and.to.emit(token, 'Transfer') + .withArgs(wallet.address, transferToAddress, amount) + .and.to.emit(gateway, 'ContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, payload, symbol, amount) + .and.to.emit(gasService, 'NativeGasPaidForContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, symbol, amount, gasValue, otherWallet.address) + .to.emit(service, 'InterchainTransfer') + .withArgs(tokenId, wallet.address, destinationChain, destAddress, sendAmount, HashZero); + }); + }); describe('Send Interchain Token With Data', () => { @@ -1896,6 +2012,31 @@ describe('Interchain Token Service', () => { .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, keccak256(data)); }); } + + it(`Should be able to initiate an interchain token transfer [gateway]`, async () => { + const symbol = 'TT3'; + const [token, , tokenId] = await deployFunctions.gateway(`Test Token gateway`, symbol, 12, amount, false); + const sendAmount = amount; + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], + [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, sourceAddress, destAddress, sendAmount, data], + ); + const payloadHash = keccak256(payload); + + const transferToAddress = service.address; + + const metadata = solidityPack(['uint32', 'bytes'], [0, data]); + await expect(token.interchainTransfer(destinationChain, destAddress, amount, metadata, { value: gasValue })) + .and.to.emit(token, 'Transfer') + .withArgs(wallet.address, transferToAddress, amount) + .and.to.emit(gateway, 'ContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, payload, symbol, amount) + .and.to.emit(gasService, 'NativeGasPaidForContractCallWithToken') + .withArgs(service.address, destinationChain, service.address, payloadHash, symbol, amount, gasValue, wallet.address) + .to.emit(service, 'InterchainTransfer') + .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, keccak256(data)); + }); }); describe('Express Execute', () => { @@ -2190,6 +2331,31 @@ describe('Interchain Token Service', () => { .and.to.emit(service, 'ExpressExecutionFulfilled') .withArgs(commandId, sourceChain, sourceAddress, keccak256(payload), wallet.address); }); + + it('Should be able to receive mint/burn token', async () => { + const symbol = 'TT4'; + const [token, , tokenId] = await deployFunctions.gateway(`Test Token Mint Burn`, symbol, 12, 2 * amount); + + await (await token.approve(service.address, amount)).wait(); + await (await token.transfer(gateway.address, amount)).wait(); + + const payload = defaultAbiCoder.encode( + ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], + [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, hexlify(wallet.address), destAddress, amount, '0x'], + ); + + const commandId = getRandomBytes32(); + await (await service.expressExecuteWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount)).wait(); + await approveContractCallWithMint(gateway, sourceChain, sourceAddress, service.address, payload, symbol, amount, getRandomBytes32(), 0, commandId); + + await expect(service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount)) + .to.emit(token, 'Transfer') + .withArgs(gateway.address, service.address, amount) + .to.emit(token, 'Transfer') + .withArgs(service.address, wallet.address, amount) + .and.to.emit(service, 'ExpressExecutionFulfilled') + .withArgs(commandId, sourceChain, sourceAddress, keccak256(payload), wallet.address); + }); }); describe('Express Receive Remote Token with Data', () => { From 46f730c25fa0cc6d0b7f3ff8ed96515a4fe4f7f8 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 9 Jan 2024 18:13:31 +0200 Subject: [PATCH 05/18] made lint happy --- contracts/InterchainTokenService.sol | 36 ++++++++++++++++++----- contracts/TokenHandler.sol | 6 ++-- test/InterchainTokenService.js | 44 +++++++++++++++++++++------- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index b8b70ab0..781685b0 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -466,7 +466,17 @@ contract InterchainTokenService is (MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata); - _transmitInterchainTransfer(tokenId, msg.sender, destinationChain, destinationAddress, amount, metadataVersion, data, symbol, gasValue); + _transmitInterchainTransfer( + tokenId, + msg.sender, + destinationChain, + destinationAddress, + amount, + metadataVersion, + data, + symbol, + gasValue + ); } /** @@ -529,7 +539,17 @@ contract InterchainTokenService is (MetadataVersion metadataVersion, bytes memory data) = _decodeMetadata(metadata); - _transmitInterchainTransfer(tokenId, sourceAddress, destinationChain, destinationAddress, amount, metadataVersion, data, symbol, msg.value); + _transmitInterchainTransfer( + tokenId, + sourceAddress, + destinationChain, + destinationAddress, + amount, + metadataVersion, + data, + symbol, + msg.value + ); } /*************\ @@ -652,10 +672,11 @@ contract InterchainTokenService is bytes calldata payload, string calldata tokenSymbol, uint256 amount - ) external { + ) external { bytes32 payloadHash = keccak256(payload); - if (!gateway.validateContractCallAndMint(commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount)) revert NotApprovedByGateway(); + if (!gateway.validateContractCallAndMint(commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount)) + revert NotApprovedByGateway(); _execute(commandId, sourceChain, sourceAddress, payload, payloadHash); } @@ -838,7 +859,7 @@ contract InterchainTokenService is gateway.callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount); } - + function _execute( bytes32 commandId, string calldata sourceChain, @@ -863,6 +884,7 @@ contract InterchainTokenService is revert InvalidMessageType(messageType); } } + /** * @notice Deploys a token manager on a destination chain. * @param tokenId The ID of the token. @@ -1046,7 +1068,7 @@ contract InterchainTokenService is amount, data ); - if(bytes(symbol).length > 0) { + if (bytes(symbol).length > 0) { _callContractWithToken(destinationChain, payload, symbol, amount, metadataVersion, gasValue); } else { _callContract(destinationChain, payload, metadataVersion, gasValue); @@ -1073,7 +1095,7 @@ contract InterchainTokenService is /// @dev Track the flow amount being sent out as a message ITokenManager(tokenManager_).addFlowOut(amount); - if(tokenManagerType == uint256(TokenManagerType.GATEWAY)) symbol = IERC20Named(tokenAddress).symbol(); + if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) symbol = IERC20Named(tokenAddress).symbol(); return (amount, symbol); } diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 66a653a7..baa81e80 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -20,10 +20,10 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { using SafeTokenCall for IERC20; using SafeTokenTransfer for IERC20; - address immutable gateway; + address public immutable gateway; constructor(address gateway_) { - if(gateway_ == address(0)) revert AddressZero(); + if (gateway_ == address(0)) revert AddressZero(); gateway = gateway_; } @@ -59,7 +59,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { return amount; } - if(tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { _transferToken(tokenAddress, to, amount); return amount; } diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 16a453b5..7c19aa81 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -100,9 +100,12 @@ describe('Interchain Token Service', () => { service.address, tokenId, ]); - let params = defaultAbiCoder.encode(['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], [tokenName, tokenSymbol, tokenDecimals, 0, token.address, 0]); + let params = defaultAbiCoder.encode( + ['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], + [tokenName, tokenSymbol, tokenDecimals, 0, token.address, 0], + ); await (await gateway.deployToken(params, getRandomBytes32())).wait(); - + params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); await (await service.deployTokenManager(salt, '', GATEWAY, params, 0)).wait(); @@ -1378,7 +1381,6 @@ describe('Interchain Token Service', () => { .withArgs(commandId, tokenId, sourceChain, hexlify(wallet.address), destAddress, amount, HashZero); }); - it('Should be able to receive gateway token', async () => { const symbol = 'TT5'; const [token, , tokenId] = await deployFunctions.gateway(`Test Token Lock Unlock`, symbol, 12, amount); @@ -1388,11 +1390,22 @@ describe('Interchain Token Service', () => { ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, hexlify(wallet.address), destAddress, amount, '0x'], ); - const commandId = await approveContractCallWithMint(gateway, sourceChain, sourceAddress, service.address, payload, symbol, amount); + const commandId = await approveContractCallWithMint( + gateway, + sourceChain, + sourceAddress, + service.address, + payload, + symbol, + amount, + ); await expect( - reportGas(service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount), 'Receive GMP INTERCHAIN_TRANSFER lock/unlock'), - ) + reportGas( + service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount), + 'Receive GMP INTERCHAIN_TRANSFER lock/unlock', + ), + ) .to.emit(token, 'Transfer') .withArgs(service.address, destAddress, amount) .to.emit(token, 'Transfer') @@ -1500,7 +1513,7 @@ describe('Interchain Token Service', () => { const metadataExpress = '0x00000001'; - let transferToAddress = service.address; + const transferToAddress = service.address; await expect( reportGas( @@ -1937,7 +1950,7 @@ describe('Interchain Token Service', () => { ); const payloadHash = keccak256(payload); - let transferToAddress = service.address; + const transferToAddress = service.address; await expect( reportGas( @@ -1970,7 +1983,6 @@ describe('Interchain Token Service', () => { .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, wallet.address, destinationChain, destAddress, sendAmount, HashZero); }); - }); describe('Send Interchain Token With Data', () => { @@ -2346,7 +2358,18 @@ describe('Interchain Token Service', () => { const commandId = getRandomBytes32(); await (await service.expressExecuteWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount)).wait(); - await approveContractCallWithMint(gateway, sourceChain, sourceAddress, service.address, payload, symbol, amount, getRandomBytes32(), 0, commandId); + await approveContractCallWithMint( + gateway, + sourceChain, + sourceAddress, + service.address, + payload, + symbol, + amount, + getRandomBytes32(), + 0, + commandId, + ); await expect(service.executeWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount)) .to.emit(token, 'Transfer') @@ -2638,7 +2661,6 @@ describe('Interchain Token Service', () => { }); describe('Unsupported functions', () => { - const commandId = HashZero; const sourceChain = 'Source chain'; const sourceAddress = 'Source address'; const payload = '0x'; From ee9a2b224e8c28f6b5e735bb03e02dd47fe78941 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 11 Jan 2024 17:59:01 +0200 Subject: [PATCH 06/18] Added registration capability to the factory --- contracts/InterchainTokenFactory.sol | 32 +++++++++++++++++++ contracts/InterchainTokenService.sol | 5 +-- .../interfaces/IInterchainTokenFactory.sol | 2 ++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/contracts/InterchainTokenFactory.sol b/contracts/InterchainTokenFactory.sol index 23106863..8e567bc2 100644 --- a/contracts/InterchainTokenFactory.sol +++ b/contracts/InterchainTokenFactory.sol @@ -32,6 +32,7 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M bytes32 private constant CONTRACT_ID = keccak256('interchain-token-factory'); bytes32 internal constant PREFIX_CANONICAL_TOKEN_SALT = keccak256('canonical-token-salt'); bytes32 internal constant PREFIX_INTERCHAIN_TOKEN_SALT = keccak256('interchain-token-salt'); + bytes32 internal constant PREFIX_GATEWAY_TOKEN_SALT = keccak256('gateway-token-salt'); address private constant TOKEN_FACTORY_DEPLOYER = address(0); /** @@ -47,6 +48,15 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M gateway = interchainTokenService.gateway(); } + /** + * @notice This modifier is used to ensure that only a the owner of the interchain token service can call a function. + */ + modifier onlyServiceOwner() { + if (msg.sender != interchainTokenService.owner()) revert NotServiceOwner(msg.sender); + + _; + } + /** * @notice Getter for the contract id. * @return bytes32 The contract id of this contract. @@ -76,6 +86,16 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M salt = keccak256(abi.encode(PREFIX_CANONICAL_TOKEN_SALT, chainNameHash_, tokenAddress)); } + /** + * @notice Calculates the salt for a canonical interchain token. + * @param chainNameHash_ The hash of the chain name. + * @param symbol The symbol of the address in the gateway. + * @return salt The calculated salt for the interchain token. + */ + function gatewayInterchainTokenSalt(bytes32 chainNameHash_, string calldata symbol) public pure returns (bytes32 salt) { + salt = keccak256(abi.encode(PREFIX_CANONICAL_TOKEN_SALT, chainNameHash_, symbol)); + } + /** * @notice Computes the ID for an interchain token based on the deployer and a salt. * @param deployer The address that deployed the interchain token. @@ -288,6 +308,18 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M tokenId = _deployInterchainToken(salt, destinationChain, tokenName, tokenSymbol, tokenDecimals, '', gasValue); } + /** + * @notice Enables the service oweners to register 'canonical' gateway tokens. The need to pass the same salt for the same token. + * @param salt The salt to be used for the token registration. Should be the same for all tokens and something that will not have collisions with any of the other salts used by the factory. + * @param symbol The symbol of the token to register. + */ + function registerGatewayToken(bytes32 salt, string calldata symbol) external onlyServiceOwner { + address tokenAddress = gateway.tokenAddresses(symbol); + if(tokenAddress == address(0)) revert NotGatewayToken(symbol); + bytes memory params = abi.encode('', tokenAddress); + interchainTokenService.deployTokenManager(salt, '', TokenManagerType.GATEWAY, params, 0); + } + /** * @notice Checks if a given token is a gateway token. * @param token The address of the token to check. diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 781685b0..c53a118f 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -871,11 +871,12 @@ contract InterchainTokenService is if (messageType == MESSAGE_TYPE_INTERCHAIN_TRANSFER) { address expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash); - _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); - if (expressExecutor != address(0)) { emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor); } + + _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); + } else if (messageType == MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER) { _processDeployTokenManagerPayload(payload); } else if (messageType == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) { diff --git a/contracts/interfaces/IInterchainTokenFactory.sol b/contracts/interfaces/IInterchainTokenFactory.sol index 3e792036..70b7deb1 100644 --- a/contracts/interfaces/IInterchainTokenFactory.sol +++ b/contracts/interfaces/IInterchainTokenFactory.sol @@ -17,6 +17,8 @@ interface IInterchainTokenFactory is IUpgradable, IMulticall { error NotMinter(address minter); error NotOperator(address operator); error GatewayToken(address tokenAddress); + error NotServiceOwner(address sender); + error NotGatewayToken(string symbol); /** * @notice Returns the address of the interchain token service. From 022d3de297965c4113118fe72663eb40dfc43d29 Mon Sep 17 00:00:00 2001 From: Foivos Date: Thu, 11 Jan 2024 18:16:49 +0200 Subject: [PATCH 07/18] prettier --- contracts/InterchainTokenFactory.sol | 2 +- contracts/InterchainTokenService.sol | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/InterchainTokenFactory.sol b/contracts/InterchainTokenFactory.sol index 8e567bc2..36c0d9c9 100644 --- a/contracts/InterchainTokenFactory.sol +++ b/contracts/InterchainTokenFactory.sol @@ -315,7 +315,7 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M */ function registerGatewayToken(bytes32 salt, string calldata symbol) external onlyServiceOwner { address tokenAddress = gateway.tokenAddresses(symbol); - if(tokenAddress == address(0)) revert NotGatewayToken(symbol); + if (tokenAddress == address(0)) revert NotGatewayToken(symbol); bytes memory params = abi.encode('', tokenAddress); interchainTokenService.deployTokenManager(salt, '', TokenManagerType.GATEWAY, params, 0); } diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index c53a118f..3274fd18 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -874,9 +874,8 @@ contract InterchainTokenService is if (expressExecutor != address(0)) { emit ExpressExecutionFulfilled(commandId, sourceChain, sourceAddress, payloadHash, expressExecutor); } - - _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); + _processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload); } else if (messageType == MESSAGE_TYPE_DEPLOY_TOKEN_MANAGER) { _processDeployTokenManagerPayload(payload); } else if (messageType == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN) { From 1650eede37b63b1fc6ee80cc019f1566ff1815ef Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 15 Jan 2024 19:19:25 +0200 Subject: [PATCH 08/18] added most tests --- contracts/InterchainTokenFactory.sol | 26 +------ contracts/InterchainTokenService.sol | 18 +++-- .../interfaces/IInterchainTokenFactory.sol | 7 ++ test/InterchainTokenFactory.js | 72 +++++++++++++++++++ 4 files changed, 94 insertions(+), 29 deletions(-) diff --git a/contracts/InterchainTokenFactory.sol b/contracts/InterchainTokenFactory.sol index 36c0d9c9..a5b90129 100644 --- a/contracts/InterchainTokenFactory.sol +++ b/contracts/InterchainTokenFactory.sol @@ -32,7 +32,6 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M bytes32 private constant CONTRACT_ID = keccak256('interchain-token-factory'); bytes32 internal constant PREFIX_CANONICAL_TOKEN_SALT = keccak256('canonical-token-salt'); bytes32 internal constant PREFIX_INTERCHAIN_TOKEN_SALT = keccak256('interchain-token-salt'); - bytes32 internal constant PREFIX_GATEWAY_TOKEN_SALT = keccak256('gateway-token-salt'); address private constant TOKEN_FACTORY_DEPLOYER = address(0); /** @@ -48,15 +47,6 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M gateway = interchainTokenService.gateway(); } - /** - * @notice This modifier is used to ensure that only a the owner of the interchain token service can call a function. - */ - modifier onlyServiceOwner() { - if (msg.sender != interchainTokenService.owner()) revert NotServiceOwner(msg.sender); - - _; - } - /** * @notice Getter for the contract id. * @return bytes32 The contract id of this contract. @@ -86,16 +76,6 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M salt = keccak256(abi.encode(PREFIX_CANONICAL_TOKEN_SALT, chainNameHash_, tokenAddress)); } - /** - * @notice Calculates the salt for a canonical interchain token. - * @param chainNameHash_ The hash of the chain name. - * @param symbol The symbol of the address in the gateway. - * @return salt The calculated salt for the interchain token. - */ - function gatewayInterchainTokenSalt(bytes32 chainNameHash_, string calldata symbol) public pure returns (bytes32 salt) { - salt = keccak256(abi.encode(PREFIX_CANONICAL_TOKEN_SALT, chainNameHash_, symbol)); - } - /** * @notice Computes the ID for an interchain token based on the deployer and a salt. * @param deployer The address that deployed the interchain token. @@ -309,15 +289,15 @@ contract InterchainTokenFactory is IInterchainTokenFactory, ITokenManagerType, M } /** - * @notice Enables the service oweners to register 'canonical' gateway tokens. The need to pass the same salt for the same token. + * @notice Register 'canonical' gateway tokens. The same salt needs to be used for the same gateway token on every chain. * @param salt The salt to be used for the token registration. Should be the same for all tokens and something that will not have collisions with any of the other salts used by the factory. * @param symbol The symbol of the token to register. */ - function registerGatewayToken(bytes32 salt, string calldata symbol) external onlyServiceOwner { + function registerGatewayToken(bytes32 salt, string calldata symbol) external onlyOwner returns (bytes32 tokenId) { address tokenAddress = gateway.tokenAddresses(symbol); if (tokenAddress == address(0)) revert NotGatewayToken(symbol); bytes memory params = abi.encode('', tokenAddress); - interchainTokenService.deployTokenManager(salt, '', TokenManagerType.GATEWAY, params, 0); + tokenId = interchainTokenService.deployTokenManager(salt, '', TokenManagerType.GATEWAY, params, 0); } /** diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 3274fd18..8f3a5f9a 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -8,7 +8,7 @@ import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contract import { ExpressExecutorTracker } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/express/ExpressExecutorTracker.sol'; import { Upgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol'; import { Create3Address } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/Create3Address.sol'; -import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol'; +import { SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol'; import { AddressBytes } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressBytes.sol'; import { StringToBytes32, Bytes32ToString } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/Bytes32String.sol'; import { Multicall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/Multicall.sol'; @@ -49,6 +49,7 @@ contract InterchainTokenService is using AddressBytes for bytes; using AddressBytes for address; using SafeTokenTransferFrom for IERC20; + using SafeTokenCall for IERC20; IAxelarGateway public immutable gateway; IAxelarGasService public immutable gasService; @@ -71,6 +72,8 @@ contract InterchainTokenService is bytes32 private constant EXECUTE_SUCCESS = keccak256('its-execute-success'); bytes32 private constant EXPRESS_EXECUTE_SUCCESS = keccak256('its-express-execute-success'); + uint256 internal constant UINT256_MAX = type(uint256).max; + /** * @dev The message types that are sent between InterchainTokenService on different chains. */ @@ -662,6 +665,7 @@ contract InterchainTokenService is string calldata /*tokenSymbol*/, uint256 /*amount*/ ) external payable { + // It should be ok to ignore the symbol and amount since this info exists on the payload. expressExecute(commandId, sourceChain, sourceAddress, payload); } @@ -837,9 +841,9 @@ contract InterchainTokenService is address(this), destinationChain, destinationAddress, - payload, // solhint-disable-next-line avoid-tx-origin + payload, symbol, - amount, + amount, // solhint-disable-next-line avoid-tx-origin tx.origin ); } else if (metadataVersion == MetadataVersion.EXPRESS_CALL) { @@ -847,9 +851,9 @@ contract InterchainTokenService is address(this), destinationChain, destinationAddress, - payload, // solhint-disable-next-line avoid-tx-origin + payload, symbol, - amount, + amount, // solhint-disable-next-line avoid-tx-origin tx.origin ); } else { @@ -1095,7 +1099,9 @@ contract InterchainTokenService is /// @dev Track the flow amount being sent out as a message ITokenManager(tokenManager_).addFlowOut(amount); - if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) symbol = IERC20Named(tokenAddress).symbol(); + if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + symbol = IERC20Named(tokenAddress).symbol(); + } return (amount, symbol); } diff --git a/contracts/interfaces/IInterchainTokenFactory.sol b/contracts/interfaces/IInterchainTokenFactory.sol index 70b7deb1..7e55efbf 100644 --- a/contracts/interfaces/IInterchainTokenFactory.sol +++ b/contracts/interfaces/IInterchainTokenFactory.sol @@ -129,4 +129,11 @@ interface IInterchainTokenFactory is IUpgradable, IMulticall { string calldata destinationChain, uint256 gasValue ) external payable returns (bytes32 tokenId); + + /** + * @notice Register 'canonical' gateway tokens. The same salt needs to be used for the same gateway token on every chain. + * @param salt The salt to be used for the token registration. Should be the same for all tokens and something that will not have collisions with any of the other salts used by the factory. + * @param symbol The symbol of the token to register. + */ + function registerGatewayToken(bytes32 salt, string calldata symbol) external returns (bytes32 tokenId); } diff --git a/test/InterchainTokenFactory.js b/test/InterchainTokenFactory.js index a74fce31..63c72bfd 100644 --- a/test/InterchainTokenFactory.js +++ b/test/InterchainTokenFactory.js @@ -16,6 +16,7 @@ const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN = 1; const LOCK_UNLOCK = 2; const MINT_BURN = 0; +const GATEWAY = 4; const MINTER_ROLE = 0; const OPERATOR_ROLE = 1; @@ -162,6 +163,77 @@ describe('InterchainTokenFactory', () => { }); }); + describe('Gateway Interchain Token Factory', async () => { + let token, tokenId, tokenManagerAddress, symbol; + const tokenCap = BigInt(1e18); + + async function deployToken(salt, lockUnlock = true) { + let tokenAddress = AddressZero; + + if (lockUnlock) { + token = await deployContract(wallet, 'TestInterchainTokenStandard', [ + name, + symbol, + decimals, + service.address, + getRandomBytes32(), + ]); + tokenAddress = token.address; + } + + const params = defaultAbiCoder.encode( + ['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], + [name, symbol, decimals, 0, tokenAddress, 0], + ); + + await (await gateway.deployToken(params, getRandomBytes32())).wait(); + + tokenId = await service.interchainTokenId(AddressZero, salt); + tokenManagerAddress = await service.tokenManagerAddress(tokenId); + + if (lockUnlock) { + await (await token.mint(wallet.address, tokenCap)).wait(); + await (await token.setTokenId(tokenId)).wait(); + } else { + tokenAddress = await gateway.tokenAddresses(symbol); + token = await getContractAt('IERC20', tokenAddress); + await await gateway.mintToken( + defaultAbiCoder.encode(['string', 'address', 'uint256'], [symbol, wallet.address, tokenCap]), + getRandomBytes32(), + ); + } + } + + it('Should register a token lock/unlock gateway token', async () => { + const salt = getRandomBytes32(); + symbol = 'TT0'; + await deployToken(salt, true); + const params = defaultAbiCoder.encode(['bytes', 'address'], ['0x', token.address]); + + await expect(tokenFactory.registerGatewayToken(salt, symbol)) + .to.emit(service, 'TokenManagerDeployed') + .withArgs(tokenId, tokenManagerAddress, GATEWAY, params); + }); + + it('Should register a token mint/burn gateway token', async () => { + const salt = getRandomBytes32(); + symbol = 'TT1'; + await deployToken(salt, false); + const params = defaultAbiCoder.encode(['bytes', 'address'], ['0x', token.address]); + + await expect(tokenFactory.registerGatewayToken(salt, symbol)) + .to.emit(service, 'TokenManagerDeployed') + .withArgs(tokenId, tokenManagerAddress, GATEWAY, params); + }); + + it('Should revert when trying to register a gateway token that does not exist', async () => { + const salt = getRandomBytes32(); + const symbol = 'TT2'; + + await expectRevert((gasOptions) => tokenFactory.registerGatewayToken(salt, symbol), tokenFactory, 'NotGatewayToken', [symbol]); + }); + }); + describe('Interchain Token Factory', async () => { let tokenId; const mintAmount = 1234; From fd3a3916cfcc9f3ed00a3fb3232703d8d43badc3 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 16 Jan 2024 17:20:42 +0200 Subject: [PATCH 09/18] fixed some more tests --- contracts/InterchainTokenService.sol | 11 +++++----- contracts/TokenHandler.sol | 22 +++++++++++++++++++ .../interfaces/IInterchainTokenService.sol | 1 + contracts/interfaces/ITokenHandler.sol | 2 ++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 8f3a5f9a..a2ccf36b 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -72,8 +72,6 @@ contract InterchainTokenService is bytes32 private constant EXECUTE_SUCCESS = keccak256('its-execute-success'); bytes32 private constant EXPRESS_EXECUTE_SUCCESS = keccak256('its-express-execute-success'); - uint256 internal constant UINT256_MAX = type(uint256).max; - /** * @dev The message types that are sent between InterchainTokenService on different chains. */ @@ -851,7 +849,7 @@ contract InterchainTokenService is address(this), destinationChain, destinationAddress, - payload, + payload, symbol, amount, // solhint-disable-next-line avoid-tx-origin tx.origin @@ -961,9 +959,10 @@ contract InterchainTokenService is tokenManager_ := mload(add(returnData, 0x20)) } - if (tokenManagerType == TokenManagerType.LOCK_UNLOCK || tokenManagerType == TokenManagerType.LOCK_UNLOCK_FEE) { - ITokenManager(tokenManager_).approveService(); - } + (success, returnData) = tokenHandler.delegatecall( + abi.encodeWithSelector(ITokenHandler.postTokenManagerDeploy.selector, tokenManagerType, tokenManager_) + ); + if (!success) revert PostDeployFailed(returnData); // slither-disable-next-line reentrancy-events emit TokenManagerDeployed(tokenId, tokenManager_, tokenManagerType, params); diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index baa81e80..4629efa9 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -8,6 +8,7 @@ import { SafeTokenTransfer, SafeTokenTransferFrom, SafeTokenCall } from '@axelar import { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol'; import { ITokenManagerType } from './interfaces/ITokenManagerType.sol'; +import { ITokenManager } from './interfaces/ITokenManager.sol'; import { IERC20MintableBurnable } from './interfaces/IERC20MintableBurnable.sol'; import { IERC20BurnableFrom } from './interfaces/IERC20BurnableFrom.sol'; @@ -22,6 +23,8 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { address public immutable gateway; + uint256 internal constant UINT256_MAX = type(uint256).max; + constructor(address gateway_) { if (gateway_ == address(0)) revert AddressZero(); gateway = gateway_; @@ -148,6 +151,24 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { revert UnsupportedTokenManagerType(tokenManagerType); } + /** + * @notice This function prepares a token manager after it is deployed + * @param tokenManagerType The token manager type. + * @param tokenManager The address of the token manager. + */ + // slither-disable-next-line locked-ether + function postTokenManagerDeploy(uint256 tokenManagerType, address tokenManager) external payable { + if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) || tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) { + ITokenManager(tokenManager).approveService(); + } + + // Approve the gateway here. + if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { + IERC20 token = IERC20(ITokenManager(tokenManager).tokenAddress()); + token.safeCall(abi.encodeWithSelector(IERC20.approve.selector, gateway, UINT256_MAX)); + } + } + function _transferTokenFrom(address tokenAddress, address from, address to, uint256 amount) internal { // slither-disable-next-line arbitrary-send-erc20 IERC20(tokenAddress).safeTransferFrom(from, to, amount); @@ -191,4 +212,5 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { function _approveGateway(address tokenAddress, uint256 amount) internal { IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20.approve.selector, gateway, amount)); } + } diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index 1e29b194..6913b827 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -46,6 +46,7 @@ interface IInterchainTokenService is error GiveTokenFailed(bytes data); error TokenHandlerFailed(bytes data); error EmptyData(); + error PostDeployFailed(bytes data); event InterchainTransfer( bytes32 indexed tokenId, diff --git a/contracts/interfaces/ITokenHandler.sol b/contracts/interfaces/ITokenHandler.sol index 7f304b51..41b599de 100644 --- a/contracts/interfaces/ITokenHandler.sol +++ b/contracts/interfaces/ITokenHandler.sol @@ -60,4 +60,6 @@ interface ITokenHandler { address to, uint256 amount ) external payable returns (uint256); + + function postTokenManagerDeploy(uint256 tokenManagerType, address tokenManager) external payable; } From 6d698df284f80e179617d86536b88905607f6047 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 16 Jan 2024 17:21:17 +0200 Subject: [PATCH 10/18] fixed a bug --- contracts/TokenHandler.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 4629efa9..579d958c 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -109,7 +109,6 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { _transferTokenFrom(tokenAddress, from, address(this), amount); - _approveGateway(tokenAddress, amount); return amount; } @@ -165,7 +164,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { // Approve the gateway here. if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { IERC20 token = IERC20(ITokenManager(tokenManager).tokenAddress()); - token.safeCall(abi.encodeWithSelector(IERC20.approve.selector, gateway, UINT256_MAX)); + _approveGateway(tokenAddress, amount); } } From 0fca8ebbb70e6018fcaa0062f85248ce8d35b8cf Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 16 Jan 2024 18:08:20 +0200 Subject: [PATCH 11/18] prettier --- contracts/InterchainTokenService.sol | 2 +- contracts/TokenHandler.sol | 3 +-- test/InterchainTokenFactory.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index a2ccf36b..661439cb 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -849,7 +849,7 @@ contract InterchainTokenService is address(this), destinationChain, destinationAddress, - payload, + payload, symbol, amount, // solhint-disable-next-line avoid-tx-origin tx.origin diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 579d958c..54ded98e 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -164,7 +164,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { // Approve the gateway here. if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { IERC20 token = IERC20(ITokenManager(tokenManager).tokenAddress()); - _approveGateway(tokenAddress, amount); + _approveGateway(token, UINT256_MAX); } } @@ -211,5 +211,4 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { function _approveGateway(address tokenAddress, uint256 amount) internal { IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20.approve.selector, gateway, amount)); } - } diff --git a/test/InterchainTokenFactory.js b/test/InterchainTokenFactory.js index 63c72bfd..62ecb9e7 100644 --- a/test/InterchainTokenFactory.js +++ b/test/InterchainTokenFactory.js @@ -190,7 +190,7 @@ describe('InterchainTokenFactory', () => { tokenId = await service.interchainTokenId(AddressZero, salt); tokenManagerAddress = await service.tokenManagerAddress(tokenId); - + if (lockUnlock) { await (await token.mint(wallet.address, tokenCap)).wait(); await (await token.setTokenId(tokenId)).wait(); From 62b440ef36a5bf56de935c3ae035485f8ac00c67 Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 16 Jan 2024 18:08:56 +0200 Subject: [PATCH 12/18] fix test --- contracts/TokenHandler.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 54ded98e..7903c524 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -163,7 +163,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { // Approve the gateway here. if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { - IERC20 token = IERC20(ITokenManager(tokenManager).tokenAddress()); + address token = ITokenManager(tokenManager).tokenAddress(); _approveGateway(token, UINT256_MAX); } } From c3bdb951c907d1b5de9e3ac78d521456ad971263 Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 17 Jan 2024 18:23:23 +0200 Subject: [PATCH 13/18] Update contracts/InterchainTokenService.sol Co-authored-by: Milap Sheth --- contracts/InterchainTokenService.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 661439cb..269583a1 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -817,7 +817,7 @@ contract InterchainTokenService is } /** - * @notice Calls a contract on a specific destination chain with the given payload + * @notice Calls a contract on a specific destination chain with the given payload and gateway token * @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. From c8e6f58c4e0d59796f3954e41b39e05fd6104d3a Mon Sep 17 00:00:00 2001 From: Foivos Date: Wed, 17 Jan 2024 18:30:51 +0200 Subject: [PATCH 14/18] Update contracts/TokenHandler.sol Co-authored-by: Milap Sheth --- contracts/TokenHandler.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/TokenHandler.sol b/contracts/TokenHandler.sol index 7903c524..0d1ad671 100644 --- a/contracts/TokenHandler.sol +++ b/contracts/TokenHandler.sol @@ -161,7 +161,7 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard { ITokenManager(tokenManager).approveService(); } - // Approve the gateway here. + // Approve the gateway here. One-time infinite approval works for gateway wrapped tokens, and for most origin tokens. Approval can be refreshed in the future if needed for certain tokens. if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) { address token = ITokenManager(tokenManager).tokenAddress(); _approveGateway(token, UINT256_MAX); From 75a5bb3f47bdbf722063da9a37cf02866bf29d63 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 22 Jan 2024 19:50:09 +0200 Subject: [PATCH 15/18] Add some comments --- contracts/interfaces/ITokenHandler.sol | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contracts/interfaces/ITokenHandler.sol b/contracts/interfaces/ITokenHandler.sol index 41b599de..b2167cf5 100644 --- a/contracts/interfaces/ITokenHandler.sol +++ b/contracts/interfaces/ITokenHandler.sol @@ -10,6 +10,12 @@ interface ITokenHandler { error UnsupportedTokenManagerType(uint256 tokenManagerType); error AddressZero(); + /** + * @notice Returns the address of the axelar gateway on this chain. + * @return gateway_ The address of the axelar gateway contract. + */ + function gateway() external view returns (address gateway_); + /** * @notice This function gives token to a specified address from the token manager. * @param tokenManagerType The token manager type. @@ -61,5 +67,10 @@ interface ITokenHandler { uint256 amount ) external payable returns (uint256); + /** + * @notice This function prepares a token manager after it is deployed + * @param tokenManagerType The token manager type. + * @param tokenManager The address of the token manager. + */ function postTokenManagerDeploy(uint256 tokenManagerType, address tokenManager) external payable; } From 746c7d82d843b9b88dfd9ae4d071abc9b5efc4ab Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 22 Jan 2024 19:54:54 +0200 Subject: [PATCH 16/18] using a different await syntax --- scripts/utils.js | 6 +- test/ERC20.js | 2 +- test/ERC20Permit.js | 2 +- test/InterchainToken.js | 2 +- test/InterchainTokenFactory.js | 18 ++--- test/InterchainTokenService.js | 106 ++++++++++++------------- test/InterchainTokenServiceFullFlow.js | 2 +- test/UtilsTest.js | 12 +-- 8 files changed, 75 insertions(+), 75 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index eb2d2e34..7a512156 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -21,7 +21,7 @@ async function approveContractCall( ['string', 'string', 'address', 'bytes32', 'bytes32', 'uint256'], [sourceChain, sourceAddress, contractAddress, keccak256(payload), sourceTxHash, sourceEventIndex], ); - await (await gateway.approveContractCall(params, commandId)).wait(); + await gateway.approveContractCall(params, commandId).then((tx) => tx.wait); return commandId; } @@ -42,7 +42,7 @@ async function approveContractCallWithMint( ['string', 'string', 'address', 'bytes32', 'string', 'uint256', 'bytes32', 'uint256'], [sourceChain, sourceAddress, contractAddress, keccak256(payload), symbol, amount, sourceTxHash, sourceEventIndex], ); - await (await gateway.approveContractCallWithMint(params, commandId)).wait(); + await gateway.approveContractCallWithMint(params, commandId).then((tx) => tx.wait); return commandId; } @@ -60,7 +60,7 @@ async function deployGatewayToken(gateway, tokenName, tokenSymbol, tokenDecimals [tokenName, tokenSymbol, tokenDecimals, 0, tokenAddress, 0], ); const commandId = getRandomBytes32(); - await (await gateway.deployToken(params, commandId)).wait(); + await gateway.deployToken(params, commandId).then((tx) => tx.wait); } module.exports = { diff --git a/test/ERC20.js b/test/ERC20.js index dbf231c8..4afd40c8 100644 --- a/test/ERC20.js +++ b/test/ERC20.js @@ -37,7 +37,7 @@ describe('ERC20', () => { await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); - await (await token.mint(owner.address, mintAmount)).wait(); + await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); }); diff --git a/test/ERC20Permit.js b/test/ERC20Permit.js index 65e740d7..c84a2ae4 100644 --- a/test/ERC20Permit.js +++ b/test/ERC20Permit.js @@ -39,7 +39,7 @@ describe('ERC20 Permit', () => { await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); - await (await token.mint(owner.address, mintAmount)).wait(); + await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); }); diff --git a/test/InterchainToken.js b/test/InterchainToken.js index 7bc35ca9..d1ea267d 100644 --- a/test/InterchainToken.js +++ b/test/InterchainToken.js @@ -39,7 +39,7 @@ describe('InterchainToken', () => { await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); - await (await token.mint(owner.address, mintAmount)).wait(); + await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); }); diff --git a/test/InterchainTokenFactory.js b/test/InterchainTokenFactory.js index 62ecb9e7..2c59d0fd 100644 --- a/test/InterchainTokenFactory.js +++ b/test/InterchainTokenFactory.js @@ -66,8 +66,8 @@ describe('InterchainTokenFactory', () => { ]); tokenId = await tokenFactory.canonicalInterchainTokenId(token.address); tokenManagerAddress = await service.tokenManagerAddress(tokenId); - await (await token.mint(wallet.address, tokenCap)).wait(); - await (await token.setTokenId(tokenId)).wait(); + await token.mint(wallet.address, tokenCap).then((tx) => tx.wait); + await token.setTokenId(tokenId).then((tx) => tx.wait); } before(async () => { @@ -131,7 +131,7 @@ describe('InterchainTokenFactory', () => { ['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], [name, symbol, decimals, tokenCap, tokenAddress, mintLimit], ); - await (await gateway.deployToken(params, getRandomBytes32())).wait(); + await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait); await expectRevert( (gasOptions) => tokenFactory.registerCanonicalInterchainToken(tokenAddress, gasOptions), @@ -150,7 +150,7 @@ describe('InterchainTokenFactory', () => { ['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], [name, newSymbol, decimals, tokenCap, tokenAddress, mintLimit], ); - await (await gateway.deployToken(params, getRandomBytes32())).wait(); + await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait); tokenAddress = await gateway.tokenAddresses(newSymbol); @@ -186,21 +186,21 @@ describe('InterchainTokenFactory', () => { [name, symbol, decimals, 0, tokenAddress, 0], ); - await (await gateway.deployToken(params, getRandomBytes32())).wait(); + await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait()); tokenId = await service.interchainTokenId(AddressZero, salt); tokenManagerAddress = await service.tokenManagerAddress(tokenId); if (lockUnlock) { - await (await token.mint(wallet.address, tokenCap)).wait(); - await (await token.setTokenId(tokenId)).wait(); + await token.mint(wallet.address, tokenCap).then((tx) => tx.wait()); + await token.setTokenId(tokenId).then((tx) => tx.wait()); } else { tokenAddress = await gateway.tokenAddresses(symbol); token = await getContractAt('IERC20', tokenAddress); - await await gateway.mintToken( + await gateway.mintToken( defaultAbiCoder.encode(['string', 'address', 'uint256'], [symbol, wallet.address, tokenCap]), getRandomBytes32(), - ); + ).then((tx) => tx.wait());; } } diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 7c19aa81..b89dcd43 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -72,11 +72,11 @@ describe('Interchain Token Service', () => { ]); const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - await (await service.deployTokenManager(salt, '', LOCK_UNLOCK, params, 0)).wait(); + await service.deployTokenManager(salt, '', LOCK_UNLOCK, params, 0).then((tx) => tx.wait); if (mintAmount > 0) { - await (await token.mint(wallet.address, mintAmount)).wait(); - if (!skipApprove) await (await token.approve(service.address, mintAmount)).wait(); + await token.mint(wallet.address, mintAmount).then((tx) => tx.wait); + if (!skipApprove) await token.approve(service.address, mintAmount).then((tx) => tx.wait); } return [token, tokenManager, tokenId]; @@ -104,15 +104,15 @@ describe('Interchain Token Service', () => { ['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], [tokenName, tokenSymbol, tokenDecimals, 0, token.address, 0], ); - await (await gateway.deployToken(params, getRandomBytes32())).wait(); + await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait); params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - await (await service.deployTokenManager(salt, '', GATEWAY, params, 0)).wait(); + await service.deployTokenManager(salt, '', GATEWAY, params, 0).then((tx) => tx.wait); if (mintAmount > 0) { - await (await token.mint(wallet.address, mintAmount)).wait(); - if (!skipApprove) await (await token.approve(service.address, mintAmount)).wait(); + await token.mint(wallet.address, mintAmount).then((tx) => tx.wait); + if (!skipApprove) await token.approve(service.address, mintAmount).then((tx) => tx.wait); } return [token, tokenManager, tokenId]; @@ -160,7 +160,7 @@ describe('Interchain Token Service', () => { const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - await (await service.deployTokenManager(salt, '', LOCK_UNLOCK_FEE_ON_TRANSFER, params, 0)).wait(); + await service.deployTokenManager(salt, '', LOCK_UNLOCK_FEE_ON_TRANSFER, params, 0).then((tx) => tx.wait); if (mintAmount > 0) { await token.mint(wallet.address, mintAmount).then((tx) => tx.wait()); @@ -188,13 +188,13 @@ describe('Interchain Token Service', () => { const tokenManager = await getContractAt('TokenManager', await service.tokenManagerAddress(tokenId), wallet); if (mintAmount > 0) { - await (await token.mint(wallet.address, mintAmount)).wait(); + await token.mint(wallet.address, mintAmount).then((tx) => tx.wait); } - await (await token.transferMintership(service.address)).wait(); + await token.transferMintership(service.address).then((tx) => tx.wait); const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - await (await service.deployTokenManager(salt, '', type, params, 0)).wait(); + await service.deployTokenManager(salt, '', type, params, 0).then((tx) => tx.wait); return [token, tokenManager, tokenId]; }; @@ -1305,7 +1305,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive lock/unlock token', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -1342,7 +1342,7 @@ describe('Interchain Token Service', () => { 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 token.transfer(tokenManager.address, amount + 10)).wait(); + await token.transfer(tokenManager.address, amount + 10).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -1366,7 +1366,7 @@ describe('Interchain Token Service', () => { false, 'free', ); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -1384,7 +1384,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive gateway token', async () => { const symbol = 'TT5'; const [token, , tokenId] = await deployFunctions.gateway(`Test Token Lock Unlock`, symbol, 12, amount); - (await token.transfer(gateway.address, amount)).wait(); + await token.transfer(gateway.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -1561,8 +1561,8 @@ describe('Interchain Token Service', () => { const transferToAddress = tokenManager.address; - await (await token.approve(service.address, amount)).wait(); - await (await token.approve(tokenManager.address, 0)).wait(); + await token.approve(service.address, amount).then((tx) => tx.wait); + await token.approve(tokenManager.address, 0).then((tx) => tx.wait); await expect( reportGas( @@ -1688,7 +1688,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive lock/unlock token', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); const payload = defaultAbiCoder.encode( @@ -1712,7 +1712,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive lock/unlock token with empty data and not call destination contract', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const data = '0x'; const payload = defaultAbiCoder.encode( @@ -1789,7 +1789,7 @@ describe('Interchain Token Service', () => { 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 token.transfer(tokenManager.address, amount + 10)).wait(); + await token.transfer(tokenManager.address, amount + 10).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); const payload = defaultAbiCoder.encode( @@ -1813,7 +1813,7 @@ describe('Interchain Token Service', () => { it('Should revert if token handler transfer token from fails', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); const payload = defaultAbiCoder.encode( @@ -1835,7 +1835,7 @@ describe('Interchain Token Service', () => { it('Should revert if execute with interchain token fails', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount); - (await token.transfer(tokenManager.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); const payload = defaultAbiCoder.encode( @@ -2068,7 +2068,7 @@ describe('Interchain Token Service', () => { before(async () => { [token, , tokenId] = await deployFunctions.lockUnlock(tokenName, tokenSymbol, tokenDecimals, amount * 2, true); - await (await token.approve(service.address, amount * 2)).wait(); + await token.approve(service.address, amount * 2).then((tx) => tx.wait); data = defaultAbiCoder.encode(['address', 'string'], [destinationAddress, message]); executable = await deployContract(wallet, 'TestInterchainExecutable', [service.address]); invalidExecutable = await deployContract(wallet, 'TestInvalidInterchainExecutable', [service.address]); @@ -2198,8 +2198,8 @@ describe('Interchain Token Service', () => { }); it('Should revert if command is already executed by gateway', async () => { - await (await token.transfer(tokenManager.address, amount)).wait(); - await (await token.approve(service.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2216,8 +2216,8 @@ describe('Interchain Token Service', () => { }); it('Should revert with invalid messageType', async () => { - await (await token.transfer(tokenManager.address, amount)).wait(); - await (await token.approve(service.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'uint256'], @@ -2234,8 +2234,8 @@ describe('Interchain Token Service', () => { }); it('Should be able to receive lock/unlock token', async () => { - await (await token.transfer(tokenManager.address, amount)).wait(); - await (await token.approve(service.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2243,7 +2243,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2256,7 +2256,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive mint/burn token', async () => { const [token, , tokenId] = await deployFunctions.mintBurn(`Test Token Mint Burn`, 'TT', 12, amount); - await (await token.approve(service.address, amount)).wait(); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2264,7 +2264,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2277,7 +2277,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive mint/burn from token', async () => { const [token, , tokenId] = await deployFunctions.mintBurnFrom(`Test Token Mint Burn From`, 'TT', 12, amount); - await (await token.approve(service.address, amount)).wait(); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2285,7 +2285,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2297,8 +2297,8 @@ describe('Interchain Token Service', () => { 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(); + await token.transfer(tokenManager.address, amount + 10).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2306,7 +2306,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2325,8 +2325,8 @@ describe('Interchain Token Service', () => { false, 'free', ); - await (await token.transfer(tokenManager.address, amount)).wait(); - await (await token.approve(service.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2334,7 +2334,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2348,8 +2348,8 @@ describe('Interchain Token Service', () => { const symbol = 'TT4'; const [token, , tokenId] = await deployFunctions.gateway(`Test Token Mint Burn`, symbol, 12, 2 * amount); - await (await token.approve(service.address, amount)).wait(); - await (await token.transfer(gateway.address, amount)).wait(); + await token.approve(service.address, amount).then((tx) => tx.wait); + await token.transfer(gateway.address, amount).then((tx) => tx.wait); const payload = defaultAbiCoder.encode( ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], @@ -2357,7 +2357,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecuteWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount)).wait(); + await service.expressExecuteWithToken(commandId, sourceChain, sourceAddress, payload, symbol, amount).then((tx) => tx.wait); await approveContractCallWithMint( gateway, sourceChain, @@ -2396,8 +2396,8 @@ describe('Interchain Token Service', () => { it('Should be able to receive lock/unlock token', async () => { const [token, tokenManager, tokenId] = await deployFunctions.lockUnlock(`Test Token Lock Unlock`, 'TT', 12, amount * 2); - await (await token.transfer(tokenManager.address, amount)).wait(); - await (await token.approve(service.address, amount)).wait(); + await token.transfer(tokenManager.address, amount).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); @@ -2407,7 +2407,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); const tx = service.execute(commandId, sourceChain, sourceAddress, payload); @@ -2422,7 +2422,7 @@ describe('Interchain Token Service', () => { it('Should be able to receive mint/burn token', async () => { const [token, , tokenId] = await deployFunctions.mintBurn(`Test Token Mint Burn`, 'TT', 12, amount); - await (await token.approve(service.address, amount)).wait(); + await token.approve(service.address, amount).then((tx) => tx.wait); const msg = `mint/burn`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); @@ -2432,7 +2432,7 @@ describe('Interchain Token Service', () => { ); const commandId = getRandomBytes32(); - await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await service.expressExecute(commandId, sourceChain, sourceAddress, payload).then((tx) => tx.wait); await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) @@ -2446,8 +2446,8 @@ describe('Interchain Token Service', () => { 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(); + await token.transfer(tokenManager.address, amount + 10).then((tx) => tx.wait); + await token.approve(service.address, amount).then((tx) => tx.wait); const msg = `lock/unlock`; const data = defaultAbiCoder.encode(['address', 'string'], [wallet.address, msg]); @@ -2470,11 +2470,11 @@ describe('Interchain Token Service', () => { before(async () => { [, tokenManager, tokenId] = await deployFunctions.mintBurn(`Test Token Lock Unlock`, 'TT', 12, mintAmount); - await (await tokenManager.setFlowLimit(flowLimit)).wait(); + await tokenManager.setFlowLimit(flowLimit).then((tx) => tx.wait); }); it('Should be able to send token only if it does not trigger the mint limit', async () => { - await (await service.interchainTransfer(tokenId, destinationChain, destinationAddress, sendAmount, '0x', 0)).wait(); + await service.interchainTransfer(tokenId, destinationChain, destinationAddress, sendAmount, '0x', 0).then((tx) => tx.wait); await expectRevert( (gasOptions) => service.interchainTransfer(tokenId, destinationChain, destinationAddress, sendAmount, '0x', 0, gasOptions), tokenManager, @@ -2503,7 +2503,7 @@ describe('Interchain Token Service', () => { return service.execute(commandId, destinationChain, service.address, payload); } - await (await receiveToken(sendAmount)).wait(); + await receiveToken(sendAmount).then((tx) => tx.wait); flowIn = await service.flowInAmount(tokenId); flowOut = await service.flowOutAmount(tokenId); diff --git a/test/InterchainTokenServiceFullFlow.js b/test/InterchainTokenServiceFullFlow.js index c3e50ba2..12d5426f 100644 --- a/test/InterchainTokenServiceFullFlow.js +++ b/test/InterchainTokenServiceFullFlow.js @@ -344,7 +344,7 @@ describe('Interchain Token Service Full Flow', () => { token = await deployContract(wallet, 'TestMintableBurnableERC20', [name, symbol, decimals]); tokenId = await service.interchainTokenId(wallet.address, salt); - await (await token.mint(wallet.address, tokenCap)).wait(); + await token.mint(wallet.address, tokenCap).then((tx) => tx.wait); }); it('Should register the token and initiate its deployment on other chains', async () => { diff --git a/test/UtilsTest.js b/test/UtilsTest.js index fe3919ee..84e621d4 100644 --- a/test/UtilsTest.js +++ b/test/UtilsTest.js @@ -30,7 +30,7 @@ describe('Operator', () => { }); it('Should be able to run the onlyOperatorable function as the operator', async () => { - await (await test.testOperatorable()).wait(); + await test.testOperatorable().then((tx) => tx.wait); expect(await test.nonce()).to.equal(1); }); @@ -104,7 +104,7 @@ describe('Minter', () => { }); it('Should be able to run the onlyMinter function as the minter', async () => { - await (await test.testMinter()).wait(); + await test.testMinter().then((tx) => tx.wait); expect(await test.nonce()).to.equal(1); }); @@ -204,7 +204,7 @@ describe('FlowLimit', async () => { await nextEpoch(); for (let i = 0; i < flowLimit; i++) { - await (await test.addFlowIn(1)).wait(); + await test.addFlowIn(1).then((tx) => tx.wait); expect(await test.flowInAmount()).to.equal(i + 1); } @@ -218,14 +218,14 @@ describe('FlowLimit', async () => { expect(await test.flowInAmount()).to.equal(0); - await (await test.addFlowIn(flowLimit)).wait(); + await test.addFlowIn(flowLimit).then((tx) => tx.wait); }); it('Should test flow out', async () => { await nextEpoch(); for (let i = 0; i < flowLimit; i++) { - await (await test.addFlowOut(1)).wait(); + await test.addFlowOut(1).then((tx) => tx.wait); expect(await test.flowOutAmount()).to.equal(i + 1); } @@ -239,7 +239,7 @@ describe('FlowLimit', async () => { expect(await test.flowOutAmount()).to.equal(0); - await (await test.addFlowOut(flowLimit)).wait(); + await test.addFlowOut(flowLimit).then((tx) => tx.wait); }); it('Should revert if single flow amount exceeds the flow limit', async () => { From e44fcdd02ffa1233421f9759c618ca0220a08c87 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 22 Jan 2024 19:55:06 +0200 Subject: [PATCH 17/18] prettier --- test/InterchainTokenFactory.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/InterchainTokenFactory.js b/test/InterchainTokenFactory.js index 2c59d0fd..13648dab 100644 --- a/test/InterchainTokenFactory.js +++ b/test/InterchainTokenFactory.js @@ -197,10 +197,12 @@ describe('InterchainTokenFactory', () => { } else { tokenAddress = await gateway.tokenAddresses(symbol); token = await getContractAt('IERC20', tokenAddress); - await gateway.mintToken( - defaultAbiCoder.encode(['string', 'address', 'uint256'], [symbol, wallet.address, tokenCap]), - getRandomBytes32(), - ).then((tx) => tx.wait());; + await gateway + .mintToken( + defaultAbiCoder.encode(['string', 'address', 'uint256'], [symbol, wallet.address, tokenCap]), + getRandomBytes32(), + ) + .then((tx) => tx.wait()); } } From d473eff08f429683b7c055f043ecdf7c20a78947 Mon Sep 17 00:00:00 2001 From: Foivos Date: Mon, 22 Jan 2024 20:12:40 +0200 Subject: [PATCH 18/18] fix .wait syntax --- test/ERC20.js | 2 +- test/ERC20Permit.js | 2 +- test/InterchainToken.js | 6 +-- test/InterchainTokenFactory.js | 8 ++-- test/InterchainTokenService.js | 54 +++++++++++------------ test/InterchainTokenServiceFullFlow.js | 2 +- test/InterchainTokenServiceUpgradeFlow.js | 2 +- test/UtilsTest.js | 4 +- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/test/ERC20.js b/test/ERC20.js index 4afd40c8..863ecb9c 100644 --- a/test/ERC20.js +++ b/test/ERC20.js @@ -35,7 +35,7 @@ describe('ERC20', () => { const tokenAddress = await interchainTokenDeployer.deployedAddress(salt); token = await getContractAt('InterchainToken', tokenAddress, owner); - await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); + await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait); await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); diff --git a/test/ERC20Permit.js b/test/ERC20Permit.js index c84a2ae4..b8438224 100644 --- a/test/ERC20Permit.js +++ b/test/ERC20Permit.js @@ -37,7 +37,7 @@ describe('ERC20 Permit', () => { token = await getContractAt('InterchainToken', tokenAddress, owner); - await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); + await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait); await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); diff --git a/test/InterchainToken.js b/test/InterchainToken.js index d1ea267d..5ae6961a 100644 --- a/test/InterchainToken.js +++ b/test/InterchainToken.js @@ -37,7 +37,7 @@ describe('InterchainToken', () => { token = await getContractAt('InterchainToken', tokenAddress, owner); - await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait()); + await interchainTokenDeployer.deployInterchainToken(salt, tokenId, owner.address, name, symbol, decimals).then((tx) => tx.wait); await token.mint(owner.address, mintAmount).then((tx) => tx.wait); expect(await token.interchainTokenId()).to.equal(tokenId); @@ -111,7 +111,7 @@ describe('InterchainToken', () => { const spender = user.address; const amount = 100; - await tokenTest.approve(spender, amount).then((tx) => tx.wait()); + await tokenTest.approve(spender, amount).then((tx) => tx.wait); const initialAllowance = await tokenTest.allowance(sender, spender); expect(initialAllowance).to.eq(amount); @@ -128,7 +128,7 @@ describe('InterchainToken', () => { const spender = user.address; const amount = MaxUint256; - await tokenTest.approve(spender, amount).then((tx) => tx.wait()); + await tokenTest.approve(spender, amount).then((tx) => tx.wait); const initialAllowance = await tokenTest.allowance(sender, spender); expect(initialAllowance).to.eq(amount); diff --git a/test/InterchainTokenFactory.js b/test/InterchainTokenFactory.js index 13648dab..7c14b3e4 100644 --- a/test/InterchainTokenFactory.js +++ b/test/InterchainTokenFactory.js @@ -186,14 +186,14 @@ describe('InterchainTokenFactory', () => { [name, symbol, decimals, 0, tokenAddress, 0], ); - await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait()); + await gateway.deployToken(params, getRandomBytes32()).then((tx) => tx.wait); tokenId = await service.interchainTokenId(AddressZero, salt); tokenManagerAddress = await service.tokenManagerAddress(tokenId); if (lockUnlock) { - await token.mint(wallet.address, tokenCap).then((tx) => tx.wait()); - await token.setTokenId(tokenId).then((tx) => tx.wait()); + await token.mint(wallet.address, tokenCap).then((tx) => tx.wait); + await token.setTokenId(tokenId).then((tx) => tx.wait); } else { tokenAddress = await gateway.tokenAddresses(symbol); token = await getContractAt('IERC20', tokenAddress); @@ -202,7 +202,7 @@ describe('InterchainTokenFactory', () => { defaultAbiCoder.encode(['string', 'address', 'uint256'], [symbol, wallet.address, tokenCap]), getRandomBytes32(), ) - .then((tx) => tx.wait()); + .then((tx) => tx.wait); } } diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index b89dcd43..53b9ca3e 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -163,10 +163,10 @@ describe('Interchain Token Service', () => { await service.deployTokenManager(salt, '', LOCK_UNLOCK_FEE_ON_TRANSFER, params, 0).then((tx) => tx.wait); if (mintAmount > 0) { - await token.mint(wallet.address, mintAmount).then((tx) => tx.wait()); + await token.mint(wallet.address, mintAmount).then((tx) => tx.wait); if (!skipApprove) { - await token.approve(service.address, mintAmount).then((tx) => tx.wait()); + await token.approve(service.address, mintAmount).then((tx) => tx.wait); } } @@ -653,7 +653,7 @@ describe('Interchain Token Service', () => { }); it('Should revert when registering an interchain token when service is paused', async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => @@ -662,7 +662,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); }); @@ -677,7 +677,7 @@ describe('Interchain Token Service', () => { salt = getRandomBytes32(); await service .deployTokenManager(salt, '', LOCK_UNLOCK, defaultAbiCoder.encode(['bytes', 'address'], ['0x', testToken.address]), 0) - .then((tx) => tx.wait()); + .then((tx) => tx.wait); }); it('Should initialize a remote interchain token deployment', async () => { @@ -716,7 +716,7 @@ describe('Interchain Token Service', () => { }); it('Should revert on remote interchain token deployment if paused', async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => @@ -728,7 +728,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); }); @@ -996,13 +996,13 @@ describe('Interchain Token Service', () => { }); it('Should revert when deploying a custom token manager if paused', async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); await expectRevert((gasOptions) => service.deployTokenManager(salt, '', LOCK_UNLOCK, params, 0, gasOptions), service, 'Pause'); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); }); @@ -1060,7 +1060,7 @@ describe('Interchain Token Service', () => { }); it('Should revert on remote custom token manager deployment if paused', async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); const salt = getRandomBytes32(); const params = '0x1234'; @@ -1076,7 +1076,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); }); @@ -1203,7 +1203,7 @@ describe('Interchain Token Service', () => { }); it(`Should revert on initiate interchain token transfer when service is paused`, async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => @@ -1227,7 +1227,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); it(`Should revert on transmit send token when not called by interchain token`, async () => { @@ -1266,13 +1266,13 @@ describe('Interchain Token Service', () => { }); it('Should revert on execute if the service is paused', async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); const commandId = getRandomBytes32(); await expectRevert((gasOptions) => service.execute(commandId, sourceChain, sourceAddress, '0x', gasOptions), service, 'Pause'); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); it('Should revert on execute with invalid messageType', async () => { @@ -1428,7 +1428,7 @@ describe('Interchain Token Service', () => { }); it(`Should revert on an interchain transfer if service is paused`, async () => { - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); const tokenId = getRandomBytes32(); @@ -1439,7 +1439,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); for (const type of ['lockUnlock', 'mintBurn', 'lockUnlockFee', 'mintBurnFrom']) { @@ -1625,7 +1625,7 @@ describe('Interchain Token Service', () => { it(`Should revert on callContractWithInterchainToken function when service is paused`, async () => { const tokenId = HashZero; - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => @@ -1645,7 +1645,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); it(`Should revert on transferToTokenManager when not called by the correct tokenManager`, async () => { @@ -1890,7 +1890,7 @@ describe('Interchain Token Service', () => { .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, wallet.address, destinationChain, destAddress, sendAmount, HashZero); - await token.approve(otherWallet.address, amount).then((tx) => tx.wait()); + await token.approve(otherWallet.address, amount).then((tx) => tx.wait); await expect( token @@ -1920,7 +1920,7 @@ describe('Interchain Token Service', () => { const sender = wallet; const spender = otherWallet; - await token.approve(spender.address, MaxUint256).then((tx) => tx.wait()); + await token.approve(spender.address, MaxUint256).then((tx) => tx.wait); await expect( reportGas( @@ -1967,7 +1967,7 @@ describe('Interchain Token Service', () => { .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, wallet.address, destinationChain, destAddress, sendAmount, HashZero); - await token.approve(otherWallet.address, amount).then((tx) => tx.wait()); + await token.approve(otherWallet.address, amount).then((tx) => tx.wait); await expect( token @@ -2115,7 +2115,7 @@ describe('Interchain Token Service', () => { it('Should revert on express execute when service is paused', async () => { const payload = '0x'; - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => service.expressExecute(commandId, sourceChain, sourceAddress, payload, gasOptions), @@ -2123,7 +2123,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); it('Should express execute', async () => { @@ -2619,9 +2619,9 @@ describe('Interchain Token Service', () => { it('Should revert on contractCallValue if service is paused', async () => { const payload = '0x'; - await service.setTrustedAddress(sourceChain, trustedAddress).then((tx) => tx.wait()); + await service.setTrustedAddress(sourceChain, trustedAddress).then((tx) => tx.wait); - await service.setPauseStatus(true).then((tx) => tx.wait()); + await service.setPauseStatus(true).then((tx) => tx.wait); await expectRevert( (gasOptions) => service.contractCallValue(sourceChain, trustedAddress, payload, gasOptions), @@ -2629,7 +2629,7 @@ describe('Interchain Token Service', () => { 'Pause', ); - await service.setPauseStatus(false).then((tx) => tx.wait()); + await service.setPauseStatus(false).then((tx) => tx.wait); }); it('Should revert on invalid express message type', async () => { diff --git a/test/InterchainTokenServiceFullFlow.js b/test/InterchainTokenServiceFullFlow.js index 12d5426f..0d207eab 100644 --- a/test/InterchainTokenServiceFullFlow.js +++ b/test/InterchainTokenServiceFullFlow.js @@ -57,7 +57,7 @@ describe('Interchain Token Service Full Flow', () => { before(async () => { // Any ERC20 can be used here token = await deployContract(wallet, 'TestMintableBurnableERC20', [name, symbol, decimals]); - await token.mint(wallet.address, tokenCap + transferAmount).then((tx) => tx.wait()); + await token.mint(wallet.address, tokenCap + transferAmount).then((tx) => tx.wait); }); it('Should register the token and initiate its deployment on other chains', async () => { diff --git a/test/InterchainTokenServiceUpgradeFlow.js b/test/InterchainTokenServiceUpgradeFlow.js index a0c6214e..5aa8d78b 100644 --- a/test/InterchainTokenServiceUpgradeFlow.js +++ b/test/InterchainTokenServiceUpgradeFlow.js @@ -225,7 +225,7 @@ describe('Interchain Token Service Upgrade Flow', () => { await axelarServiceGovernance .connect(wallet) .executeMultisigProposal(target, calldata, nativeValue) - .then((tx) => tx.wait()); + .then((tx) => tx.wait); await expect(axelarServiceGovernance.connect(otherWallet).executeMultisigProposal(target, calldata, nativeValue)) .to.emit(axelarServiceGovernance, 'MultisigExecuted') diff --git a/test/UtilsTest.js b/test/UtilsTest.js index 84e621d4..f368431d 100644 --- a/test/UtilsTest.js +++ b/test/UtilsTest.js @@ -244,9 +244,9 @@ describe('FlowLimit', async () => { it('Should revert if single flow amount exceeds the flow limit', async () => { const excessiveFlowAmount = flowLimit + 1; - await test.setFlowLimit(flowLimit).then((tx) => tx.wait()); + await test.setFlowLimit(flowLimit).then((tx) => tx.wait); - await test.addFlowIn(flowLimit - 1).then((tx) => tx.wait()); + await test.addFlowIn(flowLimit - 1).then((tx) => tx.wait); await expectRevert((gasOptions) => test.addFlowIn(excessiveFlowAmount, gasOptions), test, 'FlowLimitExceeded', [ flowLimit,