Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SC-148] Add Gnosis Chain domain #3

Merged
merged 9 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/forge-std
Submodule forge-std updated 2 files
+450 −285 src/Vm.sol
+15 −0 test/Vm.t.sol
117 changes: 117 additions & 0 deletions src/GnosisDomain.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
pragma solidity >=0.8.0;

import { Vm } from "forge-std/Vm.sol";
import { StdChains } from "forge-std/StdChains.sol";

import { Domain, BridgedDomain } from "./BridgedDomain.sol";
import { RecordedLogs } from "./RecordedLogs.sol";

interface IAMB {
function requireToPassMessage(address, bytes memory, uint256) external returns (bytes32);
function validatorContract() external view returns (address);
}

interface IHomeAMB is IAMB {
function executeAffirmation(bytes memory) external;
}

interface IForeignAMB is IAMB {
function executeSignatures(bytes memory, bytes memory) external;
}

interface IValidatorContract {
function validatorList() external view returns (address[] memory);
function requiredSignatures() external view returns (uint256);
}

contract GnosisDomain is BridgedDomain {

bytes32 private constant USER_REQUEST_FOR_AFFIRMATION_TOPIC = keccak256("UserRequestForAffirmation(bytes32,bytes)");
bytes32 private constant USER_REQUEST_FOR_SIGNATURE_TOPIC = keccak256("UserRequestForSignature(bytes32,bytes)");

IForeignAMB public L1_AMB_CROSS_DOMAIN_MESSENGER;
IHomeAMB public L2_AMB_CROSS_DOMAIN_MESSENGER;

uint256 internal lastFromHostLogIndex;
uint256 internal lastToHostLogIndex;

constructor(StdChains.Chain memory _chain, Domain _hostDomain) Domain(_chain) BridgedDomain(_hostDomain) {
bytes32 name = keccak256(bytes(_chain.chainAlias));
if (name == keccak256("gnosis_chain")) {
L1_AMB_CROSS_DOMAIN_MESSENGER = IForeignAMB(0x4C36d2919e407f0Cc2Ee3c993ccF8ac26d9CE64e);
L2_AMB_CROSS_DOMAIN_MESSENGER = IHomeAMB(0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59);
} else if (name == keccak256("chiado")) {
L1_AMB_CROSS_DOMAIN_MESSENGER = IForeignAMB(0x87A19d769D875964E9Cd41dDBfc397B2543764E6);
L2_AMB_CROSS_DOMAIN_MESSENGER = IHomeAMB(0x99Ca51a3534785ED619f46A79C7Ad65Fa8d85e7a);
} else {
revert("Unsupported chain");
}

hostDomain.selectFork();

// Set minimum required signatures on L1 to 0
IValidatorContract validatorContract = IValidatorContract(L1_AMB_CROSS_DOMAIN_MESSENGER.validatorContract());
vm.store(
address(validatorContract),
0x8a247e09a5673bd4d93a4e76d8fb9553523aa0d77f51f3d576e7421f5295b9bc,
0
);

vm.recordLogs();
}

function relayFromHost(bool switchToGuest) external override {
selectFork(); // switch to Gnosis domain

Vm.Log[] memory logs = RecordedLogs.getLogs();
for (; lastFromHostLogIndex < logs.length; lastFromHostLogIndex++) {
Vm.Log memory log = logs[lastFromHostLogIndex];
if (
log.topics[0] == USER_REQUEST_FOR_AFFIRMATION_TOPIC
&& log.emitter == address(L1_AMB_CROSS_DOMAIN_MESSENGER)
) {
IValidatorContract validatorContract = IValidatorContract(L2_AMB_CROSS_DOMAIN_MESSENGER.validatorContract());
address[] memory validators = validatorContract.validatorList();
uint256 requiredSignatures = validatorContract.requiredSignatures();
bytes memory messageToRelay = removeFirst64Bytes(log.data);
for (uint256 i = 0; i < requiredSignatures; i++) {
vm.prank(validators[i]);
L2_AMB_CROSS_DOMAIN_MESSENGER.executeAffirmation(messageToRelay);
}
}
}

if (!switchToGuest) {
hostDomain.selectFork();
}
}

function relayToHost(bool switchToHost) external override {
hostDomain.selectFork();

Vm.Log[] memory logs = RecordedLogs.getLogs();
for (; lastToHostLogIndex < logs.length; lastToHostLogIndex++) {
Vm.Log memory log = logs[lastToHostLogIndex];
if (
log.topics[0] == USER_REQUEST_FOR_SIGNATURE_TOPIC
&& log.emitter == address(L2_AMB_CROSS_DOMAIN_MESSENGER)
) {
bytes memory messageToRelay = removeFirst64Bytes(log.data);
L1_AMB_CROSS_DOMAIN_MESSENGER.executeSignatures(messageToRelay, abi.encodePacked(uint256(0)));
}
}

if (!switchToHost) {
selectFork();
}
}

function removeFirst64Bytes(bytes memory inputData) public pure returns (bytes memory) {
bytes memory returnValue = new bytes(inputData.length - 64);
for (uint256 i = 0; i < inputData.length - 64; i++) {
returnValue[i] = inputData[i + 64];
}
return returnValue;
}
barrutko marked this conversation as resolved.
Show resolved Hide resolved

}
66 changes: 66 additions & 0 deletions test/Integration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "forge-std/Test.sol";
import { Domain } from "../src/Domain.sol";
import { OptimismDomain } from "../src/OptimismDomain.sol";
import { ArbitrumDomain, ArbSysOverride } from "../src/ArbitrumDomain.sol";
import { GnosisDomain } from "../src/GnosisDomain.sol";

