From 06fe10b1c1e53d17caedfd084c5d870aa254d956 Mon Sep 17 00:00:00 2001 From: Foivos Date: Fri, 28 Jun 2024 18:15:05 +0300 Subject: [PATCH 1/4] Squashed commit of the following: commit 0e817aeb28db92402402844247f027dc747ac361 Merge: 8e24478 4c4b3f0 Author: Foivos Date: Fri Jun 28 17:20:07 2024 +0300 Merge remote-tracking branch 'origin/feat/address-audit-comments' into feat/address-audit-comments commit 8e2447819a7e49b8dab551de298dd605796b6e3f Author: Foivos Date: Fri Jun 28 17:19:29 2024 +0300 sqush commits commit 4c4b3f0ac0e3569925670a3b272996f6ece7afb4 Author: Foivos Date: Fri Jun 28 13:29:45 2024 +0300 fix error commit c167b146ff55efc1e1578f841fb049fc1f9bd789 Author: Foivos Date: Fri Jun 28 13:09:16 2024 +0300 add tests for checks commit 92465cf1e45f4fd814c84d482dfdb7e3bc05dc2f Author: Foivos Date: Fri Jun 28 13:06:37 2024 +0300 added additional check for setAxelarChainId commit 6ff792884cf68c28f4b7def33a90e2b122d6003d Author: Foivos Date: Thu Jun 27 17:57:29 2024 +0300 forge fmt commit c639f11389e9efd1f8919f70ef843906fd3653a9 Author: Foivos Date: Thu Jun 27 16:53:02 2024 +0300 fix end to end tests commit ad272af8ca9b5f2123273332a491f86dafccc662 Author: Foivos Date: Thu Jun 27 16:31:47 2024 +0300 fix more capitaliaztion commit c45a2de342d37a51da6425a28e1492316fd0fee8 Author: Foivos Date: Thu Jun 27 16:14:01 2024 +0300 differnet import again commit 8273c1a02739a97a2e299be7e2adb899a51102ba Merge: 6eac1b9 1c0f731 Author: Foivos Date: Thu Jun 27 16:13:06 2024 +0300 Merge remote-tracking branch 'origin/main' into feat/address-audit-comments commit 6eac1b92c29901bcc9ebfd21b89e5c4fb5ea485f Author: Foivos Date: Thu Jun 27 16:11:50 2024 +0300 try different import commit 6aaf137e1d8bc873426214cf0e738d6807f9b10f Author: Foivos Date: Thu Jun 27 16:07:57 2024 +0300 trying more stuff commit 7bd8932ed387a2505ec533f3c482fd53edc5c677 Author: Foivos Date: Thu Jun 27 16:05:02 2024 +0300 trying to fix CLI commit f6e60a2819ab31c58cb8af147a7fe1eff247436b Author: Foivos Date: Thu Jun 27 16:04:22 2024 +0300 try a different import commit 53b0e535cedb7c408e5efbf95c5f16c324174965 Author: Foivos Date: Thu Jun 27 15:53:22 2024 +0300 revert change commit 4e576bea77709d6d803fab6ec0d529422325c4be Author: Foivos Date: Thu Jun 27 15:46:19 2024 +0300 forge fmt commit 2d6af586800894e6b4e66007316c9082a5b3086d Author: Foivos Date: Thu Jun 27 15:44:06 2024 +0300 fix import in test commit 7eb17a4423e8c6c2795bd201fec05514c1bbf7f8 Author: Foivos Date: Wed Jun 26 20:39:14 2024 +0300 remove confusing comment commit 2c000b2d113a6165a0fec29fda7da560da17af88 Author: Foivos Date: Tue Jun 25 11:14:28 2024 +0300 restrict use of setAxelarChainId commit 56ff88292b9398d635f670b113d95cc1113620ff Author: Canh Trinh Date: Mon Jun 24 15:17:03 2024 -0400 Update test/axelar/AxelarTransceiver.t.sol Co-authored-by: Milap Sheth commit be3491711b80c1211da93089de71f1381ce1024a Author: Canh Trinh Date: Mon Jun 24 15:15:19 2024 -0400 Update test/axelar/AxelarTransceiver.t.sol Co-authored-by: Milap Sheth commit dd1288c66e1464722a5e2c2d78df19d0abcc36c2 Author: Canh Trinh Date: Mon Jun 24 15:14:47 2024 -0400 Update src/axelar/AxelarTransceiver.sol Co-authored-by: Milap Sheth commit 2fa5cde5421194d9ec8ee49f92e95d46ac9274c4 Author: Foivos Date: Wed Jun 19 14:29:49 2024 +0300 run fmt commit d5159a5c5f16412ad50c85bebd506ad202a79075 Author: Foivos Date: Wed Jun 19 14:16:09 2024 +0300 Added better tests commit f03f0eb4f679c7a6a07d0e90868c6a97d9f3fb43 Author: Foivos Date: Wed Jun 19 13:23:07 2024 +0300 Add validation for setAxelarChainId commit f4c441aaed5d8ae2d137c98f476078fe5894191c Author: Foivos Date: Wed Jun 19 13:16:48 2024 +0300 Add event to setAxelarChainId commit 02eaea59f59881a7f066ad9234ae01539cded39d Merge: 43e425c d7a07d9 Author: Foivos Date: Wed Jun 19 13:16:21 2024 +0300 Merge branch 'feat/update-wormhole-examples-version' into feat/address-audit-comments commit d7a07d9fd618db3c70271e9f7b3125483a4ce8c1 Author: Foivos Date: Thu Jun 13 14:55:07 2024 +0300 forge fmt commit 1ed9e1d62c61a9e86ea49db7b66d1ca6beb8fe00 Author: Foivos Date: Thu Jun 13 14:46:17 2024 +0300 Fix axelar transceiver to include version commit e642d8d3b14f6d56f54307d98255f92e75aea7e2 Author: Foivos Date: Thu Jun 13 14:29:58 2024 +0300 update wormhole-examples to new main commit 1b6520a3438d240561942d87042a8e593d8edd0c Author: Foivos Date: Tue Jun 11 18:19:43 2024 +0300 added more destriptive error message commit ef0dc87da5eaeb049947d2824b23a9898b94d036 Author: Foivos Date: Tue Jun 11 16:21:12 2024 +0300 forge fmt commit 5b66ae8986ab5ffaea9cd088c1338e3a56adae52 Author: Foivos Date: Tue Jun 11 16:20:53 2024 +0300 added a constant for easy identification commit 4c3e0783e139f470509fd78f1e8d520e0b1180a6 Author: Foivos Date: Tue Jun 11 13:47:16 2024 +0300 tests now prperly check for reverts commit b8b2bb3c8cd06f4bd95ede1af6abe6634bb668dc Author: Foivos Date: Mon Jun 10 15:12:06 2024 +0300 run forge fmt again commit fc2dfea0b16bb022657d28b52105b8b1b6d950ac Author: Foivos Date: Mon Jun 10 15:02:58 2024 +0300 run forge fmt commit d8e46e4344913bae7c29063ad01fb5e9dc7eb01a Author: Foivos Date: Mon Jun 10 15:01:57 2024 +0300 remove unused var commit 30c5c6df75f334f5428642dc3041b7349e1d7e07 Author: Foivos Date: Mon Jun 10 14:58:57 2024 +0300 try to fix CI again commit 4b76355c8f586fb96813acf12a2eacd89126163d Author: Foivos Date: Mon Jun 10 14:56:57 2024 +0300 try to fix CI commit 69e5f401231e2caab34a232fd7e5ba9bce430434 Author: Foivos Date: Sun Jun 9 22:57:40 2024 +0300 update readme commit fe2b4418d040b71868f1ae9bcd73b1945b299ba7 Author: Foivos Date: Sat Jun 8 20:59:02 2024 +0300 added a fail test if the address is not trusted. commit d07ebe077ae2a527b0133e547f8408622db5651f Author: Foivos Date: Sat Jun 8 20:54:16 2024 +0300 Added a receiving token test commit c1041cb73a88d1734c68e58353cf4dc88ecedecb Author: Foivos Date: Fri Jun 7 12:00:44 2024 +0300 added a script to set remote siblings commit ad9e213e8731135aa82ffc20083a7b27697b2805 Author: Milap Sheth Date: Thu Jun 6 13:16:22 2024 -0400 Update script/README.md commit eebec31081f975150843d812b601217aa1a63018 Author: Milap Sheth Date: Thu Jun 6 13:16:14 2024 -0400 Update script/README.md commit d839bd4543b3fb1619291b9b2bd6793a40ca15d8 Author: Milap Sheth Date: Thu Jun 6 13:06:25 2024 -0400 Update src/axelar/AxelarTransceiver.sol commit c482fcb2e2b4284c1077696b5fa3a5b4da7e13d0 Author: Foivos Date: Thu Jun 6 19:18:21 2024 +0300 correct decoding of message commit 6cda8f914d14e072dce728c78ae673138e9cdc95 Author: Foivos Date: Thu Jun 6 19:14:50 2024 +0300 checking for immutable immutables commit 985b915380d4b0220085257ff47bbca4e584e0c0 Author: Foivos Date: Thu Jun 6 19:10:30 2024 +0300 remove unecesairy modifier commit d9b4f6c7eafd99b4ae312ef09021e909b0017f8d Author: Foivos Date: Thu Jun 6 19:09:24 2024 +0300 added some natspec commit 709ff54f12eccd75e763106fc46cb332264128a8 Author: Foivos Date: Thu Jun 6 18:25:20 2024 +0300 moved some errors commit 4d98b1550e4ea10dddbe056c3e326015322c33b1 Author: Foivos Date: Thu Jun 6 14:07:38 2024 +0300 add readme and rename dir commit ac40e0d19fc6bccd0e1492ff6b7aa325b645e452 Author: Foivos Date: Thu Jun 6 14:03:48 2024 +0300 update deployment script commit f4fb0cbfe25da5576b7bedd3bb7185fe534b43cf Author: Foivos Date: Wed Jun 5 18:04:51 2024 +0300 added a deployment script commit b4463827b6a3021f66679b9f185eb1074bc38b1f Author: Nikhil Suri Date: Mon Jun 3 17:41:53 2024 -0700 Fix CI and format commit ca08e9977fd19649ac6d1bc65573c80dc0bf84fc Author: Nikhil Suri Date: Mon Jun 3 17:37:04 2024 -0700 Fix OZ contracts issue commit 01edb753f153d9ee1940f43d2c4953a3e81b4c1e Author: Foivos Date: Fri May 31 15:42:53 2024 +0300 update tests a bit commit ac31c4d077368417cccf42394a43393b8999ce53 Author: Foivos Date: Fri May 31 15:29:10 2024 +0300 change some names commit 1f25b4447a3c05cb57dae65fe60dbd55d094ca06 Author: Foivos Date: Fri May 31 15:28:39 2024 +0300 Update src/axelar/AxelarTransceiver.sol Co-authored-by: Milap Sheth commit 9f42e321fdea8c63a6d019443f8230240e5a7f92 Author: Foivos Date: Fri May 31 15:28:16 2024 +0300 Update src/axelar/AxelarTransceiver.sol Co-authored-by: Milap Sheth commit 9f2cd614f0a1ce0aed441b5ecabc8cfff7722001 Author: Foivos Date: Thu May 30 21:46:18 2024 +0300 using payGas instead of payNativeGasForContractCall commit a6d5211d670a42b1261dd6f3b55634c2ef1c9fe2 Author: Foivos Date: Thu May 30 21:37:53 2024 +0300 using the gas service estimateGasFee commit f3b02feced002ccbc32dbf42552ef6437d31b49f Author: Foivos Date: Thu May 30 21:26:00 2024 +0300 fixed a naminginconsistency commit 71f586fdde6617b5cd6b77c5fcd4e1772f246999 Author: Foivos Date: Thu May 30 21:23:57 2024 +0300 some more comments addressed commit 89ffcb697843ac21801e70d1d03a97627cf89d7a Author: Foivos Date: Thu May 30 21:01:00 2024 +0300 remove cgp-solidity as it is unused commit 72e05aaa1ad1b3705847f726d482c21f0ce696d1 Author: Foivos Date: Thu May 30 20:59:33 2024 +0300 address some comments commit 5f75247201d0bb56fdf10a6936c0616987bce67c Author: Foivos Date: Thu May 30 20:27:56 2024 +0300 using axelar gmp executable commit 23640f447752a0a33358b1ee3318cbbcd03f05f8 Author: Foivos Date: Thu May 30 18:39:24 2024 +0300 remove the proxy commit 053d9fb588ea0f955e5027b848596d028962ddc0 Merge: e4cbb67 c4361e7 Author: Foivos Date: Thu May 30 18:35:57 2024 +0300 Merge remote-tracking branch 'origin/main' into feat/axelar-transceiver commit e4cbb674dd7c65045e00564801863c4e28267a3d Author: Foivos Date: Thu May 30 18:27:22 2024 +0300 Tests work commit da280263e882c5846f2d0a1a0e8c6945d28698b6 Author: Foivos Date: Thu May 30 16:24:44 2024 +0300 change oz to an older version commit 356d603155ea44bb45e503ecc4e4dff799e10c2d Author: Foivos Date: Wed May 29 18:16:28 2024 +0300 rename storage_ to slot commit 748b98997e44c06eaf1aee063ecae42dec6d1a12 Author: Nikhil Suri Date: Tue May 28 17:18:18 2024 -0700 downgrade to oz v4.8.1 commit 32f2600fbd7d3dbfc83d58eb759f09ede4095934 Author: Foivos Date: Mon May 27 20:28:39 2024 +0300 using Transceiver abstract contract commit 490202f68e45b436b3a0c88c6c19c9386bb04c3c Author: Foivos Date: Fri May 24 16:51:52 2024 +0300 fix the test commit a228d681825b813e7bcdaeff30e1b199dac73a58 Author: Foivos Date: Fri May 24 16:02:45 2024 +0300 added some tests commit 96c4258b241fc3864c6d07a256b5185de0346e42 Author: Foivos Date: Thu May 23 17:57:58 2024 +0300 forge install: axelar-cgp-solidity v6.3.1 commit b31cda477987e82224ebd15d49c6375899ab2b62 Author: Foivos Date: Thu May 23 17:57:54 2024 +0300 trying to add some tests commit 62edca406ac6011abda5ae7d1f56dd69dab51d8f Author: Foivos Date: Thu May 23 17:42:29 2024 +0300 added a proxy as well commit 06ed4c4a64550733fef99149998733f58714d6d9 Author: Foivos Date: Fri May 17 13:21:27 2024 +0300 Added the rest of the files commit cacecd03d2213086f08e7880d0559f4edb30019d Author: Foivos Date: Fri May 17 13:16:19 2024 +0300 add axelar tranceiver --- lib/example-native-token-transfers | 2 +- src/axelar/AxelarTransceiver.sol | 9 + src/axelar/interfaces/IAxelarTransceiver.sol | 19 +- test/axelar/AxelarTransceiver.t.sol | 64 +++++- test/axelar/AxelarTransceiverEndToEnd.sol | 199 +++++++++++++++++++ test/axelar/mock/MockGateway.sol | 58 +++++- 6 files changed, 330 insertions(+), 21 deletions(-) create mode 100644 test/axelar/AxelarTransceiverEndToEnd.sol diff --git a/lib/example-native-token-transfers b/lib/example-native-token-transfers index 0d37b0f..348570f 160000 --- a/lib/example-native-token-transfers +++ b/lib/example-native-token-transfers @@ -1 +1 @@ -Subproject commit 0d37b0f4975084492c72ca881c1218d6e1aae9e3 +Subproject commit 348570fbbbf6ed212406eb65dbda2c8975783bef diff --git a/src/axelar/AxelarTransceiver.sol b/src/axelar/AxelarTransceiver.sol index a51b8ec..90c6273 100644 --- a/src/axelar/AxelarTransceiver.sol +++ b/src/axelar/AxelarTransceiver.sol @@ -79,11 +79,20 @@ contract AxelarTransceiver is IAxelarTransceiver, AxelarGMPExecutable, Transceiv string calldata chainName, string calldata transceiverAddress ) external virtual onlyOwner { + if (chainId == 0 || bytes(chainName).length == 0 || bytes(transceiverAddress).length == 0) { + revert InvalidChainIdParams(); + } + AxelarTransceiverStorage storage slot = _storage(); + if (bytes(slot.idToAxelarChainId[chainId]).length != 0) revert ChainIdAlreadySet(chainId); + + if (slot.axelarChainIdToId[chainName] != 0) revert AxelarChainIdAlreadySet(chainName); slot.idToAxelarChainId[chainId] = chainName; slot.axelarChainIdToId[chainName] = chainId; slot.idToTransceiverAddress[chainId] = transceiverAddress; slot.transceiverAddressToId[transceiverAddress] = chainId; + + emit AxelarChainIdSet(chainId, chainName, transceiverAddress); } /// @notice Fetch the delivery price for a given recipient chain transfer. diff --git a/src/axelar/interfaces/IAxelarTransceiver.sol b/src/axelar/interfaces/IAxelarTransceiver.sol index 0e3a1f3..8891eed 100644 --- a/src/axelar/interfaces/IAxelarTransceiver.sol +++ b/src/axelar/interfaces/IAxelarTransceiver.sol @@ -12,7 +12,18 @@ interface IAxelarTransceiver is ITransceiver { /// @notice Chain Id passed is not valid. /// @param chainId The wormhole chainId. - error InvalidChainId(uint16 chainId, string chainName, string destinationContract); + /// @param chainName The axelar chainName. + /// @param transceiverAddress The address of the Transceiver as a string. + error InvalidChainId(uint16 chainId, string chainName, string transceiverAddress); + + /// @notice Chain Id passed is zero, or Axelar Chain Id or Transceiver Address were empty. + error InvalidChainIdParams(); + + /// @notice Chain Id is already being used. + error ChainIdAlreadySet(uint16 chainId); + + /// @notice Axelar chain Id is already being used. + error AxelarChainIdAlreadySet(string axelarChainId); /// @notice Emmited when a transceiver message is sent. /// @param recipientChainId The wormhole chainId of the destination chain. @@ -26,6 +37,12 @@ interface IAxelarTransceiver is ITransceiver { bytes32 indexed refundAddress ); + /// @notice Emmited when the chain id is set. + /// @param chainId The wormhole chainId of the destination chain. + /// @param chainName The axelar chain name. + /// @param transceiverAddress The transceiver address as a string. + event AxelarChainIdSet(uint16 chainId, string chainName, string transceiverAddress); + /** * Set the bridge manager contract address * @param chainId The chainId of the chain. This is used to identify the chain in the EndpointManager. diff --git a/test/axelar/AxelarTransceiver.t.sol b/test/axelar/AxelarTransceiver.t.sol index 712c35b..d978126 100644 --- a/test/axelar/AxelarTransceiver.t.sol +++ b/test/axelar/AxelarTransceiver.t.sol @@ -19,6 +19,16 @@ import "forge-std/Test.sol"; import "openzeppelin-contracts/contracts/access/Ownable.sol"; contract AxelarTransceiverTest is Test { + event ContractCall( + address indexed sender, + string destinationChain, + string destinationContractAddress, + bytes32 indexed payloadHash, + bytes payload + ); + + event AxelarChainIdSet(uint16 chainId, string chainName, string transceiverAddress); + address constant OWNER = address(1004); uint64 constant RATE_LIMIT_DURATION = 0; @@ -34,9 +44,6 @@ contract AxelarTransceiverTest is Test { WstEthL2TokenHarness token; function setUp() public { - string memory url = "https://ethereum-sepolia-rpc.publicnode.com"; - vm.createSelectFork(url); - gateway = IAxelarGateway(new MockAxelarGateway()); gasService = IAxelarGasService(address(new MockAxelarGasService())); @@ -75,12 +82,31 @@ contract AxelarTransceiverTest is Test { string memory chainName = "chainName"; string memory axelarAddress = "axelarAddress"; + vm.expectEmit(address(transceiver)); + emit AxelarChainIdSet(chainId, chainName, axelarAddress); + vm.prank(OWNER); transceiver.setAxelarChainId(chainId, chainName, axelarAddress); - /*assertEq(transceiver.idToAxelarChainIds(chainId), chainName); - assertEq(transceiver.axelarChainIdToId(chainName),chainId); - assertEq(transceiver.idToAxelarAddress(chainId), axelarAddress); - assertEq(transceiver.axelarAddressToId(axelarAddress), chainId);*/ + } + + function test_setAxelarChainIdDuplicateChainId() public { + uint16 chainId = 1; + string memory chainName = "chainName"; + string memory axelarAddress = "axelarAddress"; + + vm.expectEmit(address(transceiver)); + emit AxelarChainIdSet(chainId, chainName, axelarAddress); + + vm.prank(OWNER); + transceiver.setAxelarChainId(chainId, chainName, axelarAddress); + + vm.prank(OWNER); + vm.expectRevert(abi.encodeWithSignature("ChainIdAlreadySet(uint16)", chainId)); + transceiver.setAxelarChainId(chainId, chainName, axelarAddress); + + vm.prank(OWNER); + vm.expectRevert(abi.encodeWithSignature("AxelarChainIdAlreadySet(string)", chainName)); + transceiver.setAxelarChainId(chainId + 1, chainName, axelarAddress); } function test_setAxelarChainIdNotOwner() public { @@ -101,11 +127,18 @@ contract AxelarTransceiverTest is Test { bytes32 recipientNttManagerAddress = bytes32(uint256(1010)); bytes memory nttManagerMessage = bytes("nttManagerMessage"); bytes32 refundAddress = bytes32(uint256(1011)); + bytes memory payload = abi.encode(manager, nttManagerMessage, recipientNttManagerAddress); TransceiverStructs.TransceiverInstruction memory instruction = TransceiverStructs.TransceiverInstruction(0, bytes("")); vm.prank(OWNER); transceiver.setAxelarChainId(chainId, chainName, axelarAddress); + + vm.expectEmit(address(gateway)); + emit ContractCall( + address(transceiver), chainName, axelarAddress, keccak256(payload), payload + ); + vm.prank(address(manager)); transceiver.sendMessage( chainId, instruction, nttManagerMessage, recipientNttManagerAddress, refundAddress @@ -167,6 +200,7 @@ contract AxelarTransceiverTest is Test { uint16 chainId = 2; string memory chainName = "chainName"; string memory axelarAddress = "axelarAddress"; + bytes32 messageId = bytes32(uint256(25)); bytes32 recipientNttManagerAddress = bytes32(uint256(uint160(address(manager)))); bytes32 to = bytes32(uint256(1234)); @@ -184,9 +218,9 @@ contract AxelarTransceiverTest is Test { bytes memory nttManagerMessage; { uint16 length = uint16(nttPayload.length); - bytes32 messageId = bytes32(uint256(0)); + bytes32 nttMessageId = bytes32(uint256(0)); bytes32 sender = bytes32(uint256(1)); - nttManagerMessage = abi.encodePacked(messageId, sender, length, nttPayload); + nttManagerMessage = abi.encodePacked(nttMessageId, sender, length, nttPayload); } bytes32 sourceNttManagerAddress = bytes32(uint256(1012)); @@ -201,21 +235,29 @@ contract AxelarTransceiverTest is Test { token.setMinter(OWNER); vm.prank(OWNER); token.mint(address(manager), amount); + gateway.approveContractCall(messageId, chainName, axelarAddress, keccak256(payload)); - transceiver.execute(bytes32(0), chainName, axelarAddress, payload); + transceiver.execute(messageId, chainName, axelarAddress, payload); if (token.balanceOf(fromWormholeFormat(to)) != amount) revert("Amount Incorrect"); + + vm.prank(OWNER); + token.mint(address(manager), amount); + vm.expectRevert(abi.encodeWithSignature("NotApprovedByGateway()")); + transceiver.execute(bytes32(0), chainName, axelarAddress, payload); } function test_executeNotTrustedAddress() public { string memory chainName = "chainName"; string memory axelarAddress = "axelarAddress"; bytes memory payload = bytes(""); + bytes32 messageId = keccak256(bytes("message Id")); + gateway.approveContractCall(messageId, chainName, axelarAddress, keccak256(payload)); vm.expectRevert( abi.encodeWithSignature( "InvalidSibling(uint16,string,string)", 0, chainName, axelarAddress ) ); - transceiver.execute(bytes32(0), chainName, axelarAddress, payload); + transceiver.execute(messageId, chainName, axelarAddress, payload); } } diff --git a/test/axelar/AxelarTransceiverEndToEnd.sol b/test/axelar/AxelarTransceiverEndToEnd.sol new file mode 100644 index 0000000..91e6354 --- /dev/null +++ b/test/axelar/AxelarTransceiverEndToEnd.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "../../src/axelar/AxelarTransceiver.sol"; +import "./mock/MockGateway.sol"; +import {MockAxelarGasService} from "./mock/MockGasService.sol"; +import {TransceiverStructs} from + "@wormhole-foundation/native_token_transfer/libraries/TransceiverStructs.sol"; +import {NttManager} from "@wormhole-foundation/native_token_transfer/NttManager/NttManager.sol"; +import {INttManager} from "@wormhole-foundation/native_token_transfer/interfaces/INttManager.sol"; +import {IManagerBase} from "@wormhole-foundation/native_token_transfer/interfaces/IManagerBase.sol"; +import {ERC1967Proxy} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {WstEthL2Token} from "src/token/WstEthL2Token.sol"; + +import "forge-std/console.sol"; +import "forge-std/Test.sol"; +import "openzeppelin-contracts/contracts/access/Ownable.sol"; + +contract AxelarTransceiverEndToEnd is Test { + address constant OWNER = address(1004); + uint64 constant RATE_LIMIT_DURATION = 0; + bool constant SKIP_RATE_LIMITING = true; + + uint256 constant DEVNET_GUARDIAN_PK = + 0xcfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0; + + AxelarTransceiver sourceTransceiver; + IAxelarGateway gateway; + IAxelarGasService gasService; + NttManager sourceNttmanager; + WstEthL2Token sourceToken; + uint16 sourceChainId; + + AxelarTransceiver recipientTransceiver; + NttManager recipientNttManager; + WstEthL2Token recipientToken; + uint16 recipientChainId; + + function setUp() public { + gateway = IAxelarGateway(new MockAxelarGateway()); + gasService = IAxelarGasService(address(new MockAxelarGasService())); + // Setup Source Infrastructure + sourceChainId = 1; + address tokenImplementaion = address(new WstEthL2Token()); + sourceToken = WstEthL2Token( + address( + new ERC1967Proxy( + tokenImplementaion, + abi.encodeWithSelector( + WstEthL2Token.initialize.selector, "Source Token", "ST", OWNER + ) + ) + ) + ); + vm.prank(OWNER); + sourceToken.setMinter(OWNER); + address sourceManagerImplementation = address( + new NttManager( + address(sourceToken), + IManagerBase.Mode.LOCKING, + sourceChainId, + RATE_LIMIT_DURATION, + SKIP_RATE_LIMITING + ) + ); + sourceNttmanager = NttManager(address(new ERC1967Proxy(sourceManagerImplementation, ""))); + sourceNttmanager.initialize(); + sourceNttmanager.transferOwnership(OWNER); + address srcTransceiverImplementation = address( + new AxelarTransceiver(address(gateway), address(gasService), address(sourceNttmanager)) + ); + sourceTransceiver = + AxelarTransceiver(address(new ERC1967Proxy(srcTransceiverImplementation, ""))); + sourceTransceiver.initialize(); + vm.prank(OWNER); + sourceNttmanager.setTransceiver(address(sourceTransceiver)); + + // Setup Recipient Infrastructure + recipientChainId = 2; + recipientToken = WstEthL2Token( + address( + new ERC1967Proxy( + tokenImplementaion, + abi.encodeWithSelector( + WstEthL2Token.initialize.selector, "Source Token", "ST", OWNER + ) + ) + ) + ); + vm.prank(OWNER); + recipientToken.setMinter(OWNER); + address recipientManagerImplementation = address( + new NttManager( + address(recipientToken), + IManagerBase.Mode.LOCKING, + recipientChainId, + RATE_LIMIT_DURATION, + SKIP_RATE_LIMITING + ) + ); + recipientNttManager = + NttManager(address(new ERC1967Proxy(recipientManagerImplementation, ""))); + recipientNttManager.initialize(); + recipientNttManager.transferOwnership(OWNER); + address rcptTransceiverImplementation = address( + new AxelarTransceiver( + address(gateway), address(gasService), address(recipientNttManager) + ) + ); + recipientTransceiver = + AxelarTransceiver(address(new ERC1967Proxy(rcptTransceiverImplementation, ""))); + recipientTransceiver.initialize(); + vm.prank(OWNER); + recipientNttManager.setTransceiver(address(recipientTransceiver)); + + bytes32 sourceNttManagerAddress = bytes32(uint256(uint160(address(sourceNttmanager)))); + bytes32 recipientNttManagerAddress = bytes32(uint256(uint160(address(recipientNttManager)))); + + // set peer ntt manager on source + vm.prank(OWNER); + sourceNttmanager.setPeer(recipientChainId, recipientNttManagerAddress, 18, 100000000); + + // set peer ntt manager on recipient + vm.prank(OWNER); + recipientNttManager.setPeer(sourceChainId, sourceNttManagerAddress, 18, 100000000); + + string memory sourceChainName = "srcChain"; + string memory sourceAxelarAddress = "srcAxelar"; + + string memory recipientChainName = "recipientChain"; + string memory recipientAxelarAddress = "recipientAxelar"; + + vm.prank(OWNER); + sourceTransceiver.setAxelarChainId( + recipientChainId, recipientChainName, recipientAxelarAddress + ); + + vm.prank(OWNER); + recipientTransceiver.setAxelarChainId(sourceChainId, sourceChainName, sourceAxelarAddress); + + // token mint source + vm.prank(OWNER); + sourceToken.mint(address(sourceNttmanager), 10e6 ether); + + vm.prank(OWNER); + recipientToken.mint(address(recipientNttManager), 10e6 ether); + } + + function testAxelarTransceiverEndToEnd() public { + bytes32 refundAddress = bytes32(uint256(1011)); + TransceiverStructs.TransceiverInstruction memory instruction = + TransceiverStructs.TransceiverInstruction(0, bytes("")); + + // SEND MESSAGE ON SOURCE CHAIN + bytes32 to = bytes32(uint256(1234)); + uint64 amount = 12345670000000000; + bytes memory nttPayload; + { + bytes4 prefix = TransceiverStructs.NTT_PREFIX; + uint8 decimals = 18; + bytes32 srcToken = bytes32(uint256(uint160(address(sourceToken)))); + uint16 toChain = 2; + nttPayload = abi.encodePacked(prefix, decimals, amount, srcToken, to, toChain); + } + + bytes memory nttManagerMessage; + { + uint16 length = uint16(nttPayload.length); + bytes32 nttMessageId = bytes32(uint256(0)); + bytes32 sender = bytes32(uint256(1)); + nttManagerMessage = abi.encodePacked(nttMessageId, sender, length, nttPayload); + } + bytes32 sourceNttManagerAddress = bytes32(uint256(uint160(address(sourceNttmanager)))); + bytes32 recipientNttManagerAddress = bytes32(uint256(uint160(address(recipientNttManager)))); + + vm.prank(address(sourceNttmanager)); + sourceTransceiver.sendMessage( + recipientChainId, + instruction, + nttManagerMessage, + recipientNttManagerAddress, + refundAddress + ); + + // EXECUTE ON RECIPIENT CHAIN + bytes memory payload = + abi.encode(sourceNttManagerAddress, nttManagerMessage, recipientNttManagerAddress); + + string memory sourceChainName = "srcChain"; + string memory sourceAxelarAddress = "srcAxelar"; + bytes32 messageId = keccak256(bytes("message Id")); + + gateway.approveContractCall( + messageId, sourceChainName, sourceAxelarAddress, keccak256(payload) + ); + recipientTransceiver.execute(messageId, sourceChainName, sourceAxelarAddress, payload); + if (recipientToken.balanceOf(fromWormholeFormat(to)) != amount) revert("Amount Incorrect"); + } +} diff --git a/test/axelar/mock/MockGateway.sol b/test/axelar/mock/MockGateway.sol index 85ac077..480b3d6 100644 --- a/test/axelar/mock/MockGateway.sol +++ b/test/axelar/mock/MockGateway.sol @@ -2,6 +2,14 @@ pragma solidity ^0.8.22; interface IAxelarGateway { + event ContractCall( + address indexed sender, + string destinationChain, + string destinationContractAddress, + bytes32 indexed payloadHash, + bytes payload + ); + function validateContractCall( bytes32 commandId, string calldata sourceChain, @@ -14,21 +22,55 @@ interface IAxelarGateway { string calldata contractAddress, bytes calldata payload ) external; + + function approveContractCall( + bytes32 messageId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash + ) external; } contract MockAxelarGateway is IAxelarGateway { + mapping(bytes32 => bool) approved; + function callContract( string calldata destinationChain, - string calldata contractAddress, + string calldata destinationContractAddress, bytes calldata payload - ) external override {} + ) external override { + emit ContractCall( + msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload + ); + } + + function _getContractCallKey( + bytes32 messageId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash + ) internal pure returns (bytes32) { + return keccak256(abi.encode(messageId, sourceChain, sourceAddress, payloadHash)); + } + + function approveContractCall( + bytes32 messageId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash + ) external { + approved[_getContractCallKey(messageId, sourceChain, sourceAddress, payloadHash)] = true; + } function validateContractCall( - bytes32, - string memory, - string memory, - bytes32 - ) external pure override returns (bool) { - return true; + bytes32 messageId, + string calldata sourceChain, + string calldata sourceAddress, + bytes32 payloadHash + ) external override returns (bool) { + bytes32 key = _getContractCallKey(messageId, sourceChain, sourceAddress, payloadHash); + bool messageApproved = approved[key]; + if (messageApproved) approved[key] = false; + return messageApproved; } } From 9e031463171bc66e76e565e8990caca50223b255 Mon Sep 17 00:00:00 2001 From: Dirk Brink Date: Fri, 28 Jun 2024 09:37:28 -0700 Subject: [PATCH 2/4] Fix submodule commit hash --- lib/example-native-token-transfers | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/example-native-token-transfers b/lib/example-native-token-transfers index 348570f..0d37b0f 160000 --- a/lib/example-native-token-transfers +++ b/lib/example-native-token-transfers @@ -1 +1 @@ -Subproject commit 348570fbbbf6ed212406eb65dbda2c8975783bef +Subproject commit 0d37b0f4975084492c72ca881c1218d6e1aae9e3 From 01b4ed68c4bb0fb4a4de9dc8ddcace20351e022b Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 28 Jun 2024 19:42:37 -0400 Subject: [PATCH 3/4] Update src/axelar/AxelarTransceiver.sol --- src/axelar/AxelarTransceiver.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/axelar/AxelarTransceiver.sol b/src/axelar/AxelarTransceiver.sol index 90c6273..f154550 100644 --- a/src/axelar/AxelarTransceiver.sol +++ b/src/axelar/AxelarTransceiver.sol @@ -84,9 +84,11 @@ contract AxelarTransceiver is IAxelarTransceiver, AxelarGMPExecutable, Transceiv } AxelarTransceiverStorage storage slot = _storage(); + if (bytes(slot.idToAxelarChainId[chainId]).length != 0) revert ChainIdAlreadySet(chainId); if (slot.axelarChainIdToId[chainName] != 0) revert AxelarChainIdAlreadySet(chainName); + slot.idToAxelarChainId[chainId] = chainName; slot.axelarChainIdToId[chainName] = chainId; slot.idToTransceiverAddress[chainId] = transceiverAddress; From 7c47f134e17329a77770e0b3327fc1e46294a74f Mon Sep 17 00:00:00 2001 From: Foivos Date: Tue, 2 Jul 2024 18:15:02 +0300 Subject: [PATCH 4/4] fix: there can be multiple tranceivers on the same address on different chains. (#23) * fix it so that there can be multiple tranceivers on the same address on different chains. * fix spelling error * add token back * add cast to bytes * run forge fmt * update examples-native-token-transfers * try to revert to older package --- src/axelar/AxelarTransceiver.sol | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/axelar/AxelarTransceiver.sol b/src/axelar/AxelarTransceiver.sol index f154550..2736221 100644 --- a/src/axelar/AxelarTransceiver.sol +++ b/src/axelar/AxelarTransceiver.sol @@ -30,7 +30,7 @@ contract AxelarTransceiver is IAxelarTransceiver, AxelarGMPExecutable, Transceiv mapping(uint16 => string) idToAxelarChainId; mapping(string => uint16) axelarChainIdToId; mapping(uint16 => string) idToTransceiverAddress; - mapping(string => uint16) transceiverAddressToId; + mapping(uint16 => bytes32) idToTransceiverAddressHash; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AxelarTransceiver")) - 1)) & ~bytes32(uint256(0xff)) @@ -92,7 +92,7 @@ contract AxelarTransceiver is IAxelarTransceiver, AxelarGMPExecutable, Transceiv slot.idToAxelarChainId[chainId] = chainName; slot.axelarChainIdToId[chainName] = chainId; slot.idToTransceiverAddress[chainId] = transceiverAddress; - slot.transceiverAddressToId[transceiverAddress] = chainId; + slot.idToTransceiverAddressHash[chainId] = keccak256(bytes(transceiverAddress)); emit AxelarChainIdSet(chainId, chainName, transceiverAddress); } @@ -185,7 +185,10 @@ contract AxelarTransceiver is IAxelarTransceiver, AxelarGMPExecutable, Transceiv ) internal virtual override { AxelarTransceiverStorage storage slot = _storage(); uint16 sourceChainId = slot.axelarChainIdToId[sourceChain]; - if (sourceChainId == 0 || slot.transceiverAddressToId[sourceAddress] != sourceChainId) { + if ( + sourceChainId == 0 + || slot.idToTransceiverAddressHash[sourceChainId] != keccak256(bytes(sourceAddress)) + ) { revert InvalidSibling(sourceChainId, sourceChain, sourceAddress); }