The home for Hyperlane core contracts, sdk packages, and other infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
hyperlane-monorepo/solidity/abacus-core/test/outbox.test.ts

130 lines
3.9 KiB

import { ethers, abacus } from 'hardhat';
import { expect } from 'chai';
import { AbacusState, Validator } from './lib/core';
import { Signer } from './lib/types';
import { TestOutbox, TestOutbox__factory } from '../typechain';
const destinationNonceTestCases = require('../../../vectors/destinationNonce.json');
const localDomain = 1000;
const destDomain = 2000;
const nullAddress: string = '0x' + '00'.repeat(32);
describe('Outbox', async () => {
let outbox: TestOutbox, signer: Signer, recipient: Signer;
before(async () => {
[signer, recipient] = await ethers.getSigners();
});
beforeEach(async () => {
// redeploy the outbox before each test run
const outboxFactory = new TestOutbox__factory(signer);
outbox = await outboxFactory.deploy(localDomain);
// The ValidatorManager is unused in these tests *but* needs to be a
// contract.
await outbox.initialize(outbox.address);
});
it('Cannot be initialized twice', async () => {
await expect(outbox.initialize(outbox.address)).to.be.revertedWith(
'Initializable: contract is already initialized',
);
});
it('ValidatorManager can fail', async () => {
await outbox.testSetValidatorManager(signer.address);
await outbox.fail();
expect(await outbox.state()).to.equal(AbacusState.FAILED);
const message = ethers.utils.formatBytes32String('message');
await expect(
outbox.dispatch(
destDomain,
abacus.ethersAddressToBytes32(recipient.address),
message,
),
).to.be.revertedWith('failed state');
});
it('Non ValidatorManager cannot fail', async () => {
await expect(outbox.connect(recipient).fail()).to.be.revertedWith(
'!validatorManager',
);
});
it('Does not dispatch too large messages', async () => {
const message = `0x${Buffer.alloc(3000).toString('hex')}`;
await expect(
outbox.dispatch(
destDomain,
abacus.ethersAddressToBytes32(recipient.address),
message,
),
).to.be.revertedWith('msg too long');
});
it('Dispatches a message', async () => {
const message = ethers.utils.formatBytes32String('message');
const nonce = await outbox.nonces(localDomain);
// Format data that will be emitted from Dispatch event
const destinationAndNonce = abacus.destinationAndNonce(destDomain, nonce);
const abacusMessage = abacus.formatMessage(
localDomain,
signer.address,
nonce,
destDomain,
recipient.address,
message,
);
const messageHash = abacus.messageHash(abacusMessage);
const leafIndex = await outbox.tree();
const [checkpointedRoot] = await outbox.latestCheckpoint();
// Send message with signer address as msg.sender
await expect(
outbox
.connect(signer)
.dispatch(
destDomain,
abacus.ethersAddressToBytes32(recipient.address),
message,
),
)
.to.emit(outbox, 'Dispatch')
.withArgs(
messageHash,
leafIndex,
destinationAndNonce,
checkpointedRoot,
abacusMessage,
);
});
it('Checkpoints the latest root', async () => {
const message = ethers.utils.formatBytes32String('message');
await outbox.dispatch(
destDomain,
abacus.ethersAddressToBytes32(recipient.address),
message,
);
await outbox.checkpoint();
const [root, index] = await outbox.latestCheckpoint();
expect(root).to.not.equal(nullAddress);
expect(index).to.equal(1);
});
it('Correctly calculates destinationAndNonce', async () => {
for (let testCase of destinationNonceTestCases) {
let { destination, nonce, expectedDestinationAndNonce } = testCase;
const solidityDestinationAndNonce = await outbox.destinationAndNonce(
destination,
nonce,
);
expect(solidityDestinationAndNonce).to.equal(expectedDestinationAndNonce);
}
});
});