Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 13 additions & 13 deletions axelar-chains-config/info/devnet-amplifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -1495,12 +1495,12 @@
"Router": {
"adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"codeId": 850,
"lastUploadedCodeId": 888,
"codeId": 1533,
"lastUploadedCodeId": 1533,
"address": "axelar14jjdxqhuxk803e9pq64w4fgf385y86xxhkpzswe9crmu6vxycezst0zq8y",
"executeProposalId": "54",
"storeCodeProposalId": "101",
"storeCodeProposalCodeHash": "7368e7507f29ae9236c9c41fc1fbe5456260fb91acf1e2ff07d677bdcbca7e9f",
"storeCodeProposalId": "1134",
"storeCodeProposalCodeHash": "1444b7333018584a316bd6e056083668a9d4351aab395b90ab5ec18ea3a8a208",
"axelar": {
"codeId": 888,
"address": "axelar14jjdxqhuxk803e9pq64w4fgf385y86xxhkpzswe9crmu6vxycezst0zq8y"
Expand All @@ -1509,25 +1509,25 @@
"Multisig": {
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"blockExpiry": 10,
"codeId": 1302,
"lastUploadedCodeId": 1302,
"codeId": 1541,
"lastUploadedCodeId": 1541,
"address": "axelar19jxy26z0qnnspa45y5nru0l5rmy9d637z5km2ndjxthfxf5qaswst9290r",
"executeProposalId": "55",
"storeCodeProposalId": "580",
"storeCodeProposalCodeHash": "cd6109a37eab844941ea09266e54bf3fdb18bfb55e02a0ed91aa5a8d47aea2ec"
"storeCodeProposalId": "1159",
"storeCodeProposalCodeHash": "c6045b0782280349d7651b1c990b7951d18d5b21de167ac9948fd7522b06dc55"
},
"Coordinator": {
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
"codeId": 615,
"lastUploadedCodeId": 846,
"codeId": 1542,
"lastUploadedCodeId": 1542,
"address": "axelar1m2498n4h2tskcsmssjnzswl5e6eflmqnh487ds47yxyu6y5h4zuqr9zk4g",
"executeProposalId": "56",
"axelar": {
"codeId": 846,
"codeId": 1542,
"address": "axelar1m2498n4h2tskcsmssjnzswl5e6eflmqnh487ds47yxyu6y5h4zuqr9zk4g"
},
"storeCodeProposalId": "62",
"storeCodeProposalCodeHash": "a57dccb229cfab931b904618af2ebc854699a25a963c231834837d88ee4a0217"
"storeCodeProposalId": "1188",
"storeCodeProposalCodeHash": "dc9d7f18a03970e0d7a6d81b2307d76eec2114a6f8bf27dc4336e1813f362bc9"
},
"Rewards": {
"governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9",
Expand Down
190 changes: 121 additions & 69 deletions cosmwasm/migrate/coordinator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { StdFee } from '@cosmjs/stargate';

import { encodeMigrateContractProposal, submitProposal } from '../utils';
import { MigrationOptions } from './types';

// cosmwasm-stargate imports protobufjs which does not have a default export
// Therefore, import SigningCosmWasmClient using CommonJS to avoid error TS1192
// eslint-disable-next-line @typescript-eslint/no-require-imports
export const { SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate');

interface ChainContracts {
chain_name: string;
prover_address?: string;
gateway_address: string;
verifier_address: string;
chainName: string;
proverAddress?: string;
gatewayAddress: string;
verifierAddress: string;
}

export interface ChainEndpoint {
Expand All @@ -20,106 +20,157 @@ export interface ChainEndpoint {
};
}

export async function queryChainsFromRouter(client: typeof SigningCosmWasmClient, router_address: string): Promise<ChainEndpoint[]> {
export async function queryChainsFromRouter(client: typeof SigningCosmWasmClient, routerAddress: string): Promise<ChainEndpoint[]> {
try {
const res: ChainEndpoint[] = await client.queryContractSmart(router_address, { chains: {} });
const res: ChainEndpoint[] = await client.queryContractSmart(routerAddress, { chains: {} });
return res;
} catch (error) {
throw error;
}
}

async function constructChainContracts(client: typeof SigningCosmWasmClient, chain_endpoints: ChainEndpoint[]): Promise<ChainContracts[]> {
interface GatewayConfig {
verifier: string;
}
function checkForDuplicates(chains: ChainContracts[]) {
const provers: Map<string, string[]> = new Map();
const verifiers: Map<string, string[]> = new Map();
const gateways: Map<string, string[]> = new Map();

try {
const chain_contracts: ChainContracts[] = [];

for (let i = 0; i < chain_endpoints.length; i++) {
const res = await client.queryContractRaw(chain_endpoints[i].gateway.address, Buffer.from('config'));
const config: GatewayConfig = JSON.parse(Buffer.from(res).toString('ascii'));
if (chain_endpoints[i].name && chain_endpoints[i].gateway.address && config.verifier) {
chain_contracts.push({
chain_name: chain_endpoints[i].name,
gateway_address: chain_endpoints[i].gateway.address,
verifier_address: config.verifier,
});
}
chains.forEach((c) => {
if (c.proverAddress && !provers.has(c.proverAddress)) {
provers.set(c.proverAddress, [c.chainName]);
} else if (provers.has(c.proverAddress)) {
provers.set(c.proverAddress, provers.get(c.proverAddress).concat([c.chainName]));
}

return chain_contracts;
} catch (e) {
throw e;
if (!verifiers.has(c.verifierAddress)) {
verifiers.set(c.verifierAddress, [c.chainName]);
} else if (verifiers.has(c.verifierAddress)) {
verifiers.set(c.verifierAddress, verifiers.get(c.verifierAddress).concat([c.chainName]));
}

if (!gateways.has(c.gatewayAddress)) {
gateways.set(c.gatewayAddress, [c.chainName]);
} else if (gateways.has(c.gatewayAddress)) {
gateways.set(c.gatewayAddress, gateways.get(c.gatewayAddress).concat([c.chainName]));
}
});

let duplicatesFound = false;

provers.forEach((v, k) => {
if (v.length > 1) {
duplicatesFound = true;
console.log(`Prover ${k} duplicated between ${v}`);
}
});

verifiers.forEach((v, k) => {
if (v.length > 1) {
duplicatesFound = true;
console.log(`Verifier ${k} duplicated between ${v}`);
}
});

gateways.forEach((v, k) => {
if (v.length > 1) {
duplicatesFound = true;
console.log(`Gateway ${k} duplicated between ${v}`);
}
});

if (duplicatesFound) {
throw new Error('uniqueness constraints not maintained for chain contracts');
}
}

async function addMissingProvers(
async function constructChainContracts(
client: typeof SigningCosmWasmClient,
multisig_address: string,
chain_contracts: ChainContracts[],
multisigAddress: string,
chainEndpoints: ChainEndpoint[],
ignoreChains: string[],
): Promise<ChainContracts[]> {
try {
for (let i = 0; i < chain_contracts.length; i++) {
const authorized_provers = await client.queryContractSmart(multisig_address, {
authorized_caller: { chain_name: chain_contracts[i].chain_name },
});
chain_contracts[i].prover_address = authorized_provers ?? '';
interface GatewayConfig {
verifier: string;
}

const chainContracts: ChainContracts[] = [];

for (const endpoint of chainEndpoints) {
try {
const res = await client.queryContractRaw(endpoint.gateway.address, Buffer.from('config'));
const config: GatewayConfig = JSON.parse(Buffer.from(res).toString('ascii'));
if (endpoint.name && !ignoreChains.includes(endpoint.name) && endpoint.gateway.address && config.verifier) {
const authorizedProvers = await client.queryContractSmart(multisigAddress, {
authorized_caller: { chain_name: endpoint.name },
});

chainContracts.push({
chainName: endpoint.name,
gatewayAddress: endpoint.gateway.address,
verifierAddress: config.verifier,
proverAddress: authorizedProvers ?? '',
});
}
} catch (e) {
console.log(`Warning: ${e}`);
}
}

return chain_contracts;
checkForDuplicates(chainContracts);

return chainContracts;
} catch (e) {
throw e;
}
}

async function coordinatorToVersion2_1_0(
async function coordinatorToVersion2_1_1(
client: typeof SigningCosmWasmClient,
options: MigrationOptions,
config,
sender_address: string,
coordinator_address: string,
code_id: number,
senderAddress: string,
coordinatorAddress: string,
codeId: number,
fee: string | StdFee,
) {
const router_address = config.axelar.contracts.Router.address;
const multisig_address = config.axelar.contracts.Multisig.address;
const routerAddress = config.axelar.contracts.Router.address;
const multisigAddress = config.axelar.contracts.Multisig.address;
const ignore: string[] = options.ignoreChains ? JSON.parse(options.ignoreChains) : [];

const chain_endpoints = await queryChainsFromRouter(client, router_address);
let chain_contracts = await constructChainContracts(client, chain_endpoints);
chain_contracts = await addMissingProvers(client, multisig_address, chain_contracts);
const chainEndpoints = await queryChainsFromRouter(client, routerAddress);
const chainContracts = await constructChainContracts(client, multisigAddress, chainEndpoints, ignore);

const migration_msg = {
router: router_address,
multisig: multisig_address,
chain_contracts: chain_contracts,
const migrationMsg = {
router: routerAddress,
multisig: multisigAddress,
chain_contracts: chainContracts,
};

console.log('Migration Msg:', migration_msg);
console.log('Migration Msg:', migrationMsg);

const migrate_options = {
const migrateOptions = {
contractName: 'Coordinator',
msg: JSON.stringify(migration_msg),
title: 'Migrate Coordinator v2.1.0',
description: 'Migrate Coordinator v2.1.0',
runAs: sender_address,
codeId: code_id,
msg: JSON.stringify(migrationMsg),
title: 'Migrate Coordinator v2.1.1',
description: 'Migrate Coordinator v2.1.1',
runAs: senderAddress,
codeId: codeId,
deposit: options.deposit,
fetchCodeId: false,
address: coordinator_address,
address: coordinatorAddress,
};

const proposal = encodeMigrateContractProposal(config, migrate_options);
const proposal = encodeMigrateContractProposal(config, migrateOptions);

if (!options.dry) {
try {
console.log('Executing migration...');
if (options.proposal) {
await submitProposal(client, config, migrate_options, proposal);
console.log('Migration proposal successfully submitted');
} else {
await client.migrate(sender_address, coordinator_address, Number(code_id), migration_msg, options.fees);
console.log('Executing migration...', migrateOptions);
if (options.direct) {
await client.migrate(senderAddress, coordinatorAddress, Number(codeId), migrationMsg, fee);
console.log('Migration succeeded');
} else {
await submitProposal(client, config, migrateOptions, proposal, fee);
console.log('Migration proposal successfully submitted');
}
} catch (e) {
console.log('Error:', e);
Expand All @@ -131,14 +182,15 @@ export async function migrate(
client: typeof SigningCosmWasmClient,
options: MigrationOptions,
config,
sender_address: string,
coordinator_address: string,
senderAddress: string,
coordinatorAddress: string,
version: string,
code_id: number,
codeId: number,
fee: string | StdFee,
) {
switch (version) {
case '1.1.0':
return coordinatorToVersion2_1_0(client, options, config, sender_address, coordinator_address, code_id);
return coordinatorToVersion2_1_1(client, options, config, senderAddress, coordinatorAddress, codeId, fee);
default:
console.error(`no migration script found for coordinator ${version}`);
}
Expand Down
28 changes: 16 additions & 12 deletions cosmwasm/migrate/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { Command, Option } from 'commander';
import { FullConfig } from '../../common/config';
import { addAmplifierOptions } from '../cli-utils';
import { ClientManager, mainProcessor } from '../processor';
import { ContractInfo, getContractInfo } from '../query';
import { getContractInfo } from '../query';
import { migrate as migrateCoordinator } from './coordinator';
import { migrate as migrateMultisig } from './multisig';
import { MigrationOptions } from './types';

async function migrate(
Expand All @@ -17,20 +18,23 @@ async function migrate(
args: string[],
fee: string | StdFee,
): Promise<void> {
const sender_address = client.accounts[0].address;
const contract_address = options.address ?? config.axelar.contracts[options.contractName]?.address;
const senderAddress = client.accounts[0].address;
const contractAddress = options.address ?? config.axelar.contracts[options.contractName]?.address;
if (args.length === 0 || args[0] === undefined) {
throw new Error('code_id argument is required');
}
const code_id = Number(args[0]);
if (isNaN(code_id)) {
const codeId = Number(args[0]);
if (isNaN(codeId)) {
throw new Error('code_id must be a valid number');
}

const contract_info = await getContractInfo(client, contract_address);
switch (contract_info.contract) {
const contractInfo = await getContractInfo(client, contractAddress);
switch (contractInfo.contract) {
case 'coordinator':
await migrateCoordinator(client, options, config, sender_address, contract_address, contract_info.version, code_id);
await migrateCoordinator(client, options, config, senderAddress, contractAddress, contractInfo.version, codeId, fee);
break;
case 'multisig':
await migrateMultisig(client, options, config, senderAddress, contractAddress, contractInfo.version, codeId, fee);
break;
}
}
Expand All @@ -44,14 +48,14 @@ const programHandler = () => {
program
.command('migrate')
.argument('<code_id>', 'code id of new contract')
.addOption(new Option('--fees <fees>', 'fees').default('auto'))
.addOption(new Option('--ignoreChains [chains]', 'chains to ignore'))
.addOption(new Option('--address <address>', 'contract address').makeOptionMandatory(true))
.addOption(new Option('--deposit <deposit>', 'deposit amount').makeOptionMandatory(true))
.option('--proposal', 'make a proposal rather than a direct migration')
.option('--direct', 'make a direct migration rather than a proposal')
.option('--dry', 'only generate migration msg')
.description('Migrate contract')
.action((code_id: string, options: MigrationOptions) => {
mainProcessor(migrate, options, [code_id]);
.action((codeId: string, options: MigrationOptions) => {
mainProcessor(migrate, options, [codeId]);
}),
{},
);
Expand Down
Loading