From 60efbfe3bc74a3410145fcd73346b004e59fe5c0 Mon Sep 17 00:00:00 2001 From: Dean Amiel Date: Wed, 7 Feb 2024 10:03:11 -0500 Subject: [PATCH] feat: remove old deployment scripts, link to contract deployments repo --- README.md | 76 +++++----- scripts/deploy-gateway-v3.2.x.js | 107 --------------- scripts/deploy-gateway-v4.0.x.js | 102 -------------- scripts/deploy-gateway-v4.3.x.js | 104 -------------- scripts/deploy-upgradable.js | 160 ---------------------- scripts/prepare-gateway-upgrade-v3.2.0.js | 113 --------------- scripts/prepare-gateway-upgrade-v4.3.x.js | 116 ---------------- 7 files changed, 43 insertions(+), 735 deletions(-) delete mode 100644 scripts/deploy-gateway-v3.2.x.js delete mode 100644 scripts/deploy-gateway-v4.0.x.js delete mode 100644 scripts/deploy-gateway-v4.3.x.js delete mode 100644 scripts/deploy-upgradable.js delete mode 100644 scripts/prepare-gateway-upgrade-v3.2.0.js delete mode 100644 scripts/prepare-gateway-upgrade-v4.3.x.js diff --git a/README.md b/README.md index 61a13ddb..0efc4903 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ npm run test Pre-compiled bytecodes can be found under [Releases](https://github.com/axelarnetwork/axelar-cgp-solidity/releases). Furthermore, pre-compiled bytecodes and ABI are shipped in the [npm package](https://www.npmjs.com/package/@axelar-network/axelar-cgp-solidity) and can be imported via: + ```bash npm i @axelar-network/axelar-cgp-solidity ``` @@ -40,40 +41,45 @@ const AxelarGateway = require('@axelar-network/axelar-cgp-solidity/artifacts/con 1. Check if the contract deployments repository supports the chain you will be using. Supported chains can be found [here](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/axelar-chains-config). If the chain is not already supported, proceed to steps 2-4, otherwise you may skip to step 5. 2. Navigate to the contract deployments repo [here](https://github.com/axelarnetwork/axelar-contract-deployments/) and clone the repository locally. 3. Within the contract deployments repo, edit the environment specific file inside the `axelar-chains-config/info` folder to add the chain you'll be testing. The following values need to be provided: + ```json { - "chains": { - "example": { - "name": "Example", - "axelarId": "example", - "chainId": 123, - "rpc": "PROVIDER_RPC", - "tokenSymbol": "EXM", - "gasOptions": { - "gasLimit": 8000000 - }, - "confirmations": 1 + "chains": { + "example": { + "name": "Example", + "axelarId": "example", + "chainId": 123, + "rpc": "PROVIDER_RPC", + "tokenSymbol": "EXM", + "gasOptions": { + "gasLimit": 8000000 + }, + "confirmations": 1 + } } - } } ``` + `gasLimit` override will skip auto gas estimation (which might be unreliable on certain chains for certain txs). `confirmations` indicates the number of block confirmations to wait for. `axelarId` is the unique id used to reference the chain on Axelar. 4. Return to the `axelar-cgp-solidity` repository. Once there, in the root directory of this repository, navigate to the `hardhat.config.js` file and modify the chains import line as shown below: + ```javascript const chains = require(`/path/to/axelar-contract-deployments/axelar-chains-config/info/${env}.json`); ``` 5. Create a `keys.json` file in this repo that contains the private keys for your accounts that will be used for testing. For some tests, such as the Axelar gateway tests, you may need to provide at least two private keys (you can refer the [test](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d0c040330d7498d52dee7eedbebf2aefeb5c87fb/test/BurnableMintableCappedERC20.js#L22) to find the number of accounts needed). At this point the `keys.json` file should resemble the example file below (`chains` can be left empty): + ```json { - "chains": {}, - "accounts": ["PRIVATE_KEY1", "PRIVATE_KEY2"] + "chains": {}, + "accounts": ["PRIVATE_KEY1", "PRIVATE_KEY2"] } ``` 6. Ensure that your accounts corresponding to the private keys provided have sufficient gas tokens on the chain. 7. Run + ```bash npm ci @@ -93,39 +99,43 @@ npx hardhat test --network example --grep 'AxelarGateway' ## Debugging Steps -- Explicitly pass `getGasOptions()` using utils.js file for some spceific transactions. See the code below for example +- Explicitly pass `getGasOptions()` using utils.js file for some spceific transactions. See the code below for example + ```javascript await sourceChainGateway - .execute( - await getSignedWeightedExecuteInput(await getTokenDeployData(false), [operatorWallet], [1], 1, [operatorWallet]), - getGasOptions(), - ) - .then((tx) => tx.wait(network.config.confirmations)); + .execute( + await getSignedWeightedExecuteInput(await getTokenDeployData(false), [operatorWallet], [1], 1, [operatorWallet]), + getGasOptions() + ) + .then((tx) => tx.wait(network.config.confirmations)); ``` -- Using the most up to date and fast rpc can help in tests execution runtime. Make sure the rate limit for the rpc is not exceeded. +- Using the most up to date and fast rpc can help in tests execution runtime. Make sure the rate limit for the rpc is not exceeded. + +- Make sure that the account being used to broadcast transactions has enough native balance. The maximum `gasLimit` for a chain should be fetched from an explorer and set it in config file. You may also need to update the `confirmations` required for a transaction to be successfully included in a block in the config [here](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/axelar-chains-config/info) depending on the network. -- Make sure that the account being used to broadcast transactions has enough native balance. The maximum `gasLimit` for a chain should be fetched from an explorer and set it in config file. You may also need to update the `confirmations` required for a transaction to be successfully included in a block in the config [here](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/axelar-chains-config/info) depending on the network. +- Note that certain tests can require upto 3 accounts. -- Note that certain tests can require upto 3 accounts. +- Transactions can fail if previous transactions are not mined and picked up by the provide, therefore wait for a transaction to be mined after broadcasting. See the code below for example -- Transactions can fail if previous transactions are not mined and picked up by the provide, therefore wait for a transaction to be mined after broadcasting. See the code below for example ```javascript await testToken.mint(userWallet.address, 1e9).then((tx) => tx.wait(network.config.confirmations)); // Or -const txExecute = await interchainGovernance.execute( - commandIdGateway, - governanceChain, - governanceAddress, - payload, - getGasOptions(), - ); +const txExecute = await interchainGovernance.execute(commandIdGateway, governanceChain, governanceAddress, payload, getGasOptions()); const receiptExecute = await txExecute.wait(network.config.confirmations); - ``` +``` + +- The `changeEtherBalance` check expects one tx in a block so change in balances might need to be tested explicitly for unit tests using `changeEtherBalance`. + +## Deploying contracts + +See the Axelar contract deployments [repository](https://github.com/axelarnetwork/axelar-contract-deployments) for relevant deployment/upgrade scripts: -- The `changeEtherBalance` check expects one tx in a block so change in balances might need to be tested explicitly for unit tests using `changeEtherBalance`. +1. [Gateway deployment](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/evm#axelargateway) +2. [Gateway upgrade](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/evm#gateway-upgrade) +3. [Gas service and deposit service deployment and upgrades](https://github.com/axelarnetwork/axelar-contract-deployments/tree/main/evm#axelargasservice-and-axelardepositservice) ## Example flows diff --git a/scripts/deploy-gateway-v3.2.x.js b/scripts/deploy-gateway-v3.2.x.js deleted file mode 100644 index ee6255e5..00000000 --- a/scripts/deploy-gateway-v3.2.x.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict'; - -require('dotenv').config(); - -const { - ContractFactory, - Wallet, - providers: { JsonRpcProvider }, - utils: { defaultAbiCoder, arrayify }, -} = require('ethers'); - -const { join, resolve } = require('node:path'); -const { existsSync } = require('node:fs'); -const { printLog, printObj, confirm, getAdminAddresses, getOwners, getOperators } = require('./utils'); - -// these environment variables should be defined in an '.env' file -const contractsPath = resolve(process.env.CONTRACTS_PATH || './build'); -const skipConfirm = process.env.SKIP_CONFIRM; -const prefix = process.env.PREFIX; -const chain = process.env.CHAIN; -const url = process.env.URL; -const privKey = process.env.PRIVATE_KEY; -const adminThreshold = parseInt(process.env.ADMIN_THRESHOLD); - -confirm( - { - CONTRACTS_PATH: contractsPath || null, - PREFIX: prefix || null, - CHAIN: chain || null, - URL: url || null, - PRIVATE_KEY: privKey || null, - ADMIN_THRESHOLD: adminThreshold || null, - SKIP_CONFIRM: skipConfirm || null, - }, - prefix && chain && url && privKey && adminThreshold, -); - -// the ABIs for the contracts below must be manually downloaded/compiled -const TokenDeployerPath = join(contractsPath, 'TokenDeployer.json'); -const AxelarGatewayMultisigPath = join(contractsPath, 'AxelarGatewayMultisig.json'); -const AxelarGatewayProxyPath = join(contractsPath, 'AxelarGatewayProxy.json'); - -if (!(existsSync(TokenDeployerPath) && existsSync(AxelarGatewayMultisigPath) && existsSync(AxelarGatewayProxyPath))) { - console.error( - `Missing one or more ABIs/bytecodes. Make sure TokenDeployer.json, AxelarGatewayMultisig.json, and AxelarGatewayProxy.json are present in ${contractsPath}`, - ); - process.exit(1); -} - -const TokenDeployer = require(TokenDeployerPath); -const AxelarGatewayMultisig = require(AxelarGatewayMultisigPath); -const AxelarGatewayProxy = require(AxelarGatewayProxyPath); - -const provider = new JsonRpcProvider(url); -const wallet = new Wallet(privKey, provider); - -printLog('retrieving admin addresses'); -const admins = getAdminAddresses(prefix, chain); -printObj({ admins: { addresses: admins, threshold: adminThreshold } }); - -printLog('retrieving owner addresses'); -const { addresses: owners, threshold: ownerThreshold } = getOwners(prefix, chain); -printObj({ owners, threshold: ownerThreshold }); - -printLog('retrieving operator addresses'); -const { addresses: operators, threshold: operatorThreshold } = getOperators(prefix, chain); -printObj({ operators, threshold: operatorThreshold }); - -const tokenDeployerFactory = new ContractFactory(TokenDeployer.abi, TokenDeployer.bytecode, wallet); -const axelarGatewayMultisigFactory = new ContractFactory(AxelarGatewayMultisig.abi, AxelarGatewayMultisig.bytecode, wallet); -const axelarGatewayProxyFactory = new ContractFactory(AxelarGatewayProxy.abi, AxelarGatewayProxy.bytecode, wallet); - -const contracts = {}; -const params = arrayify( - defaultAbiCoder.encode( - ['address[]', 'uint8', 'address[]', 'uint8', 'address[]', 'uint8'], - [admins, adminThreshold, owners, ownerThreshold, operators, operatorThreshold], - ), -); - -printLog('deploying contracts'); - -tokenDeployerFactory - .deploy() - .then((tokenDeployer) => tokenDeployer.deployed()) - .then(({ address }) => { - printLog(`deployed token deployer at address ${address}`); - contracts.tokenDeployed = address; - return axelarGatewayMultisigFactory.deploy(address); - }) - .then((axelarGatewayMultisig) => axelarGatewayMultisig.deployed()) - .then(({ address }) => { - printLog(`deployed axelar gateway multisig at address ${address}`); - contracts.gatewayMultisig = address; - return axelarGatewayProxyFactory.deploy(address, params); - }) - .then((axelarGatewayProxy) => axelarGatewayProxy.deployed()) - .then(({ address }) => { - printLog(`deployed axelar gateway proxy at address ${address}`); - contracts.gatewayProxy = address; - }) - .catch((err) => { - console.error(err); - }) - .finally(() => { - printObj({ contract_addresses: contracts }); - }); diff --git a/scripts/deploy-gateway-v4.0.x.js b/scripts/deploy-gateway-v4.0.x.js deleted file mode 100644 index 39de31a5..00000000 --- a/scripts/deploy-gateway-v4.0.x.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -require('dotenv').config(); - -const { printLog, printObj, confirm, getOperators, getAdminAddresses, parseWei, getTxOptions } = require('./utils'); -const { ethers } = require('hardhat'); -const { - getContractFactory, - Wallet, - providers: { JsonRpcProvider }, - utils: { defaultAbiCoder, arrayify }, -} = ethers; - -// these environment variables should be defined in an '.env' file -const skipConfirm = process.env.SKIP_CONFIRM; -const prefix = process.env.PREFIX; -const chain = process.env.CHAIN; -const url = process.env.URL; -const privKey = process.env.PRIVATE_KEY; -const adminThreshold = parseInt(process.env.ADMIN_THRESHOLD); -const gasPrice = parseWei(process.env.GAS_PRICE); -const maxFeePerGas = parseWei(process.env.MAX_FEE_PER_GAS); -const maxPriorityFeePerGas = parseWei(process.env.MAX_PRIORITY_FEE_PER_GAS); -const gasLimit = process.env.GAS_LIMIT ? Number(process.env.GAS_LIMIT) : Number(21000); - -// main execution -confirm( - { - PREFIX: prefix || null, - CHAIN: chain || null, - URL: url || null, - PRIVATE_KEY: privKey ? '*****REDACTED*****' : null, - ADMIN_THRESHOLD: adminThreshold || null, - MAX_FEE_PER_GAS: maxFeePerGas?.toString() || null, - MAX_PRIORITY_FEE_PER_GAS: maxPriorityFeePerGas?.toString() || null, - GAS_PRICE: gasPrice?.toString() || null, - GAS_LIMIT: gasLimit || null, - SKIP_CONFIRM: skipConfirm || null, - }, - prefix && chain && url && privKey && adminThreshold, -); - -const provider = new JsonRpcProvider(url); -const wallet = new Wallet(privKey, provider); - -printLog('retrieving admin addresses'); -const admins = getAdminAddresses(prefix, chain); -printObj({ admins: { addresses: admins, threshold: adminThreshold } }); - -printLog('retrieving operator addresses'); -const { addresses: operators, threshold: operatorThreshold } = getOperators(prefix, chain); -printObj({ operators: { addresses: operators, threshold: operatorThreshold } }); - -const contracts = {}; -const paramsAuth = [defaultAbiCoder.encode(['address[]', 'uint256'], [operators, operatorThreshold])]; -const paramsProxy = arrayify(defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [admins, adminThreshold, '0x'])); - -(async () => { - printLog('fetching fee data'); - const feeData = await provider.getFeeData(); - printObj({ feeData }); - const options = getTxOptions(feeData, { maxFeePerGas, maxPriorityFeePerGas, gasPrice, gasLimit }); - printObj({ tx_options: options }); - - printLog('loading contract factories'); - // the ABIs for the contracts below must be manually downloaded/compiled - const gatewayFactory = await getContractFactory('AxelarGateway', wallet); - const authFactory = await getContractFactory('AxelarAuthMultisig', wallet); - const tokenDeployerFactory = await getContractFactory('TokenDeployer', wallet); - const gatewayProxyFactory = await getContractFactory('AxelarGatewayProxy', wallet); - printLog('contract factories loaded'); - - printLog(`deploying auth contract`); - const auth = await authFactory.deploy(paramsAuth).then((d) => d.deployed()); - printLog(`deployed auth at address ${auth.address}`); - contracts.auth = auth.address; - - printLog(`deploying token deployer contract`); - const tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); - printLog(`deployed token deployer at address ${tokenDeployer.address}`); - contracts.tokenDeployer = tokenDeployer.address; - - printLog(`deploying gateway implementation contract`); - const gatewayImplementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address).then((d) => d.deployed()); - printLog(`deployed gateway implementation at address ${gatewayImplementation.address}`); - contracts.gatewayImplementation = gatewayImplementation.address; - - printLog(`deploying gateway proxy contract`); - const gatewayProxy = await gatewayProxyFactory.deploy(gatewayImplementation.address, paramsProxy).then((d) => d.deployed()); - printLog(`deployed gateway proxy at address ${gatewayProxy.address}`); - contracts.gatewayProxy = gatewayProxy.address; - - printLog('transferring auth ownership'); - await auth.transferOwnership(gatewayProxy.address, options); - printLog('transferred auth ownership. All done!'); -})() - .catch((err) => { - console.error(err); - }) - .finally(() => { - printObj({ contract_addresses: contracts }); - }); diff --git a/scripts/deploy-gateway-v4.3.x.js b/scripts/deploy-gateway-v4.3.x.js deleted file mode 100644 index 3fa0cbc7..00000000 --- a/scripts/deploy-gateway-v4.3.x.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -require('dotenv').config(); - -const { printLog, printObj, confirm, getEVMAddresses, pubkeysToAddresses, parseWei, getTxOptions } = require('./utils'); -const { ethers } = require('hardhat'); -const { - getContractFactory, - Wallet, - providers: { JsonRpcProvider }, - utils: { defaultAbiCoder, arrayify }, -} = ethers; - -// these environment variables should be defined in an '.env' file -const skipConfirm = process.env.SKIP_CONFIRM; -const prefix = process.env.PREFIX; -const chain = process.env.CHAIN; -const url = process.env.URL; -const privKey = process.env.PRIVATE_KEY; -const adminPubkeys = process.env.ADMIN_PUBKEYS; -const adminAddresses = process.env.ADMIN_ADDRESSES; -const adminThreshold = parseInt(process.env.ADMIN_THRESHOLD); -const gasPrice = parseWei(process.env.GAS_PRICE); -const maxFeePerGas = parseWei(process.env.MAX_FEE_PER_GAS); -const maxPriorityFeePerGas = parseWei(process.env.MAX_PRIORITY_FEE_PER_GAS); -const gasLimit = process.env.GAS_LIMIT ? Number(process.env.GAS_LIMIT) : Number(21000); - -// main execution -confirm( - { - PREFIX: prefix || null, - CHAIN: chain || null, - URL: url || null, - PRIVATE_KEY: privKey ? '*****REDACTED*****' : null, - ADMIN_PUBKEYS: adminPubkeys || null, - ADMIN_ADDRESSES: adminAddresses || null, - ADMIN_THRESHOLD: adminThreshold || null, - MAX_FEE_PER_GAS: maxFeePerGas?.toString() || null, - MAX_PRIORITY_FEE_PER_GAS: maxPriorityFeePerGas?.toString() || null, - GAS_PRICE: gasPrice?.toString() || null, - GAS_LIMIT: gasLimit || null, - SKIP_CONFIRM: skipConfirm || null, - }, - prefix && chain && url && privKey && adminThreshold && (adminPubkeys || adminAddresses), -); - -const provider = new JsonRpcProvider(url); -const wallet = new Wallet(privKey, provider); - -printLog('retrieving addresses'); -const { addresses, weights, threshold } = getEVMAddresses(prefix, chain); -printObj({ addresses, weights, threshold }); -const admins = adminAddresses ? JSON.parse(adminAddresses) : pubkeysToAddresses(JSON.parse(adminPubkeys)); -printObj({ admins }); - -const contracts = {}; -const paramsAuth = [defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold])]; -const paramsProxy = arrayify(defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [admins, adminThreshold, '0x'])); - -(async () => { - printLog('fetching fee data'); - const feeData = await provider.getFeeData(); - printObj({ feeData }); - const options = getTxOptions(feeData, { maxFeePerGas, maxPriorityFeePerGas, gasPrice, gasLimit }); - printObj({ tx_options: options }); - - printLog('loading contract factories'); - // the ABIs for the contracts below must be manually downloaded/compiled - const gatewayFactory = await getContractFactory('AxelarGateway', wallet); - const authFactory = await getContractFactory('AxelarAuthWeighted', wallet); - const tokenDeployerFactory = await getContractFactory('TokenDeployer', wallet); - const gatewayProxyFactory = await getContractFactory('AxelarGatewayProxy', wallet); - printLog('contract factories loaded'); - - printLog(`deploying auth contract`); - const auth = await authFactory.deploy(paramsAuth).then((d) => d.deployed()); - printLog(`deployed auth at address ${auth.address}`); - contracts.auth = auth.address; - - printLog(`deploying token deployer contract`); - const tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); - printLog(`deployed token deployer at address ${tokenDeployer.address}`); - contracts.tokenDeployer = tokenDeployer.address; - - printLog(`deploying gateway implementation contract`); - const gatewayImplementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address).then((d) => d.deployed()); - printLog(`deployed gateway implementation at address ${gatewayImplementation.address}`); - contracts.gatewayImplementation = gatewayImplementation.address; - - printLog(`deploying gateway proxy contract`); - const gatewayProxy = await gatewayProxyFactory.deploy(gatewayImplementation.address, paramsProxy).then((d) => d.deployed()); - printLog(`deployed gateway proxy at address ${gatewayProxy.address}`); - contracts.gatewayProxy = gatewayProxy.address; - - printLog('transferring auth ownership'); - await auth.transferOwnership(gatewayProxy.address, options); - printLog('transferred auth ownership. All done!'); -})() - .catch((err) => { - console.error(err); - }) - .finally(() => { - printObj({ contract_addresses: contracts }); - }); diff --git a/scripts/deploy-upgradable.js b/scripts/deploy-upgradable.js deleted file mode 100644 index 7261fa09..00000000 --- a/scripts/deploy-upgradable.js +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; -require('dotenv').config(); -const { get, getOr, isEmpty } = require('lodash/fp'); -const { - Contract, - Wallet, - getDefaultProvider, - utils: { isAddress }, -} = require('ethers'); -const readlineSync = require('readline-sync'); -const { writeJSON } = require('./utils'); -const { deployUpgradable, upgradeUpgradable, predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-solidity'); -const IUpgradable = require('@axelar-network/axelar-gmp-sdk-solidity/dist/IUpgradable.json'); - -function getProxy(wallet, proxyAddress) { - return new Contract(proxyAddress, IUpgradable.abi, wallet); -} - -async function getImplementationArgs(contractName, chain, wallet) { - if (contractName === 'AxelarGasService') { - const collector = get('AxelarGasService.collector', chain); - if (!isAddress(collector)) throw new Error(`Missing AxelarGasService.collector in the chain info.`); - return [collector]; - } - - if (contractName === 'AxelarDepositService') { - const symbol = getOr('', 'AxelarDepositService.wrappedSymbol', chain); - if (isEmpty(symbol)) console.log(`${chain.name} | AxelarDepositService.wrappedSymbol: wrapped token is disabled`); - - const refundIssuer = get('AxelarDepositService.refundIssuer', chain); - if (!isAddress(refundIssuer)) throw new Error(`${chain.name} | Missing AxelarDepositService.refundIssuer in the chain info.`); - - return [chain.gateway, symbol, refundIssuer]; - } - - throw new Error(`${contractName} is not supported.`); -} - -function getInitArgs(contractName, chain) { - if (contractName === 'AxelarGasService') return '0x'; - if (contractName === 'AxelarDepositService') return '0x'; - throw new Error(`${contractName} is not supported.`); -} - -function getUpgradeArgs(contractName, chain) { - if (contractName === 'AxelarGasService') return '0x'; - if (contractName === 'AxelarDepositService') return '0x'; - throw new Error(`${contractName} is not supported.`); -} - -async function deploy(env, chains, wallet, artifactPath, contractName, deployTo) { - const implementationPath = artifactPath + contractName + '.sol/' + contractName + '.json'; - const proxyPath = artifactPath + contractName + 'Proxy.sol/' + contractName + 'Proxy.json'; - const implementationJson = require(implementationPath); - const proxyJson = require(proxyPath); - console.log(`Deployer address ${wallet.address}`); - - for (const chain of chains) { - if (deployTo.length > 0 && !deployTo.find((name) => chain.name === name)) continue; - const rpc = chain.rpc; - const provider = getDefaultProvider(rpc); - console.log( - `Deployer has ${(await provider.getBalance(wallet.address)) / 1e18} ${ - chain.tokenSymbol - } and nonce ${await provider.getTransactionCount(wallet.address)} on ${chain.name}.`, - ); - } - - for (const chain of chains) { - if (deployTo.length > 0 && !deployTo.find((name) => chain.name === name)) continue; - const rpc = chain.rpc; - const provider = getDefaultProvider(rpc); - const args = await getImplementationArgs(contractName, chain); - console.log(`Implementation args for chain ${chain.name}: ${args}`); - console.log(`Gas override for chain ${chain.name}:`, chain.gasOptions); - - if (chain[contractName] && chain[contractName].address) { - const contract = getProxy(wallet.connect(provider), chain[contractName]['address']); - const owner = await contract.owner(); - console.log(`Proxy already exists for ${chain.name}: ${contract.address}`); - console.log(`Existing implementation ${await contract.implementation()}`); - console.log(`Existing owner ${owner}`); - - if (wallet.address !== owner) { - throw new Error( - `${chain.name} | Signer ${wallet.address} does not match contract owner ${owner} for chain ${chain.name} in info.`, - ); - } - - const anwser = readlineSync.question(`Perform an upgrade for ${chain.name}? (y/n) `); - if (anwser !== 'y') continue; - - await upgradeUpgradable( - wallet.connect(provider), - chain[contractName]['address'], - implementationJson, - args, - getUpgradeArgs(contractName, chain), - get('gasOptions.gasLimit', chain), - ); - - chain[contractName]['implementation'] = await contract.implementation(); - - writeJSON(chains, `../info/${env}.json`); - console.log(`${chain.name} | New Implementation for ${contractName} is at ${chain[contractName]['implementation']}`); - console.log(`${chain.name} | Upgraded.`); - } else { - const key = env.includes('devnet') ? `${contractName}-${env}` : contractName; - const setupArgs = getInitArgs(contractName, chain); - console.log(`Proxy setup args: ${setupArgs}`); - console.log(`Proxy deployment salt: '${key}'`); - - const proxyAddress = await predictContractConstant(chain.constAddressDeployer, wallet.connect(provider), proxyJson, key); - console.log(`Proxy will be deployed to ${proxyAddress} Does this match any existing deployments?`); - const anwser = readlineSync.question(`Proceed with deployment on ${chain.name}? (y/n) `); - if (anwser !== 'y') return; - - const contract = await deployUpgradable( - chain.constAddressDeployer, - wallet.connect(provider), - implementationJson, - proxyJson, - args, - [], - setupArgs, - key, - get('gasOptions.gasLimit', chain), - ); - - chain[contractName]['salt'] = key; - chain[contractName]['address'] = contract.address; - chain[contractName]['implementation'] = await contract.implementation(); - chain[contractName]['deployer'] = wallet.address; - - writeJSON(chains, `../info/${env}.json`); - console.log(`${chain.name} | ConstAddressDeployer is at ${chain.constAddressDeployer}`); - console.log(`${chain.name} | Implementation for ${contractName} is at ${chain[contractName]['implementation']}`); - console.log(`${chain.name} | Proxy for ${contractName} is at ${contract.address}`); - } - } -} - -if (require.main === module) { - const env = process.argv[2]; - if (env === null || (env !== 'local' && !env.includes('devnet') && env !== 'testnet' && env !== 'mainnet')) - throw new Error('Need to specify local | devnet* | testnet | mainnet as an argument to this script.'); - - const chains = require(`../info/${env}.json`); - - const private_key = process.env.PRIVATE_KEY; - const wallet = new Wallet(private_key); - - const artifactPath = process.argv[3]; - - const contractName = process.argv[4]; - - const deployTo = process.argv.slice(5); - - deploy(env, chains, wallet, artifactPath, contractName, deployTo); -} diff --git a/scripts/prepare-gateway-upgrade-v3.2.0.js b/scripts/prepare-gateway-upgrade-v3.2.0.js deleted file mode 100644 index 3916b015..00000000 --- a/scripts/prepare-gateway-upgrade-v3.2.0.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -require('dotenv').config(); - -const { - Contract, - ContractFactory, - Wallet, - providers: { JsonRpcProvider }, - utils: { defaultAbiCoder, arrayify, keccak256 }, -} = require('ethers'); - -const { join, resolve } = require('node:path'); -const { printLog, printObj, confirm, getOwners, getOperators, getAdminAddresses, parseWei, getTxOptions } = require('./utils'); - -// these environment variables should be defined in an '.env' file -const contractsPath = resolve(process.env.CONTRACTS_PATH || './build'); -const skipConfirm = process.env.SKIP_CONFIRM; -const prefix = process.env.PREFIX; -const chain = process.env.CHAIN; -const url = process.env.URL; -const proxyAddress = process.env.PROXY_ADDRESS; -const privKey = process.env.PRIVATE_KEY; -const adminThreshold = parseInt(process.env.ADMIN_THRESHOLD); -const gasPrice = parseWei(process.env.GAS_PRICE); -const maxFeePerGas = parseWei(process.env.MAX_FEE_PER_GAS); -const maxPriorityFeePerGas = parseWei(process.env.MAX_PRIORITY_FEE_PER_GAS); -const gasLimit = process.env.GAS_LIMIT ? Number(process.env.GAS_LIMIT) : Number(21000); - -confirm( - { - CONTRACTS_PATH: contractsPath || null, - PREFIX: prefix || null, - CHAIN: chain || null, - URL: url || null, - PRIVATE_KEY: privKey || null, - ADMIN_THRESHOLD: adminThreshold || null, - PROXY_ADDRESS: proxyAddress || null, - MAX_FEE_PER_GAS: maxFeePerGas?.toString() || null, - MAX_PRIORITY_FEE_PER_GAS: maxPriorityFeePerGas?.toString() || null, - GAS_PRICE: gasPrice?.toString() || null, - GAS_LIMIT: gasLimit || null, - SKIP_CONFIRM: skipConfirm || null, - }, - prefix && chain && url && privKey && adminThreshold && proxyAddress, -); - -const provider = new JsonRpcProvider(url); -const wallet = new Wallet(privKey, provider); - -const admins = getAdminAddresses(prefix, chain); -printObj({ admins: { addresses: admins, threshold: adminThreshold } }); - -printLog('retrieving owner addresses'); -const { addresses: owners, threshold: ownerThreshold } = getOwners(prefix, chain); -printObj({ owners, threshold: ownerThreshold }); - -printLog('retrieving operator addresses'); -const { addresses: operators, threshold: operatorThreshold } = getOperators(prefix, chain); -printObj({ operators, threshold: operatorThreshold }); - -const params = defaultAbiCoder.encode( - ['address[]', 'uint8', 'address[]', 'uint8', 'address[]', 'uint8'], - [admins, adminThreshold, owners, ownerThreshold, operators, operatorThreshold], -); - -const TokenDeployerPath = join(contractsPath, 'TokenDeployer.json'); -const TokenDeployer = require(TokenDeployerPath); -const tokenDeployerFactory = new ContractFactory(TokenDeployer.abi, TokenDeployer.bytecode, wallet); - -const AxelarGatewayMultisigPath = join(contractsPath, 'AxelarGatewayMultisig.json'); -const AxelarGatewayMultisig = require(AxelarGatewayMultisigPath); -const axelarGatewayMultisigFactory = new ContractFactory(AxelarGatewayMultisig.abi, AxelarGatewayMultisig.bytecode, wallet); - -const AxelarGatewayPath = join(contractsPath, 'AxelarGateway.json'); -const AxelarGateway = require(AxelarGatewayPath); - -printLog(`deploying token deployer contract`); - -tokenDeployerFactory - .deploy() - .then((tokenDeployer) => tokenDeployer.deployed()) - .then(({ address }) => { - printObj({ token_deployer: address }); - printLog(`deploying gateway implementation contract`); - return axelarGatewayMultisigFactory.deploy(address); - }) - .then((axelarGatewayMultisig) => axelarGatewayMultisig.deployed()) - .then(async ({ address }) => { - const newImplementationCode = await provider.getCode(address); - const newImplementationCodeHash = keccak256(newImplementationCode); - - printLog('fetching fee data'); - const feeData = await provider.getFeeData(); - printObj({ feeData }); - const options = getTxOptions(feeData, { maxFeePerGas, maxPriorityFeePerGas, gasPrice, gasLimit }); - printObj({ tx_options: options }); - - printObj({ - upgrade_cmd: { - gateway_implementation_address: address, - gateway_implementation_code_hash: newImplementationCodeHash, - params: params, - }, - }); - - const proxy = new Contract(proxyAddress, AxelarGateway.abi, wallet); - const tx_req = await proxy.populateTransaction.upgrade(address, newImplementationCodeHash, arrayify(params)); - printObj({ upgrade_tx_data: tx_req.data }); - }) - .catch((err) => { - console.error(err); - }); diff --git a/scripts/prepare-gateway-upgrade-v4.3.x.js b/scripts/prepare-gateway-upgrade-v4.3.x.js deleted file mode 100644 index 4d5bbe79..00000000 --- a/scripts/prepare-gateway-upgrade-v4.3.x.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -require('dotenv').config(); - -const { printLog, printObj, confirm, getEVMAddresses, parseWei, getTxOptions, pubkeysToAddresses } = require('./utils'); -const { ethers } = require('hardhat'); -const { - getContractFactory, - getContractAt, - Wallet, - providers: { JsonRpcProvider }, - utils: { defaultAbiCoder, arrayify, keccak256 }, -} = ethers; - -// these environment variables should be defined in an '.env' file -const skipConfirm = process.env.SKIP_CONFIRM; -const prefix = process.env.PREFIX; -const chain = process.env.CHAIN; -const url = process.env.URL; -const privKey = process.env.PRIVATE_KEY; -const proxyAddress = process.env.PROXY_ADDRESS; - -const adminPubkeys = process.env.ADMIN_PUBKEYS; -const adminAddresses = process.env.ADMIN_ADDRESSES; -const adminThreshold = parseInt(process.env.ADMIN_THRESHOLD); -const gasPrice = parseWei(process.env.GAS_PRICE); -const maxFeePerGas = parseWei(process.env.MAX_FEE_PER_GAS); -const maxPriorityFeePerGas = parseWei(process.env.MAX_PRIORITY_FEE_PER_GAS); -const gasLimit = process.env.GAS_LIMIT ? Number(process.env.GAS_LIMIT) : Number(21000); - -// main execution -confirm( - { - PREFIX: prefix || null, - CHAIN: chain || null, - URL: url || null, - PRIVATE_KEY: privKey ? '*****REDACTED*****' : null, - PROXY_ADDRESS: proxyAddress || null, - ADMIN_THRESHOLD: adminThreshold || null, - ADMIN_PUBKEYS: adminPubkeys || null, - ADMIN_ADDRESSES: adminAddresses || null, - MAX_FEE_PER_GAS: maxFeePerGas?.toString() || null, - MAX_PRIORITY_FEE_PER_GAS: maxPriorityFeePerGas?.toString() || null, - GAS_PRICE: gasPrice?.toString() || null, - GAS_LIMIT: gasLimit || null, - SKIP_CONFIRM: skipConfirm || null, - }, - prefix && chain && url && privKey && proxyAddress && adminThreshold && (adminPubkeys || adminAddresses), -); - -const provider = new JsonRpcProvider(url); -const wallet = new Wallet(privKey, provider); - -printLog('retrieving addresses'); -const { addresses, weights, threshold } = getEVMAddresses(prefix, chain); -printObj({ operators: addresses, weights, threshold }); -const admins = adminAddresses ? JSON.parse(adminAddresses) : pubkeysToAddresses(JSON.parse(adminPubkeys)); -printObj({ admins }); - -const paramsAuth = [defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold])]; -const paramsUpgrade = defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [admins, adminThreshold, '0x']); - -(async () => { - printLog('fetching fee data'); - const feeData = await provider.getFeeData(); - printObj({ feeData }); - const options = getTxOptions(feeData, { maxFeePerGas, maxPriorityFeePerGas, gasPrice, gasLimit }); - printObj({ tx_options: options }); - - printLog('loading contract factories'); - // the ABIs for the contracts below must be manually downloaded/compiled - const gatewayFactory = await getContractFactory('AxelarGateway', wallet); - const authFactory = await getContractFactory('AxelarAuthWeighted', wallet); - const tokenDeployerFactory = await getContractFactory('TokenDeployer', wallet); - printLog('contract factories loaded'); - - printLog(`deploying auth contract`); - const auth = await authFactory.deploy(paramsAuth).then((d) => d.deployed()); - printObj({ auth_address: auth.address }); - - printLog(`deploying token deployer contract`); - const tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); - printObj({ token_deployer_address: tokenDeployer.address }); - - printLog(`deploying gateway implementation contract`); - const gatewayImplementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address).then((d) => d.deployed()); - printLog(`deployed gateway implementation at address ${gatewayImplementation.address}`); - - printLog(`transferring auth ownership to proxy address ${proxyAddress}`); - const tx = await auth.transferOwnership(proxyAddress, options); - await tx.wait(); - printLog(`transferred auth ownership to proxy address ${proxyAddress}`); - - const newImplementationCode = await provider.getCode(gatewayImplementation.address); - const newImplementationCodeHash = keccak256(newImplementationCode); - - printObj({ - auth_address: auth.address, - token_deployer_address: tokenDeployer.address, - upgrade_cmd: { - gateway_implementation_address: gatewayImplementation.address, - gateway_implementation_code_hash: newImplementationCodeHash, - params: paramsUpgrade, - }, - }); - - const proxy = await getContractAt('IAxelarGateway', proxyAddress, wallet); - const tx_req = await proxy.populateTransaction.upgrade( - gatewayImplementation.address, - newImplementationCodeHash, - arrayify(paramsUpgrade), - ); - printObj({ upgrade_tx_data: tx_req.data }); -})().catch((err) => { - console.error(err); -});