diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 651d4eeb..70c15a70 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -119,3 +119,13 @@ jobs: - name: InterchainTokenService deploy interchain token on current chain run: node evm/its.js --action deployInterchainToken --name "test" --symbol "TST" --decimals 18 --distributor 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 --destinationChain '' --gasValue 0 --salt "salt" -y + + - name: Add gasOptions to local.json + run: | + jq '.chains.test += {"gasOptions": {"gasLimit": 8000000}} | .chains.test.contracts.AxelarGateway += {"gasOptions": {"gasLimit": 8000000}}' ./axelar-chains-config/info/local.json > temp.json && mv temp.json ./axelar-chains-config/info/local.json + + - name: Redeploy AxelarGateway with gasOptions + run: node evm/deploy-gateway-v6.2.x.js -m create3 -s "AxelarGateway v6.2" --governance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --mintLimiter 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --keyID 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -y + + - name: Redeploy ITS with gasOptions in Chain Config + run: node evm/deploy-its.js -s "ITS v1.0.0" -f "ITS v1.0.0 Factory" -m create2 -y diff --git a/axelar-chains-config/info/mainnet.json b/axelar-chains-config/info/mainnet.json index aa624841..22af0354 100644 --- a/axelar-chains-config/info/mainnet.json +++ b/axelar-chains-config/info/mainnet.json @@ -270,7 +270,8 @@ "api": "https://api.ftmscan.com/api" }, "gasOptions": { - "gasLimit": 5000000 + "gasLimit": 5000000, + "gasPriceAdjustment": 1.4 }, "staticGasOptions": { "gasLimit": 3000000, @@ -363,7 +364,8 @@ "api": "https://api.polygonscan.com/api" }, "gasOptions": { - "gasLimit": 6000000 + "gasLimit": 6000000, + "gasPriceAdjustment": 1.6 }, "staticGasOptions": { "gasLimit": 3000000, @@ -547,7 +549,8 @@ "api": "https://api.bscscan.com/api" }, "gasOptions": { - "gasLimit": 8000000 + "gasLimit": 8000000, + "gasPriceAdjustment": 1.4 }, "staticGasOptions": { "gasLimit": 3000000, diff --git a/evm/deploy-const-address-deployer.js b/evm/deploy-const-address-deployer.js index c64703ce..e685cd04 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, getGasOptions } = 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'; @@ -48,8 +48,7 @@ async function deployConstAddressDeployer(wallet, chain, options = {}, verifyOpt console.log(`Deployer has ${balance / 1e18} ${chalk.green(chain.tokenSymbol)} and nonce ${nonce} on ${chain.name}.`); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - console.log(`Gas override for chain ${chain.name}: ${JSON.stringify(gasOptions)}`); + const gasOptions = await getGasOptions(chain, options, contractName); const constAddressDeployerAddress = await predictAddressCreate(wallet.address, nonce); printInfo('ConstAddressDeployer will be deployed to', constAddressDeployerAddress); diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index 884330d4..8259ba6a 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -14,7 +14,7 @@ const { printInfo, printWarn, printError, - copyObject, + getGasOptions, isNonEmptyString, isNumber, isAddressArray, @@ -255,15 +255,9 @@ async function processCommand(config, chain, options) { printInfo('Pre-deploy Contract bytecode hash', predeployCodehash); const constructorArgs = await getConstructorArgs(contractName, chain, wallet, options); - const gasOptions = copyObject(contractConfig.gasOptions || chain.gasOptions || {}); - - // Some chains require a gas adjustment - if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) { - gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.6); - } + const gasOptions = await getGasOptions(chain, options, contractName); printInfo(`Constructor args for chain ${chain.name}`, constructorArgs); - printInfo(`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/deploy-create3-deployer.js b/evm/deploy-create3-deployer.js index 8f570bf9..cbf70626 100644 --- a/evm/deploy-create3-deployer.js +++ b/evm/deploy-create3-deployer.js @@ -9,13 +9,13 @@ const { predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-soli const { Command } = require('commander'); const chalk = require('chalk'); -const { printInfo, writeJSON, deployCreate2 } = require('./utils'); +const { printInfo, writeJSON, deployCreate2, getGasOptions } = 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'; -async function deployCreate3Deployer(wallet, chain, options = {}, verifyOptions = null) { +async function deployCreate3Deployer(wallet, chain, provider, options = {}, verifyOptions = null) { printInfo('Deployer address', wallet.address); console.log( @@ -31,8 +31,7 @@ async function deployCreate3Deployer(wallet, chain, options = {}, verifyOptions } const contractConfig = contracts[contractName]; - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - console.log(`Gas override for chain ${chain.name}: ${JSON.stringify(gasOptions)}`); + const gasOptions = await getGasOptions(chain, options, contractName); const salt = options.salt || contractName; printInfo('Create3 deployer deployment salt', salt); @@ -74,6 +73,7 @@ async function main(options) { const verifyOptions = options.verify ? { env: options.env, chain: chain.name, only: options.verify } : null; let wallet; + let provider; if (options.env === 'local') { const [funder] = await ethers.getSigners(); @@ -81,11 +81,11 @@ async function main(options) { await (await funder.sendTransaction({ to: wallet.address, value: BigInt(1e21) })).wait(); await deployConstAddressDeployer(wallet, config.chains[chains[0].toLowerCase()]); } else { - const provider = getDefaultProvider(chain.rpc); + provider = getDefaultProvider(chain.rpc); wallet = new Wallet(options.privateKey, provider); } - await deployCreate3Deployer(wallet, chain, { salt: options.salt, yes: options.yes }, verifyOptions); + await deployCreate3Deployer(wallet, chain, provider, { salt: options.salt, yes: options.yes }, verifyOptions); writeJSON(config, `${__dirname}/../axelar-chains-config/info/${options.env}.json`); } } diff --git a/evm/deploy-gateway-v4.3.x.js b/evm/deploy-gateway-v4.3.x.js index 866188a4..f5b15993 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, + getGasOptions, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); const { ethers } = require('hardhat'); @@ -65,8 +66,8 @@ async function deploy(config, options) { }); printInfo('Predicted proxy address', proxyAddress); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || { gasLimit: 6e6 }; - printInfo('Gas override', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); + printInfo('Is verification enabled?', verify ? 'y' : 'n'); printInfo('Skip existing contracts?', skipExisting ? 'y' : 'n'); @@ -272,8 +273,7 @@ async function upgrade(config, options) { printInfo('Upgrading to implementation', contractConfig.implementation); printInfo('Implementation codehash', implementationCodehash); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); if (prompt(`Proceed with upgrade on ${chain.name}?`, yes)) { return; diff --git a/evm/deploy-gateway-v6.2.x.js b/evm/deploy-gateway-v6.2.x.js index f9dbf8c6..bbd897fe 100644 --- a/evm/deploy-gateway-v6.2.x.js +++ b/evm/deploy-gateway-v6.2.x.js @@ -28,6 +28,7 @@ const { mainProcessor, isContract, deployContract, + getGasOptions, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); const { storeSignedTx, signTransaction, getWallet } = require('./sign-utils.js'); @@ -82,7 +83,7 @@ function getProxyParams(governance, mintLimiter) { } async function deploy(config, chain, options) { - const { env, privateKey, reuseProxy, reuseHelpers, verify, yes } = options; + const { privateKey, reuseProxy, reuseHelpers, verify, yes } = options; const contractName = 'AxelarGateway'; @@ -131,14 +132,8 @@ async function deploy(config, chain, options) { printInfo('MintLimiter address', mintLimiter); } - const gasOptions = JSON.parse(JSON.stringify(contractConfig.gasOptions || chain.gasOptions || {})); + const gasOptions = await getGasOptions(chain, options, contractName); - // Some chains require a gas adjustment - if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) { - gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.6); - } - - printInfo('Gas override', JSON.stringify(gasOptions, null, 2)); const gatewayFactory = new ContractFactory(AxelarGateway.abi, AxelarGateway.bytecode, wallet); const authFactory = new ContractFactory(AxelarAuthWeighted.abi, AxelarAuthWeighted.bytecode, wallet); const tokenDeployerFactory = new ContractFactory(TokenDeployer.abi, TokenDeployer.bytecode, wallet); @@ -481,14 +476,13 @@ async function upgrade(_, chain, options) { printInfo('Mint limiter', mintLimiter); printInfo('Setup params', setupParams); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); if (prompt(`Proceed with an upgrade on ${chain.name}?`, yes)) { return; } - const tx = await gateway.populateTransaction.upgrade(contractConfig.implementation, implementationCodehash, setupParams); + const tx = await gateway.populateTransaction.upgrade(contractConfig.implementation, implementationCodehash, setupParams, gasOptions); const { baseTx, signedTx } = await signTransaction(wallet, chain, tx, options); diff --git a/evm/deploy-its.js b/evm/deploy-its.js index 01ea95ff..f8149602 100644 --- a/evm/deploy-its.js +++ b/evm/deploy-its.js @@ -8,6 +8,7 @@ const { getDefaultProvider, utils: { defaultAbiCoder, isAddress }, } = ethers; + const { deployContract, printWalletInfo, @@ -18,6 +19,7 @@ const { prompt, sleep, getBytecodeHash, + getGasOptions, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); const InterchainTokenService = getContractJSON('InterchainTokenService'); @@ -62,7 +64,7 @@ async function deployImplementation(config, wallet, chain, options) { return; } - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; + const gasOptions = await getGasOptions(chain, options, contractName); const deployOptions = deployMethod === 'create' @@ -335,7 +337,7 @@ async function upgrade(config, chain, options) { printInfo(`Upgrading Interchain Token Service.`); - const gasOptions = chain.gasOptions || {}; + const gasOptions = await getGasOptions(chain, options, contractName); const contract = new Contract(contractConfig.address, InterchainTokenService.abi, wallet); const codehash = await getBytecodeHash(contractConfig.implementation, chain.id, provider); diff --git a/evm/deploy-upgradable.js b/evm/deploy-upgradable.js index 3f6298cb..9cfc78a1 100644 --- a/evm/deploy-upgradable.js +++ b/evm/deploy-upgradable.js @@ -14,7 +14,7 @@ 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, getGasOptions } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); function getProxy(wallet, proxyAddress) { @@ -130,9 +130,8 @@ async function deploy(options, chain) { const contractConfig = contracts[contractName]; const implArgs = await getImplementationArgs(contractName, contracts, options); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; + const gasOptions = await getGasOptions(chain, options, contractName); printInfo(`Implementation args for chain ${chain.name}`, implArgs); - 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/gateway.js b/evm/gateway.js index 820d7e13..5c2c1ab0 100644 --- a/evm/gateway.js +++ b/evm/gateway.js @@ -21,6 +21,7 @@ const { wasEventEmitted, mainProcessor, printError, + getGasOptions, } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const { getWallet } = require('./sign-utils'); @@ -61,7 +62,6 @@ async function processCommand(config, chain, options) { const contracts = chain.contracts; const contractName = 'AxelarGateway'; - const contractConfig = contracts.AxelarGateway; const gatewayAddress = address || contracts.AxelarGateway?.address; @@ -82,8 +82,7 @@ async function processCommand(config, chain, options) { const gateway = new Contract(gatewayAddress, IGateway.abi, wallet); - const gasOptions = contractConfig?.gasOptions || chain?.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Action', action); diff --git a/evm/governance.js b/evm/governance.js index 6d01f3e7..244b9984 100644 --- a/evm/governance.js +++ b/evm/governance.js @@ -13,7 +13,7 @@ const { const { Command, Option } = require('commander'); const { printInfo, - copyObject, + getGasOptions, printWalletInfo, isValidTimeFormat, dateToEta, @@ -65,7 +65,7 @@ async function getGatewaySetupParams(governance, gateway, contracts, options) { } async function processCommand(_, chain, options) { - const { env, contractName, address, action, date, privateKey, yes } = options; + const { contractName, address, action, date, privateKey, yes } = options; const contracts = chain.contracts; const contractConfig = contracts[contractName]; @@ -106,14 +106,7 @@ async function processCommand(_, chain, options) { const governance = new Contract(governanceAddress, IGovernance.abi, wallet); - const gasOptions = copyObject(contractConfig?.gasOptions || chain?.gasOptions || { gasLimit: 5e6 }); - - // Some chains require a gas adjustment - if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) { - gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.4); - } - - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Proposal Action', action); diff --git a/evm/interchainTokenFactory.js b/evm/interchainTokenFactory.js index ffdc1e33..6fba09a9 100644 --- a/evm/interchainTokenFactory.js +++ b/evm/interchainTokenFactory.js @@ -9,7 +9,7 @@ const { Contract, } = ethers; const { Command, Option } = require('commander'); -const { printInfo, prompt, mainProcessor, validateParameters, getContractJSON } = require('./utils'); +const { printInfo, prompt, mainProcessor, validateParameters, getContractJSON, getGasOptions } = require('./utils'); const { getWallet } = require('./sign-utils'); const { addExtendedOptions } = require('./cli-utils'); const { getDeploymentSalt, handleTx } = require('./its'); @@ -22,7 +22,6 @@ async function processCommand(config, chain, options) { const contracts = chain.contracts; const contractName = 'InterchainTokenFactory'; - const contractConfig = contracts.InterchainTokenService; const interchainTokenFactoryAddress = address || contracts.InterchainTokenService?.interchainTokenFactory; const interchainTokenServiceAddress = contracts.InterchainTokenService?.address; @@ -42,8 +41,7 @@ async function processCommand(config, chain, options) { const interchainTokenFactory = new Contract(interchainTokenFactoryAddress, IInterchainTokenFactory.abi, wallet); const interchainTokenService = new Contract(interchainTokenServiceAddress, IInterchainTokenService.abi, wallet); - const gasOptions = contractConfig?.gasOptions || chain?.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Action', action); @@ -131,7 +129,15 @@ async function processCommand(config, chain, options) { isValidNumber: { decimals, mintAmount }, }); - const tx = await interchainTokenFactory.deployInterchainToken(deploymentSalt, name, symbol, decimals, mintAmount, distributor); + const tx = await interchainTokenFactory.deployInterchainToken( + deploymentSalt, + name, + symbol, + decimals, + mintAmount, + distributor, + gasOptions, + ); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'InterchainTokenDeploymentStarted'); @@ -155,6 +161,7 @@ async function processCommand(config, chain, options) { distributor, destinationChain, gasValue, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'InterchainTokenDeploymentStarted'); @@ -167,7 +174,7 @@ async function processCommand(config, chain, options) { validateParameters({ isValidAddress: { tokenAddress } }); - const tx = await interchainTokenFactory.registerCanonicalInterchainToken(tokenAddress); + const tx = await interchainTokenFactory.registerCanonicalInterchainToken(tokenAddress, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'TokenManagerDeploymentStarted'); @@ -188,6 +195,7 @@ async function processCommand(config, chain, options) { tokenAddress, destinationChain, gasValue, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'InterchainTokenDeploymentStarted'); @@ -213,6 +221,7 @@ async function processCommand(config, chain, options) { destinationAddress, amount, gasValue, + gasOptions, ); if (destinationChain === '') { @@ -237,7 +246,7 @@ async function processCommand(config, chain, options) { const tokenAddress = await interchainTokenService.interchainTokenAddress(tokenIdBytes32); const token = new Contract(tokenAddress, IERC20.abi, wallet); - const tx = await interchainTokenFactory.tokenTransferFrom(tokenIdBytes32, amount); + const tx = await interchainTokenFactory.tokenTransferFrom(tokenIdBytes32, amount, gasOptions); await handleTx(tx, chain, token, options.action, 'Transfer'); @@ -254,7 +263,7 @@ async function processCommand(config, chain, options) { const tokenAddress = await interchainTokenService.interchainTokenAddress(tokenIdBytes32); const token = new Contract(tokenAddress, IERC20.abi, wallet); - const tx = await interchainTokenFactory.tokenApprove(tokenIdBytes32, amount); + const tx = await interchainTokenFactory.tokenApprove(tokenIdBytes32, amount, gasOptions); await handleTx(tx, chain, token, options.action, 'Approval'); diff --git a/evm/its.js b/evm/its.js index fd100809..69e18b1b 100644 --- a/evm/its.js +++ b/evm/its.js @@ -19,6 +19,7 @@ const { validateParameters, getContractJSON, isValidTokenId, + getGasOptions, } = require('./utils'); const { getWallet } = require('./sign-utils'); const IInterchainTokenService = getContractJSON('IInterchainTokenService'); @@ -62,7 +63,6 @@ async function processCommand(config, chain, options) { const contracts = chain.contracts; const contractName = 'InterchainTokenService'; - const contractConfig = contracts.InterchainTokenService; const interchainTokenServiceAddress = address || contracts.InterchainTokenService?.address; @@ -81,8 +81,7 @@ async function processCommand(config, chain, options) { const interchainTokenService = new Contract(interchainTokenServiceAddress, IInterchainTokenService.abi, wallet); - const gasOptions = contractConfig?.gasOptions || chain?.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Action', action); @@ -201,6 +200,7 @@ async function processCommand(config, chain, options) { tokenManagerImplementations[type], params, gasValue, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'TokenManagerDeploymentStarted'); @@ -228,6 +228,7 @@ async function processCommand(config, chain, options) { decimals, distributor, gasValue, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'TokenManagerDeployed', 'InterchainTokenDeploymentStarted'); @@ -263,7 +264,7 @@ async function processCommand(config, chain, options) { isValidCalldata: { payload }, }); - const tx = await interchainTokenService.expressExecute(commandID, sourceChain, sourceAddress, payload); + const tx = await interchainTokenService.expressExecute(commandID, sourceChain, sourceAddress, payload, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'ExpressExecuted'); @@ -288,6 +289,7 @@ async function processCommand(config, chain, options) { destinationAddress, amount, metadata, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'InterchainTransfer', 'InterchainTransferWithData'); @@ -313,6 +315,7 @@ async function processCommand(config, chain, options) { destinationAddress, amount, data, + gasOptions, ); await handleTx(tx, chain, interchainTokenService, options.action, 'InterchainTransfer', 'InterchainTransferWithData'); @@ -335,7 +338,7 @@ async function processCommand(config, chain, options) { validateParameters({ isNumberArray: { flowLimits } }); - const tx = await interchainTokenService.setFlowLimits(tokenIdsBytes32, flowLimits); + const tx = await interchainTokenService.setFlowLimits(tokenIdsBytes32, flowLimits, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'FlowLimitSet'); @@ -369,7 +372,7 @@ async function processCommand(config, chain, options) { validateParameters({ isNonEmptyString: { trustedChain, trustedAddress } }); - const tx = await interchainTokenService.setTrustedAddress(trustedChain, trustedAddress); + const tx = await interchainTokenService.setTrustedAddress(trustedChain, trustedAddress, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'TrustedAddressSet'); @@ -387,7 +390,7 @@ async function processCommand(config, chain, options) { validateParameters({ isNonEmptyString: { trustedChain } }); - const tx = await interchainTokenService.removeTrustedAddress(trustedChain); + const tx = await interchainTokenService.removeTrustedAddress(trustedChain, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'TrustedAddressRemoved'); @@ -403,7 +406,7 @@ async function processCommand(config, chain, options) { const pauseStatus = options.pauseStatus; - const tx = await interchainTokenService.setPauseStatus(pauseStatus); + const tx = await interchainTokenService.setPauseStatus(pauseStatus, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action, 'Paused', 'Unpaused'); @@ -423,7 +426,7 @@ async function processCommand(config, chain, options) { validateParameters({ isValidCalldata: { payload } }); - const tx = await interchainTokenService.execute(commandID, sourceChain, sourceAddress, payload); + const tx = await interchainTokenService.execute(commandID, sourceChain, sourceAddress, payload, gasOptions); await handleTx(tx, chain, interchainTokenService, options.action); diff --git a/evm/multisig.js b/evm/multisig.js index dbdf5a70..40732fd2 100644 --- a/evm/multisig.js +++ b/evm/multisig.js @@ -22,6 +22,7 @@ const { mainProcessor, isValidDecimal, prompt, + getGasOptions, } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const IMultisig = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IMultisig.json'); @@ -123,8 +124,7 @@ async function processCommand(_, chain, options) { const multisigContract = new Contract(multisigAddress, IMultisig.abi, wallet); - const gasOptions = contractConfig?.gasOptions || chain?.gasOptions || {}; - printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Multisig Action', action); diff --git a/evm/operators.js b/evm/operators.js index 205a91b0..29c03e0c 100644 --- a/evm/operators.js +++ b/evm/operators.js @@ -21,6 +21,7 @@ const { isKeccak256Hash, parseArgs, prompt, + getGasOptions, } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const IAxelarGasService = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/IAxelarGasService.json'); @@ -58,8 +59,7 @@ async function processCommand(options, chain) { const operatorsContract = new Contract(operatorsAddress, IOperators.abi, wallet); - const gasOptions = contractConfig.gasOptions || chain.gasOptions || {}; - console.log(`Gas override for chain ${chain.name}: ${JSON.stringify(gasOptions)}`); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Operator Action', action); diff --git a/evm/ownership.js b/evm/ownership.js index 517573f0..74e7a1fa 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, getGasOptions } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const IOwnable = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/interfaces/IOwnable.sol/IOwnable.json'); @@ -45,8 +45,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, null, 2)); + const gasOptions = await getGasOptions(chain, options, contractName); printInfo('Ownership Action', action); diff --git a/evm/send-tokens.js b/evm/send-tokens.js index 32445031..1bbd1983 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, copyObject } = require('./utils'); +const { printInfo, printError, printWalletInfo, isAddressArray, mainProcessor, isValidDecimal, prompt, getGasOptions } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const { storeSignedTx, getWallet, signTransaction } = require('./sign-utils.js'); @@ -51,7 +51,7 @@ async function processCommand(_, chain, options) { printInfo('Chain', chain.name); - const gasOptions = copyObject(chain.gasOptions || {}); + const gasOptions = await getGasOptions(chain, options); if ( prompt( diff --git a/evm/utils.js b/evm/utils.js index 27d1e2f8..d0b6750c 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -6,6 +6,7 @@ const { Contract, utils: { computeAddress, getContractAddress, keccak256, isAddress, getCreate2Address, defaultAbiCoder, isHexString }, constants: { AddressZero }, + getDefaultProvider, } = ethers; const https = require('https'); const http = require('http'); @@ -926,6 +927,56 @@ function getContractJSON(contractName, artifactPath) { } } +/** + * Retrieves gas options for contract interactions. + * + * This function determines the appropriate gas options for a given transaction. + * It supports offline scenarios and applies gas price adjustments if specified. + * + * @param {Object} chain - The chain config object. + * @param {Object} options - Script options, including the 'offline' flag. + * @param {String} contractName - The name of the contract to deploy/interact with. + * @param {Object} defaultGasOptions - Optional default gas options if none are provided in the chain or contract configs. + * + * @returns {Object} An object containing gas options for the transaction. + * + * @throws {Error} Throws an error if fetching the gas price fails. + * + * Note: + * - If 'options.offline' is true, static gas options from the contract or chain config are used. + * - If 'gasPriceAdjustment' is set in gas options and 'gasPrice' is not pre-defined, the gas price + * is fetched from the provider and adjusted according to 'gasPriceAdjustment'. + */ +async function getGasOptions(chain, options, contractName, defaultGasOptions = {}) { + const { offline } = options; + + const contractConfig = contractName ? chain?.contracts[contractName] : null; + + if (offline) { + return copyObject(contractConfig?.staticGasOptions || chain?.staticGasOptions || defaultGasOptions); + } + + const gasOptions = copyObject(contractConfig?.gasOptions || chain?.gasOptions || defaultGasOptions); + const gasPriceAdjustment = gasOptions.gasPriceAdjustment; + + if (gasPriceAdjustment && !gasOptions.gasPrice) { + try { + const provider = getDefaultProvider(chain.rpc); + gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * gasPriceAdjustment); + } catch (err) { + throw new Error(`Provider failed to retrieve gas price on chain ${chain.name}: ${err}`); + } + } + + if (gasPriceAdjustment) { + delete gasOptions.gasPriceAdjustment; + } + + printInfo('Gas options', JSON.stringify(gasOptions, null, 2)); + + return gasOptions; +} + module.exports = { deployCreate, deployCreate2, @@ -977,4 +1028,5 @@ module.exports = { mainProcessor, getContractPath, getContractJSON, + getGasOptions, };