diff --git a/packages/deployments/contracts/contracts/messaging/connectors/wormhole/BaseWormhole.sol b/packages/deployments/contracts/contracts/messaging/connectors/wormhole/BaseWormhole.sol index 5b17d949c0..8b0e3b2613 100644 --- a/packages/deployments/contracts/contracts/messaging/connectors/wormhole/BaseWormhole.sol +++ b/packages/deployments/contracts/contracts/messaging/connectors/wormhole/BaseWormhole.sol @@ -50,7 +50,9 @@ abstract contract BaseWormhole is GasCap { * https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/relayer/deliveryProvider/DeliveryProvider.sol */ function quoteEVMDeliveryPrice(uint256 _gasLimit, address _amb) public view returns (uint256 _cost) { - (_cost, ) = IWormholeRelayer(_amb).quoteEVMDeliveryPrice(MIRROR_WORMHOLE_ID, 0, _gasLimit); + // First Get the gas, if it is more than the cap use the cap + // And calculcate delievery price with gasCap + (_cost, ) = IWormholeRelayer(_amb).quoteEVMDeliveryPrice(MIRROR_WORMHOLE_ID, 0, _getGas(_gasLimit)); } // ============ Private fns ============ @@ -105,8 +107,11 @@ abstract contract BaseWormhole is GasCap { // Should always be sending a merkle root require(_data.length == 32, "!data length"); + // Should include gas limit info in specialized calldata + require(_encodedData.length == 32, "!encoded data length"); + //calculate cost to deliver message - uint256 gasLimit = _getGasFromEncoded(_encodedData); + uint256 gasLimit = abi.decode(_encodedData, (uint256)); uint256 deliveryCost = quoteEVMDeliveryPrice(gasLimit, _amb); require(deliveryCost == msg.value, "!msg.value"); @@ -129,15 +134,4 @@ abstract contract BaseWormhole is GasCap { require(uint256(_whFormatAddress) >> 160 == 0, "!evm address"); return address(uint160(uint256(_whFormatAddress))); } - - /** - * @notice Using Wormhole relayer (AMB), the gas is provided to `sendMessage` as an encoded uint - */ - function _getGasFromEncoded(bytes memory _encodedData) internal view returns (uint256 _gas) { - // Should include gssas info in specialized calldata - require(_encodedData.length == 32, "!encoded data length"); - - // Get the gas, if it is more than the cap use the cap - _gas = _getGas(abi.decode(_encodedData, (uint256))); - } } diff --git a/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeHubConnector.t.sol b/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeHubConnector.t.sol index cf5b5ba4e8..f593cade0c 100644 --- a/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeHubConnector.t.sol +++ b/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeHubConnector.t.sol @@ -101,8 +101,69 @@ contract WormholeHubConnectorTest is ConnectorHelper { WormholeHubConnector(_l1Connector).sendMessage{value: 100}(_data, encodedData); } + function test_WormholeHubConnector_sendMessage_sendMessageWithGasCap(bytes memory _data) public { + vm.assume(_data.length == 32); + + uint256 gasLimit = _gasCapL2 + 1; + bytes memory encodedData = abi.encode(gasLimit); + + // Mock the call to fees + vm.mockCall( + _amb, + abi.encodeWithSignature("quoteEVMDeliveryPrice(uint16,uint256,uint256)", _chainIdL2, 0, _gasCapL2), + abi.encode(100, 100) + ); + + // Mock the call to sendPayloadToEvm + vm.mockCall( + _amb, + 100, + abi.encodeWithSignature( + "sendPayloadToEvm(uint16,address,bytes,uint256,uint256,uint16,address)", + _chainIdL2, + address(_l2Connector), + _data, + uint256(0), + gasLimit, + _chainIdL2, + _owner + ), + abi.encode(uint64(1)) + ); + + // Check: correct event? + vm.expectEmit(false, false, false, true, _l1Connector); + emit MessageSent(_data, encodedData, _rootManager); + + // Check: call to sendPayloadToEvm? + vm.expectCall( + _amb, + 100, + abi.encodeWithSignature( + "sendPayloadToEvm(uint16,address,bytes,uint256,uint256,uint16,address)", + _chainIdL2, + address(_l2Connector), + _data, + 0, + gasLimit, + _chainIdL2, + _owner + ) + ); + + // Check: call to fees? + vm.expectCall( + _amb, + abi.encodeWithSignature("quoteEVMDeliveryPrice(uint16,uint256,uint256)", _chainIdL2, 0, _gasCapL2) + ); + + vm.deal(_rootManager, 1 ether); + vm.prank(_rootManager); + WormholeHubConnector(_l1Connector).sendMessage{value: 100}(_data, encodedData); + } + // Access control - function test_WormholeHubConnector_sendMessage_revertIfSenderIsNotRootManager( + function test_WormholeConnector_sendMessage_revertIfSenderIsNotRootManager( address _nonRootManager, bytes memory _data ) public { diff --git a/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeSpokeConnector.t.sol b/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeSpokeConnector.t.sol index b96ac8e6a0..3c8978083c 100644 --- a/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeSpokeConnector.t.sol +++ b/packages/deployments/contracts/contracts_forge/messaging/connectors/wormhole/WormholeSpokeConnector.t.sol @@ -116,6 +116,65 @@ contract WormholeSpokeConnectorTest is ConnectorHelper { WormholeSpokeConnector(_l2Connector).send{value: 100}(encodedData); } + function test_WormholeSpokeConnector_send_sendWithGasCap(bytes32 _root) public { + vm.assume(_root != bytes32(0)); + uint256 gasLimit = _gasCapL1 + 1; + bytes memory encodedData = abi.encode(gasLimit); + bytes memory _data = abi.encodePacked(_root); + + // Mock the call to fees + vm.mockCall( + _amb, + abi.encodeWithSignature("quoteEVMDeliveryPrice(uint16,uint256,uint256)", _chainIdL1, 0, _gasCapL1), + abi.encode(100, 100) + ); + + vm.mockCall(_merkle, abi.encodeWithSelector(MerkleTreeManager.root.selector), abi.encode(_root)); + + // Mock the call to sendPayloadToEvm + vm.mockCall( + _amb, + 100, + abi.encodeWithSignature( + "sendPayloadToEvm(uint16,address,bytes,uint256,uint256,uint16,address)", + _chainIdL1, + address(_l1Connector), + _data, + uint256(0), + gasLimit, + _chainIdL1, + _owner + ), + abi.encode(uint64(1)) + ); + + // Check: call to sendPayloadToEvm? + vm.expectCall( + _amb, + 100, + abi.encodeWithSignature( + "sendPayloadToEvm(uint16,address,bytes,uint256,uint256,uint16,address)", + _chainIdL1, + address(_l1Connector), + _data, + 0, + gasLimit, + _chainIdL1, + _owner + ) + ); + + // Check: call to fees? + vm.expectCall( + _amb, + abi.encodeWithSignature("quoteEVMDeliveryPrice(uint16,uint256,uint256)", _chainIdL1, 0, _gasCapL1) + ); + + vm.deal(_owner, 1 ether); + vm.prank(_owner); + WormholeSpokeConnector(_l2Connector).send{value: 100}(encodedData); + } + // data length function test_WormholeSpokeConnector_send_failsIfBadDataLength(bytes memory _data) public { vm.assume(_data.length != 32);