From 80cc541218c6995715a5fd7fcb653c1aab5a70a4 Mon Sep 17 00:00:00 2001 From: viatrix Date: Tue, 10 Oct 2023 17:23:14 +0300 Subject: [PATCH 1/3] feat: add SygmaMessageRelayer --- .../adapters/Sygma/SygmaHeaderReporter.sol | 55 ++------- .../adapters/Sygma/SygmaMessageRelayer.sol | 39 +++++++ .../adapters/Sygma/SygmaReporter.sol | 59 ++++++++++ .../adapters/Sygma/interfaces/IBridge.sol | 2 +- .../Sygma/test/SygmaTestContracts.sol | 3 +- .../Sygma/03_SygmaMessageRelayer.spec.ts | 110 ++++++++++++++++++ 6 files changed, 219 insertions(+), 49 deletions(-) create mode 100644 packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol create mode 100644 packages/evm/contracts/adapters/Sygma/SygmaReporter.sol create mode 100644 packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts diff --git a/packages/evm/contracts/adapters/Sygma/SygmaHeaderReporter.sol b/packages/evm/contracts/adapters/Sygma/SygmaHeaderReporter.sol index 9f447a1d..f7c95f87 100644 --- a/packages/evm/contracts/adapters/Sygma/SygmaHeaderReporter.sol +++ b/packages/evm/contracts/adapters/Sygma/SygmaHeaderReporter.sol @@ -1,31 +1,22 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.17; -import "./interfaces/IBridge.sol"; -import "./interfaces/ISygmaAdapter.sol"; -import "../../utils/HeaderStorage.sol"; +import { SygmaReporter } from "./SygmaReporter.sol"; +import { HeaderStorage } from "../../utils/HeaderStorage.sol"; -contract SygmaHeaderReporter { - IBridge public immutable _bridge; +contract SygmaHeaderReporter is SygmaReporter { HeaderStorage public immutable _headerStorage; - bytes32 public immutable _resourceID; - uint8 public immutable _defaultDestinationDomainID; - address public immutable _defaultSygmaAdapter; event HeaderReported(address indexed emitter, uint256 indexed blockNumber, bytes32 indexed blockHeader); constructor( - IBridge bridge, + address bridge, HeaderStorage headerStorage, bytes32 resourceID, uint8 defaultDestinationDomainID, address defaultSygmaAdapter - ) { - _bridge = bridge; + ) SygmaReporter(bridge, resourceID, defaultDestinationDomainID, defaultSygmaAdapter) { _headerStorage = headerStorage; - _resourceID = resourceID; - _defaultDestinationDomainID = defaultDestinationDomainID; - _defaultSygmaAdapter = defaultSygmaAdapter; } /** @@ -48,7 +39,7 @@ contract SygmaHeaderReporter { uint256[] memory blockNumbers, address sygmaAdapter, uint8 destinationDomainID, - bytes calldata feeData + bytes memory feeData ) public payable { _reportHeaders(blockNumbers, sygmaAdapter, destinationDomainID, feeData); } @@ -57,42 +48,12 @@ contract SygmaHeaderReporter { uint256[] memory blockNumbers, address sygmaAdapter, uint8 destinationDomainID, - bytes calldata feeData + bytes memory feeData ) internal { bytes32[] memory blockHeaders = _headerStorage.storeBlockHeaders(blockNumbers); - bytes memory depositData = abi.encodePacked( - // uint256 maxFee - uint256(0), - // uint16 len(executeFuncSignature) - uint16(4), - // bytes executeFuncSignature - ISygmaAdapter(address(0)).storeHashes.selector, - // uint8 len(executeContractAddress) - uint8(20), - // bytes executeContractAddress - sygmaAdapter, - // uint8 len(executionDataDepositor) - uint8(20), - // bytes executionDataDepositor - address(this), - // bytes executionDataDepositor + executionData - prepareDepositData(blockNumbers, blockHeaders) - ); - IBridge(_bridge).deposit{ value: msg.value }(destinationDomainID, _resourceID, depositData, feeData); + _reportData(blockNumbers, blockHeaders, sygmaAdapter, destinationDomainID, feeData); for (uint i = 0; i < blockNumbers.length; i++) { emit HeaderReported(address(this), blockNumbers[i], blockHeaders[i]); } } - - function slice(bytes calldata input, uint256 position) public pure returns (bytes memory) { - return input[position:]; - } - - function prepareDepositData( - uint256[] memory blockNumbers, - bytes32[] memory blockHeaders - ) public view returns (bytes memory) { - bytes memory encoded = abi.encode(address(0), blockNumbers, blockHeaders); - return this.slice(encoded, 32); - } } diff --git a/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol b/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol new file mode 100644 index 00000000..9b6cac9c --- /dev/null +++ b/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.17; + +import { IMessageRelay } from "../../interfaces/IMessageRelay.sol"; +import { SygmaReporter } from "./SygmaReporter.sol"; +import { Yaho } from "../../Yaho.sol"; + +contract SygmaMessageRelayer is SygmaReporter, IMessageRelay { + Yaho public immutable _yaho; + + event MessageRelayed(address indexed emitter, uint256 indexed messageId); + + constructor( + address bridge, + Yaho yaho, + bytes32 resourceID, + uint8 defaultDestinationDomainID, + address defaultSygmaAdapter, + bytes memory defaultFeeData + ) SygmaReporter(bridge, resourceID, defaultDestinationDomainID, defaultSygmaAdapter) { + _yaho = yaho; + } + + /** + @dev Relays the messages via the Sygma bridge to default domain. + @param messageIds IDs of the messages to pass over the Sygma bridge. + @param sygmaAdapter Address of the Sygma adapter on the target chain. + */ + function relayMessages(uint256[] memory messageIds, address sygmaAdapter) public payable returns (bytes32) { + bytes32[] memory hashes = new bytes32[](messageIds.length); + for (uint256 i = 0; i < messageIds.length; i++) { + uint256 id = messageIds[i]; + hashes[i] = _yaho.hashes(id); + emit MessageRelayed(address(this), messageIds[i]); + } + (uint64 depositNonce, ) = _reportData(messageIds, hashes, sygmaAdapter, _defaultDestinationDomainID, ""); + return bytes32(uint256(depositNonce)); + } +} diff --git a/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol new file mode 100644 index 00000000..df8db786 --- /dev/null +++ b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.17; + +import "./interfaces/ISygmaAdapter.sol"; +import "./interfaces/IBridge.sol"; + +contract SygmaReporter { + address public immutable _bridge; + bytes32 public immutable _resourceID; + uint8 public immutable _defaultDestinationDomainID; + address public immutable _defaultSygmaAdapter; + + constructor(address bridge, bytes32 resourceID, uint8 defaultDestinationDomainID, address defaultSygmaAdapter) { + _bridge = bridge; + _resourceID = resourceID; + _defaultDestinationDomainID = defaultDestinationDomainID; + _defaultSygmaAdapter = defaultSygmaAdapter; + } + + function _reportData( + uint256[] memory ids, + bytes32[] memory items, + address sygmaAdapter, + uint8 destinationDomainID, + bytes memory feeData + ) internal returns (uint64 depositNonce, bytes memory handlerResponse) { + bytes memory depositData = abi.encodePacked( + // uint256 maxFee + uint256(0), + // uint16 len(executeFuncSignature) + uint16(4), + // bytes executeFuncSignature + ISygmaAdapter(address(0)).storeHashes.selector, + // uint8 len(executeContractAddress) + uint8(20), + // bytes executeContractAddress + sygmaAdapter, + // uint8 len(executionDataDepositor) + uint8(20), + // bytes executionDataDepositor + address(this), + // bytes executionDataDepositor + executionData + prepareDepositData(ids, items) + ); + return IBridge(_bridge).deposit{ value: msg.value }(destinationDomainID, _resourceID, depositData, feeData); + } + + function slice(bytes calldata input, uint256 position) public pure returns (bytes memory) { + return input[position:]; + } + + function prepareDepositData( + uint256[] memory blockNumbers, + bytes32[] memory blockHeaders + ) public view returns (bytes memory) { + bytes memory encoded = abi.encode(address(0), blockNumbers, blockHeaders); + return this.slice(encoded, 32); + } +} diff --git a/packages/evm/contracts/adapters/Sygma/interfaces/IBridge.sol b/packages/evm/contracts/adapters/Sygma/interfaces/IBridge.sol index 3ab1faad..b3d81c1c 100644 --- a/packages/evm/contracts/adapters/Sygma/interfaces/IBridge.sol +++ b/packages/evm/contracts/adapters/Sygma/interfaces/IBridge.sol @@ -20,5 +20,5 @@ interface IBridge { bytes32 resourceID, bytes calldata depositData, bytes calldata feeData - ) external payable; + ) external payable returns (uint64 depositNonce, bytes memory handlerResponse); } diff --git a/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol b/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol index 719e56cc..1d8af2d3 100644 --- a/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol +++ b/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol @@ -18,7 +18,8 @@ contract MockSygmaBridge { bytes32 resourceID, bytes calldata depositData, bytes calldata feeData - ) external payable { + ) external payable returns (uint64 depositNonce, bytes memory handlerResponse) { emit Deposit(destinationDomainID, resourceID, 1, msg.sender, depositData, feeData); + return (1, bytes("2")); } } diff --git a/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts new file mode 100644 index 00000000..0da54770 --- /dev/null +++ b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts @@ -0,0 +1,110 @@ +import { expect } from "chai" +import { ethers, network } from "hardhat" + +const DOMAIN_ID = 5 +const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000500" + +const setup = async () => { + await network.provider.request({ method: "hardhat_reset", params: [] }) + const signers = await ethers.getSigners() + const sender = signers[0].address + const adapter = signers[1].address + const otherAddress = signers[2].address + const Yaho = await ethers.getContractFactory("Yaho") + const yaho = await Yaho.deploy() + const SygmaBridge = await ethers.getContractFactory("MockSygmaBridge") + const sygmaBridge = await SygmaBridge.deploy() + const SygmaMessageRelayer = await ethers.getContractFactory("SygmaMessageRelayer") + // IBridge bridge, HeaderStorage headerStorage, bytes32 resourceID, uint8 defaultDestinationDomainID, address defaultSygmaAdapter + const sygmaMessageRelayer = await SygmaMessageRelayer.deploy( + sygmaBridge.address, + yaho.address, + resourceID, + DOMAIN_ID, + adapter, + "0x00", + ) + const PingPong = await ethers.getContractFactory("PingPong") + const pingPong = await PingPong.deploy() + const message_1 = { + to: pingPong.address, + toChainId: 1, + data: pingPong.interface.getSighash("ping"), + } + await yaho.dispatchMessages([message_1, message_1]) + // await mine(10) + return { + sender, + adapter, + otherAddress, + yaho, + sygmaBridge, + sygmaMessageRelayer, + pingPong, + message_1, + } +} + +const prepareDepositData = async (reporterAddress: string, ids: string[], hashes: string[], adapter: string) => { + const abiCoder = ethers.utils.defaultAbiCoder + const executionData = abiCoder + .encode(["address", "uint256[]", "bytes32[]"], [ethers.constants.AddressZero, ids, hashes]) + .substring(66) + + const SygmaAdapter = await ethers.getContractFactory("SygmaAdapter") + const functionSig = SygmaAdapter.interface.getSighash("storeHashes") + + // bytes memory depositData = abi.encodePacked( + // uint256(0), + // uint16(4), + // IDepositAdapterTarget(address(0)).execute.selector, + // uint8(20), + // _targetDepositAdapter, + // uint8(20), + // _depositorAddress, + // abi.encode(depositContractCalldata) + // ); + + const depositData = + ethers.utils.hexZeroPad("0x0", 32) + + "0004" + + functionSig.substring(2) + + "14" + + adapter.toLowerCase().substring(2) + + "14" + + reporterAddress.toLowerCase().substring(2) + + executionData + return depositData +} + +describe("SygmaMessageRelayer", function () { + describe("Deploy", function () { + it("Successfully deploys contract", async function () { + const { sygmaBridge, yaho, adapter, sygmaMessageRelayer } = await setup() + expect(await sygmaMessageRelayer.deployed()) + expect(await sygmaMessageRelayer._bridge()).to.equal(sygmaBridge.address) + expect(await sygmaMessageRelayer._yaho()).to.equal(yaho.address) + expect(await sygmaMessageRelayer._resourceID()).to.equal(resourceID) + expect(await sygmaMessageRelayer._defaultDestinationDomainID()).to.equal(DOMAIN_ID) + expect(await sygmaMessageRelayer._defaultSygmaAdapter()).to.equal(adapter) + }) + }) + + describe("relayMessages()", function () { + it("Relays messages to Sygma to default domain", async function () { + const { sender, sygmaMessageRelayer, adapter, sygmaBridge, yaho, message_1 } = await setup() + const hash0 = await yaho.calculateHash(network.config.chainId, 0, yaho.address, sender, message_1) + const hash1 = await yaho.calculateHash(network.config.chainId, 1, yaho.address, sender, message_1) + const depositData = await prepareDepositData(sygmaMessageRelayer.address, ["0", "1"], [hash0, hash1], adapter) + await expect(sygmaMessageRelayer.callStatic.relayMessages([0, 1], adapter)).to.equal(2) + await expect(sygmaMessageRelayer.relayMessages([0, 1], adapter)) + .to.emit(sygmaMessageRelayer, "MessageRelayed") + .withArgs(sygmaMessageRelayer.address, 0) + .and.to.emit(sygmaMessageRelayer, "MessageRelayed") + .withArgs(sygmaMessageRelayer.address, 1) + .and.to.emit(sygmaBridge, "Deposit") + // (destinationDomainID, resourceID, 1, msg.sender, depositData, feeData); + .withArgs(DOMAIN_ID, resourceID, 1, sygmaMessageRelayer.address, depositData, "0x") + }) + }) +}) From a34126e90a498f80650c992a58160a11b58840c9 Mon Sep 17 00:00:00 2001 From: viatrix Date: Thu, 12 Oct 2023 09:21:27 +0300 Subject: [PATCH 2/3] fix: after review --- .../evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol | 3 +-- packages/evm/contracts/adapters/Sygma/SygmaReporter.sol | 7 ++----- .../evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts | 5 +++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol b/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol index 9b6cac9c..0f031a8f 100644 --- a/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol +++ b/packages/evm/contracts/adapters/Sygma/SygmaMessageRelayer.sol @@ -15,8 +15,7 @@ contract SygmaMessageRelayer is SygmaReporter, IMessageRelay { Yaho yaho, bytes32 resourceID, uint8 defaultDestinationDomainID, - address defaultSygmaAdapter, - bytes memory defaultFeeData + address defaultSygmaAdapter ) SygmaReporter(bridge, resourceID, defaultDestinationDomainID, defaultSygmaAdapter) { _yaho = yaho; } diff --git a/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol index df8db786..c04ad47e 100644 --- a/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol +++ b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol @@ -49,11 +49,8 @@ contract SygmaReporter { return input[position:]; } - function prepareDepositData( - uint256[] memory blockNumbers, - bytes32[] memory blockHeaders - ) public view returns (bytes memory) { - bytes memory encoded = abi.encode(address(0), blockNumbers, blockHeaders); + function prepareDepositData(uint256[] memory ids, bytes32[] memory items) public view returns (bytes memory) { + bytes memory encoded = abi.encode(address(0), ids, items); return this.slice(encoded, 32); } } diff --git a/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts index 0da54770..9caf0192 100644 --- a/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts +++ b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts @@ -22,7 +22,6 @@ const setup = async () => { resourceID, DOMAIN_ID, adapter, - "0x00", ) const PingPong = await ethers.getContractFactory("PingPong") const pingPong = await PingPong.deploy() @@ -96,7 +95,9 @@ describe("SygmaMessageRelayer", function () { const hash0 = await yaho.calculateHash(network.config.chainId, 0, yaho.address, sender, message_1) const hash1 = await yaho.calculateHash(network.config.chainId, 1, yaho.address, sender, message_1) const depositData = await prepareDepositData(sygmaMessageRelayer.address, ["0", "1"], [hash0, hash1], adapter) - await expect(sygmaMessageRelayer.callStatic.relayMessages([0, 1], adapter)).to.equal(2) + expect(await sygmaMessageRelayer.callStatic.relayMessages([0, 1], adapter)).to.equal( + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) await expect(sygmaMessageRelayer.relayMessages([0, 1], adapter)) .to.emit(sygmaMessageRelayer, "MessageRelayed") .withArgs(sygmaMessageRelayer.address, 0) From 8fc33e678f6acae910c2272568bc56e09e3089fd Mon Sep 17 00:00:00 2001 From: viatrix Date: Fri, 13 Oct 2023 16:56:24 +0300 Subject: [PATCH 3/3] fix: fixes and E2E test for Sygma --- .../adapters/Sygma/SygmaReporter.sol | 13 +- .../Sygma/test/SygmaTestContracts.sol | 53 ++++++++ .../Sygma/03_SygmaMessageRelayer.spec.ts | 27 ++-- .../test/adapters/Sygma/04_Sygma_E2E.spec.ts | 117 ++++++++++++++++++ 4 files changed, 196 insertions(+), 14 deletions(-) create mode 100644 packages/evm/test/adapters/Sygma/04_Sygma_E2E.spec.ts diff --git a/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol index c04ad47e..3d1841d9 100644 --- a/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol +++ b/packages/evm/contracts/adapters/Sygma/SygmaReporter.sol @@ -18,8 +18,8 @@ contract SygmaReporter { } function _reportData( - uint256[] memory ids, - bytes32[] memory items, + uint256[] memory messageIds, + bytes32[] memory hashes, address sygmaAdapter, uint8 destinationDomainID, bytes memory feeData @@ -40,7 +40,7 @@ contract SygmaReporter { // bytes executionDataDepositor address(this), // bytes executionDataDepositor + executionData - prepareDepositData(ids, items) + prepareDepositData(messageIds, hashes) ); return IBridge(_bridge).deposit{ value: msg.value }(destinationDomainID, _resourceID, depositData, feeData); } @@ -49,8 +49,11 @@ contract SygmaReporter { return input[position:]; } - function prepareDepositData(uint256[] memory ids, bytes32[] memory items) public view returns (bytes memory) { - bytes memory encoded = abi.encode(address(0), ids, items); + function prepareDepositData( + uint256[] memory messageIds, + bytes32[] memory hashes + ) public view returns (bytes memory) { + bytes memory encoded = abi.encode(address(0), messageIds, hashes); return this.slice(encoded, 32); } } diff --git a/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol b/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol index 1d8af2d3..4c1b7058 100644 --- a/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol +++ b/packages/evm/contracts/adapters/Sygma/test/SygmaTestContracts.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.17; import "../interfaces/IBridge.sol"; contract MockSygmaBridge { + error CallReverted(); + event Deposit( uint8 destinationDomainID, bytes32 resourceID, @@ -20,6 +22,57 @@ contract MockSygmaBridge { bytes calldata feeData ) external payable returns (uint64 depositNonce, bytes memory handlerResponse) { emit Deposit(destinationDomainID, resourceID, 1, msg.sender, depositData, feeData); + + bool success = _executeProposal(resourceID, depositData); + + if (!success) revert CallReverted(); + return (1, bytes("2")); } + + function _executeProposal(bytes32 resourceID, bytes calldata data) internal returns (bool success) { + uint16 lenExecuteFuncSignature; + bytes4 executeFuncSignature; + uint8 lenExecuteContractAddress; + address executeContractAddress; + uint8 lenExecutionDataDepositor; + address executionDataDepositor; + bytes memory executionData; + + lenExecuteFuncSignature = uint16(bytes2(data[32:34])); + executeFuncSignature = bytes4(data[34:34 + lenExecuteFuncSignature]); + lenExecuteContractAddress = uint8(bytes1(data[34 + lenExecuteFuncSignature:35 + lenExecuteFuncSignature])); + executeContractAddress = address( + uint160( + bytes20(data[35 + lenExecuteFuncSignature:35 + lenExecuteFuncSignature + lenExecuteContractAddress]) + ) + ); + lenExecutionDataDepositor = uint8( + bytes1( + data[35 + lenExecuteFuncSignature + lenExecuteContractAddress:36 + + lenExecuteFuncSignature + + lenExecuteContractAddress] + ) + ); + executionDataDepositor = address( + uint160( + bytes20( + data[36 + lenExecuteFuncSignature + lenExecuteContractAddress:36 + + lenExecuteFuncSignature + + lenExecuteContractAddress + + lenExecutionDataDepositor] + ) + ) + ); + executionData = bytes( + data[36 + lenExecuteFuncSignature + lenExecuteContractAddress + lenExecutionDataDepositor:] + ); + + bytes memory callData = abi.encodePacked( + executeFuncSignature, + abi.encode(executionDataDepositor), + executionData + ); + (success, ) = executeContractAddress.call(callData); + } } diff --git a/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts index 9caf0192..ee9b00a8 100644 --- a/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts +++ b/packages/evm/test/adapters/Sygma/03_SygmaMessageRelayer.spec.ts @@ -8,21 +8,25 @@ const setup = async () => { await network.provider.request({ method: "hardhat_reset", params: [] }) const signers = await ethers.getSigners() const sender = signers[0].address - const adapter = signers[1].address const otherAddress = signers[2].address const Yaho = await ethers.getContractFactory("Yaho") const yaho = await Yaho.deploy() const SygmaBridge = await ethers.getContractFactory("MockSygmaBridge") const sygmaBridge = await SygmaBridge.deploy() const SygmaMessageRelayer = await ethers.getContractFactory("SygmaMessageRelayer") + const SygmaAdapter = await ethers.getContractFactory("SygmaAdapter") + const sygmaAdapter = await SygmaAdapter.deploy(sygmaBridge.address) // IBridge bridge, HeaderStorage headerStorage, bytes32 resourceID, uint8 defaultDestinationDomainID, address defaultSygmaAdapter const sygmaMessageRelayer = await SygmaMessageRelayer.deploy( sygmaBridge.address, yaho.address, resourceID, DOMAIN_ID, - adapter, + sygmaAdapter.address, ) + + await sygmaAdapter.setReporter(sygmaMessageRelayer.address, DOMAIN_ID, true) + const PingPong = await ethers.getContractFactory("PingPong") const pingPong = await PingPong.deploy() const message_1 = { @@ -34,7 +38,7 @@ const setup = async () => { // await mine(10) return { sender, - adapter, + sygmaAdapter, otherAddress, yaho, sygmaBridge, @@ -79,26 +83,31 @@ const prepareDepositData = async (reporterAddress: string, ids: string[], hashes describe("SygmaMessageRelayer", function () { describe("Deploy", function () { it("Successfully deploys contract", async function () { - const { sygmaBridge, yaho, adapter, sygmaMessageRelayer } = await setup() + const { sygmaBridge, yaho, sygmaAdapter, sygmaMessageRelayer } = await setup() expect(await sygmaMessageRelayer.deployed()) expect(await sygmaMessageRelayer._bridge()).to.equal(sygmaBridge.address) expect(await sygmaMessageRelayer._yaho()).to.equal(yaho.address) expect(await sygmaMessageRelayer._resourceID()).to.equal(resourceID) expect(await sygmaMessageRelayer._defaultDestinationDomainID()).to.equal(DOMAIN_ID) - expect(await sygmaMessageRelayer._defaultSygmaAdapter()).to.equal(adapter) + expect(await sygmaMessageRelayer._defaultSygmaAdapter()).to.equal(sygmaAdapter.address) }) }) describe("relayMessages()", function () { it("Relays messages to Sygma to default domain", async function () { - const { sender, sygmaMessageRelayer, adapter, sygmaBridge, yaho, message_1 } = await setup() + const { sender, sygmaMessageRelayer, sygmaAdapter, sygmaBridge, yaho, message_1 } = await setup() const hash0 = await yaho.calculateHash(network.config.chainId, 0, yaho.address, sender, message_1) const hash1 = await yaho.calculateHash(network.config.chainId, 1, yaho.address, sender, message_1) - const depositData = await prepareDepositData(sygmaMessageRelayer.address, ["0", "1"], [hash0, hash1], adapter) - expect(await sygmaMessageRelayer.callStatic.relayMessages([0, 1], adapter)).to.equal( + const depositData = await prepareDepositData( + sygmaMessageRelayer.address, + ["0", "1"], + [hash0, hash1], + sygmaAdapter.address, + ) + expect(await sygmaMessageRelayer.callStatic.relayMessages([0, 1], sygmaAdapter.address)).to.equal( "0x0000000000000000000000000000000000000000000000000000000000000001", ) - await expect(sygmaMessageRelayer.relayMessages([0, 1], adapter)) + await expect(sygmaMessageRelayer.relayMessages([0, 1], sygmaAdapter.address)) .to.emit(sygmaMessageRelayer, "MessageRelayed") .withArgs(sygmaMessageRelayer.address, 0) .and.to.emit(sygmaMessageRelayer, "MessageRelayed") diff --git a/packages/evm/test/adapters/Sygma/04_Sygma_E2E.spec.ts b/packages/evm/test/adapters/Sygma/04_Sygma_E2E.spec.ts new file mode 100644 index 00000000..f3075455 --- /dev/null +++ b/packages/evm/test/adapters/Sygma/04_Sygma_E2E.spec.ts @@ -0,0 +1,117 @@ +/* +Note that these E2E tests simulate cross-chain interactions but, +for the sake of convenience, use only one network as both the origin and destination chain. + +*/ +import { expect } from "chai" +import { ethers, network } from "hardhat" + +// Source chain ID +const CHAIN_ID = network.config.chainId +// Destination domain ID +const DOMAIN_ID = 5 +const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000500" + +const ID_ZERO = 0 + +const baseSetup = async () => { + const [wallet] = await ethers.getSigners() + + // deploy hashi + const Hashi = await ethers.getContractFactory("Hashi") + const hashi = await Hashi.deploy() + + // deploy ShoyuBashi + const ShoyuBashi = await ethers.getContractFactory("ShoyuBashi") + const shoyuBashi = ShoyuBashi.deploy(wallet.address, hashi.address) + + // deploy Yaho + const Yaho = await ethers.getContractFactory("Yaho") + const yaho = await Yaho.deploy() + + // deploy Mock Sygma Bridge + const SygmaBridge = await ethers.getContractFactory("MockSygmaBridge") + const sygmaBridge = await SygmaBridge.deploy() + + // deploy Sygma Adapter + const SygmaAdapter = await ethers.getContractFactory("SygmaAdapter") + const sygmaAdapter = await SygmaAdapter.deploy(sygmaBridge.address) + + // deploy Sygma Message Relayer + const SygmaMessageRelayer = await ethers.getContractFactory("SygmaMessageRelayer") + const sygmaMessageRelayer = await SygmaMessageRelayer.deploy( + sygmaBridge.address, + yaho.address, + resourceID, + DOMAIN_ID, + sygmaAdapter.address, + ) + + await sygmaAdapter.setReporter(sygmaMessageRelayer.address, CHAIN_ID, true) + + // deploy Yaru + const Yaru = await ethers.getContractFactory("Yaru") + const yaru = await Yaru.deploy(hashi.address, yaho.address, CHAIN_ID) + + // deploy avatar + const Avatar = await ethers.getContractFactory("TestAvatar") + const avatar = await Avatar.deploy() + + // const deploy PingPong test contract + const PingPong = await ethers.getContractFactory("PingPong") + const pingPong = await PingPong.deploy() + + return { + avatar, + sygmaBridge, + sygmaMessageRelayer, + sygmaAdapter, + wallet, + hashi, + shoyuBashi, + yaho, + yaru, + pingPong, + } +} + +const setupTestWithTestAvatar = async () => { + const base = await baseSetup() + const Module = await ethers.getContractFactory("HashiModule") + const provider = await ethers.getDefaultProvider() + const network = await provider.getNetwork() + const module = await Module.deploy( + base.avatar.address, + base.avatar.address, + base.avatar.address, + base.yaru.address, + base.wallet.address, + CHAIN_ID, + ) + await base.avatar.setModule(module.address) + return { ...base, Module, module, network } +} + +describe("SygmaMessageRelayer End-to-End", function () { + describe("executeTransaction()", function () { + it("executes a transaction", async () => { + const { pingPong, yaho, sygmaMessageRelayer, sygmaAdapter, module, wallet, yaru } = + await setupTestWithTestAvatar() + const calldata = await pingPong.interface.encodeFunctionData("ping", []) + const tx = await module.interface.encodeFunctionData("executeTransaction", [pingPong.address, 0, calldata, 0]) + const message = { + to: module.address, + toChainId: DOMAIN_ID, + data: tx, + } + const pingCount = await pingPong.count() + + // dispatch message + await yaho.dispatchMessagesToAdapters([message], [sygmaMessageRelayer.address], [sygmaAdapter.address]) + // execute messages + await yaru.executeMessages([message], [ID_ZERO], [wallet.address], [sygmaAdapter.address]) + + expect(await pingPong.count()).to.equal(pingCount + 1) + }) + }) +})