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: deploy v6.2 gateway contracts #85

Merged
merged 12 commits into from
Oct 20, 2023
589 changes: 555 additions & 34 deletions axelar-chains-config/info/mainnet.json

Large diffs are not rendered by default.

200 changes: 100 additions & 100 deletions axelar-chains-config/info/stagenet.json

Large diffs are not rendered by default.

333 changes: 167 additions & 166 deletions axelar-chains-config/info/testnet.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions evm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,20 @@ async function getConstructorArgs(contractName, chain, wallet, options) {
}

case 'Multisig': {
const signers = contractConfig.signers;
const signers = contractConfig.signers || [
'0x3f5876a2b06E54949aB106651Ab6694d0289b2b4',
'0x9256Fd872118ed3a97754B0fB42c15015d17E0CC',
'0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b',
'0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821',
'0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f',
'0x027c1882B975E2cd771AE068b0389FA38B9dda73',
];

if (!isAddressArray(signers)) {
throw new Error(`Missing Multisig.signers in the chain info.`);
}

const threshold = contractConfig.threshold || (signers.length + 1) / 2;
const threshold = contractConfig.threshold || Math.floor((signers.length + 1) / 2);
contractConfig.threshold = threshold;
contractConfig.signers = signers;

Expand Down Expand Up @@ -251,7 +258,13 @@ async function processCommand(config, chain, options) {
printInfo('Pre-deploy Contract bytecode hash', predeployCodehash);

const constructorArgs = await getConstructorArgs(contractName, chain, wallet, options);
const gasOptions = contractConfig.gasOptions || chain.gasOptions || {};
const gasOptions = JSON.parse(JSON.stringify(contractConfig.gasOptions || chain.gasOptions || {}));

// Some chains require a gas adjustment
if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) {
gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.6);
}

printInfo(`Constructor args for chain ${chain.name}`, constructorArgs);
printInfo(`Gas override for chain ${chain.name}`, JSON.stringify(gasOptions, null, 2));

Expand Down
27 changes: 19 additions & 8 deletions evm/deploy-gateway-v6.2.x.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,31 @@ async function getAuthParams(config, chain, options) {
}

const params = [];
const keyIDs = [];

if (options.prevKeyIDs) {
for (const keyID of options.prevKeyIDs.split(',')) {
const { addresses, weights, threshold } = await getEVMAddresses(config, chain, { ...options, keyID });
printInfo(JSON.stringify({ status: 'old', keyID, addresses, weights, threshold }));
params.push(defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold]));
keyIDs.push(keyID);
}
}

const { addresses, weights, threshold, keyID } = await getEVMAddresses(config, chain, options);
printInfo(JSON.stringify({ status: 'latest', keyID, addresses, weights, threshold }));
params.push(defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold]));
keyIDs.push(keyID);

return params;
return { params, keyIDs };
}

function getProxyParams(governance, mintLimiter) {
return defaultAbiCoder.encode(['address', 'address', 'bytes'], [governance, mintLimiter, '0x']);
}

async function deploy(config, chain, options) {
const { privateKey, reuseProxy, reuseHelpers, verify, yes } = options;
const chainName = chain.name.toLowerCase();
const { env, privateKey, reuseProxy, reuseHelpers, verify, yes } = options;

const contractName = 'AxelarGateway';

Expand Down Expand Up @@ -142,7 +144,13 @@ async function deploy(config, chain, options) {
printInfo('Predicted proxy address', proxyAddress);
}

const gasOptions = contractConfig.gasOptions || chain.gasOptions || {};
const gasOptions = JSON.parse(JSON.stringify(contractConfig.gasOptions || chain.gasOptions || {}));

// Some chains require a gas adjustment
if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) {
gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.6);
}

printInfo('Gas override', JSON.stringify(gasOptions, null, 2));
printInfo('Is verification enabled?', verify ? 'y' : 'n');

