@@ -6,6 +6,24 @@ import { verifyOnCustomEtherscan } from './scripts/customContractVerifier';
66
77const OUTPUT_FILE = 'output.json' ;
88
9+ // Balance check configuration
10+ /**
11+ * Safety multiplier for balance checks.
12+ * A value of 150n with divisor 100n creates a 1.5x safety buffer.
13+ * This ensures we have 50% more funds than the estimated gas cost.
14+ */
15+ export const BALANCE_SAFETY_MULTIPLIER = 150n ; // 1.5x safety buffer (150/100 = 1.5)
16+ export const BALANCE_SAFETY_DIVISOR = 100n ;
17+
18+ /**
19+ * Calculates the required amount with safety buffer applied.
20+ * @param estimatedCost - The estimated gas cost in wei
21+ * @returns The required amount with safety buffer applied
22+ */
23+ export function applyBalanceSafetyBuffer ( estimatedCost : bigint ) : bigint {
24+ return ( estimatedCost * BALANCE_SAFETY_MULTIPLIER ) / BALANCE_SAFETY_DIVISOR ;
25+ }
26+
927export const logger = {
1028 info : ( msg : string ) => console . log ( `[INFO] ${ msg } ` ) ,
1129 config : ( msg : string ) => console . log ( `[CONFIG] ${ msg } ` ) ,
@@ -15,6 +33,86 @@ export const logger = {
1533 step : ( msg : string ) => console . log ( `\n--- ${ msg } ---` )
1634} ;
1735
36+ /**
37+ * Checks if the deployer has sufficient balance for the deployment.
38+ * Requires 1.5x the estimated gas cost to provide a safety buffer.
39+ */
40+ export async function checkSufficientBalance (
41+ deployerAddress : string ,
42+ estimatedGasCost : bigint ,
43+ contractName : string = 'contract'
44+ ) : Promise < void > {
45+ const balance = await ethers . provider . getBalance ( deployerAddress ) ;
46+ const requiredAmount = applyBalanceSafetyBuffer ( estimatedGasCost ) ;
47+
48+ logger . info ( `💰 Balance check for ${ contractName } deployment:` ) ;
49+ logger . info ( ` Deployer balance: ${ ethers . formatEther ( balance ) } ETH` ) ;
50+ logger . info (
51+ ` Estimated gas cost: ${ ethers . formatEther ( estimatedGasCost ) } ETH`
52+ ) ;
53+ logger . info (
54+ ` Required (1.5x buffer): ${ ethers . formatEther ( requiredAmount ) } ETH`
55+ ) ;
56+
57+ if ( balance < requiredAmount ) {
58+ const shortfall = requiredAmount - balance ;
59+ logger . error ( `Insufficient funds for ${ contractName } deployment!` ) ;
60+ logger . error ( ` Shortfall: ${ ethers . formatEther ( shortfall ) } ETH` ) ;
61+ logger . error ( ` Please fund the deployer account: ${ deployerAddress } ` ) ;
62+ throw new Error (
63+ `Insufficient funds: need ${ ethers . formatEther (
64+ requiredAmount
65+ ) } ETH, have ${ ethers . formatEther ( balance ) } ETH`
66+ ) ;
67+ }
68+
69+ logger . success (
70+ `✅ Sufficient balance confirmed for ${ contractName } deployment`
71+ ) ;
72+ }
73+
74+ /**
75+ * Checks balance before individual contract deployment.
76+ * Estimates gas for a typical contract deployment transaction.
77+ */
78+ export async function checkIndividualContractBalance (
79+ deployerAddress : string ,
80+ contractName : string ,
81+ gasOverrides ?: any
82+ ) : Promise < void > {
83+ try {
84+ // Get current fee data
85+ const feeData = await ethers . provider . getFeeData ( ) ;
86+
87+ // Estimate typical contract deployment gas (fallback if we can't estimate precisely)
88+ const estimatedGas = 500000n ; // 500k gas - reasonable estimate for contract deployment
89+
90+ // Calculate gas price
91+ let gasPrice : bigint ;
92+ if ( gasOverrides ?. gasPrice ) {
93+ gasPrice = gasOverrides . gasPrice ;
94+ } else if ( gasOverrides ?. maxFeePerGas ) {
95+ gasPrice = gasOverrides . maxFeePerGas ;
96+ } else {
97+ gasPrice = feeData . gasPrice || 1_000_000_000n ; // 1 gwei fallback
98+ }
99+
100+ const estimatedCost = estimatedGas * gasPrice ;
101+
102+ // Check balance with 1.5x buffer
103+ await checkSufficientBalance ( deployerAddress , estimatedCost , contractName ) ;
104+ } catch ( error ) {
105+ logger . warn (
106+ `⚠️ Could not perform precise balance check for ${ contractName } : ${
107+ ( error as Error ) . message
108+ } `
109+ ) ;
110+ logger . info (
111+ `🔄 Proceeding with deployment - will fail fast if insufficient funds`
112+ ) ;
113+ }
114+ }
115+
18116export type DeploymentAddresses = {
19117 walletImplementation ?: string ;
20118 walletFactory ?: string ;
@@ -31,7 +129,8 @@ export async function deployIfNeededAtNonce(
31129 expectedNonce : number ,
32130 deployerAddress : string ,
33131 contractName : string ,
34- deployFn : ( ) => Promise < string >
132+ deployFn : ( ) => Promise < string > ,
133+ gasOverrides ?: any
35134) : Promise < string > {
36135 const predictedAddress = getCreateAddress ( {
37136 from : deployerAddress ,
@@ -83,12 +182,19 @@ export async function deployIfNeededAtNonce(
83182 throw new Error ( errorMsg ) ;
84183 }
85184
86- // 5. Deploy
185+ // 5. Balance check before deployment
186+ await checkIndividualContractBalance (
187+ deployerAddress ,
188+ contractName ,
189+ gasOverrides
190+ ) ;
191+
192+ // 6. Deploy
87193 logger . info ( `🚀 Deploying ${ contractName } at nonce ${ expectedNonce } ...` ) ;
88194 return await deployFn ( ) ;
89195}
90196
91- async function isContractDeployed ( address : string ) {
197+ export async function isContractDeployed ( address : string ) {
92198 const code = await ethers . provider . getCode ( address ) ;
93199 return code && code !== '0x' ;
94200}
0 commit comments