contract MessageOrdering {

Expand Down Expand Up @@ -73,6 +74,16 @@ contract IntegrationTest is Test {
checkArbitrumStyle(new ArbitrumDomain(getChain("arbitrum_nova"), mainnet));
}

function test_gnosisChain() public {
checkGnosisStyle(new GnosisDomain(getChain('gnosis_chain'), mainnet));
}

function test_chiado() public {
setChain("chiado", ChainData("Chiado", 10200, "https://rpc.chiadochain.net"));

checkGnosisStyle(new GnosisDomain(getChain('chiado'), goerli));
}

function checkOptimismStyle(OptimismDomain optimism) public {
Domain host = optimism.hostDomain();

Expand Down Expand Up @@ -191,4 +202,59 @@ contract IntegrationTest is Test {
assertEq(moHost.messages(1), 4);
}

function checkGnosisStyle(GnosisDomain gnosis) public {
Domain host = gnosis.hostDomain();

host.selectFork();

MessageOrdering moHost = new MessageOrdering();

gnosis.selectFork();

MessageOrdering moGnosis = new MessageOrdering();

// Queue up some L2 -> L1 messages
gnosis.L2_AMB_CROSS_DOMAIN_MESSENGER().requireToPassMessage(
address(moHost),
abi.encodeWithSelector(MessageOrdering.push.selector, 3),
100000
);
gnosis.L2_AMB_CROSS_DOMAIN_MESSENGER().requireToPassMessage(
address(moHost),
abi.encodeWithSelector(MessageOrdering.push.selector, 4),
100000
);

assertEq(moGnosis.length(), 0);

// Do not relay right away
host.selectFork();

// Queue up two more L1 -> L2 messages
gnosis.L1_AMB_CROSS_DOMAIN_MESSENGER().requireToPassMessage(
address(moGnosis),
abi.encodeWithSelector(MessageOrdering.push.selector, 1),
100000
);
gnosis.L1_AMB_CROSS_DOMAIN_MESSENGER().requireToPassMessage(
address(moGnosis),
abi.encodeWithSelector(MessageOrdering.push.selector, 2),
100000
);

assertEq(moHost.length(), 0);

gnosis.relayFromHost(true);

assertEq(moGnosis.length(), 2);
assertEq(moGnosis.messages(0), 1);
assertEq(moGnosis.messages(1), 2);

gnosis.relayToHost(true);

assertEq(moHost.length(), 2);
assertEq(moHost.messages(0), 3);
assertEq(moHost.messages(1), 4);

}
}