From 710bb9bf88c6d5a78795458c59bc77330a09e6e8 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 13 Feb 2026 07:57:41 +0000 Subject: [PATCH] fix(auth-eth): retry verifyDeployment for public RPC latency Public RPC endpoints may return stale data right after a transaction is mined, causing getCode() to return '0x' and the deploy script to fail with "Contract deployment failed - no code at address" even though the contract was deployed successfully. Add retry with linear back-off (5 attempts, 2s/4s/6s/8s/10s) to verifyDeployment() so deployments on public RPCs succeed without manual intervention. --- kms/auth-eth/lib/deployment-helpers.ts | 27 +++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/kms/auth-eth/lib/deployment-helpers.ts b/kms/auth-eth/lib/deployment-helpers.ts index dbcb2b66..49bcced2 100644 --- a/kms/auth-eth/lib/deployment-helpers.ts +++ b/kms/auth-eth/lib/deployment-helpers.ts @@ -110,17 +110,34 @@ export async function estimateDeploymentCost( } /** - * Verify contract deployment + * Verify contract deployment with retry logic for public RPCs. + * + * Public RPC endpoints may return stale data immediately after a transaction + * is mined, causing `getCode()` to return `'0x'` even though the contract was + * deployed successfully. We retry a few times with exponential back-off + * before giving up. */ export async function verifyDeployment( hre: HardhatRuntimeEnvironment, contractAddress: string, quiet: boolean = false ) { - // Verify that contract was deployed successfully - const code = await hre.ethers.provider.getCode(contractAddress); - if (code === '0x') { - throw new Error('Contract deployment failed - no code at address'); + const maxRetries = 5; + const baseDelayMs = 2000; + + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const code = await hre.ethers.provider.getCode(contractAddress); + if (code !== '0x') { + break; + } + if (attempt === maxRetries) { + throw new Error('Contract deployment failed - no code at address after ' + maxRetries + ' attempts'); + } + const delay = baseDelayMs * attempt; + if (!quiet) { + console.log(`Waiting for contract code at ${contractAddress} (attempt ${attempt}/${maxRetries}, next retry in ${delay}ms)...`); + } + await new Promise(resolve => setTimeout(resolve, delay)); } // Get implementation contract address