Skip to content

Commit 7e623de

Browse files
committed
executeMessage returns bytes4
1 parent 111ca6e commit 7e623de

File tree

6 files changed

+67
-17
lines changed

6 files changed

+67
-17
lines changed

contracts/crosschain/axelar/AxelarGatewayDestination.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,14 @@ abstract contract AxelarGatewayDestination is IERC7786GatewayDestinationPassive,
8181
require(getRemoteGateway(source).equal(remoteAccount), "Invalid origin gateway");
8282

8383
// Active mode
84-
IERC7786Receiver(receiver.parseAddress()).executeMessage(
84+
bytes4 result = IERC7786Receiver(receiver.parseAddress()).executeMessage(
8585
address(0), // not needed in active mode
8686
new bytes(0), // not needed in active mode
8787
source,
8888
sender,
8989
payload,
9090
attributes
9191
);
92+
require(result == IERC7786Receiver.executeMessage.selector, "Receiver execution failed");
9293
}
9394
}

contracts/crosschain/interfaces/draft-IERC7786.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,5 @@ interface IERC7786Receiver {
8787
string calldata sender,
8888
bytes calldata payload,
8989
bytes[] calldata attributes
90-
) external payable;
90+
) external payable returns (bytes4);
9191
}

contracts/crosschain/mocks/ERC7786GatewayMock.sol

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,17 @@ contract ERC7786GatewayMock is IERC7786GatewaySource, IERC7786GatewayDestination
3838

3939
if (_activeMode) {
4040
address target = Strings.parseAddress(receiver);
41-
IERC7786Receiver(target).executeMessage(address(this), new bytes(0), source, sender, payload, attributes);
41+
require(
42+
IERC7786Receiver(target).executeMessage(
43+
address(this),
44+
new bytes(0),
45+
source,
46+
sender,
47+
payload,
48+
attributes
49+
) == IERC7786Receiver.executeMessage.selector,
50+
"Receiver error"
51+
);
4252
} else {
4353
_outbox.set(uint256(keccak256(abi.encode(source, sender, receiver, payload, attributes))));
4454
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import {IERC7786Receiver} from "../interfaces/draft-IERC7786.sol";
6+
7+
contract ERC7786ReceiverInvalidMock is IERC7786Receiver {
8+
function executeMessage(
9+
address,
10+
bytes calldata,
11+
string calldata,
12+
string calldata,
13+
bytes calldata,
14+
bytes[] calldata
15+
) public payable virtual returns (bytes4) {
16+
return 0xffffffff;
17+
}
18+
}

contracts/crosschain/utils/draft-ERC7786Receiver.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ abstract contract ERC7786Receiver is IERC7786Receiver {
2828
string calldata sender,
2929
bytes calldata payload,
3030
bytes[] calldata attributes
31-
) public payable virtual {
31+
) public payable virtual returns (bytes4) {
3232
if (_isKnownGateway(msg.sender)) {
3333
// Active mode
3434
// no extra check
@@ -46,6 +46,7 @@ abstract contract ERC7786Receiver is IERC7786Receiver {
4646
revert ERC7786ReceiverInvalidGateway(gateway);
4747
}
4848
_processMessage(gateway, source, sender, payload, attributes);
49+
return IERC7786Receiver.executeMessage.selector;
4950
}
5051

5152
/// @dev Virtual getter that returns whether an address in a valid ERC-7786 gateway.

test/crosschain/axelar/AxelarGateway.test.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ async function fixture() {
1212
const CAIP2 = `eip155:${chainId}`;
1313
const asCAIP10 = account => `eip155:${chainId}:${getAddress(account)}`;
1414

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('$ERC7786ReceiverMock', [ dstGateway ]);
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('$ERC7786ReceiverMock', [ dstGateway ]);
19+
const invalidReceiver = await ethers.deployContract('$ERC7786ReceiverInvalidMock');
1920

2021
await srcGateway.registerChainEquivalence(CAIP2, 'local');
2122
await dstGateway.registerChainEquivalence(CAIP2, 'local');
2223
await srcGateway.registerRemoteGateway(CAIP2, getAddress(dstGateway));
2324
await dstGateway.registerRemoteGateway(CAIP2, getAddress(srcGateway));
2425

25-
return { owner, sender, accounts, CAIP2, asCAIP10, axelar, srcGateway, dstGateway, receiver };
26+
return { owner, sender, accounts, CAIP2, asCAIP10, axelar, srcGateway, dstGateway, receiver, invalidReceiver };
2627
}
2728

2829
describe('AxelarGateway', function () {
@@ -31,13 +32,13 @@ describe('AxelarGateway', function () {
3132
});
3233

3334
it('initial setup', async function () {
34-
expect(await this.srcGateway.localGateway()).to.equal(this.axelar);
35-
expect(await this.srcGateway.getEquivalentChain(this.CAIP2)).to.equal('local');
36-
expect(await this.srcGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.dstGateway));
35+
expect(this.srcGateway.localGateway()).to.eventually.equal(this.axelar);
36+
expect(this.srcGateway.getEquivalentChain(this.CAIP2)).to.eventually.equal('local');
37+
expect(this.srcGateway.getRemoteGateway(this.CAIP2)).to.eventually.equal(getAddress(this.dstGateway));
3738

38-
expect(await this.dstGateway.localGateway()).to.equal(this.axelar);
39-
expect(await this.dstGateway.getEquivalentChain(this.CAIP2)).to.equal('local');
40-
expect(await this.dstGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.srcGateway));
39+
expect(this.dstGateway.localGateway()).to.eventually.equal(this.axelar);
40+
expect(this.dstGateway.getEquivalentChain(this.CAIP2)).to.eventually.equal('local');
41+
expect(this.dstGateway.getRemoteGateway(this.CAIP2)).to.eventually.equal(getAddress(this.srcGateway));
4142
});
4243

4344
describe('Active mode', function () {
@@ -52,13 +53,32 @@ describe('AxelarGateway', function () {
5253
const attributes = [];
5354
const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ getAddress(this.sender), getAddress(this.receiver), payload, attributes ]);
5455

55-
const tx = await this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes);
56-
await expect(tx)
56+
await expect(this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes))
5757
.to.emit(this.srcGateway, 'MessagePosted').withArgs(ethers.ZeroHash, srcCAIP10, dstCAIP10, payload, attributes)
5858
.to.emit(this.axelar, 'ContractCall').withArgs(this.srcGateway, 'local', getAddress(this.dstGateway), ethers.keccak256(package), package)
5959
.to.emit(this.axelar, 'ContractCallExecuted').withArgs(anyValue)
6060
.to.emit(this.receiver, 'MessageReceived').withArgs(ethers.ZeroAddress, this.CAIP2, getAddress(this.sender), payload, attributes);
6161
});
62+
63+
it('invalid receiver - bad return value', async function () {
64+
await expect(this.srcGateway.connect(this.sender).sendMessage(
65+
this.CAIP2,
66+
getAddress(this.invalidReceiver),
67+
ethers.randomBytes(128),
68+
[],
69+
))
70+
.to.be.revertedWith('Receiver execution failed');
71+
});
72+
73+
it('invalid receiver - EOA', async function () {
74+
await expect(this.srcGateway.connect(this.sender).sendMessage(
75+
this.CAIP2,
76+
getAddress(this.accounts[0]),
77+
ethers.randomBytes(128),
78+
[],
79+
))
80+
.to.be.revertedWithoutReason();
81+
});
6282
});
6383

6484
describe('Passive mode', function () {

0 commit comments

Comments
 (0)