Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(evm)!: support its v2 deployment #332

Merged
merged 24 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -419,6 +479,16 @@
"codeId": 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 @@ -525,8 +595,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 @@ -409,14 +409,14 @@ async function getDomainSeparator(config, chain, options) {
return expectedDomainSeparator;
}

const getChainConfig = (config, chainName) => {
const getChainConfig = (config, chainName, options = {}) => {
if (chainName === 'none') {
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
38 changes: 28 additions & 10 deletions cosmwasm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,21 +440,18 @@ const makeMultisigProverInstantiateMsg = (config, chainName) => {
};
};

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

const { axelarId } = chainConfig;

const {
Router: { address: routerAddress },
NexusGateway: { address: nexusAddress },
} = 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 @@ -468,6 +465,27 @@ const makeAxelarnetGatewayInstantiateMsg = (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: {},
milapsheth marked this conversation as resolved.
Show resolved Hide resolved
};
};

const makeInstantiateMsg = (contractName, chainName, config) => {
const {
axelar: { contracts },
Expand Down Expand Up @@ -550,11 +568,11 @@ const makeInstantiateMsg = (contractName, chainName, config) => {
}

case 'AxelarnetGateway': {
if (!chainConfig) {
throw new Error('AxelarnetGateway requires chainNames option');
}
return makeAxelarnetGatewayInstantiateMsg(config);
}

return makeAxelarnetGatewayInstantiateMsg(config, chainName);
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
34 changes: 20 additions & 14 deletions evm/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ 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 +241,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 +280,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 +299,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 +511,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'));
milapsheth marked this conversation as resolved.
Show resolved Hide resolved
program.addOption(new Option('--batchID <batchID>', 'EVM batch ID').default(''));
Expand Down
Loading