From 1c1282ce733d39373126ee5e86adb97e96e48132 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Tue, 31 Oct 2023 02:34:23 -0400 Subject: [PATCH 1/6] feat: script optimizations --- evm/balances.js | 12 ++--- evm/broadcast-transactions.js | 10 +---- evm/check-wallet-balance.js | 12 ++--- evm/deploy-const-address-deployer.js | 15 ++----- evm/deploy-contract.js | 66 +++++++++++++++++++++------- evm/deploy-create3-deployer.js | 17 ++----- evm/deploy-gateway-v4.3.x.js | 16 ++----- evm/deploy-gateway-v6.2.x.js | 18 ++------ evm/deploy-its.js | 16 ++----- evm/deploy-upgradable.js | 33 ++++++-------- evm/execute-contract.js | 12 ++--- evm/gateway.js | 15 ++----- evm/governance.js | 15 ++----- evm/multisig.js | 15 ++----- evm/operators.js | 14 ++---- evm/ownership.js | 14 +----- evm/remove-info.js | 12 ++--- evm/send-tokens.js | 21 +++++---- evm/update-nonces.js | 12 ++--- evm/update-static-gas-options.js | 12 ++--- evm/utils.js | 55 +++++++++++++++++++++++ evm/verify-contract.js | 12 ++--- 22 files changed, 182 insertions(+), 242 deletions(-) diff --git a/evm/balances.js b/evm/balances.js index c02b0ce9..6a248857 100644 --- a/evm/balances.js +++ b/evm/balances.js @@ -5,7 +5,7 @@ require('dotenv').config(); const { ethers } = require('hardhat'); const { getDefaultProvider } = ethers; const { Command, Option } = require('commander'); -const { mainProcessor, printWalletInfo, printInfo } = require('./utils'); +const { mainProcessor, printWalletInfo, printInfo, addEnvironmentOptions } = require('./utils'); const { getWallet } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -26,14 +26,8 @@ if (require.main === module) { program.name('balances').description('Display balance of the wallet on specified chains.'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true).env('CHAINS')); + addEnvironmentOptions(program); + program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); program.action((options) => { diff --git a/evm/broadcast-transactions.js b/evm/broadcast-transactions.js index c0368563..1ef85dc8 100644 --- a/evm/broadcast-transactions.js +++ b/evm/broadcast-transactions.js @@ -7,7 +7,7 @@ const { providers: { getDefaultProvider }, } = ethers; -const { printError, printInfo, printWarn, getConfigByChainId, prompt, loadConfig } = require('./utils'); +const { printError, printInfo, printWarn, getConfigByChainId, prompt, loadConfig, addEnvironmentOptions } = require('./utils'); const { sendTransaction, getSignedTx, storeSignedTx } = require('./sign-utils'); async function processCommand(config, _, options, file) { @@ -76,13 +76,7 @@ const program = new Command(); program.name('broadcast-transactions').description('Broadcast all the pending signed transactions of the signer'); program.addOption(new Option('--files [files...]', 'The file where the signed tx are stored').makeOptionMandatory(true)); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addEnvironmentOptions(program, true); program.addOption(new Option('-r, --rpc ', 'The chain rpc')); program.addOption(new Option('-y, --yes', 'skip prompts')); diff --git a/evm/check-wallet-balance.js b/evm/check-wallet-balance.js index 8c0553a3..4a4c8aa1 100644 --- a/evm/check-wallet-balance.js +++ b/evm/check-wallet-balance.js @@ -4,7 +4,7 @@ const { Command, Option } = require('commander'); const { ethers } = require('hardhat'); const { getDefaultProvider, BigNumber } = ethers; -const { printError, mainProcessor } = require('./utils'); +const { printError, mainProcessor, addEnvironmentOptions } = require('./utils'); const { getNonceFileData } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -51,14 +51,8 @@ const program = new Command(); program.name('check-wallet-balance').description('Before offline signing checks if each signer has minimum required wallet balance'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); +addEnvironmentOptions(program); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); program.addOption(new Option('--addresses ', 'The Array of addresses for which the balance to check').env('ADDRESSES')); diff --git a/evm/deploy-const-address-deployer.js b/evm/deploy-const-address-deployer.js index 442e7d57..02b54204 100644 --- a/evm/deploy-const-address-deployer.js +++ b/evm/deploy-const-address-deployer.js @@ -8,7 +8,7 @@ const readlineSync = require('readline-sync'); const { Command, Option } = require('commander'); const chalk = require('chalk'); -const { printInfo, writeJSON, predictAddressCreate, deployCreate } = require('./utils'); +const { printInfo, writeJSON, predictAddressCreate, deployCreate, addDeploymentOptions } = require('./utils'); const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'); const contractName = 'ConstAddressDeployer'; @@ -125,19 +125,10 @@ if (require.main === module) { program.name('deploy-const-address-deployer').description('Deploy const address deployer'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + addDeploymentOptions(program); + program.addOption(new Option('-i, --ignore', 'ignore the nonce value check')); - program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); program.addOption(new Option('-f, --force', 'proceed with contract deployment even if address already returns a bytecode')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.action((options) => { main(options); diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index a444ccbf..7027302d 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -26,8 +26,47 @@ const { prompt, mainProcessor, isContract, + addDeploymentOptions, } = require('./utils'); +function getContractPath(contractName) { + switch (contractName) { + case 'AxelarServiceGovernance': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/AxelarServiceGovernance.sol/AxelarServiceGovernance.json'; + } + + case 'InterchainProposalSender': { + throw new Error(`Artifact path for ${contractName} must be entered manually.`); + } + + case 'InterchainGovernance': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/InterchainGovernance.sol/InterchainGovernance.json'; + } + + case 'Multisig': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/Multisig.sol/Multisig.json'; + } + + case 'Operators': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/utils/Operators.sol/Operators.json'; + } + + case 'ConstAddressDeployer': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'; + } + + case 'Create3Deployer': { + return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'; + } + + case 'TokenDeployer': { + return '@axelar-network/axelar-cgp-solidity/artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'; + } + } + + throw new Error(`${contractName} is not supported.`); +} + async function getConstructorArgs(contractName, chain, wallet, options) { const config = chain.contracts; const contractConfig = config[contractName]; @@ -250,7 +289,14 @@ async function processCommand(config, chain, options) { printInfo('Contract name', contractName); - const contractPath = artifactPath.charAt(0) === '@' ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; + let contractPath; + + if (artifactPath) { + contractPath = artifactPath.charAt(0) === '@' ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; + } else { + contractPath = getContractPath(contractName); + } + printInfo('Contract path', contractPath); const contractJson = require(contractPath); @@ -340,25 +386,11 @@ const program = new Command(); program.name('deploy-contract').description('Deploy contracts using create, create2, or create3'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-a, --artifactPath ', 'artifact path').makeOptionMandatory(true)); -program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true).env('CHAINS')); -program.addOption(new Option('--skipChains ', 'chains to skip over')); +addDeploymentOptions(program, true, true, true, true, true); + program.addOption( new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), ); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); -program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment')); -program.addOption(new Option('-v, --verify ', 'verify the deployed contract on the explorer').env('VERIFY')); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); -program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain')); program.addOption(new Option('--ignoreError', 'ignore errors during deployment for a given chain')); program.action((options) => { diff --git a/evm/deploy-create3-deployer.js b/evm/deploy-create3-deployer.js index 88c37abd..e3e4a0fe 100644 --- a/evm/deploy-create3-deployer.js +++ b/evm/deploy-create3-deployer.js @@ -6,10 +6,10 @@ const { ethers } = require('hardhat'); const { Wallet, getDefaultProvider } = ethers; const readlineSync = require('readline-sync'); const { predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-solidity'); -const { Command, Option } = require('commander'); +const { Command } = require('commander'); const chalk = require('chalk'); -const { printInfo, writeJSON, deployCreate2 } = require('./utils'); +const { printInfo, writeJSON, deployCreate2, addDeploymentOptions } = require('./utils'); const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'); const { deployConstAddressDeployer } = require('./deploy-const-address-deployer'); const contractName = 'Create3Deployer'; @@ -94,18 +94,7 @@ if (require.main === module) { program.name('deploy-create3-deployer').description('Deploy create3 deployer'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); - program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment')); - program.addOption(new Option('-v, --verify ', 'verify the deployed contract on the explorer').env('VERIFY')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + addDeploymentOptions(program, false, false, true); program.action((options) => { main(options); diff --git a/evm/deploy-gateway-v4.3.x.js b/evm/deploy-gateway-v4.3.x.js index fed49ee8..d8517b0c 100644 --- a/evm/deploy-gateway-v4.3.x.js +++ b/evm/deploy-gateway-v4.3.x.js @@ -16,6 +16,7 @@ const { isAddressArray, isNumber, prompt, + addDeploymentOptions, } = require('./utils'); const { ethers } = require('hardhat'); const { @@ -311,22 +312,11 @@ async function programHandler() { program.name('deploy-gateway-v4.3.x').description('Deploy gateway v4.3.x'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainName ', 'chain name').makeOptionMandatory(true).env('CHAIN')); + addDeploymentOptions(program, false, false, false, false, true, true); + program.addOption(new Option('-r, --rpc ', 'chain rpc url').env('URL')); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); - program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); - program.addOption(new Option('-x, --skipExisting', 'skip deployment for existing contracts in the info files').env('SKIP_EXISTING')); program.addOption(new Option('-a, --adminAddresses ', 'admin addresses').env('ADMIN_ADDRESSES')); program.addOption(new Option('-t, --adminThreshold ', 'admin threshold').env('ADMIN_THRESHOLD')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); - program.addOption(new Option('-u, --upgrade', 'upgrade gateway').env('UPGRADE')); program.action((options) => { main(options); diff --git a/evm/deploy-gateway-v6.2.x.js b/evm/deploy-gateway-v6.2.x.js index bcf5145a..6d2eadc6 100644 --- a/evm/deploy-gateway-v6.2.x.js +++ b/evm/deploy-gateway-v6.2.x.js @@ -27,6 +27,7 @@ const { mainProcessor, isContract, deployContract, + addDeploymentOptions, } = require('./utils'); const { storeSignedTx, signTransaction, getWallet } = require('./sign-utils.js'); @@ -478,22 +479,12 @@ async function programHandler() { program.name('deploy-gateway-v6.2.x').description('Deploy gateway v6.2.x'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS')); - program.addOption(new Option('--skipChains ', 'chains to skip over')); + addDeploymentOptions(program, false, false, true, true, true, true); + program.addOption(new Option('-r, --rpc ', 'chain rpc url').env('URL')); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); program.addOption( new Option('--deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create'), ); - program.addOption(new Option('-s, --salt ', 'salt to use for deployment method')); - program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); program.addOption(new Option('-r, --reuseProxy', 'reuse proxy contract modules for new implementation deployment').env('REUSE_PROXY')); program.addOption( new Option('--reuseHelpers', 'reuse helper auth and token deployer contract modules for new implementation deployment').env( @@ -503,14 +494,11 @@ async function programHandler() { program.addOption(new Option('--ignoreError', 'Ignore deployment errors and proceed to next chain')); program.addOption(new Option('-g, --governance ', 'governance address').env('GOVERNANCE')); program.addOption(new Option('-m, --mintLimiter ', 'mint limiter address').env('MINT_LIMITER')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.addOption(new Option('-k, --keyID ', 'key ID').env('KEY_ID')); program.addOption(new Option('-a, --amplifier', 'deploy amplifier gateway').env('AMPLIFIER')); program.addOption(new Option('--prevKeyIDs ', 'previous key IDs to be used for auth contract')); - program.addOption(new Option('-u, --upgrade', 'upgrade gateway').env('UPGRADE')); program.addOption(new Option('--offline', 'Run in offline mode')); program.addOption(new Option('--nonceOffset ', 'The value to add in local nonce if it deviates from actual wallet nonce')); - program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain')); program.action((options) => { main(options); diff --git a/evm/deploy-its.js b/evm/deploy-its.js index 9b647c43..6777905c 100644 --- a/evm/deploy-its.js +++ b/evm/deploy-its.js @@ -11,7 +11,7 @@ const { } = ethers; const readlineSync = require('readline-sync'); const chalk = require('chalk'); -const { printInfo, loadConfig, saveConfig } = require('./utils'); +const { printInfo, loadConfig, saveConfig, addDeploymentOptions } = require('./utils'); const TokenManagerDeployer = require('@axelar-network/interchain-token-service/dist/utils/TokenManagerDeployer.sol/TokenManagerDeployer.json'); const StandardizedTokenLockUnlock = require('@axelar-network/interchain-token-service/dist/token-implementations/StandardizedTokenLockUnlock.sol/StandardizedTokenLockUnlock.json'); @@ -362,20 +362,10 @@ if (require.main === module) { program.name('deploy-its').description('Deploy interchain token service'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + addDeploymentOptions(program, false, false, false, false, true, true); + program.addOption(new Option('-s, --salt ', 'deployment salt to use for ITS deployment').makeOptionMandatory(true).env('SALT')); - program.addOption(new Option('-v, --verify ', 'verify the deployed contract on the explorer [true|false|only]').env('VERIFY')); - program.addOption(new Option('-x, --skipExisting ', 'skip deploying contracts if they already exist').env('SKIP_EXISTING')); program.addOption(new Option('-o, --operator', 'address of the ITS operator').env('OPERATOR_ADDRESS')); - program.addOption(new Option('-u, --upgrade', 'upgrade ITS').env('UPGRADE')); program.action(async (options) => { options.skipExisting = options.skipExisting === 'true'; diff --git a/evm/deploy-upgradable.js b/evm/deploy-upgradable.js index ba55fe30..463a6f1b 100644 --- a/evm/deploy-upgradable.js +++ b/evm/deploy-upgradable.js @@ -13,7 +13,16 @@ const IUpgradable = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/ const { Command, Option } = require('commander'); const { deployUpgradable, deployCreate2Upgradable, deployCreate3Upgradable, upgradeUpgradable } = require('./upgradable'); -const { printInfo, printError, saveConfig, loadConfig, printWalletInfo, getDeployedAddress, prompt } = require('./utils'); +const { + printInfo, + printError, + saveConfig, + loadConfig, + printWalletInfo, + getDeployedAddress, + prompt, + addDeploymentOptions, +} = require('./utils'); function getProxy(wallet, proxyAddress) { return new Contract(proxyAddress, IUpgradable.abi, wallet); @@ -65,7 +74,7 @@ async function getImplementationArgs(contractName, config, options) { throw new Error(`${contractName} is not supported.`); } -function getInitArgs(contractName, config) { +function getInitArgs(contractName) { switch (contractName) { case 'AxelarGasService': { return '0x'; @@ -79,7 +88,7 @@ function getInitArgs(contractName, config) { throw new Error(`${contractName} is not supported.`); } -function getUpgradeArgs(contractName, config) { +function getUpgradeArgs(contractName) { switch (contractName) { case 'AxelarGasService': { return '0x'; @@ -304,25 +313,11 @@ const program = new Command(); program.name('deploy-upgradable').description('Deploy upgradable contracts'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); -program.addOption(new Option('--skipChains ', 'chains to skip over')); +addDeploymentOptions(program, true, true, true, true, false, true); + program.addOption( new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), ); -program.addOption(new Option('-a, --artifactPath ', 'artifact path')); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); -program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment')); -program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract')); -program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.addOption(new Option('--args ', 'customize deployment args')); program.action((options) => { diff --git a/evm/execute-contract.js b/evm/execute-contract.js index 3daddeb4..35eb7a50 100644 --- a/evm/execute-contract.js +++ b/evm/execute-contract.js @@ -12,7 +12,7 @@ const { const readlineSync = require('readline-sync'); const { Command, Option } = require('commander'); -const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, printInfo } = require('./utils'); +const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, printInfo, addEnvironmentOptions } = require('./utils'); async function getCallData(methodName, targetContract, inputRecipient, inputAmount) { var recipient, amount; @@ -203,14 +203,8 @@ const program = new Command(); program.name('execute-contract').description('Executes a call to an external contract'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); +addEnvironmentOptions(program); + program.addOption( new Option('-pc, --callContractPath ', 'artifact path for the called contract').makeOptionMandatory(true), ); diff --git a/evm/gateway.js b/evm/gateway.js index ec4a68f8..8f6d1c87 100644 --- a/evm/gateway.js +++ b/evm/gateway.js @@ -20,6 +20,7 @@ const { wasEventEmitted, mainProcessor, printError, + addCallContractOptions, } = require('./utils'); const { getWallet } = require('./sign-utils'); @@ -330,17 +331,9 @@ const program = new Command(); program.name('gateway').description('Script to perform gateway commands'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addCallContractOptions(program, true); + program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig')); -program.addOption(new Option('-a, --address
', 'override address')); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true).env('CHAINS')); -program.addOption(new Option('--skipChains ', 'chains to skip over')); program.addOption( new Option('--action ', 'gateway action') .choices([ @@ -359,8 +352,6 @@ program.addOption( ]) .makeOptionMandatory(true), ); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.addOption(new Option('--payload ', 'gmp payload')); program.addOption(new Option('--commandID ', 'execute command ID')); diff --git a/evm/governance.js b/evm/governance.js index 83953b06..7689ac82 100644 --- a/evm/governance.js +++ b/evm/governance.js @@ -27,6 +27,7 @@ const { mainProcessor, isValidDecimal, prompt, + addCallContractOptions, } = require('./utils'); const { getWallet } = require('./sign-utils.js'); const IGovernance = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarServiceGovernance.json'); @@ -606,23 +607,13 @@ const program = new Command(); program.name('governance').description('Script to manage interchain governance actions'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addCallContractOptions(program, true); + program.addOption( new Option('-c, --contractName ', 'contract name') .choices(['InterchainGovernance', 'AxelarServiceGovernance']) .default('InterchainGovernance'), ); -program.addOption(new Option('-a, --address
', 'override address')); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); -program.addOption(new Option('--skipChains ', 'chains to skip over')); program.addOption( new Option('--action ', 'governance action').choices([ 'scheduleTimeLock', diff --git a/evm/multisig.js b/evm/multisig.js index 6bf7a851..655dc3e7 100644 --- a/evm/multisig.js +++ b/evm/multisig.js @@ -22,6 +22,7 @@ const { mainProcessor, isValidDecimal, prompt, + addCallContractOptions, } = require('./utils'); const IMultisig = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IMultisig.json'); const IGateway = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGateway.json'); @@ -317,24 +318,14 @@ const program = new Command(); program.name('multisig').description('Script to manage multisig actions'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addCallContractOptions(program, true); + program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig').makeOptionMandatory(false)); -program.addOption(new Option('-a, --address
', 'override address')); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); -program.addOption(new Option('--skipChains ', 'chains to skip over')); program.addOption( new Option('--action ', 'multisig action') .choices(['signers', 'setTokenMintLimits', 'transferMintLimiter', 'withdraw', 'executeMultisigProposal']) .makeOptionMandatory(true), ); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.addOption(new Option('--offline', 'run script in offline mode')); program.addOption(new Option('--nonceOffset ', 'The value to add in local nonce if it deviates from actual wallet nonce')); diff --git a/evm/operators.js b/evm/operators.js index b7acad61..42386c83 100644 --- a/evm/operators.js +++ b/evm/operators.js @@ -21,6 +21,7 @@ const { isKeccak256Hash, parseArgs, prompt, + addCallContractOptions, } = require('./utils'); const IAxelarGasService = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGasService.json'); const IOperators = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IOperators.json'); @@ -266,22 +267,13 @@ const program = new Command(); program.name('operators').description('script to manage operators contract'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); +addCallContractOptions(program); + program.addOption(new Option('-c, --contractName ', 'contract name').default('Operators').makeOptionMandatory(false)); -program.addOption(new Option('-n, --chainNames ', 'chains').makeOptionMandatory(true)); -program.addOption(new Option('--address
', 'override address').makeOptionMandatory(false)); program.addOption( new Option('--action ', 'operator action').choices(['isOperator', 'addOperator', 'removeOperator', 'collectFees', 'refund']), ); program.addOption(new Option('--args ', 'operator action arguments').makeOptionMandatory(true)); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.action((options) => { main(options); diff --git a/evm/ownership.js b/evm/ownership.js index f7447d3c..f419bec9 100644 --- a/evm/ownership.js +++ b/evm/ownership.js @@ -11,7 +11,7 @@ const { Contract, } = ethers; const { Command, Option } = require('commander'); -const { printInfo, printWalletInfo, loadConfig, saveConfig, prompt } = require('./utils'); +const { printInfo, printWalletInfo, loadConfig, saveConfig, prompt, addCallContractOptions } = require('./utils'); const IOwnable = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/interfaces/IOwnable.sol/IOwnable.json'); @@ -192,18 +192,9 @@ const program = new Command(); program.name('ownership').description('script to manage contract ownership'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addCallContractOptions(program); -program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); -program.addOption(new Option('--address
', 'override address').makeOptionMandatory(false)); program.addOption( new Option('--action ', 'ownership action').choices([ 'owner', @@ -214,7 +205,6 @@ program.addOption( ]), ); program.addOption(new Option('--newOwner ', 'new owner address').makeOptionMandatory(false)); -program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); program.action((options) => { main(options); diff --git a/evm/remove-info.js b/evm/remove-info.js index 6b1f4a5e..1d60e7ca 100644 --- a/evm/remove-info.js +++ b/evm/remove-info.js @@ -3,7 +3,7 @@ require('dotenv').config(); const { Command, Option } = require('commander'); -const { mainProcessor } = require('./utils'); +const { mainProcessor, addEnvironmentOptions } = require('./utils'); async function processCommand(options, chain, _) { const { contractName } = options; @@ -23,15 +23,9 @@ const program = new Command(); program.name('remove-info').description('Remove info about contract from the info file.'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); +addEnvironmentOptions(program); + program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); program.action((options) => { main(options); diff --git a/evm/send-tokens.js b/evm/send-tokens.js index cf0548f0..930011f4 100644 --- a/evm/send-tokens.js +++ b/evm/send-tokens.js @@ -10,7 +10,16 @@ const { utils: { parseEther, parseUnits }, } = ethers; -const { printInfo, printError, printWalletInfo, isAddressArray, mainProcessor, isValidDecimal, prompt } = require('./utils'); +const { + printInfo, + printError, + printWalletInfo, + isAddressArray, + mainProcessor, + isValidDecimal, + prompt, + addEnvironmentOptions, +} = require('./utils'); const { storeSignedTx, getWallet, signTransaction } = require('./sign-utils.js'); async function processCommand(_, chain, options) { @@ -102,14 +111,8 @@ if (require.main === module) { program.name('send-tokens').description('Send native tokens to an address.'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); + addEnvironmentOptions(program); + program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); program.addOption(new Option('-r, --recipients ', 'comma-separated recipients of tokens').makeOptionMandatory(true)); program.addOption(new Option('-a, --amount ', 'amount to transfer (in terms of ETH)')); diff --git a/evm/update-nonces.js b/evm/update-nonces.js index 6c740ea6..bb04660d 100644 --- a/evm/update-nonces.js +++ b/evm/update-nonces.js @@ -5,7 +5,7 @@ const { Command, Option } = require('commander'); const { ethers } = require('hardhat'); const { getDefaultProvider } = ethers; -const { mainProcessor, printInfo, prompt } = require('./utils'); +const { mainProcessor, printInfo, prompt, addEnvironmentOptions } = require('./utils'); const { getNonceFromProvider, getNonceFileData, updateNonceFileData } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -53,14 +53,8 @@ const program = new Command(); program.name('update-nonces').description('Update nonces for addresses'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); +addEnvironmentOptions(program); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); program.addOption(new Option('--addresses ', 'The Array of addresses for which the nonces to update').env('ADDRESSES')); program.addOption(new Option('-y, --yes', 'skip prompts')); diff --git a/evm/update-static-gas-options.js b/evm/update-static-gas-options.js index b9f9577b..a4c6156e 100644 --- a/evm/update-static-gas-options.js +++ b/evm/update-static-gas-options.js @@ -9,7 +9,7 @@ const { BigNumber, } = ethers; -const { printInfo, mainProcessor, prompt } = require('./utils'); +const { printInfo, mainProcessor, prompt, addEnvironmentOptions } = require('./utils'); const defaultGasLimit = 3e6; const gasPriceMultiplier = 5; @@ -101,14 +101,8 @@ const program = new Command(); program.name('update-static-gas-options').description('Update staticGasOptions'); -program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), -); -program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); +addEnvironmentOptions(program); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); program.addOption(new Option('-y, --yes', 'skip prompts')); diff --git a/evm/utils.js b/evm/utils.js index 97b0ad17..c60ca73b 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -24,6 +24,7 @@ const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const CreateDeploy = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/CreateDeploy.sol/CreateDeploy.json'); const IDeployer = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IDeployer.json'); const { verifyContract } = require(`${__dirname}/../axelar-chains-config`); +const { Option } = require('commander'); const getSaltFromKey = (key) => { return keccak256(defaultAbiCoder.encode(['string'], [key.toString()])); @@ -777,6 +778,57 @@ function getConfigByChainId(chainId, config) { throw new Error(`Chain with chainId ${chainId} not found in the config`); } +const addEnvironmentOptions = (program, ignoreChainNames) => { + program.addOption( + new Option('-e, --env ', 'environment') + .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) + .default('testnet') + .makeOptionMandatory(true) + .env('ENV'), + ); + + if (!ignoreChainNames) { + program.addOption( + new Option('-n, --chainNames ', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), + ); + } + + return program; +}; + +const addDeploymentOptions = (program, artifactPath, contractName, salt, skipChains, skipExisting, upgrade) => { + addEnvironmentOptions(program); + + program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); + program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + + if (artifactPath) program.addOption(new Option('-a, --artifactPath ', 'artifact path')); + if (contractName) program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + if (salt) program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment').env('SALT')); + if (skipChains) program.addOption(new Option('--skipChains ', 'chains to skip over')); + + if (skipExisting) { + program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); + } + + if (upgrade) program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + + return program; +}; + +const addCallContractOptions = (program, skipChains) => { + addEnvironmentOptions(program); + + program.addOption(new Option('-a, --address
', 'override address')); + program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + + if (skipChains) program.addOption(new Option('--skipChains ', 'chains to skip over')); + + return program; +}; + module.exports = { deployCreate, deployCreate2, @@ -822,4 +874,7 @@ module.exports = { verifyContract, prompt, mainProcessor, + addEnvironmentOptions, + addDeploymentOptions, + addCallContractOptions, }; diff --git a/evm/verify-contract.js b/evm/verify-contract.js index ec58fe04..c4b3dc64 100644 --- a/evm/verify-contract.js +++ b/evm/verify-contract.js @@ -11,7 +11,7 @@ const { utils: { defaultAbiCoder }, } = ethers; const { Command, Option } = require('commander'); -const { verifyContract, getEVMAddresses, printInfo, printError, mainProcessor } = require('./utils'); +const { verifyContract, getEVMAddresses, printInfo, printError, mainProcessor, addEnvironmentOptions } = require('./utils'); async function processCommand(config, chain, options) { const { env, contractName, dir } = options; @@ -217,14 +217,8 @@ if (require.main === module) { program.name('balances').description('Display balance of the wallet on specified chains.'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true)); + addEnvironmentOptions(program); + program.addOption(new Option('--skipChains ', 'skip chains')); program.addOption(new Option('-c, --contractName ', 'contract name')); program.addOption(new Option('-a, --address
', 'contract address')); From 51baefec311855487c35785306ee34e4868c6416 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Sat, 4 Nov 2023 16:06:55 -0400 Subject: [PATCH 2/6] feat: address comments --- evm/balances.js | 9 ++- evm/broadcast-transactions.js | 24 +++---- evm/check-wallet-balance.js | 23 ++++--- evm/cli-utils.js | 54 ++++++++++++++++ evm/deploy-const-address-deployer.js | 5 +- evm/deploy-contract.js | 68 +++++--------------- evm/deploy-create3-deployer.js | 5 +- evm/deploy-gateway-v4.3.x.js | 4 +- evm/deploy-gateway-v6.2.x.js | 4 +- evm/deploy-its.js | 5 +- evm/deploy-upgradable.js | 36 +++++------ evm/execute-contract.js | 94 +++++++++++++++------------- evm/gateway.js | 80 +++++++++++------------ evm/governance.js | 90 +++++++++++++------------- evm/min-deposit-proposal.js | 12 +--- evm/multisig.js | 60 +++++++++--------- evm/operators.js | 34 ++++++---- evm/ownership.js | 41 ++++++------ evm/remove-info.js | 21 ++++--- evm/send-tokens.js | 17 +---- evm/update-nonces.js | 24 +++---- evm/update-static-gas-options.js | 22 ++++--- evm/utils.js | 85 +++++++++++++------------ evm/verify-contract.js | 7 +-- 24 files changed, 427 insertions(+), 397 deletions(-) create mode 100644 evm/cli-utils.js diff --git a/evm/balances.js b/evm/balances.js index 6a248857..3f125bbb 100644 --- a/evm/balances.js +++ b/evm/balances.js @@ -4,8 +4,9 @@ require('dotenv').config(); const { ethers } = require('hardhat'); const { getDefaultProvider } = ethers; -const { Command, Option } = require('commander'); -const { mainProcessor, printWalletInfo, printInfo, addEnvironmentOptions } = require('./utils'); +const { Command } = require('commander'); +const { mainProcessor, printWalletInfo, printInfo } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { getWallet } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -26,9 +27,7 @@ if (require.main === module) { program.name('balances').description('Display balance of the wallet on specified chains.'); - addEnvironmentOptions(program); - - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + addBaseOptions(program); program.action((options) => { main(options); diff --git a/evm/broadcast-transactions.js b/evm/broadcast-transactions.js index 1ef85dc8..6b3cbead 100644 --- a/evm/broadcast-transactions.js +++ b/evm/broadcast-transactions.js @@ -7,7 +7,8 @@ const { providers: { getDefaultProvider }, } = ethers; -const { printError, printInfo, printWarn, getConfigByChainId, prompt, loadConfig, addEnvironmentOptions } = require('./utils'); +const { printError, printInfo, printWarn, getConfigByChainId, prompt, loadConfig } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { sendTransaction, getSignedTx, storeSignedTx } = require('./sign-utils'); async function processCommand(config, _, options, file) { @@ -71,17 +72,18 @@ async function main(options) { } } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('broadcast-transactions').description('Broadcast all the pending signed transactions of the signer'); + program.name('broadcast-transactions').description('Broadcast all the pending signed transactions of the signer'); -program.addOption(new Option('--files [files...]', 'The file where the signed tx are stored').makeOptionMandatory(true)); -addEnvironmentOptions(program, true); -program.addOption(new Option('-r, --rpc ', 'The chain rpc')); -program.addOption(new Option('-y, --yes', 'skip prompts')); + program.addOption(new Option('--files [files...]', 'The file where the signed tx are stored').makeOptionMandatory(true)); + addBaseOptions(program, { ignoreChainNames: true }); + program.addOption(new Option('-r, --rpc ', 'The chain rpc')); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/check-wallet-balance.js b/evm/check-wallet-balance.js index 4a4c8aa1..011c5b25 100644 --- a/evm/check-wallet-balance.js +++ b/evm/check-wallet-balance.js @@ -4,7 +4,8 @@ const { Command, Option } = require('commander'); const { ethers } = require('hardhat'); const { getDefaultProvider, BigNumber } = ethers; -const { printError, mainProcessor, addEnvironmentOptions } = require('./utils'); +const { printError, mainProcessor } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { getNonceFileData } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -47,17 +48,19 @@ async function main(options) { await mainProcessor(options, processCommand); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('check-wallet-balance').description('Before offline signing checks if each signer has minimum required wallet balance'); + program.name('check-wallet-balance').description('Before offline signing checks if each signer has minimum required wallet balance'); -addEnvironmentOptions(program); + addBaseOptions(program, { ignorePrivateKey: true }); -program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); -program.addOption(new Option('--addresses ', 'The Array of addresses for which the balance to check').env('ADDRESSES')); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); + program.addOption(new Option('--addresses ', 'The Array of addresses for which the balance to check').env('ADDRESSES')); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/cli-utils.js b/evm/cli-utils.js new file mode 100644 index 00000000..cbc84bd5 --- /dev/null +++ b/evm/cli-utils.js @@ -0,0 +1,54 @@ +'use strict'; + +const { Option } = require('commander'); + +const addBaseOptions = (program, options = {}) => { + program.addOption( + new Option('-e, --env ', 'environment') + .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) + .default('testnet') + .makeOptionMandatory(true) + .env('ENV'), + ); + program.addOption(new Option('--skipChains ', 'chains to skip over')); + program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + + if (!options.ignoreChainNames) { + program.addOption( + new Option('-n, --chainNames ', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), + ); + } + + if (!options.ignorePrivateKey) { + program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + } + + if (options.address) { + program.addOption(new Option('-a, --address
', 'override address')); + } + + return program; +}; + +const addExtendedOptions = (program, options = {}) => { + addBaseOptions(program, options); + + program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); + + if (options.artifactPath) program.addOption(new Option('-a, --artifactPath ', 'artifact path')); + if (options.contractName) program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + if (options.salt) program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment').env('SALT')); + + if (options.skipExisting) { + program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); + } + + if (options.upgrade) program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + + return program; +}; + +module.exports = { + addBaseOptions, + addExtendedOptions, +}; diff --git a/evm/deploy-const-address-deployer.js b/evm/deploy-const-address-deployer.js index 02b54204..0292ecbd 100644 --- a/evm/deploy-const-address-deployer.js +++ b/evm/deploy-const-address-deployer.js @@ -8,7 +8,8 @@ const readlineSync = require('readline-sync'); const { Command, Option } = require('commander'); const chalk = require('chalk'); -const { printInfo, writeJSON, predictAddressCreate, deployCreate, addDeploymentOptions } = require('./utils'); +const { printInfo, writeJSON, predictAddressCreate, deployCreate } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'); const contractName = 'ConstAddressDeployer'; @@ -125,7 +126,7 @@ if (require.main === module) { program.name('deploy-const-address-deployer').description('Deploy const address deployer'); - addDeploymentOptions(program); + addExtendedOptions(program); program.addOption(new Option('-i, --ignore', 'ignore the nonce value check')); program.addOption(new Option('-f, --force', 'proceed with contract deployment even if address already returns a bytecode')); diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index 7027302d..f8ecacd1 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -9,7 +9,6 @@ const { utils: { isAddress, keccak256, toUtf8Bytes }, } = ethers; const { Command, Option } = require('commander'); - const { printInfo, printWarn, @@ -26,48 +25,11 @@ const { prompt, mainProcessor, isContract, - addDeploymentOptions, + getContractPath, } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); -function getContractPath(contractName) { - switch (contractName) { - case 'AxelarServiceGovernance': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/AxelarServiceGovernance.sol/AxelarServiceGovernance.json'; - } - - case 'InterchainProposalSender': { - throw new Error(`Artifact path for ${contractName} must be entered manually.`); - } - - case 'InterchainGovernance': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/InterchainGovernance.sol/InterchainGovernance.json'; - } - - case 'Multisig': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/Multisig.sol/Multisig.json'; - } - - case 'Operators': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/utils/Operators.sol/Operators.json'; - } - - case 'ConstAddressDeployer': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'; - } - - case 'Create3Deployer': { - return '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'; - } - - case 'TokenDeployer': { - return '@axelar-network/axelar-cgp-solidity/artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'; - } - } - - throw new Error(`${contractName} is not supported.`); -} - -async function getConstructorArgs(contractName, chain, wallet, options) { +async function getConstructorArgs(contractName, chain, wallet) { const config = chain.contracts; const contractConfig = config[contractName]; @@ -382,19 +344,21 @@ async function main(options) { await mainProcessor(options, processCommand); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('deploy-contract').description('Deploy contracts using create, create2, or create3'); + program.name('deploy-contract').description('Deploy contracts using create, create2, or create3'); -addDeploymentOptions(program, true, true, true, true, true); + addExtendedOptions(program, { artifactPath: true, contractName: true, salt: true, skipChains: true, skipExisting: true }); -program.addOption( - new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), -); -program.addOption(new Option('--ignoreError', 'ignore errors during deployment for a given chain')); + program.addOption( + new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), + ); + program.addOption(new Option('--ignoreError', 'ignore errors during deployment for a given chain')); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/deploy-create3-deployer.js b/evm/deploy-create3-deployer.js index e3e4a0fe..02ffa666 100644 --- a/evm/deploy-create3-deployer.js +++ b/evm/deploy-create3-deployer.js @@ -9,7 +9,8 @@ const { predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-soli const { Command } = require('commander'); const chalk = require('chalk'); -const { printInfo, writeJSON, deployCreate2, addDeploymentOptions } = require('./utils'); +const { printInfo, writeJSON, deployCreate2 } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'); const { deployConstAddressDeployer } = require('./deploy-const-address-deployer'); const contractName = 'Create3Deployer'; @@ -94,7 +95,7 @@ if (require.main === module) { program.name('deploy-create3-deployer').description('Deploy create3 deployer'); - addDeploymentOptions(program, false, false, true); + addExtendedOptions(program, { salt: true }); program.action((options) => { main(options); diff --git a/evm/deploy-gateway-v4.3.x.js b/evm/deploy-gateway-v4.3.x.js index f911f446..866188a4 100644 --- a/evm/deploy-gateway-v4.3.x.js +++ b/evm/deploy-gateway-v4.3.x.js @@ -16,8 +16,8 @@ const { isAddressArray, isNumber, prompt, - addDeploymentOptions, } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); const { ethers } = require('hardhat'); const { getContractFactory, @@ -312,7 +312,7 @@ async function programHandler() { program.name('deploy-gateway-v4.3.x').description('Deploy gateway v4.3.x'); - addDeploymentOptions(program, false, false, false, false, true, true); + addExtendedOptions(program, { skipExisting: true, upgrade: true }); program.addOption(new Option('-r, --rpc ', 'chain rpc url').env('URL')); program.addOption(new Option('-a, --adminAddresses ', 'admin addresses').env('ADMIN_ADDRESSES')); diff --git a/evm/deploy-gateway-v6.2.x.js b/evm/deploy-gateway-v6.2.x.js index 9dfc44f7..75ec39f2 100644 --- a/evm/deploy-gateway-v6.2.x.js +++ b/evm/deploy-gateway-v6.2.x.js @@ -27,8 +27,8 @@ const { mainProcessor, isContract, deployContract, - addDeploymentOptions, } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); const { storeSignedTx, signTransaction, getWallet } = require('./sign-utils.js'); const AxelarGatewayProxy = require('@axelar-network/axelar-cgp-solidity/artifacts/contracts/AxelarGatewayProxy.sol/AxelarGatewayProxy.json'); @@ -501,7 +501,7 @@ async function programHandler() { program.name('deploy-gateway-v6.2.x').description('Deploy gateway v6.2.x'); - addDeploymentOptions(program, false, false, true, true, true, true); + addExtendedOptions(program, { salt: true, skipChains: true, skipExisting: true, upgrade: true }); program.addOption(new Option('-r, --rpc ', 'chain rpc url').env('URL')); program.addOption( diff --git a/evm/deploy-its.js b/evm/deploy-its.js index 363f5010..7739870e 100644 --- a/evm/deploy-its.js +++ b/evm/deploy-its.js @@ -11,7 +11,8 @@ const { } = ethers; const readlineSync = require('readline-sync'); const chalk = require('chalk'); -const { printInfo, loadConfig, saveConfig, addDeploymentOptions } = require('./utils'); +const { printInfo, loadConfig, saveConfig } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); const TokenManagerDeployer = require('@axelar-network/interchain-token-service/dist/utils/TokenManagerDeployer.sol/TokenManagerDeployer.json'); const StandardizedTokenLockUnlock = require('@axelar-network/interchain-token-service/dist/token-implementations/StandardizedTokenLockUnlock.sol/StandardizedTokenLockUnlock.json'); @@ -362,7 +363,7 @@ if (require.main === module) { program.name('deploy-its').description('Deploy interchain token service'); - addDeploymentOptions(program, false, false, false, false, true, true); + addExtendedOptions(program, { skipExisting: true, upgrade: true }); program.addOption(new Option('-s, --salt ', 'deployment salt to use for ITS deployment').makeOptionMandatory(true).env('SALT')); program.addOption(new Option('-o, --operator', 'address of the ITS operator').env('OPERATOR_ADDRESS')); diff --git a/evm/deploy-upgradable.js b/evm/deploy-upgradable.js index 463a6f1b..5b82ebc1 100644 --- a/evm/deploy-upgradable.js +++ b/evm/deploy-upgradable.js @@ -13,16 +13,8 @@ const IUpgradable = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/ const { Command, Option } = require('commander'); const { deployUpgradable, deployCreate2Upgradable, deployCreate3Upgradable, upgradeUpgradable } = require('./upgradable'); -const { - printInfo, - printError, - saveConfig, - loadConfig, - printWalletInfo, - getDeployedAddress, - prompt, - addDeploymentOptions, -} = require('./utils'); +const { printInfo, printError, saveConfig, loadConfig, printWalletInfo, getDeployedAddress, prompt } = require('./utils'); +const { addExtendedOptions } = require('./cli-utils'); function getProxy(wallet, proxyAddress) { return new Contract(proxyAddress, IUpgradable.abi, wallet); @@ -309,19 +301,21 @@ async function main(options) { } } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('deploy-upgradable').description('Deploy upgradable contracts'); + program.name('deploy-upgradable').description('Deploy upgradable contracts'); -addDeploymentOptions(program, true, true, true, true, false, true); + addExtendedOptions(program, { artifactPath: true, contractName: true, salt: true, skipChains: true, upgrade: true }); -program.addOption( - new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), -); -program.addOption(new Option('--args ', 'customize deployment args')); + program.addOption( + new Option('-m, --deployMethod ', 'deployment method').choices(['create', 'create2', 'create3']).default('create2'), + ); + program.addOption(new Option('--args ', 'customize deployment args')); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/execute-contract.js b/evm/execute-contract.js index 35eb7a50..ae429b5d 100644 --- a/evm/execute-contract.js +++ b/evm/execute-contract.js @@ -12,7 +12,8 @@ const { const readlineSync = require('readline-sync'); const { Command, Option } = require('commander'); -const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, printInfo, addEnvironmentOptions } = require('./utils'); +const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, printInfo } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); async function getCallData(methodName, targetContract, inputRecipient, inputAmount) { var recipient, amount; @@ -199,47 +200,50 @@ async function main(options) { } } -const program = new Command(); - -program.name('execute-contract').description('Executes a call to an external contract'); - -addEnvironmentOptions(program); - -program.addOption( - new Option('-pc, --callContractPath ', 'artifact path for the called contract').makeOptionMandatory(true), -); -program.addOption(new Option('-cn, --callContractName ', 'name of the called contract').makeOptionMandatory(true)); -program.addOption( - new Option('-pt, --targetContractPath ', 'artifact path for the target contract').makeOptionMandatory(true), -); -program.addOption( - new Option( - '-tn, --targetContractName ', - 'name of the target contract that is called through executeContract', - ).makeOptionMandatory(false), -); -program.addOption( - new Option('-ta, --targetContractAddress ', 'The address of the contract to be called') - .makeOptionMandatory(true) - .env('TARGET_ADDR'), -); -program.addOption( - new Option('-v, --nativeValue ', 'The amount of native token (e.g., Ether) to be sent along with the call').default(0), -); -program.addOption( - new Option('-m, --methodName ', 'method name to call in executeContract') - .choices(['withdraw', 'transfer', 'approve', 'default']) - .default('default'), -); -program.addOption( - new Option('-k, --privateKey ', 'The private key of the caller').makeOptionMandatory(true).env('PRIVATE_KEY'), -); -program.addOption(new Option('-c, --callData ', 'The calldata to be sent').env('CALL_DATA').default('0x')); -program.addOption(new Option('-ra, --recipientAddress ', 'The recipient address for the tokens').env('RECIPIENT_ADDR')); -program.addOption(new Option('-am, --amount ', 'The amount of tokens to transfer/withdraw/provide allowance etc.').env('AMOUNT')); - -program.action((options) => { - main(options); -}); - -program.parse(); +if (require.main === module) { + const program = new Command(); + + program.name('execute-contract').description('Executes a call to an external contract'); + + addBaseOptions(program); + + program.addOption( + new Option('-pc, --callContractPath ', 'artifact path for the called contract').makeOptionMandatory(true), + ); + program.addOption(new Option('-cn, --callContractName ', 'name of the called contract').makeOptionMandatory(true)); + program.addOption( + new Option('-pt, --targetContractPath ', 'artifact path for the target contract').makeOptionMandatory(true), + ); + program.addOption( + new Option( + '-tn, --targetContractName ', + 'name of the target contract that is called through executeContract', + ).makeOptionMandatory(false), + ); + program.addOption( + new Option('-ta, --targetContractAddress ', 'The address of the contract to be called') + .makeOptionMandatory(true) + .env('TARGET_ADDR'), + ); + program.addOption( + new Option('-v, --nativeValue ', 'The amount of native token (e.g., Ether) to be sent along with the call').default(0), + ); + program.addOption( + new Option('-m, --methodName ', 'method name to call in executeContract') + .choices(['withdraw', 'transfer', 'approve', 'default']) + .default('default'), + ); + program.addOption(new Option('-c, --callData ', 'The calldata to be sent').env('CALL_DATA').default('0x')); + program.addOption( + new Option('-ra, --recipientAddress ', 'The recipient address for the tokens').env('RECIPIENT_ADDR'), + ); + program.addOption( + new Option('-am, --amount ', 'The amount of tokens to transfer/withdraw/provide allowance etc.').env('AMOUNT'), + ); + + program.action((options) => { + main(options); + }); + + program.parse(); +} diff --git a/evm/gateway.js b/evm/gateway.js index 8f6d1c87..660de949 100644 --- a/evm/gateway.js +++ b/evm/gateway.js @@ -20,8 +20,8 @@ const { wasEventEmitted, mainProcessor, printError, - addCallContractOptions, } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { getWallet } = require('./sign-utils'); const IGateway = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGateway.json'); @@ -327,41 +327,43 @@ async function main(options) { await mainProcessor(options, processCommand); } -const program = new Command(); - -program.name('gateway').description('Script to perform gateway commands'); - -addCallContractOptions(program, true); - -program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig')); -program.addOption( - new Option('--action ', 'gateway action') - .choices([ - 'admins', - 'operators', - 'callContract', - 'submitBatch', - 'approve', - 'execute', - 'approveAndExecute', - 'transferGovernance', - 'governance', - 'mintLimiter', - 'mintLimit', - 'params', - ]) - .makeOptionMandatory(true), -); - -program.addOption(new Option('--payload ', 'gmp payload')); -program.addOption(new Option('--commandID ', 'execute command ID')); -program.addOption(new Option('--destination ', 'GMP destination address')); -program.addOption(new Option('--destinationChain ', 'GMP destination chain')); -program.addOption(new Option('--batchID ', 'EVM batch ID').default('')); -program.addOption(new Option('--symbol ', 'EVM token symbol')); - -program.action((options) => { - main(options); -}); - -program.parse(); +if (require.main === module) { + const program = new Command(); + + program.name('gateway').description('Script to perform gateway commands'); + + addBaseOptions(program, { address: true }); + + program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig')); + program.addOption( + new Option('--action ', 'gateway action') + .choices([ + 'admins', + 'operators', + 'callContract', + 'submitBatch', + 'approve', + 'execute', + 'approveAndExecute', + 'transferGovernance', + 'governance', + 'mintLimiter', + 'mintLimit', + 'params', + ]) + .makeOptionMandatory(true), + ); + + program.addOption(new Option('--payload ', 'gmp payload')); + program.addOption(new Option('--commandID ', 'execute command ID')); + program.addOption(new Option('--destination ', 'GMP destination address')); + program.addOption(new Option('--destinationChain ', 'GMP destination chain')); + program.addOption(new Option('--batchID ', 'EVM batch ID').default('')); + program.addOption(new Option('--symbol ', 'EVM token symbol')); + + program.action((options) => { + main(options); + }); + + program.parse(); +} diff --git a/evm/governance.js b/evm/governance.js index 7689ac82..6d01f3e7 100644 --- a/evm/governance.js +++ b/evm/governance.js @@ -27,8 +27,8 @@ const { mainProcessor, isValidDecimal, prompt, - addCallContractOptions, } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); 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'); @@ -603,46 +603,48 @@ async function main(options) { } } -const program = new Command(); - -program.name('governance').description('Script to manage interchain governance actions'); - -addCallContractOptions(program, true); - -program.addOption( - new Option('-c, --contractName ', 'contract name') - .choices(['InterchainGovernance', 'AxelarServiceGovernance']) - .default('InterchainGovernance'), -); -program.addOption( - new Option('--action ', 'governance action').choices([ - 'scheduleTimeLock', - 'cancelTimeLock', - 'approveMultisig', - 'cancelMultisig', - 'executeProposal', - 'executeMultisigProposal', - 'gatewayUpgrade', - 'submitUpgrade', - 'executeUpgrade', - 'cancelUpgrade', - 'withdraw', - 'getProposalEta', - ]), -); -program.addOption(new Option('--newGovernance ', 'governance address').env('GOVERNANCE')); -program.addOption(new Option('--newMintLimiter ', 'mint limiter address').env('MINT_LIMITER')); -program.addOption(new Option('--commandId ', 'command id')); -program.addOption(new Option('--target ', 'governance execution target')); -program.addOption(new Option('--calldata ', 'calldata')); -program.addOption(new Option('--nativeValue ', 'nativeValue').default(0)); -program.addOption(new Option('--proposal ', 'governance proposal payload')); -program.addOption(new Option('--amount ', 'withdraw amount')); -program.addOption(new Option('--date ', 'proposal activation date')); -program.addOption(new Option('--implementation ', 'new gateway implementation')); - -program.action((options) => { - main(options); -}); - -program.parse(); +if (require.main === module) { + const program = new Command(); + + program.name('governance').description('Script to manage interchain governance actions'); + + addBaseOptions(program, { address: true }); + + program.addOption( + new Option('-c, --contractName ', 'contract name') + .choices(['InterchainGovernance', 'AxelarServiceGovernance']) + .default('InterchainGovernance'), + ); + program.addOption( + new Option('--action ', 'governance action').choices([ + 'scheduleTimeLock', + 'cancelTimeLock', + 'approveMultisig', + 'cancelMultisig', + 'executeProposal', + 'executeMultisigProposal', + 'gatewayUpgrade', + 'submitUpgrade', + 'executeUpgrade', + 'cancelUpgrade', + 'withdraw', + 'getProposalEta', + ]), + ); + program.addOption(new Option('--newGovernance ', 'governance address').env('GOVERNANCE')); + program.addOption(new Option('--newMintLimiter ', 'mint limiter address').env('MINT_LIMITER')); + program.addOption(new Option('--commandId ', 'command id')); + program.addOption(new Option('--target ', 'governance execution target')); + program.addOption(new Option('--calldata ', 'calldata')); + program.addOption(new Option('--nativeValue ', 'nativeValue').default(0)); + program.addOption(new Option('--proposal ', 'governance proposal payload')); + program.addOption(new Option('--amount ', 'withdraw amount')); + program.addOption(new Option('--date ', 'proposal activation date')); + program.addOption(new Option('--implementation ', 'new gateway implementation')); + + program.action((options) => { + main(options); + }); + + program.parse(); +} diff --git a/evm/min-deposit-proposal.js b/evm/min-deposit-proposal.js index 09d49e5e..86ffab77 100644 --- a/evm/min-deposit-proposal.js +++ b/evm/min-deposit-proposal.js @@ -3,6 +3,7 @@ require('dotenv').config(); const { Command, Option } = require('commander'); +const { addBaseOptions } = require('./cli-utils'); const { mainProcessor, printInfo, isValidNumber, isValidAddress } = require('./utils'); const values = []; @@ -67,15 +68,8 @@ if (require.main === module) { program.name('balances').description('Display balance of the wallet on specified chains.'); - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-n, --chainNames ', 'chain names').makeOptionMandatory(true).env('CHAINS')); - program.addOption(new Option('-a, --address
', 'override governance address')); + addBaseOptions(program, { ignorePrivateKey: true, address: true }); + program.addOption(new Option('--deposit ', 'min deposit for governance proposals, in terms of AXL')); program.action((options) => { diff --git a/evm/multisig.js b/evm/multisig.js index 655dc3e7..d6118800 100644 --- a/evm/multisig.js +++ b/evm/multisig.js @@ -22,8 +22,8 @@ const { mainProcessor, isValidDecimal, prompt, - addCallContractOptions, } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const IMultisig = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IMultisig.json'); const IGateway = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGateway.json'); const IGovernance = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarServiceGovernance.json'); @@ -314,39 +314,43 @@ async function main(options) { await mainProcessor(options, processCommand, false); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('multisig').description('Script to manage multisig actions'); + program.name('multisig').description('Script to manage multisig actions'); -addCallContractOptions(program, true); + addBaseOptions(program, { address: true }); -program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig').makeOptionMandatory(false)); -program.addOption( - new Option('--action ', 'multisig action') - .choices(['signers', 'setTokenMintLimits', 'transferMintLimiter', 'withdraw', 'executeMultisigProposal']) - .makeOptionMandatory(true), -); -program.addOption(new Option('--offline', 'run script in offline mode')); -program.addOption(new Option('--nonceOffset ', 'The value to add in local nonce if it deviates from actual wallet nonce')); + program.addOption(new Option('-c, --contractName ', 'contract name').default('Multisig').makeOptionMandatory(false)); + program.addOption( + new Option('--action ', 'multisig action') + .choices(['signers', 'setTokenMintLimits', 'transferMintLimiter', 'withdraw', 'executeMultisigProposal']) + .makeOptionMandatory(true), + ); + program.addOption(new Option('--offline', 'run script in offline mode')); + program.addOption(new Option('--nonceOffset ', 'The value to add in local nonce if it deviates from actual wallet nonce')); -// options for setTokenMintLimits -program.addOption(new Option('--symbols ', 'token symbols').makeOptionMandatory(false)); -program.addOption(new Option('--limits ', 'token limits').makeOptionMandatory(false)); + // options for setTokenMintLimits + program.addOption(new Option('--symbols ', 'token symbols').makeOptionMandatory(false)); + program.addOption(new Option('--limits ', 'token limits').makeOptionMandatory(false)); -// option for transferMintLimiter -program.addOption(new Option('--mintLimiter ', 'new mint limiter address').makeOptionMandatory(false)); + // option for transferMintLimiter + program.addOption(new Option('--mintLimiter ', 'new mint limiter address').makeOptionMandatory(false)); -// options for withdraw -program.addOption(new Option('--recipient ', 'withdraw recipient address').makeOptionMandatory(false)); -program.addOption(new Option('--withdrawAmount ', 'withdraw amount').makeOptionMandatory(false)); + // options for withdraw + program.addOption(new Option('--recipient ', 'withdraw recipient address').makeOptionMandatory(false)); + program.addOption(new Option('--withdrawAmount ', 'withdraw amount').makeOptionMandatory(false)); -// options for executeMultisigProposal -program.addOption(new Option('--target ', 'execute multisig proposal target').makeOptionMandatory(false)); -program.addOption(new Option('--calldata ', 'execute multisig proposal calldata').makeOptionMandatory(false)); -program.addOption(new Option('--nativeValue ', 'execute multisig proposal nativeValue').makeOptionMandatory(false).default(0)); + // options for executeMultisigProposal + program.addOption(new Option('--target ', 'execute multisig proposal target').makeOptionMandatory(false)); + program.addOption(new Option('--calldata ', 'execute multisig proposal calldata').makeOptionMandatory(false)); + program.addOption( + new Option('--nativeValue ', 'execute multisig proposal nativeValue').makeOptionMandatory(false).default(0), + ); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/operators.js b/evm/operators.js index 42386c83..205a91b0 100644 --- a/evm/operators.js +++ b/evm/operators.js @@ -21,8 +21,8 @@ const { isKeccak256Hash, parseArgs, prompt, - addCallContractOptions, } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const IAxelarGasService = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGasService.json'); const IOperators = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IOperators.json'); @@ -263,20 +263,28 @@ async function main(options) { } } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('operators').description('script to manage operators contract'); + program.name('operators').description('script to manage operators contract'); -addCallContractOptions(program); + addBaseOptions(program, { address: true }); -program.addOption(new Option('-c, --contractName ', 'contract name').default('Operators').makeOptionMandatory(false)); -program.addOption( - new Option('--action ', 'operator action').choices(['isOperator', 'addOperator', 'removeOperator', 'collectFees', 'refund']), -); -program.addOption(new Option('--args ', 'operator action arguments').makeOptionMandatory(true)); + program.addOption(new Option('-c, --contractName ', 'contract name').default('Operators').makeOptionMandatory(false)); + program.addOption( + new Option('--action ', 'operator action').choices([ + 'isOperator', + 'addOperator', + 'removeOperator', + 'collectFees', + 'refund', + ]), + ); + program.addOption(new Option('--args ', 'operator action arguments').makeOptionMandatory(true)); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/ownership.js b/evm/ownership.js index f419bec9..3cf811d1 100644 --- a/evm/ownership.js +++ b/evm/ownership.js @@ -11,7 +11,8 @@ const { Contract, } = ethers; const { Command, Option } = require('commander'); -const { printInfo, printWalletInfo, loadConfig, saveConfig, prompt, addCallContractOptions } = require('./utils'); +const { printInfo, printWalletInfo, loadConfig, saveConfig, prompt } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const IOwnable = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/interfaces/IOwnable.sol/IOwnable.json'); @@ -188,26 +189,28 @@ async function main(options) { } } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('ownership').description('script to manage contract ownership'); + program.name('ownership').description('script to manage contract ownership'); -addCallContractOptions(program); + addBaseOptions(program, { address: true }); -program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.addOption( - new Option('--action ', 'ownership action').choices([ - 'owner', - 'pendingOwner', - 'transferOwnership', - 'proposeOwnership', - 'acceptOwnership', - ]), -); -program.addOption(new Option('--newOwner ', 'new owner address').makeOptionMandatory(false)); + program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + program.addOption( + new Option('--action ', 'ownership action').choices([ + 'owner', + 'pendingOwner', + 'transferOwnership', + 'proposeOwnership', + 'acceptOwnership', + ]), + ); + program.addOption(new Option('--newOwner ', 'new owner address').makeOptionMandatory(false)); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/remove-info.js b/evm/remove-info.js index 1d60e7ca..8f3bb676 100644 --- a/evm/remove-info.js +++ b/evm/remove-info.js @@ -3,7 +3,8 @@ require('dotenv').config(); const { Command, Option } = require('commander'); -const { mainProcessor, addEnvironmentOptions } = require('./utils'); +const { mainProcessor } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); async function processCommand(options, chain, _) { const { contractName } = options; @@ -19,16 +20,18 @@ async function main(options) { await mainProcessor(options, processCommand, true); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('remove-info').description('Remove info about contract from the info file.'); + program.name('remove-info').description('Remove info about contract from the info file.'); -addEnvironmentOptions(program); + addBaseOptions(program, { ignorePrivateKey: true }); -program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/send-tokens.js b/evm/send-tokens.js index 930011f4..89f035e0 100644 --- a/evm/send-tokens.js +++ b/evm/send-tokens.js @@ -9,17 +9,8 @@ const { getDefaultProvider, utils: { parseEther, parseUnits }, } = ethers; - -const { - printInfo, - printError, - printWalletInfo, - isAddressArray, - mainProcessor, - isValidDecimal, - prompt, - addEnvironmentOptions, -} = require('./utils'); +const { printInfo, printError, printWalletInfo, isAddressArray, mainProcessor, isValidDecimal, prompt } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { storeSignedTx, getWallet, signTransaction } = require('./sign-utils.js'); async function processCommand(_, chain, options) { @@ -111,15 +102,13 @@ if (require.main === module) { program.name('send-tokens').description('Send native tokens to an address.'); - addEnvironmentOptions(program); + addBaseOptions(program); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); program.addOption(new Option('-r, --recipients ', 'comma-separated recipients of tokens').makeOptionMandatory(true)); program.addOption(new Option('-a, --amount ', 'amount to transfer (in terms of ETH)')); program.addOption(new Option('--gasUsage ', 'amount to transfer based on gas usage and gas price').default('5000000')); program.addOption(new Option('--offline', 'Run in offline mode')); program.addOption(new Option('--nonceOffset ', 'The value to add in local nonce if it deviates from actual wallet nonce')); - program.addOption(new Option('-y, --yes', 'skip prompts')); program.action((options) => { main(options); diff --git a/evm/update-nonces.js b/evm/update-nonces.js index bb04660d..ff315df1 100644 --- a/evm/update-nonces.js +++ b/evm/update-nonces.js @@ -5,7 +5,8 @@ const { Command, Option } = require('commander'); const { ethers } = require('hardhat'); const { getDefaultProvider } = ethers; -const { mainProcessor, printInfo, prompt, addEnvironmentOptions } = require('./utils'); +const { mainProcessor, printInfo, prompt } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const { getNonceFromProvider, getNonceFileData, updateNonceFileData } = require('./sign-utils'); async function processCommand(_, chain, options) { @@ -49,17 +50,18 @@ async function main(options) { await mainProcessor(options, processCommand); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('update-nonces').description('Update nonces for addresses'); + program.name('update-nonces').description('Update nonces for addresses'); -addEnvironmentOptions(program); + addBaseOptions(program, { ignorePrivateKey: true }); -program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); -program.addOption(new Option('--addresses ', 'The Array of addresses for which the nonces to update').env('ADDRESSES')); -program.addOption(new Option('-y, --yes', 'skip prompts')); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); + program.addOption(new Option('--addresses ', 'The Array of addresses for which the nonces to update').env('ADDRESSES')); -program.action((options) => { - main(options); -}); -program.parse(); + program.action((options) => { + main(options); + }); + program.parse(); +} diff --git a/evm/update-static-gas-options.js b/evm/update-static-gas-options.js index a4c6156e..12542c67 100644 --- a/evm/update-static-gas-options.js +++ b/evm/update-static-gas-options.js @@ -9,7 +9,8 @@ const { BigNumber, } = ethers; -const { printInfo, mainProcessor, prompt, addEnvironmentOptions } = require('./utils'); +const { printInfo, mainProcessor, prompt } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); const defaultGasLimit = 3e6; const gasPriceMultiplier = 5; @@ -97,17 +98,18 @@ async function main(options) { await mainProcessor(options, processCommand, true); } -const program = new Command(); +if (require.main === module) { + const program = new Command(); -program.name('update-static-gas-options').description('Update staticGasOptions'); + program.name('update-static-gas-options').description('Update staticGasOptions'); -addEnvironmentOptions(program); + addBaseOptions(program, { ignorePrivateKey: true }); -program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); -program.addOption(new Option('-y, --yes', 'skip prompts')); + program.addOption(new Option('-r, --rpc ', 'The rpc url for creating a provider to fetch gasOptions')); -program.action((options) => { - main(options); -}); + program.action((options) => { + main(options); + }); -program.parse(); + program.parse(); +} diff --git a/evm/utils.js b/evm/utils.js index c60ca73b..3c10a494 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -9,6 +9,8 @@ const { } = ethers; const https = require('https'); const http = require('http'); +const fs = require('fs'); +const path = require('path'); const { outputJsonSync } = require('fs-extra'); const zkevm = require('@0xpolygonhermez/zkevm-commonjs'); const readlineSync = require('readline-sync'); @@ -24,7 +26,6 @@ const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const CreateDeploy = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/CreateDeploy.sol/CreateDeploy.json'); const IDeployer = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IDeployer.json'); const { verifyContract } = require(`${__dirname}/../axelar-chains-config`); -const { Option } = require('commander'); const getSaltFromKey = (key) => { return keccak256(defaultAbiCoder.encode(['string'], [key.toString()])); @@ -778,56 +779,56 @@ function getConfigByChainId(chainId, config) { throw new Error(`Chain with chainId ${chainId} not found in the config`); } -const addEnvironmentOptions = (program, ignoreChainNames) => { - program.addOption( - new Option('-e, --env ', 'environment') - .choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - - if (!ignoreChainNames) { - program.addOption( - new Option('-n, --chainNames ', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), - ); - } +function findProjectRoot(startDir) { + let currentDir = startDir; - return program; -}; + while (currentDir !== path.parse(currentDir).root) { + const potentialPackageJson = path.join(currentDir, 'package.json'); -const addDeploymentOptions = (program, artifactPath, contractName, salt, skipChains, skipExisting, upgrade) => { - addEnvironmentOptions(program); + if (fs.existsSync(potentialPackageJson)) { + return currentDir; + } - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); - program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + // Move up a directory + currentDir = path.resolve(currentDir, '..'); + } - if (artifactPath) program.addOption(new Option('-a, --artifactPath ', 'artifact path')); - if (contractName) program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); - if (salt) program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment').env('SALT')); - if (skipChains) program.addOption(new Option('--skipChains ', 'chains to skip over')); + throw new Error('Unable to find project root'); +} - if (skipExisting) { - program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); - } +function findContractPath(dir, contractName) { + const files = fs.readdirSync(dir); - if (upgrade) program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + for (const file of files) { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); - return program; -}; + if (stat && stat.isDirectory()) { + const recursivePath = findContractPath(filePath, contractName); + if (recursivePath) return recursivePath; + } else if (file === `${contractName}.json`) { + return filePath; + } + } +} -const addCallContractOptions = (program, skipChains) => { - addEnvironmentOptions(program); +function getContractPath(contractName) { + const projectRoot = findProjectRoot(__dirname); - program.addOption(new Option('-a, --address
', 'override address')); - program.addOption(new Option('-p, --privateKey ', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + const searchDirs = [ + path.join(projectRoot, 'node_modules', '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts'), + path.join(projectRoot, 'node_modules', '@axelar-network/axelar-cgp-solidity/artifacts/contracts'), + ]; - if (skipChains) program.addOption(new Option('--skipChains ', 'chains to skip over')); + for (const dir of searchDirs) { + if (fs.existsSync(dir)) { + const contractPath = findContractPath(dir, contractName); + if (contractPath) return contractPath; + } + } - return program; -}; + throw new Error(`Contract path for ${contractName} must be entered manually.`); +} module.exports = { deployCreate, @@ -874,7 +875,5 @@ module.exports = { verifyContract, prompt, mainProcessor, - addEnvironmentOptions, - addDeploymentOptions, - addCallContractOptions, + getContractPath, }; diff --git a/evm/verify-contract.js b/evm/verify-contract.js index c4b3dc64..77eb14b2 100644 --- a/evm/verify-contract.js +++ b/evm/verify-contract.js @@ -11,7 +11,8 @@ const { utils: { defaultAbiCoder }, } = ethers; const { Command, Option } = require('commander'); -const { verifyContract, getEVMAddresses, printInfo, printError, mainProcessor, addEnvironmentOptions } = require('./utils'); +const { verifyContract, getEVMAddresses, printInfo, printError, mainProcessor } = require('./utils'); +const { addBaseOptions } = require('./cli-utils'); async function processCommand(config, chain, options) { const { env, contractName, dir } = options; @@ -217,11 +218,9 @@ if (require.main === module) { program.name('balances').description('Display balance of the wallet on specified chains.'); - addEnvironmentOptions(program); + addBaseOptions(program, { ignorePrivateKey: true, address: true }); - program.addOption(new Option('--skipChains ', 'skip chains')); program.addOption(new Option('-c, --contractName ', 'contract name')); - program.addOption(new Option('-a, --address
', 'contract address')); program.addOption(new Option('-d, --dir ', 'contract artifacts dir')); program.addOption(new Option('--args ', 'contract args')); program.addOption(new Option('--constructorArgs ', 'contract constructor args')); From 21702f7d41065fcc8a220dd61524e93e648c2d42 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Mon, 6 Nov 2023 17:25:40 -0500 Subject: [PATCH 3/6] feat: address comments --- evm/cli-utils.js | 20 +++++++++++++----- evm/deploy-contract.js | 14 ++----------- evm/execute-contract.js | 46 +++++++++++++---------------------------- evm/utils.js | 35 ++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 54 deletions(-) diff --git a/evm/cli-utils.js b/evm/cli-utils.js index cbc84bd5..6ce17f32 100644 --- a/evm/cli-utils.js +++ b/evm/cli-utils.js @@ -10,13 +10,13 @@ const addBaseOptions = (program, options = {}) => { .makeOptionMandatory(true) .env('ENV'), ); - program.addOption(new Option('--skipChains ', 'chains to skip over')); program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); if (!options.ignoreChainNames) { program.addOption( new Option('-n, --chainNames ', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), ); + program.addOption(new Option('--skipChains ', 'chains to skip over')); } if (!options.ignorePrivateKey) { @@ -35,15 +35,25 @@ const addExtendedOptions = (program, options = {}) => { program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); - if (options.artifactPath) program.addOption(new Option('-a, --artifactPath ', 'artifact path')); - if (options.contractName) program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); - if (options.salt) program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment').env('SALT')); + if (options.artifactPath) { + program.addOption(new Option('-a, --artifactPath ', 'artifact path')); + } + + if (options.contractName) { + program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + } + + if (options.salt) { + program.addOption(new Option('-s, --salt ', 'salt to use for create2 deployment').env('SALT')); + } if (options.skipExisting) { program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); } - if (options.upgrade) program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + if (options.upgrade) { + program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + } return program; }; diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index f8ecacd1..5c84d522 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -25,7 +25,7 @@ const { prompt, mainProcessor, isContract, - getContractPath, + getContractJSON, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); @@ -251,17 +251,7 @@ async function processCommand(config, chain, options) { printInfo('Contract name', contractName); - let contractPath; - - if (artifactPath) { - contractPath = artifactPath.charAt(0) === '@' ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; - } else { - contractPath = getContractPath(contractName); - } - - printInfo('Contract path', contractPath); - - const contractJson = require(contractPath); + const contractJson = getContractJSON(contractName, artifactPath); const predeployCodehash = await getBytecodeHash(contractJson, chain.id); printInfo('Pre-deploy Contract bytecode hash', predeployCodehash); diff --git a/evm/execute-contract.js b/evm/execute-contract.js index ae429b5d..e7603b7c 100644 --- a/evm/execute-contract.js +++ b/evm/execute-contract.js @@ -12,7 +12,7 @@ const { const readlineSync = require('readline-sync'); const { Command, Option } = require('commander'); -const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, printInfo } = require('./utils'); +const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, getContractJSON } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); async function getCallData(methodName, targetContract, inputRecipient, inputAmount) { @@ -137,11 +137,7 @@ async function executeContract(options, chain, wallet) { throw new Error('Missing native value from user info'); } - var contractPath = - callContractPath.charAt(0) === '@' ? callContractPath : callContractPath + callContractName + '.sol/' + callContractName + '.json'; - printInfo('Call Contract path', contractPath); - - const IContractExecutor = require(contractPath); + const IContractExecutor = getContractJSON(callContractName, callContractPath); const contract = new Contract(callContractAddress, IContractExecutor.abi, wallet); var finalCallData, finalNativeValue; @@ -149,12 +145,7 @@ async function executeContract(options, chain, wallet) { finalCallData = callData; finalNativeValue = nativeValue; } else { - contractPath = - targetContractPath.charAt(0) === '@' - ? targetContractPath - : targetContractPath + targetContractName + '.sol/' + targetContractName + '.json'; - printInfo('Target Contract path', contractPath); - const ITargetContract = require(contractPath); + const ITargetContract = getContractJSON(targetContractName, targetContractPath); const targetContract = new Contract(targetContractAddress, ITargetContract.abi, wallet); finalCallData = await getCallData(methodName, targetContract, recipientAddress, Number(amount)); finalNativeValue = Number(0); @@ -207,21 +198,16 @@ if (require.main === module) { addBaseOptions(program); + program.addOption(new Option('-c, --callContractName ', 'name of the called contract').makeOptionMandatory(true)); + program.addOption(new Option('--callContractPath ', 'artifact path for the called contract')); + program.addOption(new Option('--targetContractPath ', 'artifact path for the target contract')); program.addOption( - new Option('-pc, --callContractPath ', 'artifact path for the called contract').makeOptionMandatory(true), - ); - program.addOption(new Option('-cn, --callContractName ', 'name of the called contract').makeOptionMandatory(true)); - program.addOption( - new Option('-pt, --targetContractPath ', 'artifact path for the target contract').makeOptionMandatory(true), - ); - program.addOption( - new Option( - '-tn, --targetContractName ', - 'name of the target contract that is called through executeContract', - ).makeOptionMandatory(false), + new Option('-t, --targetContractName ', 'target contract name called by executeContract').makeOptionMandatory( + true, + ), ); program.addOption( - new Option('-ta, --targetContractAddress ', 'The address of the contract to be called') + new Option('-a, --targetContractAddress ', 'target contract address') .makeOptionMandatory(true) .env('TARGET_ADDR'), ); @@ -229,17 +215,13 @@ if (require.main === module) { new Option('-v, --nativeValue ', 'The amount of native token (e.g., Ether) to be sent along with the call').default(0), ); program.addOption( - new Option('-m, --methodName ', 'method name to call in executeContract') + new Option('--action ', 'executeContract action') .choices(['withdraw', 'transfer', 'approve', 'default']) .default('default'), ); - program.addOption(new Option('-c, --callData ', 'The calldata to be sent').env('CALL_DATA').default('0x')); - program.addOption( - new Option('-ra, --recipientAddress ', 'The recipient address for the tokens').env('RECIPIENT_ADDR'), - ); - program.addOption( - new Option('-am, --amount ', 'The amount of tokens to transfer/withdraw/provide allowance etc.').env('AMOUNT'), - ); + program.addOption(new Option('--callData ', 'The calldata to be sent').env('CALL_DATA').default('0x')); + program.addOption(new Option('--recipientAddress ', 'The recipient address for the tokens').env('RECIPIENT_ADDR')); + program.addOption(new Option('--amount ', 'The amount of tokens to transfer/withdraw/provide allowance etc.').env('AMOUNT')); program.action((options) => { main(options); diff --git a/evm/utils.js b/evm/utils.js index 3c10a494..7703d592 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -789,7 +789,6 @@ function findProjectRoot(startDir) { return currentDir; } - // Move up a directory currentDir = path.resolve(currentDir, '..'); } @@ -805,7 +804,10 @@ function findContractPath(dir, contractName) { if (stat && stat.isDirectory()) { const recursivePath = findContractPath(filePath, contractName); - if (recursivePath) return recursivePath; + + if (recursivePath) { + return recursivePath; + } } else if (file === `${contractName}.json`) { return filePath; } @@ -816,20 +818,42 @@ function getContractPath(contractName) { const projectRoot = findProjectRoot(__dirname); const searchDirs = [ - path.join(projectRoot, 'node_modules', '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts'), - path.join(projectRoot, 'node_modules', '@axelar-network/axelar-cgp-solidity/artifacts/contracts'), + path.join(projectRoot, 'node_modules', '@axelar-network', 'axelar-gmp-sdk-solidity', 'artifacts', 'contracts'), + path.join(projectRoot, 'node_modules', '@axelar-network', 'axelar-cgp-solidity', 'artifacts', 'contracts'), ]; for (const dir of searchDirs) { if (fs.existsSync(dir)) { const contractPath = findContractPath(dir, contractName); - if (contractPath) return contractPath; + + if (contractPath) { + return contractPath; + } } } throw new Error(`Contract path for ${contractName} must be entered manually.`); } +function getContractJSON(contractName, artifactPath) { + let contractPath; + + if (artifactPath) { + contractPath = artifactPath.charAt(0) === '@' ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; + } else { + contractPath = getContractPath(contractName); + } + + printInfo('Contract path', contractPath); + + try { + const contractJson = require(contractPath); + return contractJson; + } catch (err) { + throw new Error(`Failed to load contract JSON for ${contractName} at path ${contractPath}`); + } +} + module.exports = { deployCreate, deployCreate2, @@ -876,4 +900,5 @@ module.exports = { prompt, mainProcessor, getContractPath, + getContractJSON, }; From 84d501f37111b7f66a19fd660e3fcb4146952690 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Mon, 6 Nov 2023 18:31:07 -0500 Subject: [PATCH 4/6] feat: add to gh action test --- .github/workflows/test.yaml | 28 +++++++++++++++++++++++++--- evm/deploy-const-address-deployer.js | 2 +- evm/deploy-contract.js | 19 +++++++++++++++---- evm/deploy-create3-deployer.js | 2 +- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 676f7896..63826e86 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -36,7 +36,14 @@ jobs: "chainId": 31337, "rpc": "http://127.0.0.1:8545", "tokenSymbol": "TEST", - "contracts": {} + "contracts": { + "InterchainGovernance": { + "minimumTimeDelay": 3600 + }, + "AxelarServiceGovernance": { + "minimumTimeDelay": 3600 + } + } } } }' > ./axelar-chains-config/info/local.json @@ -52,13 +59,28 @@ jobs: run: cat ./axelar-chains-config/info/local.json - name: Deploy ConstAddressDeployer - run: node evm/deploy-contract.js -a ../node_modules/@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ -c ConstAddressDeployer -m create -y + run: node evm/deploy-contract.js -c ConstAddressDeployer -m create -y - name: Deploy Create3Deployer - run: node evm/deploy-contract.js -a ../node_modules/@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ -c Create3Deployer -m create2 -y + run: node evm/deploy-contract.js -c Create3Deployer -m create2 -y - name: Deploy AxelarGateway run: node evm/deploy-gateway-v6.2.x.js -m create3 -s "AxelarGateway v6.2" -g 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -m 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --keyID 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -y - name: Call Method on Gateway run: node evm/gateway.js --action callContract --destinationChain test2 -y + + - name: Deploy InterchainGovernance + run: node evm/deploy-contract.js -c InterchainGovernance -m create3 -y + + - name: Deploy AxelarServiceGovernance + run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create3 -y + + - name: Deploy Multisig + run: node evm/deploy-contract.js -c Multisig -m create3 -y + + - name: Deploy Operators + run: node evm/deploy-contract.js -c Operators -m create3 -y + + - name: Deploy TokenDeployer + run: node evm/deploy-contract.js -c TokenDeployer -m create3 -y diff --git a/evm/deploy-const-address-deployer.js b/evm/deploy-const-address-deployer.js index 0292ecbd..9218d237 100644 --- a/evm/deploy-const-address-deployer.js +++ b/evm/deploy-const-address-deployer.js @@ -13,7 +13,7 @@ const { addExtendedOptions } = require('./cli-utils'); const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'); const contractName = 'ConstAddressDeployer'; -async function deployConstAddressDeployer(wallet, chain, options = null, verifyOptions = null) { +async function deployConstAddressDeployer(wallet, chain, options = {}, verifyOptions = null) { printInfo('Deployer address', wallet.address); const contracts = chain.contracts; diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index 5c84d522..f2b00a1c 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -41,13 +41,15 @@ async function getConstructorArgs(contractName, chain, wallet) { throw new Error(`Missing AxelarGateway address in the chain info.`); } - const governanceChain = contractConfig.governanceChain; + const governanceChain = contractConfig.governanceChain || 'Axelarnet'; + contractConfig.governanceChain = governanceChain; if (!isString(governanceChain)) { throw new Error(`Missing AxelarServiceGovernance.governanceChain in the chain info.`); } - const governanceAddress = contractConfig.governanceAddress; + const governanceAddress = contractConfig.governanceAddress || 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj'; + contractConfig.governanceAddress = governanceAddress; if (!isString(governanceAddress)) { throw new Error(`Missing AxelarServiceGovernance.governanceAddress in the chain info.`); @@ -59,13 +61,22 @@ async function getConstructorArgs(contractName, chain, wallet) { throw new Error(`Missing AxelarServiceGovernance.minimumTimeDelay in the chain info.`); } - const cosigners = contractConfig.cosigners; + const cosigners = contractConfig.cosigners || [ + '0x3f5876a2b06E54949aB106651Ab6694d0289b2b4', + '0x9256Fd872118ed3a97754B0fB42c15015d17E0CC', + '0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b', + '0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821', + '0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f', + '0x027c1882B975E2cd771AE068b0389FA38B9dda73', + ]; + contractConfig.cosigners = cosigners; if (!isAddressArray(cosigners)) { throw new Error(`Missing AxelarServiceGovernance.cosigners in the chain info.`); } - const threshold = contractConfig.threshold; + const threshold = contractConfig.threshold || Math.floor((cosigners.length + 1) / 2); + contractConfig.threshold = threshold; if (!isNumber(threshold)) { throw new Error(`Missing AxelarServiceGovernance.threshold in the chain info.`); diff --git a/evm/deploy-create3-deployer.js b/evm/deploy-create3-deployer.js index 02ffa666..8f570bf9 100644 --- a/evm/deploy-create3-deployer.js +++ b/evm/deploy-create3-deployer.js @@ -15,7 +15,7 @@ const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/ const { deployConstAddressDeployer } = require('./deploy-const-address-deployer'); const contractName = 'Create3Deployer'; -async function deployCreate3Deployer(wallet, chain, options = null, verifyOptions = null) { +async function deployCreate3Deployer(wallet, chain, options = {}, verifyOptions = null) { printInfo('Deployer address', wallet.address); console.log( From 3e5a6833f462699d678bbf3ed87015e529c32962 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Mon, 6 Nov 2023 18:37:20 -0500 Subject: [PATCH 5/6] feat: test different deployment methods in gh action --- .github/workflows/test.yaml | 40 ++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 63826e86..48fffd69 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -70,17 +70,47 @@ jobs: - name: Call Method on Gateway run: node evm/gateway.js --action callContract --destinationChain test2 -y - - name: Deploy InterchainGovernance + - name: Deploy InterchainGovernance using create + run: node evm/deploy-contract.js -c InterchainGovernance -m create -y + + - name: Deploy AxelarServiceGovernance using create + run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create -y + + - name: Deploy Multisig using create + run: node evm/deploy-contract.js -c Multisig -m create -y + + - name: Deploy Operators using create + run: node evm/deploy-contract.js -c Operators -m create -y + + - name: Deploy TokenDeployer using create + run: node evm/deploy-contract.js -c TokenDeployer -m create -y + + - name: Deploy InterchainGovernance using create2 + run: node evm/deploy-contract.js -c InterchainGovernance -m create2 -y + + - name: Deploy AxelarServiceGovernance using create2 + run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create2 -y + + - name: Deploy Multisig using create2 + run: node evm/deploy-contract.js -c Multisig -m create2 -y + + - name: Deploy Operators using create2 + run: node evm/deploy-contract.js -c Operators -m create2 -y + + - name: Deploy TokenDeployer using create2 + run: node evm/deploy-contract.js -c TokenDeployer -m create2 -y + + - name: Deploy InterchainGovernance using create3 run: node evm/deploy-contract.js -c InterchainGovernance -m create3 -y - - name: Deploy AxelarServiceGovernance + - name: Deploy AxelarServiceGovernance using create3 run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create3 -y - - name: Deploy Multisig + - name: Deploy Multisig using create3 run: node evm/deploy-contract.js -c Multisig -m create3 -y - - name: Deploy Operators + - name: Deploy Operators using create3 run: node evm/deploy-contract.js -c Operators -m create3 -y - - name: Deploy TokenDeployer + - name: Deploy TokenDeployer using create3 run: node evm/deploy-contract.js -c TokenDeployer -m create3 -y From aeb0f1a5a2c45fb254c8b23c9d064c4e301a0e22 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Tue, 7 Nov 2023 01:21:38 -0500 Subject: [PATCH 6/6] feat: address comments --- .github/workflows/test.yaml | 43 +++++++++++++------------------------ evm/deploy-contract.js | 26 ++++------------------ evm/execute-contract.js | 14 ++++++------ 3 files changed, 26 insertions(+), 57 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 48fffd69..a4751b6f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -41,7 +41,21 @@ jobs: "minimumTimeDelay": 3600 }, "AxelarServiceGovernance": { - "minimumTimeDelay": 3600 + "minimumTimeDelay": 3600, + "cosigners": [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + ], + "threshold": 2 + }, + "Multisig": { + "signers": [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + ], + "threshold": 2 } } } @@ -73,33 +87,9 @@ jobs: - name: Deploy InterchainGovernance using create run: node evm/deploy-contract.js -c InterchainGovernance -m create -y - - name: Deploy AxelarServiceGovernance using create - run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create -y - - - name: Deploy Multisig using create - run: node evm/deploy-contract.js -c Multisig -m create -y - - - name: Deploy Operators using create - run: node evm/deploy-contract.js -c Operators -m create -y - - - name: Deploy TokenDeployer using create - run: node evm/deploy-contract.js -c TokenDeployer -m create -y - - name: Deploy InterchainGovernance using create2 run: node evm/deploy-contract.js -c InterchainGovernance -m create2 -y - - name: Deploy AxelarServiceGovernance using create2 - run: node evm/deploy-contract.js -c AxelarServiceGovernance -m create2 -y - - - name: Deploy Multisig using create2 - run: node evm/deploy-contract.js -c Multisig -m create2 -y - - - name: Deploy Operators using create2 - run: node evm/deploy-contract.js -c Operators -m create2 -y - - - name: Deploy TokenDeployer using create2 - run: node evm/deploy-contract.js -c TokenDeployer -m create2 -y - - name: Deploy InterchainGovernance using create3 run: node evm/deploy-contract.js -c InterchainGovernance -m create3 -y @@ -111,6 +101,3 @@ jobs: - name: Deploy Operators using create3 run: node evm/deploy-contract.js -c Operators -m create3 -y - - - name: Deploy TokenDeployer using create3 - run: node evm/deploy-contract.js -c TokenDeployer -m create3 -y diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index f2b00a1c..9d7afd8b 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -61,22 +61,13 @@ async function getConstructorArgs(contractName, chain, wallet) { throw new Error(`Missing AxelarServiceGovernance.minimumTimeDelay in the chain info.`); } - const cosigners = contractConfig.cosigners || [ - '0x3f5876a2b06E54949aB106651Ab6694d0289b2b4', - '0x9256Fd872118ed3a97754B0fB42c15015d17E0CC', - '0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b', - '0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821', - '0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f', - '0x027c1882B975E2cd771AE068b0389FA38B9dda73', - ]; - contractConfig.cosigners = cosigners; + const cosigners = contractConfig.cosigners; if (!isAddressArray(cosigners)) { throw new Error(`Missing AxelarServiceGovernance.cosigners in the chain info.`); } - const threshold = contractConfig.threshold || Math.floor((cosigners.length + 1) / 2); - contractConfig.threshold = threshold; + const threshold = contractConfig.threshold; if (!isNumber(threshold)) { throw new Error(`Missing AxelarServiceGovernance.threshold in the chain info.`); @@ -132,22 +123,13 @@ async function getConstructorArgs(contractName, chain, wallet) { } case 'Multisig': { - const signers = contractConfig.signers || [ - '0x3f5876a2b06E54949aB106651Ab6694d0289b2b4', - '0x9256Fd872118ed3a97754B0fB42c15015d17E0CC', - '0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b', - '0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821', - '0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f', - '0x027c1882B975E2cd771AE068b0389FA38B9dda73', - ]; + const signers = contractConfig.signers; if (!isAddressArray(signers)) { throw new Error(`Missing Multisig.signers in the chain info.`); } - const threshold = contractConfig.threshold || Math.floor((signers.length + 1) / 2); - contractConfig.threshold = threshold; - contractConfig.signers = signers; + const threshold = contractConfig.threshold; if (!isNumber(threshold)) { throw new Error(`Missing Multisig.threshold in the chain info.`); diff --git a/evm/execute-contract.js b/evm/execute-contract.js index e7603b7c..e8189096 100644 --- a/evm/execute-contract.js +++ b/evm/execute-contract.js @@ -15,10 +15,10 @@ const { Command, Option } = require('commander'); const { isNumber, isString, loadConfig, saveConfig, printObj, printLog, printError, getContractJSON } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); -async function getCallData(methodName, targetContract, inputRecipient, inputAmount) { +async function getCallData(action, targetContract, inputRecipient, inputAmount) { var recipient, amount; - switch (methodName) { + switch (action) { case 'withdraw': { if (inputRecipient) { recipient = inputRecipient; @@ -95,7 +95,7 @@ async function getCallData(methodName, targetContract, inputRecipient, inputAmou } default: { - throw new Error('The method name does not match any of the specified choices'); + throw new Error('The action does not match any of the specified choices'); } } } @@ -109,7 +109,7 @@ async function executeContract(options, chain, wallet) { targetContractAddress, callData, nativeValue, - methodName, + action, recipientAddress, amount, } = options; @@ -129,7 +129,7 @@ async function executeContract(options, chain, wallet) { throw new Error('Missing target address in the address info.'); } - if (!isString(methodName)) { + if (!isString(action)) { throw new Error('Missing method name from the user info.'); } @@ -141,13 +141,13 @@ async function executeContract(options, chain, wallet) { const contract = new Contract(callContractAddress, IContractExecutor.abi, wallet); var finalCallData, finalNativeValue; - if (methodName === 'default') { + if (action === 'default') { finalCallData = callData; finalNativeValue = nativeValue; } else { const ITargetContract = getContractJSON(targetContractName, targetContractPath); const targetContract = new Contract(targetContractAddress, ITargetContract.abi, wallet); - finalCallData = await getCallData(methodName, targetContract, recipientAddress, Number(amount)); + finalCallData = await getCallData(action, targetContract, recipientAddress, Number(amount)); finalNativeValue = Number(0); }