Skip to content

Commit 4f0f1f0

Browse files
committed
address PR comments
1 parent b2ac19d commit 4f0f1f0

File tree

6 files changed

+60
-118
lines changed

6 files changed

+60
-118
lines changed

contracts/crosschain/axelar/AxelarGatewayBase.sol

Lines changed: 10 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,35 @@ import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/
77

88
abstract contract AxelarGatewayBase is Ownable {
99
event RegisteredRemoteGateway(string caip2, string gatewayAddress);
10-
event RegisteredCAIP2Equivalence(string caip2, string destinationChain);
10+
event RegisteredChainEquivalence(string caip2, string destinationChain);
1111

1212
error UnsupportedChain(string caip2);
1313

1414
IAxelarGateway public immutable localGateway;
1515

1616
// TODO: merge these two (and the corresponding setters?)
1717
mapping(string caip2 => string remoteGateway) private _remoteGateways;
18-
mapping(string caip2 => string destinationChain) private _equivalence;
18+
mapping(string caip2OrAxelar => string axelarOfCaip2) private _chainEquivalence;
1919

2020
constructor(IAxelarGateway _gateway) {
2121
localGateway = _gateway;
2222
}
2323

24-
function fromCAIP2(string memory caip2) public view virtual returns (string memory axelarName) {
25-
axelarName = _equivalence[caip2];
26-
require(bytes(axelarName).length > 0, UnsupportedChain(caip2));
24+
function getEquivalentChain(string memory input) public view virtual returns (string memory output) {
25+
output = _chainEquivalence[input];
26+
require(bytes(output).length > 0, UnsupportedChain(input));
2727
}
2828

2929
function getRemoteGateway(string memory caip2) public view virtual returns (string memory remoteGateway) {
3030
remoteGateway = _remoteGateways[caip2];
3131
require(bytes(remoteGateway).length > 0, UnsupportedChain(caip2));
3232
}
3333

34-
function registerCAIP2Equivalence(string calldata caip2, string calldata axelarSupported) public virtual onlyOwner {
35-
require(bytes(_equivalence[caip2]).length == 0);
36-
_equivalence[caip2] = axelarSupported;
37-
emit RegisteredCAIP2Equivalence(caip2, axelarSupported);
34+
function registerChainEquivalence(string calldata caip2, string calldata axelarSupported) public virtual onlyOwner {
35+
require(bytes(_chainEquivalence[caip2]).length == 0);
36+
_chainEquivalence[caip2] = axelarSupported;
37+
_chainEquivalence[axelarSupported] = caip2;
38+
emit RegisteredChainEquivalence(caip2, axelarSupported);
3839
}
3940

4041
function registerRemoteGateway(string calldata caip2, string calldata remoteGateway) public virtual onlyOwner {
@@ -43,74 +44,3 @@ abstract contract AxelarGatewayBase is Ownable {
4344
emit RegisteredRemoteGateway(caip2, remoteGateway);
4445
}
4546
}
46-
47-
// EVM (https://axelarscan.io/resources/chains?type=evm)
48-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("1"))] = "Ethereum";
49-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("56"))] = "binance";
50-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("137"))] = "Polygon";
51-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("43114"))] = "Avalanche";
52-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("250"))] = "Fantom";
53-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("1284"))] = "Moonbeam";
54-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("1313161554"))] = "aurora";
55-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("42161"))] = "arbitrum";
56-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("10"))] = "optimism";
57-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("8453"))] = "base";
58-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("5000"))] = "mantle";
59-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("42220"))] = "celo";
60-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("2222"))] = "kava";
61-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("314"))] = "filecoin";
62-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("59144"))] = "linea";
63-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("2031"))] = "centrifuge";
64-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("534352"))] = "scroll";
65-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("13371"))] = "immutable";
66-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("252"))] = "fraxtal";
67-
// _equivalence[CAIP2.toString(bytes8("eip155"), bytes32("81457"))] = "blast";
68-
69-
// Cosmos (https://axelarscan.io/resources/chains?type=cosmos)
70-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('axelar-dojo-1'))] = 'Axelarnet';
71-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('osmosis-1'))] = 'osmosis';
72-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('cosmoshub-4'))] = 'cosmoshub';
73-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('juno-1'))] = 'juno';
74-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('emoney-3'))] = 'e-money';
75-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('injective-1'))] = 'injective';
76-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('crescent-1'))] = 'crescent';
77-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('kaiyo-1'))] = 'kujira';
78-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('secret-4'))] = 'secret-snip';
79-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('secret-4'))] = 'secret';
80-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('pacific-1'))] = 'sei';
81-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('stargaze-1'))] = 'stargaze';
82-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('mantle-1'))] = 'assetmantle';
83-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('fetchhub-4'))] = 'fetch';
84-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('kichain-2'))] = 'ki';
85-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('evmos_9001-2'))] = 'evmos';
86-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('xstaxy-1'))] = 'aura';
87-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('comdex-1'))] = 'comdex';
88-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('core-1'))] = 'persistence';
89-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('regen-1'))] = 'regen';
90-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('umee-1'))] = 'umee';
91-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('agoric-3'))] = 'agoric';
92-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('dimension_37-1'))] = 'xpla';
93-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('acre_9052-1'))] = 'acre';
94-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('stride-1'))] = 'stride';
95-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('carbon-1'))] = 'carbon';
96-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('sommelier-3'))] = 'sommelier';
97-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('neutron-1'))] = 'neutron';
98-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('reb_1111-1'))] = 'rebus';
99-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('archway-1'))] = 'archway';
100-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('pio-mainnet-1'))] = 'provenance';
101-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('ixo-5'))] = 'ixo';
102-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('migaloo-1'))] = 'migaloo';
103-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('teritori-1'))] = 'teritori';
104-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('haqq_11235-1'))] = 'haqq';
105-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('celestia'))] = 'celestia';
106-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('agamotto'))] = 'ojo';
107-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('chihuahua-1'))] = 'chihuahua';
108-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('ssc-1'))] = 'saga';
109-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('dymension_1100-1'))] = 'dymension';
110-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('fxcore'))] = 'fxcore';
111-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('perun-1'))] = 'c4e';
112-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('bitsong-2b'))] = 'bitsong';
113-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('pirin-1'))] = 'nolus';
114-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('lava-mainnet-1'))] = 'lava';
115-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('phoenix-1'))] = 'terra-2';
116-
// _equivalence[CAIP2.toString(bytes8('cosmos'), bytes32('columbus-5'))] = 'terra';"

