|
| 1 | +const { ethers } = require('hardhat'); |
| 2 | +const { expect } = require('chai'); |
| 3 | +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); |
| 4 | +const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs'); |
| 5 | + |
| 6 | +const getAddress = account => (account.target ?? account.address ?? account).toLowerCase(); |
| 7 | + |
| 8 | +async function fixture() { |
| 9 | + const [owner, sender, ...accounts] = await ethers.getSigners(); |
| 10 | + |
| 11 | + const { chainId } = await ethers.provider.getNetwork(); |
| 12 | + const CAIP2 = `eip155:${chainId}`; |
| 13 | + const asCAIP10 = account => `eip155:${chainId}:${getAddress(account)}`; |
| 14 | + |
| 15 | + const axelar = await ethers.deployContract('$AxelarGatewayMock'); |
| 16 | + const srcGateway = await ethers.deployContract('$AxelarGatewaySource', [ owner, axelar ]); |
| 17 | + const dstGateway = await ethers.deployContract('$AxelarGatewayDestination', [ owner, axelar, axelar ]); |
| 18 | + const receiver = await ethers.deployContract('$GatewayReceiverMock', [ dstGateway ]); |
| 19 | + |
| 20 | + await srcGateway.registerCAIP2Equivalence(CAIP2, 'local'); |
| 21 | + await dstGateway.registerCAIP2Equivalence(CAIP2, 'local'); |
| 22 | + await srcGateway.registerRemoteGateway(CAIP2, getAddress(dstGateway)); |
| 23 | + await dstGateway.registerRemoteGateway(CAIP2, getAddress(srcGateway)); |
| 24 | + |
| 25 | + return { owner, sender, accounts, CAIP2, asCAIP10, axelar, srcGateway, dstGateway, receiver }; |
| 26 | +} |
| 27 | + |
| 28 | +describe('AxelarGateway', function () { |
| 29 | + beforeEach(async function () { |
| 30 | + Object.assign(this, await loadFixture(fixture)); |
| 31 | + }); |
| 32 | + |
| 33 | + it('initial setup', async function () { |
| 34 | + expect(await this.srcGateway.localGateway()).to.equal(this.axelar); |
| 35 | + expect(await this.srcGateway.fromCAIP2(this.CAIP2)).to.equal('local'); |
| 36 | + expect(await this.srcGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.dstGateway)); |
| 37 | + |
| 38 | + expect(await this.dstGateway.localGateway()).to.equal(this.axelar); |
| 39 | + expect(await this.dstGateway.fromCAIP2(this.CAIP2)).to.equal('local'); |
| 40 | + expect(await this.dstGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.srcGateway)); |
| 41 | + }); |
| 42 | + |
| 43 | + describe('Active mode', function () { |
| 44 | + beforeEach(async function () { |
| 45 | + await this.axelar.setActive(true); |
| 46 | + }); |
| 47 | + |
| 48 | + it('workflow', async function () { |
| 49 | + const srcCAIP10 = this.asCAIP10(this.sender); |
| 50 | + const dstCAIP10 = this.asCAIP10(this.receiver); |
| 51 | + const payload = ethers.randomBytes(128); |
| 52 | + const attributes = []; |
| 53 | + const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ srcCAIP10, dstCAIP10, payload, attributes ]); |
| 54 | + |
| 55 | + const tx = await this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes); |
| 56 | + await expect(tx) |
| 57 | + .to.emit(this.srcGateway, 'MessageCreated').withArgs(ethers.ZeroHash, srcCAIP10, dstCAIP10, payload, attributes) |
| 58 | + .to.emit(this.axelar, 'ContractCall').withArgs(this.srcGateway, 'local', getAddress(this.dstGateway), ethers.keccak256(package), package) |
| 59 | + .to.emit(this.axelar, 'ContractCallExecuted').withArgs(anyValue) |
| 60 | + .to.emit(this.receiver, 'MessageReceived').withArgs(anyValue, this.CAIP2, getAddress(this.sender), payload, attributes); |
| 61 | + }); |
| 62 | + }); |
| 63 | + |
| 64 | + describe('Passive mode', function () { |
| 65 | + beforeEach(async function () { |
| 66 | + await this.axelar.setActive(false); |
| 67 | + }); |
| 68 | + |
| 69 | + it('workflow', async function () { |
| 70 | + const srcCAIP10 = this.asCAIP10(this.sender); |
| 71 | + const dstCAIP10 = this.asCAIP10(this.receiver); |
| 72 | + const payload = ethers.randomBytes(128); |
| 73 | + const attributes = []; |
| 74 | + const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ srcCAIP10, dstCAIP10, payload, attributes ]); |
| 75 | + |
| 76 | + const tx = await this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes); |
| 77 | + await expect(tx) |
| 78 | + .to.emit(this.srcGateway, 'MessageCreated').withArgs(ethers.ZeroHash, srcCAIP10, dstCAIP10, payload, attributes) |
| 79 | + .to.emit(this.axelar, 'ContractCall').withArgs(this.srcGateway, 'local', getAddress(this.dstGateway), ethers.keccak256(package), package) |
| 80 | + .to.emit(this.axelar, 'CommandIdPending').withArgs(anyValue, 'local', getAddress(this.dstGateway), package); |
| 81 | + |
| 82 | + const { logs } = await tx.wait(); |
| 83 | + const commandIdEvent = logs.find(({ address, topics }) => address == this.axelar.target && topics[0] == this.axelar.interface.getEvent('CommandIdPending').topicHash); |
| 84 | + const [ commandId ] = this.axelar.interface.decodeEventLog('CommandIdPending', commandIdEvent.data, commandIdEvent.topics); |
| 85 | + |
| 86 | + await expect(this.receiver.receiveMessage( |
| 87 | + this.dstGateway, |
| 88 | + commandId, // bytes32 is already self-encoded |
| 89 | + this.CAIP2, |
| 90 | + getAddress(this.sender), |
| 91 | + payload, |
| 92 | + attributes, |
| 93 | + )) |
| 94 | + .to.emit(this.axelar, 'ContractCallExecuted').withArgs(commandId) |
| 95 | + .to.emit(this.receiver, 'MessageReceived').withArgs(commandId, this.CAIP2, getAddress(this.sender), payload, attributes); |
| 96 | + }); |
| 97 | + }); |
| 98 | +}); |
0 commit comments