From 89fd09ab0d0f9af1a9843232ab6f4424a8de770b Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 15 Dec 2023 04:03:52 -0500 Subject: [PATCH 1/2] build: bump cgp and gmp sdk dep --- .github/workflows/publish-to-npm.yaml | 2 +- package-lock.json | 34 +++++++---------- package.json | 8 ++-- test/InterchainTokenService.js | 55 +++++++-------------------- test/utils.js | 2 +- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/.github/workflows/publish-to-npm.yaml b/.github/workflows/publish-to-npm.yaml index 25c7e1db..d6a653c4 100644 --- a/.github/workflows/publish-to-npm.yaml +++ b/.github/workflows/publish-to-npm.yaml @@ -1,4 +1,4 @@ -name: 'publish to npm' +name: 'Publish to npm' on: workflow_dispatch: diff --git a/package-lock.json b/package-lock.json index 2c10b08f..9b462b6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,11 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@axelar-network/axelar-cgp-solidity": "6.2.0", - "@axelar-network/axelar-gmp-sdk-solidity": "5.6.3" + "@axelar-network/axelar-cgp-solidity": "6.2.1", + "@axelar-network/axelar-gmp-sdk-solidity": "5.6.4" }, "devDependencies": { - "@axelar-network/axelar-chains-config": "~0.1.2", + "@axelar-network/axelar-chains-config": "^1.0.0", "@axelarjs/evm": "^0.2.1", "@nomicfoundation/hardhat-toolbox": "^2.0.2", "@tsconfig/strictest": "^2.0.2", @@ -50,28 +50,20 @@ "dev": true }, "node_modules/@axelar-network/axelar-cgp-solidity": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-solidity/-/axelar-cgp-solidity-6.2.0.tgz", - "integrity": "sha512-/X1RBFu5dzbffPEKK5wXTF66tpHtQwaz+oRpeLJOUVhvIHNkEslkUCOdj7FmePFlvTpvlwViziA4bny+nIcmrQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-solidity/-/axelar-cgp-solidity-6.2.1.tgz", + "integrity": "sha512-0RaxLYmsp3elXBytn7+eZUil1KFS6jjHR/ECrN/3IC7TeTDPUYunyy6JDxCdNYNtiD6EKgUAfQ7G4DrBb6hRxg==", "dependencies": { - "@axelar-network/axelar-gmp-sdk-solidity": "5.5.2" + "@axelar-network/axelar-gmp-sdk-solidity": "5.6.4" }, "engines": { "node": ">=16" } }, - "node_modules/@axelar-network/axelar-cgp-solidity/node_modules/@axelar-network/axelar-gmp-sdk-solidity": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-gmp-sdk-solidity/-/axelar-gmp-sdk-solidity-5.5.2.tgz", - "integrity": "sha512-M7XTLE1Db40VjMYA37ZZyycU+75MygoUST5sAi/8QYweqQqkaLK3xpyzX24zbGaEpgHsdEk4L7CJiyG9WBqVCA==", - "engines": { - "node": ">=16" - } - }, "node_modules/@axelar-network/axelar-chains-config": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-chains-config/-/axelar-chains-config-0.1.2.tgz", - "integrity": "sha512-qtll6BWLT7CWv5xRXYog/ZRwmwINew4aDUbE4IBpOvAbcGcSuLj7b+Ale14KnA9yTOLvGqaR5BHrBNpa/CXcBw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-chains-config/-/axelar-chains-config-1.0.0.tgz", + "integrity": "sha512-gK2M1vSoNWpGCkBAnDu6CbfJ39BXRTJZaOjXZxRoKZpgkYCT9eDGUEaRpfsKIb5mQ4nFZY+Wk0TRXH82TGoi5A==", "dev": true, "dependencies": { "@ethersproject/keccak256": "^5.7.0", @@ -79,9 +71,9 @@ } }, "node_modules/@axelar-network/axelar-gmp-sdk-solidity": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-gmp-sdk-solidity/-/axelar-gmp-sdk-solidity-5.6.3.tgz", - "integrity": "sha512-w6Sp88H0nb0GFJMq73eUuymEcUdfX6evMObwfUVu+lZLA3Y5IyBfwbQftkLUMp8MFR6MStLjiTkMXRmz8xV9yg==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-gmp-sdk-solidity/-/axelar-gmp-sdk-solidity-5.6.4.tgz", + "integrity": "sha512-PQjV+HeJynmSRMhyM3SexwnbFNruSaiRUeNCWjV8/7CkdPsDqypoqIXVRVU8Zk92DUUHeqZZzL/3qP2LYuvlnA==", "engines": { "node": ">=16" } diff --git a/package.json b/package.json index e13bb4a1..87336310 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/interchain-token-service", - "version": "1.0.0", + "version": "1.1.0", "repository": { "type": "git", "url": "https://github.com/axelarnetwork/interchain-token-service" @@ -29,11 +29,11 @@ "node": ">=16" }, "dependencies": { - "@axelar-network/axelar-cgp-solidity": "6.2.0", - "@axelar-network/axelar-gmp-sdk-solidity": "5.6.3" + "@axelar-network/axelar-cgp-solidity": "6.2.1", + "@axelar-network/axelar-gmp-sdk-solidity": "5.6.4" }, "devDependencies": { - "@axelar-network/axelar-chains-config": "~0.1.2", + "@axelar-network/axelar-chains-config": "^1.0.0", "@axelarjs/evm": "^0.2.1", "@nomicfoundation/hardhat-toolbox": "^2.0.2", "@tsconfig/strictest": "^2.0.2", diff --git a/test/InterchainTokenService.js b/test/InterchainTokenService.js index 05f505fd..8a2a4e7e 100644 --- a/test/InterchainTokenService.js +++ b/test/InterchainTokenService.js @@ -49,6 +49,7 @@ describe('Interchain Token Service', () => { const deployFunctions = {}; const destinationChain = 'destination chain'; const sourceChain = 'source chain'; + const gasValue = 12; deployFunctions.lockUnlock = async function deployNewLockUnlock( tokenName, @@ -376,7 +377,7 @@ describe('Interchain Token Service', () => { ); }); - it('Should revert on invalid token manager', async () => { + it('Should revert on invalid token manager implementation', async () => { await expectRevert( (gasOptions) => deployInterchainTokenService( @@ -422,29 +423,6 @@ describe('Interchain Token Service', () => { ); }); - it('Should revert on invalid token manager', async () => { - await expectRevert( - (gasOptions) => - deployInterchainTokenService( - wallet, - create3Deployer.address, - tokenManagerDeployer.address, - interchainTokenDeployer.address, - gateway.address, - gasService.address, - interchainTokenFactoryAddress, - tokenManager.address, - AddressZero, - chainName, - [], - deploymentKey, - gasOptions, - ), - service, - 'ZeroAddress', - ); - }); - it('Should return the token manager implementation', async () => { const tokenManagerImplementation = await service.tokenManagerImplementation(getRandomInt(1000)); expect(tokenManagerImplementation).to.eq(tokenManager.address); @@ -656,7 +634,6 @@ describe('Interchain Token Service', () => { const tokenSymbol = 'TN'; const tokenDecimals = 13; const minter = '0x12345678'; - const gasValue = 1234; let salt; before(async () => { @@ -813,15 +790,19 @@ describe('Interchain Token Service', () => { ]); }); + it('Should revert on deploying an invalid token manager', async () => { + const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + + await expectRevert((gasOptions) => service.deployTokenManager(salt, '', 5, params, 0, gasOptions)); + }); + it('Should deploy a lock/unlock token manager', async () => { const tokenManagerAddress = await service.tokenManagerAddress(tokenId); const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); - const expectedTokenManagerAddress = await service.tokenManagerAddress(tokenId); - await expect(reportGas(service.deployTokenManager(salt, '', LOCK_UNLOCK, params, 0), 'Call deployTokenManager on source chain')) .to.emit(service, 'TokenManagerDeployed') - .withArgs(tokenId, expectedTokenManagerAddress, LOCK_UNLOCK, params); + .withArgs(tokenId, tokenManagerAddress, LOCK_UNLOCK, params); expect(tokenManagerAddress).to.not.equal(AddressZero); const tokenManager = await getContractAt('TokenManager', tokenManagerAddress, wallet); @@ -1003,7 +984,6 @@ describe('Interchain Token Service', () => { ).wait(); const tokenId = await service.interchainTokenId(wallet.address, salt); - const gasValue = 1e6; const params = '0x1234'; const type = LOCK_UNLOCK; const payload = defaultAbiCoder.encode( @@ -1034,7 +1014,6 @@ describe('Interchain Token Service', () => { it('Should revert on a remote custom token manager deployment if the token manager does does not exist', async () => { const salt = getRandomBytes32(); const tokenId = await service.interchainTokenId(wallet.address, salt); - const gasValue = 1e6; const params = '0x1234'; const type = LOCK_UNLOCK; @@ -1047,7 +1026,6 @@ describe('Interchain Token Service', () => { await service.setPauseStatus(true).then((tx) => tx.wait()); const salt = getRandomBytes32(); - const gasValue = 1e6; const params = '0x1234'; const type = LOCK_UNLOCK; @@ -1134,7 +1112,6 @@ describe('Interchain Token Service', () => { describe('Send Token', () => { const amount = 1234; const destAddress = '0x5678'; - const gasValue = 90; let token, tokenId; before(async () => { @@ -1372,7 +1349,6 @@ describe('Interchain Token Service', () => { const amount = 1234; const destAddress = '0x5678'; const data = '0x1234'; - const gasValue = 90; let sourceAddress; let token, tokenManager, tokenId; @@ -1408,11 +1384,6 @@ describe('Interchain Token Service', () => { const payloadHash = keccak256(payload); const metadataExpress = '0x00000001'; - const payloadExpress = defaultAbiCoder.encode( - ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], - [MESSAGE_TYPE_INTERCHAIN_TRANSFER, tokenId, sourceAddress, destAddress, sendAmount, '0x'], - ); - const payloadHashExpress = keccak256(payloadExpress); let transferToAddress = AddressZero; @@ -1435,6 +1406,8 @@ describe('Interchain Token Service', () => { .withArgs(wallet.address, transferToAddress, amount) .and.to.emit(gateway, 'ContractCall') .withArgs(service.address, destinationChain, service.address, payloadHash, payload) + .and.to.emit(gasService, 'NativeGasPaidForContractCall') + .withArgs(service.address, destinationChain, service.address, payloadHash, gasValue, wallet.address) .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, HashZero); @@ -1449,7 +1422,9 @@ describe('Interchain Token Service', () => { .to.emit(token, 'Transfer') .withArgs(wallet.address, transferToAddress, amount) .and.to.emit(gateway, 'ContractCall') - .withArgs(service.address, destinationChain, service.address, payloadHashExpress, payloadExpress) + .withArgs(service.address, destinationChain, service.address, payloadHash, payload) + .and.to.emit(gasService, 'NativeGasPaidForExpressCall') + .withArgs(service.address, destinationChain, service.address, payloadHash, gasValue, wallet.address) .to.emit(service, 'InterchainTransfer') .withArgs(tokenId, sourceAddress, destinationChain, destAddress, sendAmount, HashZero); }); @@ -1763,7 +1738,6 @@ describe('Interchain Token Service', () => { describe('Send Interchain Token', () => { const amount = 1234; const destAddress = '0x5678'; - const gasValue = 90; const metadata = '0x'; let token, tokenManager, tokenId; @@ -1852,7 +1826,6 @@ describe('Interchain Token Service', () => { describe('Send Interchain Token With Data', () => { const amount = 1234; const destAddress = '0x5678'; - const gasValue = 90; let sourceAddress; const data = '0x1234'; diff --git a/test/utils.js b/test/utils.js index fface87e..9450f059 100644 --- a/test/utils.js +++ b/test/utils.js @@ -25,7 +25,7 @@ const getGasOptions = () => { }; const expectRevert = async (txFunc, contract, error, args) => { - if (network.config.skipRevertTests) { + if (network.config.skipRevertTests || contract === undefined) { await expect(txFunc(getGasOptions())).to.be.reverted; } else { if (args) { From 1476bda49b0ef492d8e19e0605fdd72eb4581c95 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 15 Dec 2023 04:16:50 -0500 Subject: [PATCH 2/2] fix: address audit comments --- .../interchain-token/InterchainToken.sol | 1 + contracts/interfaces/IInterchainToken.sol | 1 + contracts/utils/InterchainTokenDeployer.sol | 2 ++ test/InterchainToken.js | 21 ++++++++++++------- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/contracts/interchain-token/InterchainToken.sol b/contracts/interchain-token/InterchainToken.sol index 1b66b582..1dea362a 100644 --- a/contracts/interchain-token/InterchainToken.sol +++ b/contracts/interchain-token/InterchainToken.sol @@ -90,6 +90,7 @@ contract InterchainToken is InterchainTokenStandard, ERC20, ERC20Permit, Minter, if (tokenId_ == bytes32(0)) revert TokenIdZero(); if (bytes(tokenName).length == 0) revert TokenNameEmpty(); + if (bytes(tokenSymbol).length == 0) revert TokenSymbolEmpty(); name = tokenName; symbol = tokenSymbol; diff --git a/contracts/interfaces/IInterchainToken.sol b/contracts/interfaces/IInterchainToken.sol index ea825627..105cabe4 100644 --- a/contracts/interfaces/IInterchainToken.sol +++ b/contracts/interfaces/IInterchainToken.sol @@ -15,6 +15,7 @@ interface IInterchainToken is IInterchainTokenStandard, IMinter, IERC20MintableB error InterchainTokenServiceAddressZero(); error TokenIdZero(); error TokenNameEmpty(); + error TokenSymbolEmpty(); error AlreadyInitialized(); /** diff --git a/contracts/utils/InterchainTokenDeployer.sol b/contracts/utils/InterchainTokenDeployer.sol index f5c07045..1fabe688 100644 --- a/contracts/utils/InterchainTokenDeployer.sol +++ b/contracts/utils/InterchainTokenDeployer.sol @@ -42,6 +42,8 @@ contract InterchainTokenDeployer is IInterchainTokenDeployer, Create3 { string calldata symbol, uint8 decimals ) external returns (address tokenAddress) { + // Use a minimal proxy for cheap token deployment and auto-verification on explorers + // https://eips.ethereum.org/EIPS/eip-1167 // The minimal proxy bytecode is the same as https://github.com/OpenZeppelin/openzeppelin-contracts/blob/94697be8a3f0dfcd95dfb13ffbd39b5973f5c65d/contracts/proxy/Clones.sol#L28 // The minimal proxy bytecode is 0x37 = 55 bytes long bytes memory bytecode = new bytes(0x37); diff --git a/test/InterchainToken.js b/test/InterchainToken.js index e5c25814..7bc35ca9 100644 --- a/test/InterchainToken.js +++ b/test/InterchainToken.js @@ -73,32 +73,37 @@ describe('InterchainToken', () => { }); it('revert on init if tokenId is 0', async () => { - const implementationAddress = await interchainTokenDeployer.implementationAddress(); - const implementation = await getContractAt('InterchainToken', implementationAddress, owner); - const salt = getRandomBytes32(); const minter = owner.address; await expectRevert( (gasOptions) => interchainTokenDeployer.deployInterchainToken(salt, HashZero, minter, name, symbol, decimals, gasOptions), - implementation, + interchainToken, 'TokenIdZero', ); }); it('revert on init if token name is invalid', async () => { - const implementationAddress = await interchainTokenDeployer.implementationAddress(); - const implementation = await getContractAt('InterchainToken', implementationAddress, owner); - const salt = getRandomBytes32(); const tokenId = getRandomBytes32(); const minter = owner.address; await expectRevert( (gasOptions) => interchainTokenDeployer.deployInterchainToken(salt, tokenId, minter, '', symbol, decimals, gasOptions), - implementation, + interchainToken, 'TokenNameEmpty', ); }); + it('revert on init if token symbol is invalid', async () => { + const salt = getRandomBytes32(); + const tokenId = getRandomBytes32(); + const minter = owner.address; + await expectRevert( + (gasOptions) => interchainTokenDeployer.deployInterchainToken(salt, tokenId, minter, name, '', decimals, gasOptions), + interchainToken, + 'TokenSymbolEmpty', + ); + }); + it('should subtract from the spender allowance', async () => { tokenTest = await deployContract(owner, 'TestInterchainToken', []);