Expand All @@ -157,9 +165,11 @@ async function deploy(config, chain, options) {
} else {
printInfo(`Deploying auth contract`);

const params = await getAuthParams(config, chain.id, options);
const { params, keyIDs } = await getAuthParams(config, chain.id, options);
printInfo('Auth deployment args', params);

contractConfig.startingKeyIDs = keyIDs;

auth = await authFactory.deploy(params, gasOptions);
await auth.deployTransaction.wait(chain.confirmations);

Expand All @@ -184,6 +194,7 @@ async function deploy(config, chain, options) {
{ salt, deployerContract },
gasOptions,
{},
chain,
);

contractsToVerify.push({
Expand All @@ -198,7 +209,7 @@ async function deploy(config, chain, options) {
printInfo(`Deploying gateway implementation contract`);
printInfo('Gateway Implementation args', `${auth.address},${tokenDeployer.address}`);

const salt = 'AxelarGateway v6.1' + (options.salt || '');
const salt = 'AxelarGateway v6.2' + (options.salt || '');

const implementation = await deployContract(
options.deployMethod,
Expand All @@ -213,7 +224,7 @@ async function deploy(config, chain, options) {

printInfo('Gateway Implementation', implementation.address);

const implementationCodehash = await getBytecodeHash(implementation, chainName);
const implementationCodehash = await getBytecodeHash(implementation, chain.id);
printInfo('Gateway Implementation codehash', implementationCodehash);

contractsToVerify.push({
Expand Down Expand Up @@ -378,7 +389,7 @@ async function upgrade(_, chain, options) {
throw new Error('mintLimiter address is not a contract');
}

const codehash = await getBytecodeHash(contractConfig.implementation, chainName, provider);
const codehash = await getBytecodeHash(contractConfig.implementation, chain.id, provider);

if (!implementationCodehash) {
// retrieve codehash dynamically if not specified in the config file
Expand Down
17 changes: 17 additions & 0 deletions evm/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ async function processCommand(config, chain, options) {
break;
}

case 'params': {
const governance = await gateway.governance();
const mintLimiter = await gateway.mintLimiter();
const authModule = await gateway.authModule();
const tokenDeployer = await gateway.tokenDeployer();
const implementation = await gateway.implementation();

printInfo('Gateway governance', governance);
printInfo('Gateway mint limiter', mintLimiter);
printInfo('Gateway auth module', authModule);
printInfo('Gateway token deployer', tokenDeployer);
printInfo('Gateway implementation', implementation);

break;
}

case 'operators': {
const { addresses, weights, threshold, keyID } = await getEVMAddresses(config, chain.id, options);
printInfo('Axelar validator key id', keyID);
Expand Down Expand Up @@ -339,6 +355,7 @@ program.addOption(
'governance',
'mintLimiter',
'mintLimit',
'params',
])
.makeOptionMandatory(true),
);
Expand Down
36 changes: 32 additions & 4 deletions evm/governance.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,21 +382,45 @@ async function processCommand(_, chain, options) {
break;
}

case 'submitUpgrade': {
const eta = dateToEta(date);
const implementation = options.implementation || chain.contracts.AxelarGateway?.implementation;
const newGatewayImplementationCodeHash = await getBytecodeHash(implementation, chain.name, provider);
const gateway = new Contract(target, IGateway.abi, wallet);
const setupParams = await getGatewaySetupParams(governance, gateway, contracts, options);
calldata = gateway.interface.encodeFunctionData('upgrade', [implementation, newGatewayImplementationCodeHash, setupParams]);

const commandType = 0;
const types = ['uint256', 'address', 'bytes', 'uint256', 'uint256'];
const values = [commandType, target, calldata, nativeValue, eta];

gmpPayload = defaultAbiCoder.encode(types, values);

const tx = await governance.execute(
options.commandId,
contracts.InterchainGovernance.governanceChain,
contracts.InterchainGovernance.governanceAddress,
gmpPayload,
gasOptions,
);
printInfo('Transaction hash', tx.hash);
await tx.wait(chain.confirmations);

return;
}

case 'executeUpgrade': {
target = contracts.AxelarGateway?.address;
const gateway = new Contract(target, IGateway.abi, wallet);
const implementation = options.implementation || chain.contracts.AxelarGateway?.implementation;
const implementationCodehash = chain.contracts.AxelarGateway?.implementationCodehash;
printInfo('New gateway implementation code hash', implementationCodehash);

if (!isValidAddress(implementation)) {
throw new Error(`Invalid new gateway implementation address: ${implementation}`);
}

const setupParams = await getGatewaySetupParams(governance, gateway, contracts, options);

printInfo('Setup Params for upgrading AxelarGateway', setupParams);

calldata = gateway.interface.encodeFunctionData('upgrade', [implementation, implementationCodehash, setupParams]);

const proposalHash = keccak256(defaultAbiCoder.encode(['address', 'bytes', 'uint256'], [target, calldata, nativeValue]));
Expand Down Expand Up @@ -548,7 +572,9 @@ async function main(options) {
contract_calls: proposals,
};

printInfo('Proposal', JSON.stringify(proposal, null, 2));
if (proposals.length > 0) {
printInfo('Proposal', JSON.stringify(proposal, null, 2));
}
}

const program = new Command();
Expand Down Expand Up @@ -581,13 +607,15 @@ program.addOption(
'executeProposal',
'executeMultisigProposal',
'gatewayUpgrade',
'submitUpgrade',
'executeUpgrade',
'withdraw',
'getProposalEta',
]),
);
program.addOption(new Option('--newGovernance <governance>', 'governance address').env('GOVERNANCE'));
program.addOption(new Option('--newMintLimiter <mintLimiter>', 'mint limiter address').env('MINT_LIMITER'));
program.addOption(new Option('--commandId <commandId>', 'command id'));
program.addOption(new Option('--target <target>', 'governance execution target'));
program.addOption(new Option('--calldata <calldata>', 'calldata'));
program.addOption(new Option('--nativeValue <nativeValue>', 'nativeValue').default(0));
Expand Down
7 changes: 4 additions & 3 deletions evm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ const deployContract = async (
});

if (await isContract(predictedAddress, wallet.provider)) {
throw new Error(`Contract is already deployed at ${predictedAddress}`);
printError(`Contract is already deployed at ${predictedAddress}, skipping`);
return new Contract(predictedAddress, contractJson.abi, wallet);
}

switch (deployMethod) {
Expand All @@ -579,7 +580,7 @@ const deployContract = async (
contractJson,
constructorArgs,
deployOptions.salt,
gasOptions.gasLimit,
gasOptions,
verifyOptions,
chain,
);
Expand Down Expand Up @@ -733,7 +734,7 @@ const mainProcessor = async (options, processCommand, save = true, catchErr = fa
} catch (error) {
printError(`Failed with error on ${chain.name}`, error.message);

if (options.ignoreError || !catchErr) {
if (!catchErr && !options.ignoreError) {
throw error;
}
}
Expand Down
19 changes: 11 additions & 8 deletions evm/verify-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const {
utils: { defaultAbiCoder },
} = ethers;
const { Command, Option } = require('commander');
const { verifyContract, getEVMAddresses, printInfo, mainProcessor } = require('./utils');
const { verifyContract, getEVMAddresses, printInfo, printError, mainProcessor } = require('./utils');

async function processCommand(config, chain, options) {
const { env, contractName, dir } = options;
Expand All @@ -25,6 +25,11 @@ async function processCommand(config, chain, options) {
verifyOptions.dir = dir;
}

if (!chain.explorer?.api) {
printError('Explorer API not found for chain', chain.name);
return;
}

printInfo('Verifying contract', contractName);
printInfo('Contract address', options.address || chain.contracts[contractName]?.address);

Expand Down Expand Up @@ -131,18 +136,15 @@ async function processCommand(config, chain, options) {
const auth = await gateway.authModule();
const tokenDeployer = await gateway.tokenDeployer();

// Assume setup params corresponds to epoch 1
const admins = await gateway.admins(1);
const adminThreshold = await gateway.adminThreshold(1);
const setupParams = defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [admins, adminThreshold, '0x']);

const { addresses, weights, threshold } = await getEVMAddresses(config, chain.id, { keyID: `evm-${chain.id}-genesis` });
const { addresses, weights, threshold } = await getEVMAddresses(config, chain.id, {
keyID: options.args || `evm-${chain.id.toLowerCase()}-genesis`,
});
const authParams = [defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold])];

await verifyContract(env, chain.name, auth, [authParams], verifyOptions);
await verifyContract(env, chain.name, tokenDeployer, [], verifyOptions);
await verifyContract(env, chain.name, implementation, [auth, tokenDeployer], verifyOptions);
await verifyContract(env, chain.name, gateway.address, [implementation, setupParams], verifyOptions);
await verifyContract(env, chain.name, gateway.address, [implementation, options.constructorArgs], verifyOptions);

break;
}
Expand Down Expand Up @@ -228,6 +230,7 @@ if (require.main === module) {
program.addOption(new Option('-a, --address <address>', 'contract address'));
program.addOption(new Option('-d, --dir <dir>', 'contract artifacts dir'));
program.addOption(new Option('--args <args>', 'contract args'));
program.addOption(new Option('--constructorArgs <constructorArgs>', 'contract constructor args'));

program.action((options) => {
main(options);
Expand Down
Loading