Skip to content

Commit

Permalink
feat(evm)!: support its v2 deployment (#332)
Browse files Browse the repository at this point in the history
Co-authored-by: ahramy <[email protected]>
  • Loading branch information
milapsheth and ahramy authored Oct 16, 2024
1 parent 167e672 commit 0858feb
Show file tree
Hide file tree
Showing 11 changed files with 1,223 additions and 1,972 deletions.
74 changes: 72 additions & 2 deletions axelar-chains-config/info/devnet-amplifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,26 @@
"codehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"predeployCodehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"salt": "Operators devnet-amplifier"
},
"InterchainTokenService": {
"salt": "ITS v2.0.0rc3 devnet-amplifier",
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"proxySalt": "ITS v2.0.0 devnet-amplifier",
"tokenManagerDeployer": "0x4cE9EC3ECB34aD0284f77BF6AafdBef9d136bd24",
"interchainToken": "0x34c8C8d2E212E3D5eBECAdf4769388B2e36C4561",
"interchainTokenDeployer": "0x8Be3C8bbFAFeE70AEAC14406a5F5C6dCD4D4fCb0",
"tokenManager": "0x64291364740eb10aeC672f06eCD7c7a91ea5A752",
"tokenHandler": "0x445C50CC6085ff2d35364bcc3CDce8b3FE08b27d",
"gatewayCaller": "0xFE0144B9C5B487Ec0a6Db38F7f100E99125117b3",
"implementation": "0x110D33345f031b9b630366c8399838bE445fF22d",
"predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf",
"address": "0x144c3d7A5f5198EF3B46A8258b35E903cf197A66"
},
"InterchainTokenFactory": {
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"salt": "ITS Factory v2.0.0 devnet-amplifier",
"implementation": "0x429E1bA4EF86B684741D04a97f18B25E78b8A8f1",
"address": "0x6Ae8C8498d5FDA930e6ABeB0E15E5A00471702a7"
}
}
},
Expand Down Expand Up @@ -297,6 +317,26 @@
"codehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"predeployCodehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"salt": "Operators devnet-amplifier"
},
"InterchainTokenService": {
"salt": "ITS v2.0.0rc3 devnet-amplifier",
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"proxySalt": "ITS v2.0.0 devnet-amplifier",
"tokenManagerDeployer": "0x4cE9EC3ECB34aD0284f77BF6AafdBef9d136bd24",
"interchainToken": "0x34c8C8d2E212E3D5eBECAdf4769388B2e36C4561",
"interchainTokenDeployer": "0x8Be3C8bbFAFeE70AEAC14406a5F5C6dCD4D4fCb0",
"tokenManager": "0x64291364740eb10aeC672f06eCD7c7a91ea5A752",
"tokenHandler": "0x445C50CC6085ff2d35364bcc3CDce8b3FE08b27d",
"gatewayCaller": "0xFE0144B9C5B487Ec0a6Db38F7f100E99125117b3",
"implementation": "0x110D33345f031b9b630366c8399838bE445fF22d",
"predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf",
"address": "0x144c3d7A5f5198EF3B46A8258b35E903cf197A66"
},
"InterchainTokenFactory": {
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"salt": "ITS Factory v2.0.0 devnet-amplifier",
"implementation": "0x429E1bA4EF86B684741D04a97f18B25E78b8A8f1",
"address": "0x6Ae8C8498d5FDA930e6ABeB0E15E5A00471702a7"
}
}
},
Expand Down Expand Up @@ -372,6 +412,26 @@
"codehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"predeployCodehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb",
"salt": "Operators devnet-amplifier"
},
"InterchainTokenService": {
"salt": "ITS v2.0.0rc3 devnet-amplifier",
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"proxySalt": "ITS v2.0.0 devnet-amplifier",
"tokenManagerDeployer": "0x4cE9EC3ECB34aD0284f77BF6AafdBef9d136bd24",
"interchainToken": "0x34c8C8d2E212E3D5eBECAdf4769388B2e36C4561",
"interchainTokenDeployer": "0x8Be3C8bbFAFeE70AEAC14406a5F5C6dCD4D4fCb0",
"tokenManager": "0x64291364740eb10aeC672f06eCD7c7a91ea5A752",
"tokenHandler": "0x445C50CC6085ff2d35364bcc3CDce8b3FE08b27d",
"gatewayCaller": "0xFE0144B9C5B487Ec0a6Db38F7f100E99125117b3",
"implementation": "0x110D33345f031b9b630366c8399838bE445fF22d",
"predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf",
"address": "0x144c3d7A5f5198EF3B46A8258b35E903cf197A66"
},
"InterchainTokenFactory": {
"deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233",
"salt": "ITS Factory v2.0.0 devnet-amplifier",
"implementation": "0x429E1bA4EF86B684741D04a97f18B25E78b8A8f1",
"address": "0x6Ae8C8498d5FDA930e6ABeB0E15E5A00471702a7"
}
}
},
Expand Down Expand Up @@ -546,6 +606,16 @@
"lastUploadedCodeId": 619,
"address": "axelar1jjjr3tqs0nzjv3y9fg4xvzkww50jq06a9qp77r8kzmqyla97556sxx7702"
},
"AxelarnetGateway": {
"codeId": 661,
"address": "axelar1yvfcrdke7fasxfaxx2r706h7h85rnk3w68cc5f4fkmafz5j755ssl8h9p0"
},
"InterchainTokenService": {
"adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"codeId": 738,
"address": "axelar10jzzmv5m7da7dn2xsfac0yqe7zamy34uedx3e28laq0p6f3f8dzqp649fp"
},
"VotingVerifier": {
"avalanche-fuji": {
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
Expand Down Expand Up @@ -724,8 +794,8 @@
}
}
},
"id": "Axelarnet",
"axelarId": "axelar",
"id": "axelarnet",
"axelarId": "axelarnet",
"chainId": "devnet-amplifier",
"rpc": "http://devnet-amplifier.axelar.dev:26657",
"lcd": "http://devnet-amplifier.axelar.dev:1317",
Expand Down
7 changes: 4 additions & 3 deletions axelar-chains-config/src/utils/verifyContract.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const verifyContract = (env, chain, contract, args, options = {}) => {

const contractArg = options.contractPath ? `--contract ${options.contractPath}` : '';
const dirPrefix = options.dir ? `cd ${options.dir};` : '';
const cmd = `${dirPrefix} ENV=${env} npx hardhat verify --network ${chain.toLowerCase()} ${contractArg} --no-compile --constructor-args ${file} ${contract} --show-stack-traces`;
const normalizedChainName = chain.toLowerCase().replace(' ', '-');
const cmd = `${dirPrefix} ENV=${env} npx hardhat verify --network ${normalizedChainName} ${contractArg} --no-compile --constructor-args ${file} ${contract} --show-stack-traces`;

writeFileSync(filePath, content, 'utf-8');

Expand All @@ -32,9 +33,9 @@ const verifyContract = (env, chain, contract, args, options = {}) => {
console.log('Verified!');
} catch (error) {
if (error.message.toLowerCase().includes('already verified')) {
console.log(`Contract ${contract} is already verified on ${chain.toLowerCase()}.`);
console.log(`Contract ${contract} is already verified on ${normalizedChainName}.`);
} else {
throw new Error(`An error occurred while trying to verify ${contract} on ${chain.toLowerCase()}:\n${error}`);
throw new Error(`An error occurred while trying to verify ${contract} on ${normalizedChainName}:\n${error}`);
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,14 +417,14 @@ async function getDomainSeparator(config, chain, options) {
return expectedDomainSeparator;
}

const getChainConfig = (config, chainName) => {
const getChainConfig = (config, chainName, options = {}) => {
if (!chainName) {
return undefined;
}

const chainConfig = config.chains[chainName] || config[chainName];

if (!chainConfig) {
if (!options.skipCheck && !chainConfig) {
throw new Error(`Chain ${chainName} not found in config`);
}

Expand Down
36 changes: 29 additions & 7 deletions cosmwasm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,20 +462,17 @@ const makeMultisigProverInstantiateMsg = (config, chainName) => {
};
};

const makeAxelarnetGatewayInstantiateMsg = ({ nexus }, config, chainName) => {
const makeAxelarnetGatewayInstantiateMsg = ({ nexus }, config) => {
const {
axelar: { contracts },
axelar: { contracts, axelarId },
} = config;
const chainConfig = getChainConfig(config, chainName);

const { axelarId } = chainConfig;

const {
Router: { address: routerAddress },
} = contracts;

if (!isString(axelarId)) {
throw new Error(`Missing or invalid axelar ID for chain ${chainName}`);
throw new Error(`Missing or invalid axelar ID for Axelar`);
}

if (!validateAddress(routerAddress)) {
Expand All @@ -489,6 +486,27 @@ const makeAxelarnetGatewayInstantiateMsg = ({ nexus }, config, chainName) => {
};
};

const makeInterchainTokenServiceInstantiateMsg = (config, { adminAddress, governanceAddress }) => {
const {
axelar: { contracts },
} = config;

const {
AxelarnetGateway: { address: axelarnetGatewayAddress },
} = contracts;

if (!validateAddress(axelarnetGatewayAddress)) {
throw new Error('Missing or invalid AxelarnetGateway.address in axelar info');
}

return {
governance_address: governanceAddress,
admin_address: adminAddress,
axelarnet_gateway_address: axelarnetGatewayAddress,
its_addresses: {},
};
};

const makeInstantiateMsg = (contractName, chainName, config) => {
const {
axelar: { contracts },
Expand Down Expand Up @@ -575,7 +593,11 @@ const makeInstantiateMsg = (contractName, chainName, config) => {
throw new Error('AxelarnetGateway requires chainName option');
}

return makeAxelarnetGatewayInstantiateMsg(contractConfig, config, chainName);
return makeAxelarnetGatewayInstantiateMsg(contractConfig, config);
}

case 'InterchainTokenService': {
return makeInterchainTokenServiceInstantiateMsg(config, contractConfig);
}
}

Expand Down
58 changes: 51 additions & 7 deletions evm/deploy-its.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,23 @@ async function deployAll(config, wallet, chain, options) {
const itsFactoryContractConfig = contracts[itsFactoryContractName] || {};

const salt = options.salt ? `ITS ${options.salt}` : 'ITS';
const proxySalt = options.proxySalt || options.salt ? `ITS ${options.proxySalt || options.salt}` : 'ITS';
const factorySalt = options.proxySalt || options.salt ? `ITS Factory ${options.proxySalt || options.salt}` : 'ITS Factory';
let proxySalt, factorySalt;

// If reusing the proxy, then proxy salt is the existing value
if (options.reuseProxy) {
proxySalt = contractConfig.proxySalt;
factorySalt = itsFactoryContractConfig.salt;
} else if (options.proxySalt) {
proxySalt = `ITS ${options.proxySalt}`;
factorySalt = `ITS Factory ${options.proxySalt}`;
} else if (options.salt) {
proxySalt = `ITS ${options.salt}`;
factorySalt = `ITS Factory ${options.salt}`;
} else {
proxySalt = 'ITS';
factorySalt = 'ITS Factory';
}

const implementationSalt = `${salt} Implementation`;

contractConfig.salt = salt;
Expand Down Expand Up @@ -86,7 +101,11 @@ async function deployAll(config, wallet, chain, options) {
throw new Error(`Invalid ITS address: ${interchainTokenService}`);
}

printInfo('Interchain Token Service will be deployed to', interchainTokenService);
if (options.reuseProxy) {
printInfo('Reusing existing Interchain Token Service proxy', interchainTokenService);
} else {
printInfo('Interchain Token Service will be deployed to', interchainTokenService);
}

const interchainTokenFactory = options.reuseProxy
? itsFactoryContractConfig.address
Expand All @@ -102,14 +121,22 @@ async function deployAll(config, wallet, chain, options) {
throw new Error(`Invalid Interchain Token Factory address: ${interchainTokenFactory}`);
}

printInfo('Interchain Token Factory will be deployed to', interchainTokenFactory);
if (options.reuseProxy) {
printInfo('Reusing existing Interchain Token Factory proxy', interchainTokenFactory);
} else {
printInfo('Interchain Token Factory will be deployed to', interchainTokenFactory);
}

// Register all chains that ITS is or will be deployed on.
// Add a "skip": true under ITS key in the config if the chain will not have ITS.
const itsChains = Object.values(config.chains).filter((chain) => chain.contracts?.InterchainTokenService?.skip !== true);
const trustedChains = itsChains.map((chain) => chain.axelarId);
const trustedAddresses = itsChains.map((_) => chain.contracts?.InterchainTokenService?.address || interchainTokenService);
printInfo('Trusted chains', trustedChains);

// Trusted addresses are only used when deploying a new proxy
if (!options.reuseProxy) {
printInfo('Trusted chains', trustedChains);
}

const existingAddress = config.chains.ethereum?.contracts?.[contractName]?.address;

Expand Down Expand Up @@ -206,7 +233,23 @@ async function deployAll(config, wallet, chain, options) {
deployMethod,
wallet,
getContractJSON('TokenHandler', artifactPath),
[],
[contracts.AxelarGateway.address],
deployOptions,
gasOptions,
verifyOptions,
chain,
);
},
},
gatewayCaller: {
name: 'Gateway Caller',
contractName: 'GatewayCaller',
async deploy() {
return await deployContract(
deployMethod,
wallet,
getContractJSON('GatewayCaller', artifactPath),
[contracts.AxelarGateway.address, contracts.AxelarGasService.address],
deployOptions,
gasOptions,
verifyOptions,
Expand All @@ -227,6 +270,7 @@ async function deployAll(config, wallet, chain, options) {
chain.axelarId,
contractConfig.tokenManager,
contractConfig.tokenHandler,
contractConfig.gatewayCaller,
];

printInfo('ITS Implementation args', args);
Expand Down Expand Up @@ -314,7 +358,7 @@ async function deployAll(config, wallet, chain, options) {

// When upgrading/reusing proxy, avoid re-deploying the proxy and the interchain token contract
if (options.reuseProxy && ['InterchainToken', 'InterchainProxy'].includes(deployment.contractName)) {
printInfo(`Reusing ${deployment.name} deployment for contract ${deployment.contractName} at ${contractConfig[key]}`);
printInfo(`Reusing ${deployment.name} deployment`);
continue;
}

Expand Down
35 changes: 21 additions & 14 deletions evm/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ async function processCommand(config, chain, options) {
return;
}

const payload = options.payload || '0x';
let payload = options.payload || '0x';

if (!payload.startsWith('0x')) {
payload = '0x' + payload;
}

if (!payload) {
throw new Error('Missing GMP payload');
Expand Down Expand Up @@ -238,7 +242,7 @@ async function processCommand(config, chain, options) {

// eslint-disable-next-line no-fallthrough
case 'approveAndExecute': {
const payloadHash = payload.startsWith('0x') ? keccak256(arrayify(payload)) : id(payload);
const payloadHash = keccak256(arrayify(payload));

const commandID = options.commandID.startsWith('0x') ? options.commandID : id(parseInt(options.commandID).toString());

Expand Down Expand Up @@ -277,9 +281,17 @@ async function processCommand(config, chain, options) {

// eslint-disable-next-line no-duplicate-case,no-fallthrough
case 'approveAndExecute': {
const payloadHash = payload.startsWith('0x') ? keccak256(arrayify(payload)) : id(payload);
const payloadHash = keccak256(arrayify(payload));
const { sourceChain, sourceAddress } = options;

const commandID = options.commandID.startsWith('0x') ? options.commandID : id(parseInt(options.commandID).toString());
let commandId;

if (options.messageId) {
// Derive commandId for Amplifier gateway
commandId = id(`${sourceChain}_${options.messageId}`);
} else {
commandId = options.commandID.startsWith('0x') ? options.commandID : id(parseInt(options.commandID).toString());
}

if (!options.destination) {
throw new Error('Missing destination contract address');
Expand All @@ -288,22 +300,14 @@ async function processCommand(config, chain, options) {
printInfo('Destination app contract', options.destination);
printInfo('Payload Hash', payloadHash);

if (
!(await gateway.isContractCallApproved(
commandID,
'Axelarnet',
'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj',
options.destination,
payloadHash,
))
) {
if (!(await gateway.isContractCallApproved(commandId, sourceChain, sourceAddress, options.destination, payloadHash))) {
printWarn('Contract call not approved at the gateway');
return;
}

const appContract = new Contract(options.destination, IAxelarExecutable.abi, wallet);

const tx = await appContract.execute(commandID, 'Axelarnet', 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj', payload);
const tx = await appContract.execute(commandId, sourceChain, sourceAddress, payload);
printInfo('Execute tx', tx.hash);
await tx.wait(chain.confirmations);

Expand Down Expand Up @@ -508,6 +512,9 @@ if (require.main === module) {

program.addOption(new Option('--payload <payload>', 'gmp payload'));
program.addOption(new Option('--commandID <commandID>', 'execute command ID'));
program.addOption(new Option('--messageId <messageId>', 'GMP call message ID'));
program.addOption(new Option('--sourceChain <sourceChain>', 'GMP source chain'));
program.addOption(new Option('--sourceAddress <sourceAddress>', 'GMP source address'));
program.addOption(new Option('--destination <destination>', 'GMP destination address'));
program.addOption(new Option('--destinationChain <destinationChain>', 'GMP destination chain'));
program.addOption(new Option('--batchID <batchID>', 'EVM batch ID').default(''));
Expand Down
Loading

0 comments on commit 0858feb

Please sign in to comment.