Run forge tests in CI (#1355)

* Move foundry workflow so it is picked up by github

* Require ISM in router config

Co-authored-by: Asa Oines <asaoines@gmail.com>
pull/1378/head
Yorke Rhodes 2 years ago committed by GitHub
parent 5b5ce88b72
commit c25cd842b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .github/workflows/node.yml
  2. 4
      solidity/contracts/HyperlaneConnectionClient.sol
  3. 2
      solidity/contracts/Mailbox.sol
  4. 16
      solidity/contracts/middleware/InterchainAccountRouter.sol
  5. 16
      solidity/contracts/middleware/InterchainQueryRouter.sol
  6. 8
      solidity/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol
  7. 21
      solidity/contracts/mock/MockHyperlaneEnvironment.sol
  8. 4
      solidity/contracts/test/TestSendReceiver.sol
  9. 26
      solidity/lib/forge-std/.github/workflows/tests.yml
  10. 2
      solidity/package.json
  11. 35
      solidity/test/InterchainAccountRouter.t.sol
  12. 13
      solidity/test/LiquidityLayerRouter.t.sol
  13. 21
      solidity/test/Messaging.t.sol
  14. 21
      typescript/sdk/src/core/TestCoreDeployer.ts
  15. 6
      typescript/sdk/src/deploy/middleware/LiquidityLayerRouterDeployer.ts
  16. 12
      typescript/sdk/src/deploy/middleware/deploy.ts
  17. 2
      typescript/sdk/src/router.ts

@ -106,5 +106,13 @@ jobs:
path: ./*
key: ${{ github.sha }}
- name: Install Foundry
uses: onbjerg/foundry-toolchain@v1
with:
version: nightly
- name: Install dependencies
run: cd solidity && forge install
- name: core
run: yarn workspace @hyperlane-xyz/core run test

@ -18,7 +18,7 @@ abstract contract HyperlaneConnectionClient is
IMailbox public mailbox;
// Interchain Gas Paymaster contract. The relayer associated with this contract
// must be willing to relay messages dispatched from the current Outbox contract,
// must be willing to relay messages dispatched from the current Mailbox contract,
// otherwise payments made to the paymaster will not result in relayed messages.
IInterchainGasPaymaster public interchainGasPaymaster;
@ -136,7 +136,7 @@ abstract contract HyperlaneConnectionClient is
}
/**
* @notice Modify the contract the Application uses to validate Inbox contracts
* @notice Modify the contract the Application uses to validate Mailbox contracts
* @param _mailbox The address of the mailbox contract
*/
function _setMailbox(address _mailbox) internal onlyContract(_mailbox) {

@ -211,7 +211,7 @@ contract Mailbox is
/**
* @notice Returns a checkpoint representing the current merkle tree.
* @return root The root of the Outbox's merkle tree.
* @return root The root of the Mailbox's merkle tree.
* @return index The index of the last element in the tree.
*/
function latestCheckpoint() public view returns (bytes32, uint32) {

@ -26,16 +26,16 @@ contract InterchainAccountRouter is Router, IInterchainAccountRouter {
);
function initialize(
address _owner,
address _mailbox,
address _interchainGasPaymaster
address _interchainGasPaymaster,
address _interchainSecurityModule
) public initializer {
// Transfer ownership of the contract to deployer
_transferOwnership(_owner);
// Set the addresses for the Mailbox and IGP
// Alternatively, this could be done later in an initialize method
_setMailbox(_mailbox);
_setInterchainGasPaymaster(_interchainGasPaymaster);
// Transfer ownership of the contract to `msg.sender`
__HyperlaneConnectionClient_initialize(
_mailbox,
_interchainGasPaymaster,
_interchainSecurityModule
);
}
function dispatch(uint32 _destinationDomain, Call[] calldata calls)

@ -32,16 +32,16 @@ contract InterchainQueryRouter is
);
function initialize(
address _owner,
address _mailbox,
address _interchainGasPaymaster
address _interchainGasPaymaster,
address _interchainSecurityModule
) public initializer {
// Transfer ownership of the contract to deployer
_transferOwnership(_owner);
// Set the addresses for the Mailbox and IGP
// Alternatively, this could be done later in an initialize method
_setMailbox(_mailbox);
_setInterchainGasPaymaster(_interchainGasPaymaster);
// Transfer ownership of the contract to `msg.sender`
__HyperlaneConnectionClient_initialize(
_mailbox,
_interchainGasPaymaster,
_interchainSecurityModule
);
}
/**

@ -20,15 +20,15 @@ contract LiquidityLayerRouter is Router {
event LiquidityLayerAdapterSet(string indexed bridge, address adapter);
function initialize(
address _owner,
address _mailbox,
address _interchainGasPaymaster
address _interchainGasPaymaster,
address _interchainSecurityModule
) public initializer {
__HyperlaneConnectionClient_initialize(
_mailbox,
_interchainGasPaymaster
_interchainGasPaymaster,
_interchainSecurityModule
);
_transferOwnership(_owner);
}
function dispatchWithTokens(

@ -3,6 +3,8 @@ pragma solidity ^0.8.13;
import "./MockMailbox.sol";
import "../middleware/InterchainQueryRouter.sol";
import "../InterchainGasPaymaster.sol";
import "../test/TestIsm.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
@ -11,6 +13,8 @@ contract MockHyperlaneEnvironment {
uint32 destinationDomain;
mapping(uint32 => MockMailbox) public mailboxes;
mapping(uint32 => InterchainGasPaymaster) public igps;
mapping(uint32 => IInterchainSecurityModule) public isms;
mapping(uint32 => InterchainQueryRouter) public queryRouters;
constructor(uint32 _originDomain, uint32 _destinationDomain) {
@ -20,6 +24,15 @@ contract MockHyperlaneEnvironment {
MockMailbox originMailbox = new MockMailbox(_originDomain);
MockMailbox destinationMailbox = new MockMailbox(_destinationDomain);
originMailbox.addRemoteMailbox(_destinationDomain, destinationMailbox);
destinationMailbox.addRemoteMailbox(_originDomain, originMailbox);
igps[originDomain] = new InterchainGasPaymaster();
igps[destinationDomain] = new InterchainGasPaymaster();
isms[originDomain] = new TestIsm();
isms[destinationDomain] = new TestIsm();
mailboxes[_originDomain] = originMailbox;
mailboxes[_destinationDomain] = destinationMailbox;
@ -27,14 +40,14 @@ contract MockHyperlaneEnvironment {
InterchainQueryRouter destinationQueryRouter = new InterchainQueryRouter();
originQueryRouter.initialize(
address(this),
address(originMailbox),
address(0)
address(igps[originDomain]),
address(isms[originDomain])
);
destinationQueryRouter.initialize(
address(this),
address(destinationMailbox),
address(0)
address(igps[destinationDomain]),
address(isms[destinationDomain])
);
originQueryRouter.enrollRemoteRouter(

@ -15,12 +15,12 @@ contract TestSendReceiver is IMessageRecipient {
event Handled(bytes32 blockHash);
function dispatchToSelf(
IMailbox _outbox,
IMailbox _mailbox,
IInterchainGasPaymaster _paymaster,
uint32 _destinationDomain,
bytes calldata _messageBody
) external payable {
bytes32 _messageId = _outbox.dispatch(
bytes32 _messageId = _mailbox.dispatch(
_destinationDomain,
address(this).addressToBytes32(),
_messageBody

@ -1,26 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
check:
name: Foundry project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install Foundry
uses: onbjerg/foundry-toolchain@v1
with:
version: nightly
- name: Install dependencies
run: forge install
- name: Run tests
run: forge test -vvv
- name: Build Test with older solc versions
run: |
forge build --contracts src/Test.sol --use solc:0.8.0
forge build --contracts src/Test.sol --use solc:0.7.0
forge build --contracts src/Test.sol --use solc:0.6.0

@ -47,7 +47,7 @@
"clean": "hardhat clean && rm -rf ./dist ./cache",
"coverage": "hardhat coverage",
"prettier": "prettier --write ./contracts ./interfaces ./test",
"test": "hardhat test"
"test": "hardhat test && forge test -vvv"
},
"types": "dist/index.d.ts"
}

@ -2,17 +2,16 @@
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../contracts/mock/MockOutbox.sol";
import "../contracts/mock/MockInbox.sol";
import "../contracts/AbacusConnectionManager.sol";
import "../contracts/mock/MockMailbox.sol";
import "../contracts/HyperlaneConnectionClient.sol";
import "../contracts/mock/MockHyperlaneEnvironment.sol";
import {TypeCasts} from "../contracts/libs/TypeCasts.sol";
import "../contracts/test/TestRecipient.sol";
import "../contracts/middleware/InterchainAccountRouter.sol";
import {OwnableMulticall, Call} from "../contracts/OwnableMulticall.sol";
contract InterchainAccountRouterTest is Test {
MockOutbox outbox;
MockInbox inbox;
MockHyperlaneEnvironment environment;
uint32 originDomain = 1;
uint32 remoteDomain = 2;
@ -20,20 +19,10 @@ contract InterchainAccountRouterTest is Test {
InterchainAccountRouter originRouter;
InterchainAccountRouter remoteRouter;
AbacusConnectionManager originManager;
AbacusConnectionManager remoteManager;
TestRecipient recipient;
function setUp() public {
inbox = new MockInbox();
outbox = new MockOutbox(originDomain, address(inbox));
originManager = new AbacusConnectionManager();
remoteManager = new AbacusConnectionManager();
originManager.setOutbox(address(outbox));
remoteManager.enrollInbox(remoteDomain, address(inbox));
environment = new MockHyperlaneEnvironment(originDomain, remoteDomain);
recipient = new TestRecipient();
@ -41,14 +30,14 @@ contract InterchainAccountRouterTest is Test {
remoteRouter = new InterchainAccountRouter();
originRouter.initialize(
address(this),
address(originManager),
address(0)
address(environment.mailboxes(originDomain)),
address(environment.igps(originDomain)),
address(environment.isms(originDomain))
);
remoteRouter.initialize(
address(this),
address(remoteManager),
address(0)
address(environment.mailboxes(remoteDomain)),
address(environment.igps(remoteDomain)),
address(environment.isms(remoteDomain))
);
originRouter.enrollRemoteRouter(
@ -68,7 +57,7 @@ contract InterchainAccountRouterTest is Test {
data: abi.encodeCall(recipient.fooBar, (1, "Test"))
});
originRouter.dispatch(remoteDomain, calls);
inbox.processNextPendingMessage();
environment.processNextPendingMessage();
assertEq(recipient.lastCallMessage(), "Test");
}
}

@ -53,16 +53,15 @@ contract LiquidityLayerRouterTest is Test {
destinationDomain
);
// TODO: set IGP?
originLiquidityLayerRouter.initialize(
address(this),
address(testEnvironment.connectionManager(originDomain)),
address(0)
address(testEnvironment.mailboxes(originDomain)),
address(testEnvironment.igps(originDomain)),
address(testEnvironment.isms(originDomain))
);
destinationLiquidityLayerRouter.initialize(
address(this),
address(testEnvironment.connectionManager(destinationDomain)),
address(0)
address(testEnvironment.mailboxes(destinationDomain)),
address(testEnvironment.igps(destinationDomain)),
address(testEnvironment.isms(destinationDomain))
);
originLiquidityLayerRouter.enrollRemoteRouter(

@ -2,16 +2,16 @@
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../contracts/mock/MockOutbox.sol";
import "../contracts/mock/MockInbox.sol";
import "../contracts/mock/MockMailbox.sol";
import "../contracts/mock/MockMailbox.sol";
import "../contracts/test/TestRecipient.sol";
import "../interfaces/IInbox.sol";
import "../interfaces/IOutbox.sol";
import "../interfaces/IMailbox.sol";
import "../interfaces/IMailbox.sol";
import {TypeCasts} from "../contracts/libs/TypeCasts.sol";
contract MessagingTest is Test {
MockOutbox outbox;
MockInbox inbox;
MockMailbox originMailbox;
MockMailbox remoteMailbox;
TestRecipient receiver;
@ -19,19 +19,20 @@ contract MessagingTest is Test {
uint32 remoteDomain = 2;
function setUp() public {
inbox = new MockInbox();
outbox = new MockOutbox(originDomain, address(inbox));
originMailbox = new MockMailbox(originDomain);
remoteMailbox = new MockMailbox(remoteDomain);
originMailbox.addRemoteMailbox(remoteDomain, remoteMailbox);
receiver = new TestRecipient();
}
function testSendMessage(string calldata _message) public {
outbox.dispatch(
originMailbox.dispatch(
remoteDomain,
TypeCasts.addressToBytes32(address(receiver)),
bytes(_message)
);
inbox.processNextPendingMessage();
remoteMailbox.processNextInboundMessage();
assertEq(string(receiver.lastData()), _message);
}
}

@ -1,10 +1,12 @@
import { ethers } from 'ethers';
import {
MultisigIsm,
TestIsm__factory,
TestMailbox,
TestMailbox__factory,
} from '@hyperlane-xyz/core';
import { types } from '@hyperlane-xyz/utils';
import { chainMetadata } from '../consts/chainMetadata';
import { HyperlaneCoreDeployer } from '../deploy/core/HyperlaneCoreDeployer';
@ -51,12 +53,10 @@ export class TestCoreDeployer<
super(multiProvider, configs, testCoreFactories);
}
// skip proxying
async deployMailbox<LocalChain extends TestChain>(
// deploy a test ISM in place of a multisig ISM
async deployMultisigIsm<LocalChain extends TestChain>(
chain: LocalChain,
): Promise<ProxiedContract<TestMailbox, BeaconProxyAddresses>> {
const localDomain = chainMetadata[chain].id;
): Promise<MultisigIsm> {
const testIsm = await this.deployContractFromFactory(
chain,
testCoreFactories.testIsm,
@ -64,9 +64,18 @@ export class TestCoreDeployer<
[],
);
await testIsm.setAccept(true);
return testIsm as unknown as MultisigIsm;
}
// skip proxying
async deployMailbox<LocalChain extends TestChain>(
chain: LocalChain,
defaultIsmAddress: types.Address,
): Promise<ProxiedContract<TestMailbox, BeaconProxyAddresses>> {
const localDomain = chainMetadata[chain].id;
const mailbox = await this.deployContract(chain, 'mailbox', [localDomain]);
await mailbox.initialize(testIsm.address);
await mailbox.initialize(defaultIsmAddress);
return new ProxiedContract(mailbox, {
kind: ProxyKind.UpgradeBeacon,
proxy: mailbox.address,

@ -80,7 +80,11 @@ export class LiquidityLayerDeployer<
const initCalldata =
LiquidityLayerRouter__factory.createInterface().encodeFunctionData(
'initialize',
[config.owner, config.mailbox, config.interchainGasPaymaster],
[
config.mailbox,
config.interchainGasPaymaster,
config.interchainSecurityModule,
],
);
const router = await this.deployContract(chain, 'router', [], {
create2Salt: this.create2salt,

@ -45,7 +45,11 @@ export class InterchainAccountDeployer<
const initCalldata =
InterchainAccountRouter__factory.createInterface().encodeFunctionData(
'initialize',
[config.owner, config.mailbox, config.interchainGasPaymaster],
[
config.mailbox,
config.interchainGasPaymaster,
config.interchainSecurityModule,
],
);
const router = await this.deployContract(chain, 'router', [], {
create2Salt: this.create2salt + 'router',
@ -86,7 +90,11 @@ export class InterchainQueryDeployer<
const initCalldata =
InterchainQueryRouter__factory.createInterface().encodeFunctionData(
'initialize',
[config.owner, config.mailbox, config.interchainGasPaymaster],
[
config.mailbox,
config.interchainGasPaymaster,
config.interchainSecurityModule,
],
);
const router = await this.deployContract(chain, 'router', [], {
create2Salt: this.create2salt + 'router',

@ -23,7 +23,7 @@ export type RouterFactories<RouterContract extends Router = Router> =
export type ConnectionClientConfig = {
mailbox: types.Address;
interchainGasPaymaster: types.Address;
interchainSecurityModule?: types.Address;
interchainSecurityModule: types.Address;
};
export { Router } from '@hyperlane-xyz/core';

Loading…
Cancel
Save