Skip to content

Commit

Permalink
add more checks
Browse files Browse the repository at this point in the history
  • Loading branch information
milapsheth committed Sep 30, 2023
1 parent d980d68 commit e2a3932
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 76 deletions.
4 changes: 2 additions & 2 deletions evm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ async function getConstructorArgs(contractName, chain, wallet, options) {
throw new Error(`Missing InterchainGovernance.governanceChain in the chain info.`);
}

const governanceAddress = contractConfig.governanceAddress || 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj';
const governanceAddress = contractConfig.governanceAddress || wallet.address || 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj';

if (!isString(governanceAddress)) {
throw new Error(`Missing InterchainGovernance.governanceAddress in the chain info.`);
}

const minimumTimeDelay = contractConfig.minimumTimeDelay || parseInt(options.args, 10);
const minimumTimeDelay = contractConfig.minimumTimeDelay;

if (!isNumber(minimumTimeDelay)) {
throw new Error(`Missing InterchainGovernance.minimumTimeDelay in the chain info.`);
Expand Down
189 changes: 119 additions & 70 deletions evm/governance.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ const {
Contract,
BigNumber,
} = ethers;
const readlineSync = require('readline-sync');
const { Command, Option } = require('commander');
const {
printInfo,
printWalletInfo,
isValidTimeFormat,
etaToUnixTimestamp,
unixTimestampToEta,
dateToEta,
etaToDate,
getCurrentTimeInSeconds,
wasEventEmitted,
printWarn,
Expand All @@ -25,13 +24,14 @@ const {
isValidAddress,
mainProcessor,
isValidDecimal,
prompt,
} = require('./utils');
const { storeSignedTx, getWallet, signTransaction } = require('./sign-utils.js');
const { getWallet } = require('./sign-utils.js');
const IGovernance = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarServiceGovernance.json');
const IGateway = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGateway.json');

async function processCommand(_, chain, options) {
const { contractName, address, newGovernance, newMintLimiter, action, calldata, nativeValue, eta, privateKey, yes } = options;
const { contractName, address, action, calldata, nativeValue, date, privateKey, yes } = options;

const contracts = chain.contracts;
const contractConfig = contracts[contractName];
Expand All @@ -58,17 +58,13 @@ async function processCommand(_, chain, options) {
throw new Error(`Invalid native value: ${nativeValue}`);
}

if (!isValidTimeFormat(eta)) {
throw new Error(`Invalid ETA: ${eta}. Please pass the eta in the format YYYY-MM-DDTHH:mm:ss`);
}

const rpc = chain.rpc;
const provider = getDefaultProvider(rpc);

printInfo('Chain', chain.name);

const wallet = await getWallet(privateKey, provider, options);
const { address: walletAddress } = await printWalletInfo(wallet, options);
await printWalletInfo(wallet, options);

printInfo('Contract name', contractName);
printInfo('Contract address', governanceAddress);
Expand All @@ -80,11 +76,6 @@ async function processCommand(_, chain, options) {

printInfo('Proposal Action', action);

const unixEta = etaToUnixTimestamp(eta);

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

let gmpPayload;

switch (action) {
Expand All @@ -93,15 +84,33 @@ async function processCommand(_, chain, options) {
throw new Error(`Calldata required for this governance action: ${action}`);
}

if (unixEta < getCurrentTimeInSeconds() + contractConfig?.minimumTimeDelay && !yes) {
printWarn(`${eta} is less than the minimum eta.`);
const answer = readlineSync.question(`Proceed with ${action}?`);
if (answer !== 'y') return;
if (!isValidTimeFormat(date)) {
throw new Error(`Invalid ETA: ${date}. Please pass the eta in the format YYYY-MM-DDTHH:mm:ss`);
}

gmpPayload = defaultAbiCoder.encode(types, values);
const eta = dateToEta(date);

const currTime = getCurrentTimeInSeconds();
printInfo('Current time', etaToDate(currTime));

const minEta = currTime + contractConfig?.minimumTimeDelay;
printInfo('Minimum eta', etaToDate(minEta));

if (eta < minEta) {
printWarn(`${date} is less than the minimum eta.`);
}

const existingProposalEta = await governance.getProposalEta(target, calldata, nativeValue);

if (!existingProposalEta.eq(BigNumber.from(0))) {
throw new Error(`Proposal already exists with eta: ${existingProposalEta}.`);
}

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

printInfo(`Destination chain: ${chain.name}\nDestination governance address: ${governanceAddress}\nGMP payload: ${gmpPayload}`);
gmpPayload = defaultAbiCoder.encode(types, values);

break;
}
Expand All @@ -113,22 +122,24 @@ async function processCommand(_, chain, options) {
throw new Error(`Calldata required for this governance action: ${action}`);
}

if (unixEta < getCurrentTimeInSeconds() && !yes) {
printWarn(`${eta} has already passed.`);
const answer = readlineSync.question(`Proceed with ${action}?`);
if (answer !== 'y') return;
}
const currTime = getCurrentTimeInSeconds();
printInfo('Current time', etaToDate(currTime));

const proposalEta = await governance.getProposalEta(target, calldata, nativeValue);
printInfo('Proposal eta', etaToDate(proposalEta));

if (proposalEta.eq(BigNumber.from(0))) {
throw new Error(`Proposal does not exist.`);
}

values[0] = commandType;
gmpPayload = defaultAbiCoder.encode(types, values);
if (proposalEta <= currTime) {
printWarn(`Proposal eta has already passed.`);
}

printInfo(`Destination chain: ${chain.name}\nDestination governance address: ${governanceAddress}\nGMP payload: ${gmpPayload}`);
const types = ['uint256', 'address', 'bytes', 'uint256', 'uint256'];
const values = [commandType, target, calldata, nativeValue, proposalEta];

gmpPayload = defaultAbiCoder.encode(types, values);

break;
}
Expand All @@ -144,10 +155,10 @@ async function processCommand(_, chain, options) {

const commandType = 2;

values[0] = commandType;
gmpPayload = defaultAbiCoder.encode(types, values);
const types = ['uint256', 'address', 'bytes', 'uint256', 'uint256'];
const values = [commandType, target, calldata, nativeValue, 0];

printInfo(`Destination chain: ${chain.name}\nDestination governance address: ${governanceAddress}\nGMP payload: ${gmpPayload}`);
gmpPayload = defaultAbiCoder.encode(types, values);

break;
}
Expand All @@ -163,10 +174,10 @@ async function processCommand(_, chain, options) {

const commandType = 3;

values[0] = commandType;
gmpPayload = defaultAbiCoder.encode(types, values);
const types = ['uint256', 'address', 'bytes', 'uint256', 'uint256'];
const values = [commandType, target, calldata, nativeValue, 0];

printInfo(`Destination chain: ${chain.name}\nDestination governance address: ${governanceAddress}\nGMP payload: ${gmpPayload}`);
gmpPayload = defaultAbiCoder.encode(types, values);

break;
}
Expand All @@ -175,29 +186,32 @@ async function processCommand(_, chain, options) {
const proposalHash = keccak256(defaultAbiCoder.encode(['address', 'bytes', 'uint256'], [target, calldata, nativeValue]));
const eta = await governance.getTimeLock(proposalHash);

if (eta === 0) {
if (eta.eq(0)) {
throw new Error('Proposal does not exist.');
}

if (!calldata) {
throw new Error(`Calldata required for this governance action: ${action}`);
}

printInfo('Proposal ETA', unixTimestampToEta(eta));
printInfo('Proposal ETA', etaToDate(eta));

if (getCurrentTimeInSeconds() < eta) {
const currTime = getCurrentTimeInSeconds();
printInfo('Current time', etaToDate(currTime));

if (currTime < eta) {
throw new Error(`TimeLock proposal is not yet eligible for execution.`);
}

let receipt;

try {
const tx = await governance.executeProposal(target, calldata, nativeValue, gasOptions);
receipt = tx.wait();
} catch (error) {
printError(error);
if (prompt('Proceed with executing this proposal?', yes)) {
throw new Error('Proposal execution cancelled.');
}

const tx = await governance.executeProposal(target, calldata, nativeValue, { gasLimit: 1e6 });
printInfo('Proposal execution tx', tx.hash);

const receipt = await tx.wait(chain.confirmations);

const eventEmitted = wasEventEmitted(receipt, governance, 'ProposalExecuted');

if (!eventEmitted) {
Expand Down Expand Up @@ -269,37 +283,63 @@ async function processCommand(_, chain, options) {
throw new Error(`Invalid governance action for AxelarServiceGovernance: ${action}`);
}

if (unixEta < getCurrentTimeInSeconds() + contractConfig?.minimumTimeDelay && !yes) {
printWarn(`${eta} is less than the minimum eta.`);
const answer = readlineSync.question(`Proceed with ${action}?`);
if (answer !== 'y') return;
if (!isValidTimeFormat(date)) {
throw new Error(`Invalid ETA: ${date}. Please pass the eta in the format YYYY-MM-DDTHH:mm:ss`);
}

const eta = dateToEta(date);

const currTime = getCurrentTimeInSeconds();
printInfo('Current time', etaToDate(currTime));

const minEta = currTime + contractConfig?.minimumTimeDelay;
printInfo('Minimum eta', etaToDate(minEta));

if (eta < minEta) {
printWarn(`${date} is less than the minimum eta.`);
}

const implementation = options.implementation || chain.contracts.AxelarGateway?.implementation;

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

const gateway = new Contract(target, IGateway.abi, wallet);

const implementationCode = await provider.getCode(implementation);
printInfo('Current gateway implementation', await gateway.implementation());
printInfo('New gateway implementation', implementation);

const newGatewayImplementationCodeHash = await getBytecodeHash(implementation, chain.name, provider);
printInfo('New gateway implementation code hash', newGatewayImplementationCodeHash);

if (implementationCode === '0x') {
printWarn(`There is no code deployed at ${implementation}`);
const answer = readlineSync.question(`Proceed with ${action}?`);
if (answer !== 'y') return;
const currGovernance = await gateway.governance();
const currMintLimiter = await gateway.mintLimiter();

if (currGovernance !== governance.address) {
printWarn(`Gateway governor ${currGovernance} does not match governance contract: ${governance.address}`);
}

const newGatewayImplementationCodeHash = await getBytecodeHash(implementation, chain.name, provider);
let newGovernance = options.newGovernance;

if (contracts.AxelarGateway?.governance === currGovernance) {
newGovernance = contracts.AxelarGateway?.governance;
} else {
newGovernance = '0x';
}

const governance = newGovernance || contracts.AxelarGateway?.governance || undefined;
const mintLimiter = newMintLimiter || contracts.AxelarGateway?.mintLimiter || undefined;
let setupParams;
let newMintLimiter = options.newMintLimiter;

if (governance && mintLimiter) {
setupParams = defaultAbiCoder.encode(['address', 'address', 'bytes'], [governance, mintLimiter, '0x']);
if (contracts.AxelarGateway?.mintLimiter === currMintLimiter) {
newMintLimiter = contracts.AxelarGateway?.mintLimiter;
} else {
setupParams = '0x';
newMintLimiter = '0x';
}

let setupParams = '0x';

if (newGovernance !== '0x' || newMintLimiter !== '0x') {
setupParams = defaultAbiCoder.encode(['address', 'address', 'bytes'], [newGovernance, newMintLimiter, '0x']);
}

printInfo('Setup Params for upgrading AxelarGateway', setupParams);
Expand All @@ -310,17 +350,17 @@ async function processCommand(_, chain, options) {
setupParams,
]);

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

gmpPayload = defaultAbiCoder.encode(types, values);
const proposalEta = await governance.getProposalEta(target, upgradeCalldata, nativeValue);

if (BigNumber.from(proposalEta).gt(0)) {
printWarn("The eta for this proposal already exixts and it's value is", proposalEta);
if (!BigNumber.from(proposalEta).eq(0)) {
printWarn('The proposal already exixts', etaToDate(proposalEta));
}

printInfo(`Destination chain: ${chain.name}\nDestination governance address: ${governanceAddress}\nGMP payload: ${gmpPayload}`);

break;
}

Expand All @@ -332,11 +372,11 @@ async function processCommand(_, chain, options) {
const proposalHash = keccak256(defaultAbiCoder.encode(['address', 'bytes', 'uint256'], [target, calldata, nativeValue]));
const eta = await governance.getTimeLock(proposalHash);

if (eta === 0) {
throw new Error('Proposal does not exist.');
if (eta.eq(0)) {
printWarn('Proposal does not exist.');
}

printInfo('Proposal ETA', unixTimestampToEta(eta));
printInfo('Proposal ETA', etaToDate(eta));

break;
}
Expand All @@ -345,6 +385,15 @@ async function processCommand(_, chain, options) {
throw new Error(`Unknown governance action ${action}`);
}
}

if (gmpPayload) {
printInfo('Destination chain', chain.name);
printInfo('Destination governance address', governanceAddress);
printInfo('GMP payload', gmpPayload);
printInfo('Target contract', target);
printInfo('Target calldata', upgradeCalldata);
printInfo('Native value', nativeValue);
}
}

async function main(options) {
Expand Down Expand Up @@ -388,7 +437,7 @@ program.addOption(new Option('--newMintLimiter <mintLimiter>', 'mint limiter add
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));
program.addOption(new Option('--eta <eta>', 'eta'));
program.addOption(new Option('--date <date>', 'proposal activation date'));
program.addOption(new Option('--implementation <implementation>', 'new gateway implementation'));

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

0 comments on commit e2a3932

Please sign in to comment.