diff --git a/packages/contracts-communication/configs/global/ExecutionService.testnet.json b/packages/contracts-communication/configs/global/ExecutionService.testnet.json index d4293802bc..459ecaca64 100644 --- a/packages/contracts-communication/configs/global/ExecutionService.testnet.json +++ b/packages/contracts-communication/configs/global/ExecutionService.testnet.json @@ -1,4 +1,4 @@ { "executorEOA": "0xD0D45E468ADF3aCB8A98391ff47267783220ba6F", - "gasOracleName": "GasOracleMock" + "gasOracleName": "SynapseGasOracleMock" } diff --git a/packages/contracts-communication/configs/global/SynapseModule.testnet.json b/packages/contracts-communication/configs/global/SynapseModule.testnet.json index 0ad395d094..e78630c1d7 100644 --- a/packages/contracts-communication/configs/global/SynapseModule.testnet.json +++ b/packages/contracts-communication/configs/global/SynapseModule.testnet.json @@ -1,7 +1,7 @@ { "claimFeeBPS": 10, "feeCollector": "0xD0D45E468ADF3aCB8A98391ff47267783220ba6F", - "gasOracleName": "GasOracleMock", + "gasOracleName": "SynapseGasOracleMock", "threshold": 6, "verifiers": [ "0x0E399F695d72033d598aC2911B8A5e9986d6cbaD", diff --git a/packages/contracts-communication/contracts/events/SynapseModuleEvents.sol b/packages/contracts-communication/contracts/events/SynapseModuleEvents.sol index 5defbe3fba..84569f0968 100644 --- a/packages/contracts-communication/contracts/events/SynapseModuleEvents.sol +++ b/packages/contracts-communication/contracts/events/SynapseModuleEvents.sol @@ -12,4 +12,7 @@ abstract contract SynapseModuleEvents { event ClaimFeeFractionChanged(uint256 claimFeeFraction); event FeesClaimed(address feeCollector, uint256 collectedFees, address claimer, uint256 claimerFee); + + event GasDataSent(uint256 dstChainId, bytes data); + event GasDataReceived(uint256 srcChainId, bytes data); } diff --git a/packages/contracts-communication/contracts/interfaces/ISynapseGasOracle.sol b/packages/contracts-communication/contracts/interfaces/ISynapseGasOracle.sol new file mode 100644 index 0000000000..18bf67b758 --- /dev/null +++ b/packages/contracts-communication/contracts/interfaces/ISynapseGasOracle.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IGasOracle} from "./IGasOracle.sol"; + +interface ISynapseGasOracle is IGasOracle { + /// @notice Allows Synapse Module to pass the gas data from a remote chain to the Gas Oracle. + /// @dev Could only be called by Synapse Module. + /// @param srcChainId The chain id of the remote chain. + /// @param data The gas data from the remote chain. + function receiveRemoteGasData(uint256 srcChainId, bytes calldata data) external; + + /// @notice Gets the gas data for the local chain. + function getLocalGasData() external view returns (bytes memory); +} diff --git a/packages/contracts-communication/contracts/interfaces/ISynapseModule.sol b/packages/contracts-communication/contracts/interfaces/ISynapseModule.sol index 02ba033590..dc74af53a1 100644 --- a/packages/contracts-communication/contracts/interfaces/ISynapseModule.sol +++ b/packages/contracts-communication/contracts/interfaces/ISynapseModule.sol @@ -7,6 +7,7 @@ interface ISynapseModule is IInterchainModule { error SynapseModule__ClaimFeeFractionExceedsMax(uint256 claimFeeFraction); error SynapseModule__FeeCollectorNotSet(); error SynapseModule__GasOracleNotContract(address gasOracle); + error SynapseModule__GasOracleNotSet(); error SynapseModule__NoFeesToClaim(); // ═══════════════════════════════════════════════ PERMISSIONED ════════════════════════════════════════════════════ diff --git a/packages/contracts-communication/contracts/libs/ModuleEntry.sol b/packages/contracts-communication/contracts/libs/ModuleEntry.sol new file mode 100644 index 0000000000..25c079f54a --- /dev/null +++ b/packages/contracts-communication/contracts/libs/ModuleEntry.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {InterchainEntry} from "./InterchainEntry.sol"; + +library ModuleEntryLib { + /// @notice Encodes the InterchainEntry and the auxiliary module data into a single bytes array + /// @param entry The InterchainEntry to encode + /// @param moduleData The auxiliary module data to encode + function encodeModuleEntry( + InterchainEntry memory entry, + bytes memory moduleData + ) + internal + pure + returns (bytes memory) + { + return abi.encode(entry, moduleData); + } + + /// @notice Decodes the bytes array into the InterchainEntry and the auxiliary module data + /// @param encodedModuleEntry The bytes array to decode + /// @return entry The decoded InterchainEntry + /// @return moduleData The decoded auxiliary module data + function decodeModuleEntry(bytes memory encodedModuleEntry) + internal + pure + returns (InterchainEntry memory entry, bytes memory moduleData) + { + return abi.decode(encodedModuleEntry, (InterchainEntry, bytes)); + } +} diff --git a/packages/contracts-communication/contracts/modules/InterchainModule.sol b/packages/contracts-communication/contracts/modules/InterchainModule.sol index bf93677d9e..52ba5c3232 100644 --- a/packages/contracts-communication/contracts/modules/InterchainModule.sol +++ b/packages/contracts-communication/contracts/modules/InterchainModule.sol @@ -5,7 +5,7 @@ import {InterchainModuleEvents} from "../events/InterchainModuleEvents.sol"; import {IInterchainDB} from "../interfaces/IInterchainDB.sol"; import {IInterchainModule} from "../interfaces/IInterchainModule.sol"; -import {InterchainEntry} from "../libs/InterchainEntry.sol"; +import {InterchainEntry, ModuleEntryLib} from "../libs/ModuleEntry.sol"; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; @@ -32,7 +32,8 @@ abstract contract InterchainModule is InterchainModuleEvents, IInterchainModule if (msg.value < requiredFee) { revert InterchainModule__InsufficientFee({actual: msg.value, required: requiredFee}); } - bytes memory encodedEntry = abi.encode(entry); + bytes memory moduleData = _fillModuleData(destChainId, entry.dbNonce); + bytes memory encodedEntry = ModuleEntryLib.encodeModuleEntry(entry, moduleData); bytes32 ethSignedEntryHash = MessageHashUtils.toEthSignedMessageHash(keccak256(encodedEntry)); _requestVerification(destChainId, encodedEntry); emit VerificationRequested(destChainId, encodedEntry, ethSignedEntryHash); @@ -46,20 +47,27 @@ abstract contract InterchainModule is InterchainModuleEvents, IInterchainModule /// @dev Should be called once the Module has verified the entry and needs to signal this /// to the InterchainDB. function _verifyEntry(bytes memory encodedEntry) internal { - InterchainEntry memory entry = abi.decode(encodedEntry, (InterchainEntry)); + (InterchainEntry memory entry, bytes memory moduleData) = ModuleEntryLib.decodeModuleEntry(encodedEntry); if (entry.srcChainId == block.chainid) { revert InterchainModule__SameChainId(); } IInterchainDB(INTERCHAIN_DB).verifyEntry(entry); + _receiveModuleData(entry.srcChainId, entry.dbNonce, moduleData); emit EntryVerified( entry.srcChainId, encodedEntry, MessageHashUtils.toEthSignedMessageHash(keccak256(encodedEntry)) ); } + // solhint-disable no-empty-blocks /// @dev Internal logic to request the verification of an entry on the destination chain. - // solhint-disable-next-line no-empty-blocks function _requestVerification(uint256 destChainId, bytes memory encodedEntry) internal virtual {} + /// @dev Internal logic to fill the module data for the specified destination chain. + function _fillModuleData(uint256 destChainId, uint256 dbNonce) internal virtual returns (bytes memory) {} + + /// @dev Internal logic to handle the auxiliary module data relayed from the remote chain. + function _receiveModuleData(uint256 srcChainId, uint256 dbNonce, bytes memory moduleData) internal virtual {} + /// @dev Internal logic to get the module fee for verifying an entry on the specified destination chain. function _getModuleFee(uint256 destChainId) internal view virtual returns (uint256); } diff --git a/packages/contracts-communication/contracts/modules/SynapseModule.sol b/packages/contracts-communication/contracts/modules/SynapseModule.sol index b71c75fe01..ca0c5f4e71 100644 --- a/packages/contracts-communication/contracts/modules/SynapseModule.sol +++ b/packages/contracts-communication/contracts/modules/SynapseModule.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.20; import {InterchainModule} from "./InterchainModule.sol"; import {SynapseModuleEvents} from "../events/SynapseModuleEvents.sol"; -import {IGasOracle} from "../interfaces/IGasOracle.sol"; +import {ISynapseGasOracle} from "../interfaces/ISynapseGasOracle.sol"; import {ISynapseModule} from "../interfaces/ISynapseModule.sol"; import {ThresholdECDSA} from "../libs/ThresholdECDSA.sol"; @@ -26,6 +26,10 @@ contract SynapseModule is InterchainModule, Ownable, SynapseModuleEvents, ISynap uint256 internal _claimFeeFraction; /// @dev Gas limit for the verifyEntry function on the remote chain. mapping(uint256 chainId => uint256 gasLimit) internal _verifyGasLimit; + /// @dev Hash of the last gas data sent to the remote chain. + mapping(uint256 chainId => bytes32 gasDataHash) internal _lastGasDataHash; + /// @dev Nonce of the last gas data received from the remote chain. + mapping(uint256 chainId => uint256 gasDataNonce) internal _lastGasDataNonce; /// @inheritdoc ISynapseModule address public feeCollector; @@ -173,6 +177,45 @@ contract SynapseModule is InterchainModule, Ownable, SynapseModuleEvents, ISynap emit VerifierRemoved(verifier); } + /// @dev Internal logic to fill the module data for the specified destination chain. + function _fillModuleData( + uint256 destChainId, + uint256 dbNonce + ) + internal + override + returns (bytes memory moduleData) + { + moduleData = _getSynapseGasOracle().getLocalGasData(); + // Exit early if data is empty + if (moduleData.length == 0) { + return moduleData; + } + bytes32 dataHash = keccak256(moduleData); + // Don't send the same data twice + if (dataHash == _lastGasDataHash[destChainId]) { + moduleData = ""; + } else { + _lastGasDataHash[destChainId] = dataHash; + emit GasDataSent(destChainId, moduleData); + } + } + + /// @dev Internal logic to handle the auxiliary module data relayed from the remote chain. + function _receiveModuleData(uint256 srcChainId, uint256 dbNonce, bytes memory moduleData) internal override { + // Exit early if data is empty + if (moduleData.length == 0) { + return; + } + // Don't process outdated data + uint256 lastNonce = _lastGasDataNonce[srcChainId]; + if (lastNonce == 0 || lastNonce < dbNonce) { + _lastGasDataNonce[srcChainId] = dbNonce; + _getSynapseGasOracle().receiveRemoteGasData(srcChainId, moduleData); + emit GasDataReceived(srcChainId, moduleData); + } + } + // ══════════════════════════════════════════════ INTERNAL VIEWS ═══════════════════════════════════════════════════ /// @dev Internal logic to get the module fee for verifying an entry on the specified destination chain. @@ -183,10 +226,18 @@ contract SynapseModule is InterchainModule, Ownable, SynapseModuleEvents, ISynap // entry is 32 (length) + 32*4 (fields) = 160 // signatures: 32 (length) + 65*threshold (padded up to be a multiple of 32 bytes) // Total formula is: 4 + 32 (entry offset) + 32 (signatures offset) + 160 + 32 - return IGasOracle(gasOracle).estimateTxCostInLocalUnits({ + return _getSynapseGasOracle().estimateTxCostInLocalUnits({ remoteChainId: destChainId, gasLimit: getVerifyGasLimit(destChainId), calldataSize: 292 + 64 * getThreshold() }); } + + /// @dev Internal logic to get the Synapse Gas Oracle. Reverts if the gas oracle is not set. + function _getSynapseGasOracle() internal view returns (ISynapseGasOracle synapseGasOracle) { + synapseGasOracle = ISynapseGasOracle(gasOracle); + if (address(synapseGasOracle) == address(0)) { + revert SynapseModule__GasOracleNotSet(); + } + } } diff --git a/packages/contracts-communication/script/MessagingBase.s.sol b/packages/contracts-communication/script/MessagingBase.s.sol deleted file mode 100644 index 4db5ced040..0000000000 --- a/packages/contracts-communication/script/MessagingBase.s.sol +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Script} from "forge-std/Script.sol"; - -import {InterchainDB} from "../contracts/InterchainDB.sol"; - -import {InterchainClientV1} from "../contracts/InterchainClientV1.sol"; - -import {SynapseModule} from "../contracts/modules/SynapseModule.sol"; - -import {InterchainApp} from "../contracts/InterchainApp.sol"; - -import {GasOracleMock} from "../test/mocks/GasOracleMock.sol"; - -import {ExecutionFeesMock} from "../test/mocks/ExecutionFeesMock.sol"; - -contract MessagingBase is Script { - InterchainDB public icDB; - InterchainClientV1 public icClient; - SynapseModule public synapseModule; - GasOracleMock public gasOracleMock; - InterchainApp public icApp; - ExecutionFeesMock public executionFees; - - function run() external { - vm.startBroadcast(); - icDB = new InterchainDB(); - // icClient deployment & config - icClient = new InterchainClientV1(address(icDB), msg.sender); - - synapseModule = new SynapseModule(address(icDB), msg.sender); - gasOracleMock = new GasOracleMock(); - executionFees = new ExecutionFeesMock(); - synapseModule.setGasOracle(address(gasOracleMock)); - icClient.setExecutionFees(address(executionFees)); - icApp = new InterchainApp(address(icClient), new address[](0), new address[](0)); - - vm.stopBroadcast(); - } - - function newApp() external { - vm.startBroadcast(); - icApp = new InterchainApp(0x007f3EC4A8E6DbaA84E50d0901F48966D83B7300, new address[](0), new address[](0)); - vm.stopBroadcast(); - } - - function newAppSepolia() public { - vm.startBroadcast(); - icApp = new InterchainApp(0xFd8A9eDf272e54614426a4c5849851D26A57C644, new address[](0), new address[](0)); - vm.stopBroadcast(); - } - - function newAppConfigOP() external { - vm.startBroadcast(); - icApp = InterchainApp(0x4a1f8D1378b614a59D0BB62EeeD811aaC1d22EC0); - uint64[] memory chainIDs = new uint64[](1); - chainIDs[0] = 11_155_111; - address[] memory linkedIApps = new address[](1); - linkedIApps[0] = 0x4a1f8D1378b614a59D0BB62EeeD811aaC1d22EC0; - address[] memory _sendingModules = new address[](1); - _sendingModules[0] = 0x48ADb7308f59d98657e779681aE6037902901918; - address[] memory _receivingModules = new address[](1); - _receivingModules[0] = 0x48ADb7308f59d98657e779681aE6037902901918; - uint256 _requiredResponses = 1; - uint64 _optimisticTimePeriod = 1; - icApp.setAppConfig( - chainIDs, - linkedIApps, - _sendingModules, - _receivingModules, - address(0), - _requiredResponses, - _optimisticTimePeriod - ); - vm.stopBroadcast(); - } - - function newAppConfigSepolia() external { - vm.startBroadcast(); - icApp = InterchainApp(0x4a1f8D1378b614a59D0BB62EeeD811aaC1d22EC0); - uint64[] memory chainIDs = new uint64[](1); - chainIDs[0] = 11_155_111; - address[] memory linkedIApps = new address[](1); - linkedIApps[0] = 0x4a1f8D1378b614a59D0BB62EeeD811aaC1d22EC0; - address[] memory _sendingModules = new address[](1); - _sendingModules[0] = 0x135189D37b0a734e4A339F0e9fd3219521729e7A; - address[] memory _receivingModules = new address[](1); - _receivingModules[0] = 0x135189D37b0a734e4A339F0e9fd3219521729e7A; - uint256 _requiredResponses = 1; - uint64 _optimisticTimePeriod = 1; - icApp.setAppConfig( - chainIDs, - linkedIApps, - _sendingModules, - _receivingModules, - address(0), - _requiredResponses, - _optimisticTimePeriod - ); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts-communication/script/testnet-deploy.sh b/packages/contracts-communication/script/testnet-deploy.sh index e6c4f38977..52857450ac 100755 --- a/packages/contracts-communication/script/testnet-deploy.sh +++ b/packages/contracts-communication/script/testnet-deploy.sh @@ -21,4 +21,4 @@ yarn fsr script/deploy/DeploySynapseModule.s.sol "$chainName" "$walletName" "$@" yarn fsr-str script/deploy/DeployWithMsgSender.s.sol "$chainName" "$walletName" "ExecutionFees" "$@" yarn fsr-str script/deploy/DeployWithMsgSender.s.sol "$chainName" "$walletName" "ExecutionService" "$@" -yarn fsr-str script/deploy/DeployNoArgs.s.sol "$chainName" "$walletName" "GasOracleMock" "$@" +yarn fsr-str script/deploy/DeployNoArgs.s.sol "$chainName" "$walletName" "SynapseGasOracleMock" "$@" diff --git a/packages/contracts-communication/test/ExecutionService.t.sol b/packages/contracts-communication/test/ExecutionService.t.sol index ad2d19d1f7..e37bd168ed 100644 --- a/packages/contracts-communication/test/ExecutionService.t.sol +++ b/packages/contracts-communication/test/ExecutionService.t.sol @@ -3,18 +3,18 @@ pragma solidity 0.8.20; import {ExecutionService, ExecutionServiceEvents, IExecutionService} from "../contracts/ExecutionService.sol"; import {Test} from "forge-std/Test.sol"; -import {GasOracleMock} from "./mocks/GasOracleMock.sol"; +import {SynapseGasOracleMock} from "./mocks/SynapseGasOracleMock.sol"; contract ExecutionServiceTest is ExecutionServiceEvents, Test { ExecutionService public executionService; - GasOracleMock public gasOracle; + SynapseGasOracleMock public gasOracle; address icClient = address(0x123); address executorEOA = address(0x456); address owner = makeAddr("Owner"); function setUp() public { - gasOracle = new GasOracleMock(); + gasOracle = new SynapseGasOracleMock(); executionService = new ExecutionService(address(this)); executionService.setInterchainClient(icClient); executionService.setExecutorEOA(executorEOA); diff --git a/packages/contracts-communication/test/harnesses/ModuleEntryLibHarness.sol b/packages/contracts-communication/test/harnesses/ModuleEntryLibHarness.sol new file mode 100644 index 0000000000..b890c8c12f --- /dev/null +++ b/packages/contracts-communication/test/harnesses/ModuleEntryLibHarness.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {InterchainEntry, ModuleEntryLib} from "../../contracts/libs/ModuleEntry.sol"; + +contract ModuleEntryLibHarness { + function encodeModuleEntry( + InterchainEntry memory entry, + bytes memory moduleData + ) + external + pure + returns (bytes memory) + { + return ModuleEntryLib.encodeModuleEntry(entry, moduleData); + } + + function decodeModuleEntry(bytes memory encodedModuleEntry) + external + pure + returns (InterchainEntry memory, bytes memory) + { + return ModuleEntryLib.decodeModuleEntry(encodedModuleEntry); + } +} diff --git a/packages/contracts-communication/test/libs/ModuleEntryLib.t.sol b/packages/contracts-communication/test/libs/ModuleEntryLib.t.sol new file mode 100644 index 0000000000..0879d94a68 --- /dev/null +++ b/packages/contracts-communication/test/libs/ModuleEntryLib.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {InterchainEntry, ModuleEntryLibHarness} from "../harnesses/ModuleEntryLibHarness.sol"; + +import {Test} from "forge-std/Test.sol"; + +// solhint-disable func-name-mixedcase +contract ModuleEntryLibTest is Test { + ModuleEntryLibHarness public libHarness; + + function setUp() public { + libHarness = new ModuleEntryLibHarness(); + } + + function assertEq(InterchainEntry memory actual, InterchainEntry memory expected) public { + assertEq(actual.srcChainId, expected.srcChainId, "!srcChainId"); + assertEq(actual.dbNonce, expected.dbNonce, "!dbNonce"); + assertEq(actual.srcWriter, expected.srcWriter, "!srcWriter"); + assertEq(actual.dataHash, expected.dataHash, "!dataHash"); + } + + function test_roundTrip(InterchainEntry memory entry, bytes memory moduleData) public { + bytes memory encoded = libHarness.encodeModuleEntry(entry, moduleData); + (InterchainEntry memory decodedEntry, bytes memory decodedModuleData) = libHarness.decodeModuleEntry(encoded); + assertEq(decodedEntry, entry); + assertEq(decodedModuleData, moduleData); + } +} diff --git a/packages/contracts-communication/test/mocks/GasOracleMock.sol b/packages/contracts-communication/test/mocks/SynapseGasOracleMock.sol similarity index 69% rename from packages/contracts-communication/test/mocks/GasOracleMock.sol rename to packages/contracts-communication/test/mocks/SynapseGasOracleMock.sol index ef38762239..f730440d58 100644 --- a/packages/contracts-communication/test/mocks/GasOracleMock.sol +++ b/packages/contracts-communication/test/mocks/SynapseGasOracleMock.sol @@ -1,9 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.20; -import {IGasOracle} from "../../contracts/interfaces/IGasOracle.sol"; +import {ISynapseGasOracle} from "../../contracts/interfaces/ISynapseGasOracle.sol"; + +contract SynapseGasOracleMock is ISynapseGasOracle { + function receiveRemoteGasData(uint256 srcChainId, bytes calldata data) external {} + + function getLocalGasData() external view returns (bytes memory) {} -contract GasOracleMock is IGasOracle { function convertRemoteValueToLocalUnits( uint256 remoteChainId, uint256 value diff --git a/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol b/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol index 85c1700490..71a0eb93c8 100644 --- a/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol +++ b/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol @@ -8,7 +8,7 @@ import {InterchainEntry} from "../../contracts/libs/InterchainEntry.sol"; import {ThresholdECDSALib} from "../../contracts/libs/ThresholdECDSA.sol"; import {SynapseModule} from "../../contracts/modules/SynapseModule.sol"; -import {GasOracleMock} from "../mocks/GasOracleMock.sol"; +import {SynapseGasOracleMock} from "../mocks/SynapseGasOracleMock.sol"; import {InterchainDBMock, IInterchainDB} from "../mocks/InterchainDBMock.sol"; import {Test} from "forge-std/Test.sol"; @@ -17,7 +17,7 @@ import {Test} from "forge-std/Test.sol"; // solhint-disable ordering contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseModuleEvents { SynapseModule public module; - GasOracleMock public gasOracle; + SynapseGasOracleMock public gasOracle; InterchainDBMock public interchainDB; address public feeCollector = makeAddr("FeeCollector"); @@ -32,6 +32,7 @@ contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseMo srcWriter: bytes32(uint256(3)), dataHash: bytes32(uint256(4)) }); + bytes public mockModuleData = ""; uint256 public constant PK_0 = 1000; uint256 public constant PK_1 = 2000; @@ -49,7 +50,7 @@ contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseMo vm.chainId(DST_CHAIN_ID); interchainDB = new InterchainDBMock(); module = new SynapseModule(address(interchainDB), owner); - gasOracle = new GasOracleMock(); + gasOracle = new SynapseGasOracleMock(); vm.startPrank(owner); module.setGasOracle(address(gasOracle)); module.setFeeCollector(feeCollector); @@ -88,10 +89,10 @@ contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseMo function encodeAndHashEntry(InterchainEntry memory entry) internal - pure + view returns (bytes memory encodedEntry, bytes32 ethSignedHash) { - encodedEntry = abi.encode(entry); + encodedEntry = abi.encode(entry, mockModuleData); ethSignedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(encodedEntry))); } @@ -100,7 +101,7 @@ contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseMo uint256[] memory pks ) internal - pure + view returns (bytes memory signatures) { (, bytes32 ethSignedHash) = encodeAndHashEntry(entry); @@ -112,7 +113,7 @@ contract SynapseModuleDestinationTest is Test, InterchainModuleEvents, SynapseMo } function verifyEntry(InterchainEntry memory entry, bytes memory signatures) internal { - module.verifyEntry(abi.encode(entry), signatures); + module.verifyEntry(abi.encode(entry, mockModuleData), signatures); } // ═══════════════════════════════════════════════ TEST HELPERS ════════════════════════════════════════════════════ diff --git a/packages/contracts-communication/test/modules/SynapseModule.Management.t.sol b/packages/contracts-communication/test/modules/SynapseModule.Management.t.sol index 7ab125ccdf..ede5c5fd3e 100644 --- a/packages/contracts-communication/test/modules/SynapseModule.Management.t.sol +++ b/packages/contracts-communication/test/modules/SynapseModule.Management.t.sol @@ -5,7 +5,7 @@ import {SynapseModuleEvents} from "../../contracts/events/SynapseModuleEvents.so import {SynapseModule, ISynapseModule} from "../../contracts/modules/SynapseModule.sol"; import {ThresholdECDSALib} from "../../contracts/libs/ThresholdECDSA.sol"; -import {GasOracleMock} from "../mocks/GasOracleMock.sol"; +import {SynapseGasOracleMock} from "../mocks/SynapseGasOracleMock.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -15,7 +15,7 @@ import {Test} from "forge-std/Test.sol"; // solhint-disable ordering contract SynapseModuleManagementTest is Test, SynapseModuleEvents { SynapseModule public module; - GasOracleMock public gasOracle; + SynapseGasOracleMock public gasOracle; address public interchainDB = makeAddr("InterchainDB"); address public owner = makeAddr("Owner"); @@ -29,7 +29,7 @@ contract SynapseModuleManagementTest is Test, SynapseModuleEvents { function setUp() public { module = new SynapseModule(interchainDB, owner); - gasOracle = new GasOracleMock(); + gasOracle = new SynapseGasOracleMock(); allVerifiers.push(VERIFIER_1); allVerifiers.push(VERIFIER_2); allVerifiers.push(VERIFIER_3); diff --git a/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol b/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol index 23a4ae7070..119474b537 100644 --- a/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol +++ b/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol @@ -7,7 +7,7 @@ import {IInterchainModule} from "../../contracts/interfaces/IInterchainModule.so import {InterchainEntry} from "../../contracts/libs/InterchainEntry.sol"; import {SynapseModule, ISynapseModule} from "../../contracts/modules/SynapseModule.sol"; -import {GasOracleMock} from "../mocks/GasOracleMock.sol"; +import {SynapseGasOracleMock} from "../mocks/SynapseGasOracleMock.sol"; import {Test} from "forge-std/Test.sol"; @@ -15,7 +15,7 @@ import {Test} from "forge-std/Test.sol"; // solhint-disable ordering contract SynapseModuleSourceTest is Test, InterchainModuleEvents, SynapseModuleEvents { SynapseModule public module; - GasOracleMock public gasOracle; + SynapseGasOracleMock public gasOracle; address public interchainDB = makeAddr("InterchainDB"); address public feeCollector = makeAddr("FeeCollector"); @@ -35,11 +35,12 @@ contract SynapseModuleSourceTest is Test, InterchainModuleEvents, SynapseModuleE srcWriter: bytes32(uint256(3)), dataHash: bytes32(uint256(4)) }); + bytes public mockModuleData = ""; function setUp() public { vm.chainId(SRC_CHAIN_ID); module = new SynapseModule(interchainDB, owner); - gasOracle = new GasOracleMock(); + gasOracle = new SynapseGasOracleMock(); vm.startPrank(owner); module.setGasOracle(address(gasOracle)); module.setFeeCollector(feeCollector); @@ -50,7 +51,7 @@ contract SynapseModuleSourceTest is Test, InterchainModuleEvents, SynapseModuleE // Mock: gasOracle.estimateTxCostInLocalUnits(DST_CHAIN_ID, *, *) to return FEE vm.mockCall( address(gasOracle), - abi.encodeWithSelector(GasOracleMock.estimateTxCostInLocalUnits.selector, DST_CHAIN_ID), + abi.encodeWithSelector(SynapseGasOracleMock.estimateTxCostInLocalUnits.selector, DST_CHAIN_ID), abi.encode(FEE) ); } @@ -63,10 +64,10 @@ contract SynapseModuleSourceTest is Test, InterchainModuleEvents, SynapseModuleE function encodeAndHashEntry(InterchainEntry memory entry) internal - pure + view returns (bytes memory encodedEntry, bytes32 ethSignedHash) { - encodedEntry = abi.encode(entry); + encodedEntry = abi.encode(entry, mockModuleData); ethSignedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(encodedEntry))); }