diff --git a/contracts/InterchainTokenService.sol b/contracts/InterchainTokenService.sol index 40652386..2f5b2e45 100644 --- a/contracts/InterchainTokenService.sol +++ b/contracts/InterchainTokenService.sol @@ -297,6 +297,8 @@ contract InterchainTokenService is bytes calldata params, uint256 gasValue ) external payable whenNotPaused returns (bytes32 tokenId) { + if (bytes(params).length == 0) revert EmptyParams(); + // Custom token managers can't be deployed with native interchain token type, which is reserved for interchain tokens if (tokenManagerType == TokenManagerType.NATIVE_INTERCHAIN_TOKEN) revert CannotDeploy(tokenManagerType); @@ -516,6 +518,7 @@ contract InterchainTokenService is uint256 gasValue ) external payable whenNotPaused { if (data.length == 0) revert EmptyData(); + amount = _takeToken(tokenId, msg.sender, amount, false); _transmitInterchainTransfer( @@ -908,6 +911,9 @@ contract InterchainTokenService is string calldata destinationChain, uint256 gasValue ) internal { + if (bytes(name).length == 0) revert EmptyTokenName(); + if (bytes(symbol).length == 0) revert EmptyTokenSymbol(); + // slither-disable-next-line unused-return deployedTokenManager(tokenId); @@ -969,6 +975,9 @@ contract InterchainTokenService is string memory symbol, uint8 decimals ) internal returns (address tokenAddress) { + if (bytes(name).length == 0) revert EmptyTokenName(); + if (bytes(symbol).length == 0) revert EmptyTokenSymbol(); + bytes32 salt = _getInterchainTokenSalt(tokenId); address minter; @@ -1030,6 +1039,7 @@ contract InterchainTokenService is bytes memory data, uint256 gasValue ) internal { + if (destinationAddress.length == 0) revert EmptyDestinationAddress(); if (amount == 0) revert ZeroAmount(); // slither-disable-next-line reentrancy-events diff --git a/contracts/interfaces/IInterchainTokenService.sol b/contracts/interfaces/IInterchainTokenService.sol index 54dadff1..d2c52cab 100644 --- a/contracts/interfaces/IInterchainTokenService.sol +++ b/contracts/interfaces/IInterchainTokenService.sol @@ -50,6 +50,10 @@ interface IInterchainTokenService is error CannotDeployRemotelyToSelf(); error InvalidPayload(); error GatewayCallFailed(bytes data); + error EmptyTokenName(); + error EmptyTokenSymbol(); + error EmptyParams(); + error EmptyDestinationAddress(); event InterchainTransfer( bytes32 indexed tokenId, diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 97509998..a4c4445f 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -675,6 +675,26 @@ describe('Interchain Token Service', () => { await service.setPauseStatus(false).then((tx) => tx.wait); }); + + it('Should revert when registering an interchain token with empty token name', async () => { + expect(await tokenManager.hasRole(wallet.address, OPERATOR_ROLE)).to.be.true; + + await expectRevert( + (gasOptions) => service.deployInterchainToken(salt, '', '', tokenSymbol, tokenDecimals, wallet.address, 0, gasOptions), + service, + 'EmptyTokenName', + ); + }); + + it('Should revert when registering an interchain token with empty token symbol', async () => { + expect(await tokenManager.hasRole(wallet.address, OPERATOR_ROLE)).to.be.true; + + await expectRevert( + (gasOptions) => service.deployInterchainToken(salt, '', tokenName, '', tokenDecimals, wallet.address, 0, gasOptions), + service, + 'EmptyTokenSymbol', + ); + }); }); describe('Deploy and Register remote Interchain Token', () => { @@ -728,6 +748,30 @@ describe('Interchain Token Service', () => { ); }); + it('Should revert on remote interchain token deployment with invalid token name', async () => { + await expectRevert( + (gasOptions) => + service.deployInterchainToken(salt, destinationChain, '', tokenSymbol, tokenDecimals, minter, gasValue, { + ...gasOptions, + value: gasValue, + }), + service, + 'EmptyTokenName', + ); + }); + + it('Should revert on remote interchain token deployment with invalid token symbol', async () => { + await expectRevert( + (gasOptions) => + service.deployInterchainToken(salt, destinationChain, tokenName, '', tokenDecimals, minter, gasValue, { + ...gasOptions, + value: gasValue, + }), + service, + 'EmptyTokenSymbol', + ); + }); + it('Should revert on remote interchain token deployment if paused', async () => { await service.setPauseStatus(true).then((tx) => tx.wait); @@ -820,6 +864,14 @@ describe('Interchain Token Service', () => { await expectRevert((gasOptions) => service.deployTokenManager(salt, '', 6, params, 0, gasOptions)); }); + it('Should revert on deploying a local token manager with invalid params', async () => { + await expectRevert( + (gasOptions) => service.deployTokenManager(salt, '', NATIVE_INTERCHAIN_TOKEN, '0x', 0, gasOptions), + service, + 'EmptyParams', + ); + }); + it('Should revert on deploying a local token manager with interchain token manager type', async () => { const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); @@ -1271,6 +1323,18 @@ describe('Interchain Token Service', () => { ); }); + it('Should revert on initiate interchain token transfer with invalid destination address', async () => { + await expectRevert( + (gasOptions) => + service.interchainTransfer(tokenId, destinationChain, '0x', amount, '0x', gasValue, { + ...gasOptions, + value: gasValue, + }), + service, + 'EmptyDestinationAddress', + ); + }); + it('Should revert on initiate interchain token transfer when service is paused', async () => { await service.setPauseStatus(true).then((tx) => tx.wait); @@ -1299,6 +1363,18 @@ describe('Interchain Token Service', () => { await service.setPauseStatus(false).then((tx) => tx.wait); }); + it('Should revert on transmit send token when destination address is zero address', async () => { + await expectRevert( + (gasOptions) => + service.transmitInterchainTransfer(tokenId, wallet.address, destinationChain, '0x', amount, '0x', { + ...gasOptions, + value: gasValue, + }), + service, + 'TakeTokenFailed', + ); + }); + it('Should revert on transmit send token when not called by interchain token', async () => { const errorSignatureHash = id('NotToken(address,address)'); const selector = errorSignatureHash.substring(0, 10); @@ -1638,6 +1714,16 @@ describe('Interchain Token Service', () => { ); }); + it('Should revert on callContractWithInterchainToken function on the service with invalid destination address', async () => { + const [, , tokenId] = await deployFunctions.lockUnlock(service, 'Test Token', 'TT', 12, amount); + + await expectRevert( + (gasOptions) => service.callContractWithInterchainToken(tokenId, destinationChain, '0x', amount, data, 0, gasOptions), + service, + 'EmptyDestinationAddress', + ); + }); + 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](service, `Test Token ${type}`, 'TT', 12, amount);