diff --git a/axelar-chains-config/info/stagenet.json b/axelar-chains-config/info/stagenet.json index f48114a0..b28ea40e 100644 --- a/axelar-chains-config/info/stagenet.json +++ b/axelar-chains-config/info/stagenet.json @@ -816,6 +816,97 @@ "gasOptions": { "gasLimit": 5000000 } + }, + "immutable-devnet": { + "name": "immutable-devnet", + "id": "immutable-devnet", + "chainId": 15003, + "rpc": "", + "tokenSymbol": "IMX", + "gasOptions": { + "gasLimit": 8000000, + "maxPriorityFeePerGas": 150000000000, + "maxFeePerGas": 160000000000 + }, + "contracts": { + "AxelarGateway": { + "startingKeyIDs": [ + "evm-immutable-devnet-genesis" + ], + "authModule": "0xe0Ad88660B5B09fE9FF8bA6f1dba1A826b1C7583", + "tokenDeployer": "0x42dBF20686794C1a82A95A629373ed2E8CFb5fEb", + "deployer": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "address": "0x6aF9C075d8C11b9A2CD66bbA801481b3c7A96488", + "implementation": "0x21BB37D5e02Ef479E34f6806C36a506c63741cc1", + "implementationCodehash": "0x25cc2857feace37fdf26f3021ac4af473923d6741611bacf7430f7e72ef99c65", + "deploymentMethod": "create3", + "salt": "AxelarGateway v6.2" + }, + "AxelarGasService": { + "collector": "0xB77A61a241a756E4817c845BEDE7e213a319b1DD", + "salt": "AxelarGasService", + "address": "0x47E840B35e0eca3E7C0577835DD78d95574873e7", + "implementation": "0x102A4324EA951BDd0105798C1fe31f8382EE1309", + "deployer": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd" + }, + "AxelarDepositService": { + "salt": "AxelarDepositService", + "address": "", + "implementation": "", + "deployer": "", + "wrappedSymbol": "", + "refundIssuer": "0x2517bA7a3E2cef54c1CD8618e7B0B661A7623817" + }, + "ConstAddressDeployer": { + "address": "0x98B2920D53612483F91F12Ed7754E51b4A77919e", + "deployer": "0xE86375704CDb8491a5Ed82D90DceCE02Ee0ac25F", + "deploymentMethod": "create", + "codehash": "0x8fda47a596dfba923270da84e0c32a2d0312f1c03389f83e16f2b5a35ed37fbe", + "predeployCodehash": "0x8fda47a596dfba923270da84e0c32a2d0312f1c03389f83e16f2b5a35ed37fbe" + }, + "Create3Deployer": { + "address": "0x6513Aedb4D1593BA12e50644401D976aebDc90d8", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "deploymentMethod": "create2", + "codehash": "0xf0ad66defbe082df243d4d274e626f557f97579c5c9e19f33d8093d6160808b7", + "predeployCodehash": "0x73fc31262c4bad113c79439fd231281201c7c7d45b50328bd86bccf37684bf92", + "salt": "Create3Deployer" + }, + "Operators": { + "owner": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "address": "0xB77A61a241a756E4817c845BEDE7e213a319b1DD", + "deployer": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "deploymentMethod": "create2", + "codehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb", + "predeployCodehash": "0xc561dc32ef670c929db9d7fbf6b5f6c074a62a30602481ba3b88912ca6d79feb", + "salt": "Operators" + }, + "Multisig": { + "threshold": 2, + "signers": [ + "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "0xA24156B88D56696a7beE61A38deB5D8aaD8Ceb55", + "0x2517bA7a3E2cef54c1CD8618e7B0B661A7623817" + ], + "address": "0x418FCD3890Ca73f5852eA727505f56396A644873", + "deployer": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "deploymentMethod": "create3", + "codehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "predeployCodehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "salt": "Multisig v5.5" + }, + "InterchainGovernance": { + "minimumTimeDelay": 300, + "governanceChain": "Axelarnet", + "governanceAddress": "axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj", + "address": "0xf6c4679c0FdA9b4e49fCcfedCEE03a730d35E64D", + "deployer": "0x9D97cf3AC20b73c81d8A5233d9FBe09618d4F8bd", + "deploymentMethod": "create3", + "codehash": "0xa8c5d3eab2aefc62e03bcf3c5e1db27cbce0e24d3f87d8dfbbb54676bfbf937c", + "predeployCodehash": "0xe2de43b29f2387b6f3575a1b50d566908fc00e03a8d88ad6be74b674a70874d2", + "salt": "InterchainGovernance v5.5" + } + } } }, "axelar": { diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index 9d7afd8b..ed2923ad 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -221,6 +221,10 @@ async function processCommand(config, chain, options) { const { env, artifactPath, contractName, deployMethod, privateKey, verify, yes } = options; const verifyOptions = verify ? { env, chain: chain.name, only: verify === 'only' } : null; + if (!chain.contracts) { + chain.contracts = {}; + } + const contracts = chain.contracts; if (!contracts[contractName]) { @@ -288,7 +292,13 @@ async function processCommand(config, chain, options) { printInfo('Deployer contract', deployerContract); printInfo(`${contractName} will be deployed to`, predictedAddress); - if (prompt(`Does derived address match existing deployments? Proceed with deployment on ${chain.name}?`, yes)) { + const existingAddress = config.chains.ethereum?.contracts?.[contractName]?.address; + if (existingAddress !== undefined && predictedAddress !== existingAddress) { + printWarn(`Predicted address ${predictedAddress} does not match existing deployment ${existingAddress} on chain ${chain.name}.`); + printWarn('For official deployment, recheck the deployer, salt, args, or contract bytecode.'); + } + + if (prompt(`Proceed with deployment on ${chain.name}?`, yes)) { return; } diff --git a/evm/deploy-gateway-v6.2.x.js b/evm/deploy-gateway-v6.2.x.js index 75ec39f2..5365c44c 100644 --- a/evm/deploy-gateway-v6.2.x.js +++ b/evm/deploy-gateway-v6.2.x.js @@ -93,6 +93,10 @@ async function deploy(config, chain, options) { const wallet = new Wallet(privateKey).connect(provider); await printWalletInfo(wallet); + if (chain.contracts === undefined) { + chain.contracts = {}; + } + if (chain.contracts[contractName] === undefined) { chain.contracts[contractName] = {}; } @@ -117,6 +121,9 @@ async function deploy(config, chain, options) { if (!(await isContract(mintLimiter, provider))) { printWarn('MintLimiter address is not a contract. This is optional for test deployments'); } + + printInfo('Governance address', governance); + printInfo('MintLimiter address', mintLimiter); } const gatewayFactory = new ContractFactory(AxelarGateway.abi, AxelarGateway.bytecode, wallet); @@ -161,7 +168,9 @@ async function deploy(config, chain, options) { contractConfig.deployer = wallet.address; - if (reuseProxy && reuseHelpers) { + if (options.skipExisting && contractConfig.authModule) { + auth = authFactory.attach(contractConfig.authModule); + } else if (reuseProxy && reuseHelpers) { auth = authFactory.attach(await gateway.authModule()); } else { printInfo(`Deploying auth contract`); @@ -180,7 +189,9 @@ async function deploy(config, chain, options) { }); } - if (reuseProxy && reuseHelpers) { + if (options.skipExisting && contractConfig.tokenDeployer) { + tokenDeployer = tokenDeployerFactory.attach(contractConfig.tokenDeployer); + } else if (reuseProxy && reuseHelpers) { tokenDeployer = tokenDeployerFactory.attach(await gateway.tokenDeployer()); } else { printInfo(`Deploying token deployer contract`); @@ -237,8 +248,6 @@ async function deploy(config, chain, options) { const params = getProxyParams(governance, mintLimiter); printInfo('Deploying gateway proxy contract'); - printInfo('Governance address', governance); - printInfo('MintLimiter address', mintLimiter); printInfo('Proxy deployment args', `${implementation.address},${params}`); const gatewayProxy = await gatewayProxyFactory.deploy(implementation.address, params, gasOptions); @@ -521,6 +530,7 @@ async function programHandler() { program.addOption(new Option('--prevKeyIDs ', 'previous key IDs to be used for auth contract')); 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-upgradable.js b/evm/deploy-upgradable.js index 5b82ebc1..7179e268 100644 --- a/evm/deploy-upgradable.js +++ b/evm/deploy-upgradable.js @@ -131,7 +131,7 @@ async function deploy(options, chain) { const implArgs = await getImplementationArgs(contractName, contracts, options); const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; printInfo(`Implementation args for chain ${chain.name}`, implArgs); - console.log(`Gas override for chain ${chain.name}: ${JSON.stringify(gasOptions)}`); + console.log(`Gas override for chain ${chain.name}: ${JSON.stringify(gasOptions, null, 2)}`); const salt = options.salt || contractName; let deployerContract = deployMethod === 'create3' ? contracts.Create3Deployer?.address : contracts.ConstAddressDeployer?.address; diff --git a/evm/legacy/ConstAddressDeployer.json b/evm/legacy/ConstAddressDeployer.json new file mode 100644 index 00000000..94463ed7 --- /dev/null +++ b/evm/legacy/ConstAddressDeployer.json @@ -0,0 +1,133 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ConstAddressDeployer", + "sourceName": "contracts/ConstAddressDeployer.sol", + "abi": [ + { + "inputs": [], + "name": "EmptyBytecode", + "type": "error" + }, + { + "inputs": [], + "name": "FailedDeploy", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInit", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "bytecodeHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "deployedAddress", + "type": "address" + } + ], + "name": "Deployed", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "bytecode", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "deploy", + "outputs": [ + { + "internalType": "address", + "name": "deployedAddress_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "bytecode", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "init", + "type": "bytes" + } + ], + "name": "deployAndInit", + "outputs": [ + { + "internalType": "address", + "name": "deployedAddress_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "bytecode", + "type": "bytes" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "deployedAddress", + "outputs": [ + { + "internalType": "address", + "name": "deployedAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b506105a4806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80634af63f0214610046578063c2b1041c14610075578063cf4d643214610088575b600080fd5b6100596100543660046103f7565b61009b565b6040516001600160a01b03909116815260200160405180910390f35b610059610083366004610485565b6100da565b6100596100963660046104ee565b6101a9565b604080513360208201529081018290526000906100d39084906060015b6040516020818303038152906040528051906020012061026e565b9392505050565b604080516001600160a01b038416602082015290810182905260009081906060016040516020818303038152906040528051906020012090503081878760405161012592919061055e565b6040519081900381206101879392916020017fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b604080513360208201529081018490526000906101ca9086906060016100b8565b90506000816001600160a01b031684846040516101e892919061055e565b6000604051808303816000865af19150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b5050905080610265576040517f4f77232300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50949350505050565b60008251600014156102ac576040517f21744a5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818351602085016000f590506001600160a01b0381166102f8576040517f4102e83a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160208401206040516001600160a01b0383169184917f27b8e3132afa95254770e1c1d214eafde52bc47d1b6e1f5dfcbb380c3ca3f53290600090a492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261037b57600080fd5b813567ffffffffffffffff808211156103965761039661033b565b604051601f8301601f19908116603f011681019082821181831017156103be576103be61033b565b816040528381528660208588010111156103d757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561040a57600080fd5b823567ffffffffffffffff81111561042157600080fd5b61042d8582860161036a565b95602094909401359450505050565b60008083601f84011261044e57600080fd5b50813567ffffffffffffffff81111561046657600080fd5b60208301915083602082850101111561047e57600080fd5b9250929050565b6000806000806060858703121561049b57600080fd5b843567ffffffffffffffff8111156104b257600080fd5b6104be8782880161043c565b90955093505060208501356001600160a01b03811681146104de57600080fd5b9396929550929360400135925050565b6000806000806060858703121561050457600080fd5b843567ffffffffffffffff8082111561051c57600080fd5b6105288883890161036a565b955060208701359450604087013591508082111561054557600080fd5b506105528782880161043c565b95989497509550505050565b818382376000910190815291905056fea26469706673582212206a8d0537e27fe239a39d5ad8e5334db0447d0a1d7d49a7e82479baaa1319b39664736f6c63430008090033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80634af63f0214610046578063c2b1041c14610075578063cf4d643214610088575b600080fd5b6100596100543660046103f7565b61009b565b6040516001600160a01b03909116815260200160405180910390f35b610059610083366004610485565b6100da565b6100596100963660046104ee565b6101a9565b604080513360208201529081018290526000906100d39084906060015b6040516020818303038152906040528051906020012061026e565b9392505050565b604080516001600160a01b038416602082015290810182905260009081906060016040516020818303038152906040528051906020012090503081878760405161012592919061055e565b6040519081900381206101879392916020017fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b604080513360208201529081018490526000906101ca9086906060016100b8565b90506000816001600160a01b031684846040516101e892919061055e565b6000604051808303816000865af19150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b5050905080610265576040517f4f77232300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50949350505050565b60008251600014156102ac576040517f21744a5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818351602085016000f590506001600160a01b0381166102f8576040517f4102e83a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160208401206040516001600160a01b0383169184917f27b8e3132afa95254770e1c1d214eafde52bc47d1b6e1f5dfcbb380c3ca3f53290600090a492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261037b57600080fd5b813567ffffffffffffffff808211156103965761039661033b565b604051601f8301601f19908116603f011681019082821181831017156103be576103be61033b565b816040528381528660208588010111156103d757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561040a57600080fd5b823567ffffffffffffffff81111561042157600080fd5b61042d8582860161036a565b95602094909401359450505050565b60008083601f84011261044e57600080fd5b50813567ffffffffffffffff81111561046657600080fd5b60208301915083602082850101111561047e57600080fd5b9250929050565b6000806000806060858703121561049b57600080fd5b843567ffffffffffffffff8111156104b257600080fd5b6104be8782880161043c565b90955093505060208501356001600160a01b03811681146104de57600080fd5b9396929550929360400135925050565b6000806000806060858703121561050457600080fd5b843567ffffffffffffffff8082111561051c57600080fd5b6105288883890161036a565b955060208701359450604087013591508082111561054557600080fd5b506105528782880161043c565b95989497509550505050565b818382376000910190815291905056fea26469706673582212206a8d0537e27fe239a39d5ad8e5334db0447d0a1d7d49a7e82479baaa1319b39664736f6c63430008090033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/evm/ownership.js b/evm/ownership.js index 3cf811d1..517573f0 100644 --- a/evm/ownership.js +++ b/evm/ownership.js @@ -20,7 +20,7 @@ async function processCommand(options, chain) { const { contractName, address, action, privateKey, newOwner, yes } = options; const contracts = chain.contracts; - const contractConfig = contracts[contractName]; + const contractConfig = contracts[contractName] || {}; let ownershipAddress; @@ -46,7 +46,7 @@ async function processCommand(options, chain) { const ownershipContract = new Contract(ownershipAddress, IOwnable.abi, wallet); const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - printInfo(`Gas override for ${chain.name}`, JSON.stringify(gasOptions)); + printInfo(`Gas override for ${chain.name}`, JSON.stringify(gasOptions, null, 2)); printInfo('Ownership Action', action); @@ -78,7 +78,7 @@ async function processCommand(options, chain) { let owner = await ownershipContract.owner(); if (owner.toLowerCase() !== wallet.address.toLowerCase()) { - throw new Error(`Caller ${wallet.address} is not the contract owner.`); + throw new Error(`Caller ${wallet.address} is not the contract owner but ${owner} is.`); } if (!isAddress(newOwner) || newOwner === AddressZero) { @@ -86,7 +86,7 @@ async function processCommand(options, chain) { } try { - await ownershipContract.transferOwnership(newOwner).then((tx) => tx.wait()); + await ownershipContract.transferOwnership(newOwner, gasOptions).then((tx) => tx.wait()); } catch (error) { throw new Error(error); } @@ -116,7 +116,7 @@ async function processCommand(options, chain) { } try { - await ownershipContract.proposeOwnership(newOwner).then((tx) => tx.wait()); + await ownershipContract.proposeOwnership(newOwner, gasOptions).then((tx) => tx.wait()); } catch (error) { throw new Error(error); } @@ -144,7 +144,7 @@ async function processCommand(options, chain) { } try { - await ownershipContract.acceptOwnership().then((tx) => tx.wait()); + await ownershipContract.acceptOwnership(gasOptions).then((tx) => tx.wait()); } catch (error) { throw new Error(error); } @@ -196,7 +196,7 @@ if (require.main === module) { addBaseOptions(program, { address: true }); - program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + program.addOption(new Option('-c, --contractName ', 'contract name')); program.addOption( new Option('--action ', 'ownership action').choices([ 'owner', diff --git a/evm/send-tokens.js b/evm/send-tokens.js index 89f035e0..32445031 100644 --- a/evm/send-tokens.js +++ b/evm/send-tokens.js @@ -9,7 +9,7 @@ const { getDefaultProvider, utils: { parseEther, parseUnits }, } = ethers; -const { printInfo, printError, printWalletInfo, isAddressArray, mainProcessor, isValidDecimal, prompt } = require('./utils'); +const { printInfo, printError, printWalletInfo, isAddressArray, mainProcessor, isValidDecimal, prompt, copyObject } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const { storeSignedTx, getWallet, signTransaction } = require('./sign-utils.js'); @@ -51,6 +51,8 @@ async function processCommand(_, chain, options) { printInfo('Chain', chain.name); + const gasOptions = copyObject(chain.gasOptions || {}); + if ( prompt( `Proceed with the transfer of ${chalk.green(amountStr)} ${chalk.green(chain.tokenSymbol)} to ${recipients} on ${chain.name}?`, @@ -66,6 +68,7 @@ async function processCommand(_, chain, options) { const tx = { to: recipient, value: amount, + ...gasOptions, }; if (!offline && chain.name.toLowerCase() === 'binance') { diff --git a/evm/upgradable.js b/evm/upgradable.js index 649df689..6c673245 100644 --- a/evm/upgradable.js +++ b/evm/upgradable.js @@ -48,7 +48,7 @@ async function deployCreate2Upgradable( txOptions = null, verifyOptions, ) { - const implementation = await deployCreate(wallet, implementationJson, implementationConstructorArgs, {}, verifyOptions); + const implementation = await deployCreate(wallet, implementationJson, implementationConstructorArgs, txOptions, verifyOptions); const proxy = await deployAndInitContractConstant( constAddressDeployerAddress, diff --git a/evm/utils.js b/evm/utils.js index 7703d592..7770d04c 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -34,7 +34,7 @@ const getSaltFromKey = (key) => { const deployCreate = async (wallet, contractJson, args = [], options = {}, verifyOptions = null, chain = {}) => { const factory = new ContractFactory(contractJson.abi, contractJson.bytecode, wallet); - const contract = await factory.deploy(...args, { ...options }); + const contract = await factory.deploy(...args, options); await contract.deployTransaction.wait(chain.confirmations); if (verifyOptions?.env) { @@ -839,7 +839,7 @@ function getContractJSON(contractName, artifactPath) { let contractPath; if (artifactPath) { - contractPath = artifactPath.charAt(0) === '@' ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; + contractPath = artifactPath.endsWith('.json') ? artifactPath : artifactPath + contractName + '.sol/' + contractName + '.json'; } else { contractPath = getContractPath(contractName); } @@ -850,7 +850,7 @@ function getContractJSON(contractName, artifactPath) { const contractJson = require(contractPath); return contractJson; } catch (err) { - throw new Error(`Failed to load contract JSON for ${contractName} at path ${contractPath}`); + throw new Error(`Failed to load contract JSON for ${contractName} at path ${contractPath} with error: ${err}`); } }