Skip to content

Commit c35a4ed

Browse files
authored
Merge branch 'main' into docs/readme
2 parents 6036711 + 8ffc9c3 commit c35a4ed

File tree

3 files changed

+211
-1
lines changed

3 files changed

+211
-1
lines changed

scripts/deploy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ async function deployAll(
118118
interchainTokenServiceAddress,
119119
factoryDeploymentKey,
120120
);
121-
return [service, gateway, gasService, factory];
121+
return [service, gateway, gasService, factory, create3Deployer];
122122
}
123123

124124
module.exports = {

test/AddressDerivation.js

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
'use strict';
2+
3+
const chai = require('chai');
4+
const { expect } = chai;
5+
const { ethers } = require('hardhat');
6+
const {
7+
constants: { AddressZero },
8+
utils: { defaultAbiCoder },
9+
} = ethers;
10+
const { deployAll } = require('../scripts/deploy');
11+
const { approveContractCall } = require('../scripts/utils');
12+
const { getRandomBytes32, getSaltFromKey, isHardhat } = require('./utils');
13+
const { create3DeployContract } = require('@axelar-network/axelar-gmp-sdk-solidity');
14+
const Token = require('../artifacts/contracts/test/TestInterchainTokenStandard.sol/TestInterchainTokenStandard.json');
15+
const MINT_BURN = 0;
16+
const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN = 1;
17+
18+
if (isHardhat) {
19+
describe('Token Address Derivation [ @skip-on-coverage ]', () => {
20+
let wallet;
21+
let service;
22+
let gateway;
23+
let create3Deployer;
24+
let factory;
25+
let token;
26+
let sourceAddress;
27+
28+
const destinationChain = 'destination chain';
29+
const sourceChain = 'source chain';
30+
const tokenName = 'Token Name';
31+
const tokenSymbol = 'TN';
32+
const tokenDecimals = 18;
33+
34+
before(async () => {
35+
const wallets = await ethers.getSigners();
36+
wallet = wallets[0];
37+
38+
[service, gateway, , factory, create3Deployer] = await deployAll(wallet, 'Test', [sourceChain, destinationChain]);
39+
token = await create3DeployContract(create3Deployer.address, wallet, Token, 'Test', [
40+
tokenName,
41+
tokenSymbol,
42+
tokenDecimals,
43+
service.address,
44+
getRandomBytes32(),
45+
]);
46+
47+
sourceAddress = service.address;
48+
});
49+
50+
describe('Interchain Token Service Deployments', () => {
51+
it('Should derive the correct token address for interchain token deployment on source chain', async () => {
52+
const salt = getSaltFromKey('deployInterchainToken');
53+
const tokenId = await service.interchainTokenId(wallet.address, salt);
54+
55+
const expectedTokenAddress = '0x2b7c2c1f7297BB9a573Fb970D086F0d113722Ceb';
56+
const expectedTokenManagerAddress = '0x1248d7831b5B231147bfbDb5e2b29B0110EeC9C8';
57+
58+
const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, expectedTokenAddress]);
59+
60+
await expect(service.deployInterchainToken(salt, '', tokenName, tokenSymbol, tokenDecimals, wallet.address, 0))
61+
.to.emit(service, 'InterchainTokenDeployed')
62+
.withArgs(tokenId, expectedTokenAddress, wallet.address, tokenName, tokenSymbol, tokenDecimals)
63+
.to.emit(service, 'TokenManagerDeployed')
64+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
65+
});
66+
67+
it('Should derive the correct token address for remote interchain token deployment', async () => {
68+
const salt = getSaltFromKey('deployRemoteInterchainToken');
69+
const tokenId = await service.interchainTokenId(wallet.address, salt);
70+
const minter = wallet.address;
71+
const operator = wallet.address;
72+
73+
const expectedTokenAddress = '0xDeB68Eb8F7D583140ce9158068f697F7B3a54Fb9';
74+
const expectedTokenManagerAddress = '0x3B058fE7Ed045f56F0152AED1e8c5fbaE7e23C70';
75+
76+
const params = defaultAbiCoder.encode(['bytes', 'address'], [operator, expectedTokenAddress]);
77+
const payload = defaultAbiCoder.encode(
78+
['uint256', 'bytes32', 'string', 'string', 'uint8', 'bytes'],
79+
[MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, tokenName, tokenSymbol, tokenDecimals, minter],
80+
);
81+
const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload);
82+
83+
await expect(service.execute(commandId, sourceChain, sourceAddress, payload))
84+
.to.emit(service, 'InterchainTokenDeployed')
85+
.withArgs(tokenId, expectedTokenAddress, minter, tokenName, tokenSymbol, tokenDecimals)
86+
.and.to.emit(service, 'TokenManagerDeployed')
87+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
88+
});
89+
90+
it('Should derive the correct token address for remote interchain token deployment with empty minter and operator', async () => {
91+
const salt = getSaltFromKey('deployRemoteInterchainTokenEmpty');
92+
const tokenId = await service.interchainTokenId(wallet.address, salt);
93+
const minter = '0x';
94+
const operator = '0x';
95+
96+
const expectedTokenAddress = '0x98D4481F4c1FC0608862e573Db15d0640F2E1B14';
97+
const expectedTokenManagerAddress = '0x89AF99D9373722De5F29ABbF706efeD020ae3E1F';
98+
99+
const params = defaultAbiCoder.encode(['bytes', 'address'], [operator, expectedTokenAddress]);
100+
const payload = defaultAbiCoder.encode(
101+
['uint256', 'bytes32', 'string', 'string', 'uint8', 'bytes'],
102+
[MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, tokenName, tokenSymbol, tokenDecimals, minter],
103+
);
104+
const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload);
105+
106+
await expect(service.execute(commandId, sourceChain, sourceAddress, payload))
107+
.to.emit(service, 'InterchainTokenDeployed')
108+
.withArgs(tokenId, expectedTokenAddress, AddressZero, tokenName, tokenSymbol, tokenDecimals)
109+
.and.to.emit(service, 'TokenManagerDeployed')
110+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
111+
});
112+
});
113+
114+
describe('Interchain Token Factory Deployments', () => {
115+
const initialSupply = 100;
116+
117+
it('Should derive the correct token address for interchain token deployment on source chain', async () => {
118+
const salt = getSaltFromKey('deployInterchainToken');
119+
const tokenId = await factory.interchainTokenId(wallet.address, salt);
120+
121+
const expectedTokenAddress = '0xD48F12c4b65135575495C476977B893D8e817B4b';
122+
const expectedTokenManagerAddress = '0xcb7DEA0Aeb34A992451717C0537b5C4eA1635A54';
123+
124+
const params = defaultAbiCoder.encode(['bytes', 'address'], [factory.address, expectedTokenAddress]);
125+
126+
await expect(factory.deployInterchainToken(salt, tokenName, tokenSymbol, tokenDecimals, initialSupply, wallet.address))
127+
.to.emit(service, 'InterchainTokenDeployed')
128+
.withArgs(tokenId, expectedTokenAddress, factory.address, tokenName, tokenSymbol, tokenDecimals)
129+
.to.emit(service, 'TokenManagerDeployed')
130+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
131+
});
132+
133+
it('Should derive the correct token address for remote interchain token deployment', async () => {
134+
const salt = getSaltFromKey('deployRemoteInterchainToken');
135+
const tokenId = await factory.interchainTokenId(wallet.address, salt);
136+
const minter = wallet.address;
137+
const operator = wallet.address;
138+
139+
const expectedTokenAddress = '0x977178149Ae62EFB70fD9BBa3e9200663Bdcb13c';
140+
const expectedTokenManagerAddress = '0x1695DD538BeDd759BE212Ed24f809eA51dbc08D0';
141+
142+
const params = defaultAbiCoder.encode(['bytes', 'address'], [operator, expectedTokenAddress]);
143+
const payload = defaultAbiCoder.encode(
144+
['uint256', 'bytes32', 'string', 'string', 'uint8', 'bytes'],
145+
[MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, tokenName, tokenSymbol, tokenDecimals, minter],
146+
);
147+
148+
const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload);
149+
150+
await expect(service.execute(commandId, sourceChain, sourceAddress, payload))
151+
.to.emit(service, 'InterchainTokenDeployed')
152+
.withArgs(tokenId, expectedTokenAddress, minter, tokenName, tokenSymbol, tokenDecimals)
153+
.and.to.emit(service, 'TokenManagerDeployed')
154+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
155+
});
156+
157+
it('Should derive the correct token address for remote interchain token deployment with empty minter and operator', async () => {
158+
const salt = getSaltFromKey('deployRemoteInterchainTokenEmpty');
159+
const tokenId = await factory.interchainTokenId(wallet.address, salt);
160+
const minter = AddressZero;
161+
const operator = '0x';
162+
163+
const expectedTokenAddress = '0x99ea4db7a1Aca4aC8d44fbbD6e2BD49960F6163a';
164+
const expectedTokenManagerAddress = '0x123908f4742664f68db857c6a10c846fb557AF08';
165+
166+
const params = defaultAbiCoder.encode(['bytes', 'address'], [operator, expectedTokenAddress]);
167+
const payload = defaultAbiCoder.encode(
168+
['uint256', 'bytes32', 'string', 'string', 'uint8', 'bytes'],
169+
[MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, tokenName, tokenSymbol, tokenDecimals, '0x'],
170+
);
171+
172+
const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload);
173+
174+
await expect(service.execute(commandId, sourceChain, sourceAddress, payload))
175+
.to.emit(service, 'InterchainTokenDeployed')
176+
.withArgs(tokenId, expectedTokenAddress, minter, tokenName, tokenSymbol, tokenDecimals)
177+
.and.to.emit(service, 'TokenManagerDeployed')
178+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
179+
});
180+
181+
it('Should derive the correct token address for remote canonical token deployment', async () => {
182+
const tokenId = await factory.canonicalInterchainTokenId(token.address);
183+
const minter = wallet.address;
184+
const operator = wallet.address;
185+
186+
const expectedTokenAddress = '0x74305d7DBD2a9Aa2994825995504b7e97bDF4430';
187+
const expectedTokenManagerAddress = '0x43eb02B89a4478128Df888260254efFd75b6D2eA';
188+
189+
const params = defaultAbiCoder.encode(['bytes', 'address'], [operator, expectedTokenAddress]);
190+
const payload = defaultAbiCoder.encode(
191+
['uint256', 'bytes32', 'string', 'string', 'uint8', 'bytes'],
192+
[MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, tokenId, tokenName, tokenSymbol, tokenDecimals, minter],
193+
);
194+
195+
const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload);
196+
197+
await expect(service.execute(commandId, sourceChain, sourceAddress, payload))
198+
.to.emit(service, 'InterchainTokenDeployed')
199+
.withArgs(tokenId, expectedTokenAddress, minter, tokenName, tokenSymbol, tokenDecimals)
200+
.and.to.emit(service, 'TokenManagerDeployed')
201+
.withArgs(tokenId, expectedTokenManagerAddress, MINT_BURN, params);
202+
});
203+
});
204+
});
205+
}

test/utils.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ function getRandomBytes32() {
99
return keccak256(defaultAbiCoder.encode(['uint256'], [Math.floor(new Date().getTime() * Math.random())]));
1010
}
1111

12+
const getSaltFromKey = (key) => {
13+
return keccak256(defaultAbiCoder.encode(['string'], [key.toString()]));
14+
};
15+
1216
const isHardhat = network.name === 'hardhat';
1317

1418
const getGasOptions = () => {
@@ -102,6 +106,7 @@ const getEVMVersion = () => {
102106

103107
module.exports = {
104108
getRandomBytes32,
109+
getSaltFromKey,
105110
isHardhat,
106111
getChainId,
107112
getGasOptions,

0 commit comments

Comments
 (0)