diff --git a/typescript/cli/ci-test.sh b/typescript/cli/ci-test.sh index 276c5c9391..df5112ee2b 100755 --- a/typescript/cli/ci-test.sh +++ b/typescript/cli/ci-test.sh @@ -18,8 +18,8 @@ do chmod -R 777 /tmp/relayer /tmp/$CHAIN done -anvil --chain-id 31337 -p 8545 --state /tmp/anvil1/state > /dev/null & -anvil --chain-id 31338 -p 8555 --state /tmp/anvil2/state > /dev/null & +anvil --chain-id 31337 -p 8545 --state /tmp/anvil1/state --gas-price 1 > /dev/null & +anvil --chain-id 31338 -p 8555 --state /tmp/anvil2/state --gas-price 1 > /dev/null & sleep 1 set -e @@ -28,6 +28,9 @@ echo "{}" > /tmp/empty-artifacts.json export DEBUG=hyperlane:* +DEPLOYER=$(cast rpc eth_accounts | jq -r '.[0]') +BEFORE=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) + echo "Deploying contracts to anvil1 and anvil2" yarn workspace @hyperlane-xyz/cli run hyperlane deploy core \ --chain-configs ./examples/anvil-chains.yaml \ @@ -39,6 +42,11 @@ yarn workspace @hyperlane-xyz/cli run hyperlane deploy core \ --key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ --yes +AFTER_CORE=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) +GAS_PRICE=$(cast gas-price --rpc-url http://localhost:8545) +CORE_MIN_GAS=$(bc <<< "($BEFORE - $AFTER_CORE) / $GAS_PRICE") +echo "Gas used: $CORE_MIN_GAS" + CORE_ARTIFACTS_PATH=`find /tmp/core-deployment* -type f -exec ls -t1 {} + | head -1` echo "Core artifacts:" echo $CORE_ARTIFACTS_PATH @@ -54,6 +62,11 @@ yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp \ --key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ --yes +AFTER_WARP=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) +GAS_PRICE=$(cast gas-price --rpc-url http://localhost:8545) +WARP_MIN_GAS=$(bc <<< "($AFTER_CORE - $AFTER_WARP) / $GAS_PRICE") +echo "Gas used: $WARP_MIN_GAS" + echo "Sending test message" yarn workspace @hyperlane-xyz/cli run hyperlane send message \ --origin anvil1 \ @@ -64,6 +77,11 @@ yarn workspace @hyperlane-xyz/cli run hyperlane send message \ --key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ | tee /tmp/message1 +AFTER_MSG=$(cast balance $DEPLOYER --rpc-url http://localhost:8545) +GAS_PRICE=$(cast gas-price --rpc-url http://localhost:8545) +MSG_MIN_GAS=$(bc <<< "($AFTER_WARP - $AFTER_MSG) / $GAS_PRICE") +echo "Gas used: $MSG_MIN_GAS" + MESSAGE1_ID=`cat /tmp/message1 | grep "Message ID" | grep -E -o '0x[0-9a-f]+'` echo "Message 1 ID: $MESSAGE1_ID" diff --git a/typescript/cli/src/consts.ts b/typescript/cli/src/consts.ts index 2b93a4eb55..9e05f2fcb6 100644 --- a/typescript/cli/src/consts.ts +++ b/typescript/cli/src/consts.ts @@ -1,4 +1,3 @@ -// TODO revisit these rough balance requirements with more precise measurements -export const MINIMUM_CORE_DEPLOY_BALANCE = '500000000000000000'; // 0.5 ETH -export const MINIMUM_WARP_DEPLOY_BALANCE = '200000000000000000'; // 0.2 Eth -export const MINIMUM_TEST_SEND_BALANCE = '10000000000000000'; // 0.01 ETH +export const MINIMUM_CORE_DEPLOY_GAS = (1e8).toString(); +export const MINIMUM_WARP_DEPLOY_GAS = (1e7).toString(); +export const MINIMUM_TEST_SEND_GAS = (3e5).toString(); diff --git a/typescript/cli/src/deploy/core.ts b/typescript/cli/src/deploy/core.ts index 3f0f99eaaf..05380ddac1 100644 --- a/typescript/cli/src/deploy/core.ts +++ b/typescript/cli/src/deploy/core.ts @@ -33,7 +33,7 @@ import { log, logBlue, logGray, logGreen, logRed } from '../../logger.js'; import { readDeploymentArtifacts } from '../config/artifacts.js'; import { readHookConfig } from '../config/hooks.js'; import { readMultisigConfig } from '../config/multisig.js'; -import { MINIMUM_CORE_DEPLOY_BALANCE } from '../consts.js'; +import { MINIMUM_CORE_DEPLOY_GAS } from '../consts.js'; import { getContextWithSigner, getMergedContractAddresses, @@ -100,7 +100,7 @@ export async function runCoreDeploy({ await runDeployPlanStep(deploymentParams); await runPreflightChecksForChains({ ...deploymentParams, - minBalanceWei: MINIMUM_CORE_DEPLOY_BALANCE, + minGas: MINIMUM_CORE_DEPLOY_GAS, }); await executeDeploy(deploymentParams); } diff --git a/typescript/cli/src/deploy/utils.ts b/typescript/cli/src/deploy/utils.ts index 82c62c90a3..871a96c5c6 100644 --- a/typescript/cli/src/deploy/utils.ts +++ b/typescript/cli/src/deploy/utils.ts @@ -4,7 +4,7 @@ import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk'; import { ProtocolType } from '@hyperlane-xyz/utils'; import { log, logGreen } from '../../logger.js'; -import { assertNativeBalances } from '../utils/balances.js'; +import { assertGasBalances } from '../utils/balances.js'; import { assertSigner } from '../utils/keys.js'; export async function runPreflightChecks({ @@ -12,13 +12,13 @@ export async function runPreflightChecks({ remotes, signer, multiProvider, - minBalanceWei, + minGas, }: { origin: ChainName; remotes: ChainName[]; signer: ethers.Signer; multiProvider: MultiProvider; - minBalanceWei: string; + minGas: string; }) { log('Running pre-flight checks...'); @@ -29,7 +29,7 @@ export async function runPreflightChecks({ chains: [origin, ...remotes], signer, multiProvider, - minBalanceWei, + minGas, }); } @@ -37,12 +37,12 @@ export async function runPreflightChecksForChains({ chains, signer, multiProvider, - minBalanceWei, + minGas, }: { chains: ChainName[]; signer: ethers.Signer; multiProvider: MultiProvider; - minBalanceWei: string; + minGas: string; }) { log('Running pre-flight checks...'); @@ -58,6 +58,6 @@ export async function runPreflightChecksForChains({ assertSigner(signer); logGreen('Signer is valid ✅'); - await assertNativeBalances(multiProvider, signer, chains, minBalanceWei); + await assertGasBalances(multiProvider, signer, chains, minGas); logGreen('Balances are sufficient ✅'); } diff --git a/typescript/cli/src/deploy/warp.ts b/typescript/cli/src/deploy/warp.ts index 3580b885cb..215c2903bc 100644 --- a/typescript/cli/src/deploy/warp.ts +++ b/typescript/cli/src/deploy/warp.ts @@ -22,7 +22,7 @@ import { Address, ProtocolType, objMap } from '@hyperlane-xyz/utils'; import { log, logBlue, logGray, logGreen } from '../../logger.js'; import { readDeploymentArtifacts } from '../config/artifacts.js'; import { WarpRouteConfig, readWarpRouteConfig } from '../config/warp.js'; -import { MINIMUM_WARP_DEPLOY_BALANCE } from '../consts.js'; +import { MINIMUM_WARP_DEPLOY_GAS } from '../consts.js'; import { getContextWithSigner, getMergedContractAddresses, @@ -86,7 +86,7 @@ export async function runWarpDeploy({ await runDeployPlanStep(deploymentParams); await runPreflightChecks({ ...deploymentParams, - minBalanceWei: MINIMUM_WARP_DEPLOY_BALANCE, + minGas: MINIMUM_WARP_DEPLOY_GAS, }); await executeDeploy(deploymentParams); } diff --git a/typescript/cli/src/send/message.ts b/typescript/cli/src/send/message.ts index b3ca0f8fd1..1b90c346cb 100644 --- a/typescript/cli/src/send/message.ts +++ b/typescript/cli/src/send/message.ts @@ -10,7 +10,7 @@ import { addressToBytes32, timeout } from '@hyperlane-xyz/utils'; import { errorRed, log, logBlue, logGreen } from '../../logger.js'; import { readDeploymentArtifacts } from '../config/artifacts.js'; -import { MINIMUM_TEST_SEND_BALANCE } from '../consts.js'; +import { MINIMUM_TEST_SEND_GAS } from '../consts.js'; import { getContextWithSigner, getMergedContractAddresses, @@ -48,7 +48,7 @@ export async function sendTestMessage({ remotes: [destination], multiProvider, signer, - minBalanceWei: MINIMUM_TEST_SEND_BALANCE, + minGas: MINIMUM_TEST_SEND_GAS, }); await timeout( diff --git a/typescript/cli/src/send/transfer.ts b/typescript/cli/src/send/transfer.ts index 44e3f287d4..5e413309ba 100644 --- a/typescript/cli/src/send/transfer.ts +++ b/typescript/cli/src/send/transfer.ts @@ -17,7 +17,7 @@ import { Address, timeout } from '@hyperlane-xyz/utils'; import { log, logBlue, logGreen } from '../../logger.js'; import { readDeploymentArtifacts } from '../config/artifacts.js'; -import { MINIMUM_TEST_SEND_BALANCE } from '../consts.js'; +import { MINIMUM_TEST_SEND_GAS } from '../consts.js'; import { getContextWithSigner, getMergedContractAddresses, @@ -78,7 +78,7 @@ export async function sendTestTransfer({ remotes: [destination], multiProvider, signer, - minBalanceWei: MINIMUM_TEST_SEND_BALANCE, + minGas: MINIMUM_TEST_SEND_GAS, }); await timeout( diff --git a/typescript/cli/src/utils/balances.ts b/typescript/cli/src/utils/balances.ts index 153cf657ba..68519eac8a 100644 --- a/typescript/cli/src/utils/balances.ts +++ b/typescript/cli/src/utils/balances.ts @@ -1,3 +1,4 @@ +import { confirm } from '@inquirer/prompts'; import { ethers } from 'ethers'; import { ERC20__factory } from '@hyperlane-xyz/core'; @@ -18,10 +19,31 @@ export async function assertNativeBalances( .getProvider(chain) .getBalance(address); const balance = ethers.utils.formatEther(balanceWei); - if (balanceWei.lt(minBalanceWei)) - throw new Error( - `${address} has insufficient balance on ${chain}. At least ${minBalance} required but found ${balance.toString()} ETH`, - ); + if (balanceWei.lt(minBalanceWei)) { + const symbol = + multiProvider.getChainMetadata(chain).nativeToken?.symbol ?? 'ETH'; + const error = `${address} has insufficient balance on ${chain}. At least ${minBalance} required but found ${balance.toString()} ${symbol}`; + const isResume = await confirm({ + message: `WARNING: ${error} Continue?`, + }); + if (!isResume) throw new Error(error); + } + }), + ); +} + +export async function assertGasBalances( + multiProvider: MultiProvider, + signer: ethers.Signer, + chains: ChainName[], + minGas: string, +) { + await Promise.all( + chains.map(async (chain) => { + const provider = multiProvider.getProvider(chain); + const gasPrice = await provider.getGasPrice(); + const minBalanceWei = gasPrice.mul(minGas).toString(); + await assertNativeBalances(multiProvider, signer, [chain], minBalanceWei); }), ); }