contracts/crosschain/axelar/AxelarGatewayDestination.sol

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {IGatewayDestinationPassive} from "../interfaces/IGatewayDestinationPassi
1212
import {IGatewayReceiver} from "../interfaces/IGatewayReceiver.sol";
1313

1414
abstract contract AxelarGatewayDestination is IGatewayDestinationPassive, AxelarGatewayBase, AxelarExecutable {
15+
using Strings for address;
1516
using Strings for string;
1617

1718
/// @dev Passive mode
@@ -26,16 +27,21 @@ abstract contract AxelarGatewayDestination is IGatewayDestinationPassive, Axelar
2627
bytes32 commandId = abi.decode(messageKey, (bytes32));
2728

2829
// Rebuild expected package
29-
bytes memory package = abi.encode(
30-
CAIP10.format(source, sender),
31-
CAIP10.format(msg.sender),
30+
bytes memory adapterPayload = abi.encode(
31+
sender,
32+
msg.sender.toHexString(), // receiver
3233
payload,
3334
attributes
3435
);
3536

3637
// Check package was received from remote gateway on src chain
3738
require(
38-
gateway.validateContractCall(commandId, fromCAIP2(source), getRemoteGateway(source), keccak256(package)),
39+
gateway.validateContractCall(
40+
commandId,
41+
getEquivalentChain(source),
42+
getRemoteGateway(source),
43+
keccak256(adapterPayload)
44+
),
3945
NotApprovedByGateway()
4046
);
4147
}
@@ -51,24 +57,18 @@ abstract contract AxelarGatewayDestination is IGatewayDestinationPassive, Axelar
5157
function _execute(
5258
string calldata remoteChain, // chain of the remote gateway - axelar format
5359
string calldata remoteAccount, // address of the remote gateway
54-
bytes calldata package
60+
bytes calldata adapterPayload
5561
) internal virtual override {
5662
// Parse the package
57-
(string memory from, string memory to, bytes memory payload, bytes[] memory attributes) = abi.decode(
58-
package,
63+
(string memory sender, string memory receiver, bytes memory payload, bytes[] memory attributes) = abi.decode(
64+
adapterPayload,
5965
(string, string, bytes, bytes[])
6066
);
61-
62-
(string memory source, string memory sender) = CAIP10.parse(from);
63-
(string memory destination, string memory receiver) = CAIP10.parse(to);
67+
string memory source = getEquivalentChain(remoteChain);
6468

6569
// check message validity
66-
// - `remoteChain` matches origin chain in the message (in caip2)
6770
// - `remoteAccount` is the remote gateway on the origin chain.
68-
require(remoteChain.equal(fromCAIP2(source)), "Invalid origin chain");
69-
require(remoteAccount.equal(getRemoteGateway(source)), "Invalid origin gateway");
70-
// This check is not required for security. That is enforced by axelar (+ source gateway)
71-
require(destination.equal(CAIP2.format()), "Invalid tardet chain");
71+
require(getRemoteGateway(source).equal(remoteAccount), "Invalid origin gateway");
7272

7373
// Active mode
7474
IGatewayReceiver(StringsUnreleased.parseAddress(receiver)).receiveMessage(

contracts/crosschain/axelar/AxelarGatewaySource.sol

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ pragma solidity ^0.8.27;
44

55
import {AxelarGatewayBase} from "./AxelarGatewayBase.sol";
66
import {IGatewaySource} from "../interfaces/IGatewaySource.sol";
7+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
8+
import {CAIP2} from "../../utils/CAIP-2.sol";
79
import {CAIP10} from "../../utils/CAIP-10.sol";
810

911
abstract contract AxelarGatewaySource is IGatewaySource, AxelarGatewayBase {
10-
function supportsAttribute(bytes4 /*signature*/) public view virtual returns (bool) {
12+
using Strings for address;
13+
14+
function supportsAttribute(bytes4 /*selector*/) public view virtual returns (bool) {
1115
return false;
1216
}
1317

@@ -20,21 +24,27 @@ abstract contract AxelarGatewaySource is IGatewaySource, AxelarGatewayBase {
2024
// TODO: add support for value and attributes ?
2125
require(msg.value == 0, "Value not supported");
2226
for (uint256 i = 0; i < attributes.length; ++i) {
23-
bytes4 signature = bytes4(attributes[i][0:4]);
24-
require(supportsAttribute(signature), UnsuportedAttribute(signature));
27+
bytes4 selector = bytes4(attributes[i][0:4]);
28+
require(supportsAttribute(selector), UnsuportedAttribute(selector));
2529
}
2630

27-
string memory from = CAIP10.format(msg.sender);
28-
string memory to = CAIP10.format(destination, receiver);
29-
3031
// Create the package
31-
bytes memory package = abi.encode(from, to, payload, attributes);
32+
string memory sender = msg.sender.toHexString();
33+
bytes memory adapterPayload = abi.encode(sender, receiver, payload, attributes);
3234

3335
// Emit event
34-
emit MessageCreated(0, from, to, payload, attributes);
36+
emit MessageCreated(
37+
0,
38+
CAIP10.format(CAIP2.format(), sender),
39+
CAIP10.format(destination, receiver),
40+
payload,
41+
attributes
42+
);
3543

3644
// Send the message
37-
localGateway.callContract(fromCAIP2(destination), getRemoteGateway(destination), package);
45+
string memory axelarDestination = getEquivalentChain(destination);
46+
string memory remoteGateway = getRemoteGateway(destination);
47+
localGateway.callContract(axelarDestination, remoteGateway, adapterPayload);
3848

3949
return 0;
4050
}

contracts/crosschain/interfaces/IGatewaySource.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ pragma solidity ^0.8.0;
55
interface IGatewaySource {
66
event MessageCreated(
77
bytes32 outboxId,
8-
string from, // CAIP-10 account ID
9-
string to, // CAIP-10 account ID
8+
string sender, // CAIP-10 account ID
9+
string receiver, // CAIP-10 account ID
1010
bytes payload,
1111
bytes[] attributes
1212
);

contracts/utils/Bytes.sol

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,19 @@ library Bytes {
4646
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf
4747
*/
4848
function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {
49-
return lastIndexOf(buffer, s, buffer.length);
49+
return lastIndexOf(buffer, s, buffer.length - 1);
5050
}
5151

5252
/**
5353
* @dev Backward search for `s` in `buffer` starting at position `pos`
54-
* * If `s` is present in the buffer (before `pos`), returns the index of the previous instance
55-
* * If `s` is not present in the buffer (before `pos`), returns the length of the buffer
54+
* * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance
55+
* * If `s` is not present in the buffer (at or before `pos`), returns the length of the buffer
5656
*
5757
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf
5858
*/
5959
function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
6060
unchecked {
61-
for (uint256 i = pos; i > 0; --i) {
61+
for (uint256 i = pos + 1; i > 0; --i) {
6262
if (buffer[i - 1] == s) {
6363
return i - 1;
6464
}
@@ -88,11 +88,13 @@ library Bytes {
8888
uint256 length = buffer.length;
8989
start = Math.min(start, length);
9090
end = Math.min(end, length);
91+
9192
// allocate and copy
9293
bytes memory result = new bytes(end - start);
93-
for (uint256 i = start; i < end; ++i) {
94-
result[i - start] = buffer[i];
94+
assembly ("memory-safe") {
95+
mcopy(add(result, 0x20), add(buffer, add(start, 0x20)), sub(end, start))
9596
}
97+
9698
return result;
9799
}
98100

test/crosschain/axelar/AxelarGateway.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ async function fixture() {
1717
const dstGateway = await ethers.deployContract('$AxelarGatewayDestination', [ owner, axelar, axelar ]);
1818
const receiver = await ethers.deployContract('$GatewayReceiverMock', [ dstGateway ]);
1919

20-
await srcGateway.registerCAIP2Equivalence(CAIP2, 'local');
21-
await dstGateway.registerCAIP2Equivalence(CAIP2, 'local');
20+
await srcGateway.registerChainEquivalence(CAIP2, 'local');
21+
await dstGateway.registerChainEquivalence(CAIP2, 'local');
2222
await srcGateway.registerRemoteGateway(CAIP2, getAddress(dstGateway));
2323
await dstGateway.registerRemoteGateway(CAIP2, getAddress(srcGateway));
2424

@@ -32,11 +32,11 @@ describe('AxelarGateway', function () {
3232

3333
it('initial setup', async function () {
3434
expect(await this.srcGateway.localGateway()).to.equal(this.axelar);
35-
expect(await this.srcGateway.fromCAIP2(this.CAIP2)).to.equal('local');
35+
expect(await this.srcGateway.getEquivalentChain(this.CAIP2)).to.equal('local');
3636
expect(await this.srcGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.dstGateway));
3737

3838
expect(await this.dstGateway.localGateway()).to.equal(this.axelar);
39-
expect(await this.dstGateway.fromCAIP2(this.CAIP2)).to.equal('local');
39+
expect(await this.dstGateway.getEquivalentChain(this.CAIP2)).to.equal('local');
4040
expect(await this.dstGateway.getRemoteGateway(this.CAIP2)).to.equal(getAddress(this.srcGateway));
4141
});
4242

@@ -50,7 +50,7 @@ describe('AxelarGateway', function () {
5050
const dstCAIP10 = this.asCAIP10(this.receiver);
5151
const payload = ethers.randomBytes(128);
5252
const attributes = [];
53-
const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ srcCAIP10, dstCAIP10, payload, attributes ]);
53+
const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ getAddress(this.sender), getAddress(this.receiver), payload, attributes ]);
5454

5555
const tx = await this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes);
5656
await expect(tx)
@@ -71,7 +71,7 @@ describe('AxelarGateway', function () {
7171
const dstCAIP10 = this.asCAIP10(this.receiver);
7272
const payload = ethers.randomBytes(128);
7373
const attributes = [];
74-
const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ srcCAIP10, dstCAIP10, payload, attributes ]);
74+
const package = ethers.AbiCoder.defaultAbiCoder().encode([ 'string', 'string', 'bytes', 'bytes[]' ], [ getAddress(this.sender), getAddress(this.receiver), payload, attributes ]);
7575

7676
const tx = await this.srcGateway.connect(this.sender).sendMessage(this.CAIP2, getAddress(this.receiver), payload, attributes);
7777
await expect(tx)

0 commit comments

Comments
 (0)