@@ -214,96 +214,288 @@ export function saveOutput(output: DeploymentAddresses) {
214214 fs . writeFileSync ( OUTPUT_FILE , JSON . stringify ( output , null , 2 ) ) ;
215215}
216216
217+ const VERIFICATION_CONFIG = {
218+ CONFIRMATION_BLOCKS : 5 ,
219+ MAX_RETRIES : 10 ,
220+ RETRY_DELAY_MS : 60_000 // 1 minute
221+ } as const ;
222+
223+ /**
224+ * Checks if an error indicates the contract is already verified
225+ */
226+ function isAlreadyVerifiedError ( error : any ) : boolean {
227+ return error . message . toLowerCase ( ) . includes ( 'already verified' ) ;
228+ }
229+
230+ /**
231+ * Creates a delay for the specified number of milliseconds
232+ */
233+ function delay ( ms : number ) : Promise < void > {
234+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
235+ }
236+
237+ /**
238+ * Waits for contract confirmations
239+ */
240+ async function waitForConfirmations (
241+ contract : BaseContract ,
242+ contractName : string ,
243+ confirmationBlocks : number = VERIFICATION_CONFIG . CONFIRMATION_BLOCKS
244+ ) : Promise < string > {
245+ logger . info (
246+ `Waiting for ${ confirmationBlocks } block confirmations for ${ contractName } ...`
247+ ) ;
248+
249+ const deployTx = contract . deploymentTransaction ( ) ;
250+ await deployTx ?. wait ( confirmationBlocks ) ;
251+
252+ const contractAddress = await contract . getAddress ( ) ;
253+ logger . success (
254+ `Contract ${ contractName } confirmed after ${ confirmationBlocks } confirmations at ${ contractAddress } `
255+ ) ;
256+
257+ return contractAddress ;
258+ }
259+
260+ /**
261+ * Checks if the current network supports Sourcify verification
262+ */
263+ async function isSourcifyNetwork (
264+ hre : HardhatRuntimeEnvironment
265+ ) : Promise < boolean > {
266+ const { sourcifyNetworks } = await import ( './hardhat.config' ) ;
267+ const network = await hre . ethers . provider . getNetwork ( ) ;
268+ const chainId = Number ( network . chainId ) ;
269+
270+ return chainId in sourcifyNetworks ;
271+ }
272+
273+ /**
274+ * Gets the Sourcify configuration for a specific network
275+ */
276+ async function getSourcifyConfig ( hre : HardhatRuntimeEnvironment ) : Promise < {
277+ enabled : boolean ;
278+ apiUrl : string ;
279+ browserUrl : string ;
280+ } > {
281+ const { sourcifyNetworks } = await import ( './hardhat.config' ) ;
282+ const network = await hre . ethers . provider . getNetwork ( ) ;
283+ const chainId = Number ( network . chainId ) ;
284+
285+ // Check if network has custom Sourcify configuration
286+ const networkConfig = (
287+ sourcifyNetworks as Record < number , { apiUrl : string ; browserUrl : string } >
288+ ) [ chainId ] ;
289+ if ( networkConfig ) {
290+ return {
291+ enabled : true ,
292+ apiUrl : networkConfig . apiUrl ,
293+ browserUrl : networkConfig . browserUrl
294+ } ;
295+ } else {
296+ throw new Error ( 'No Sourcify configuration available for this network' ) ;
297+ }
298+ }
299+
300+ /**
301+ * Attempts standard Hardhat verification
302+ */
303+ async function attemptStandardVerification (
304+ hre : HardhatRuntimeEnvironment ,
305+ contractAddress : string ,
306+ contractName : string ,
307+ constructorArguments : string [ ]
308+ ) : Promise < void > {
309+ const artifact = await hre . artifacts . readArtifact ( contractName ) ;
310+ const verificationString = `${ artifact . sourceName } :${ artifact . contractName } ` ;
311+
312+ logger . info ( 'Attempting verification with standard Hardhat verifier...' ) ;
313+
314+ await hre . run ( 'verify:verify' , {
315+ address : contractAddress ,
316+ constructorArguments,
317+ contract : verificationString
318+ } ) ;
319+
320+ logger . success ( 'Standard verification successful!' ) ;
321+ }
322+
323+ /**
324+ * Attempts custom Etherscan verification as fallback
325+ */
326+ async function attemptCustomVerification (
327+ hre : HardhatRuntimeEnvironment ,
328+ contractAddress : string ,
329+ contractName : string ,
330+ constructorArguments : string [ ]
331+ ) : Promise < void > {
332+ logger . info ( 'Falling back to custom verifier...' ) ;
333+
334+ await verifyOnCustomEtherscan ( {
335+ hre,
336+ contractAddress,
337+ contractName,
338+ constructorArguments
339+ } ) ;
340+
341+ logger . success ( 'Custom verifier fallback successful!' ) ;
342+ }
343+
344+ /**
345+ * Attempts Sourcify verification via hardhat-verify with dynamic configuration
346+ */
347+ async function attemptSourcifyVerification (
348+ hre : HardhatRuntimeEnvironment ,
349+ contractAddress : string ,
350+ contractName : string ,
351+ constructorArguments : string [ ]
352+ ) : Promise < void > {
353+ logger . info ( 'Using Sourcify verification...' ) ;
354+
355+ // Get the appropriate Sourcify configuration for this network
356+ const sourcifyConfig = await getSourcifyConfig ( hre ) ;
357+
358+ const originalConfig = hre . config . sourcify ;
359+ hre . config . sourcify = sourcifyConfig ;
360+
361+ try {
362+ const artifact = await hre . artifacts . readArtifact ( contractName ) ;
363+ const verificationString = `${ artifact . sourceName } :${ artifact . contractName } ` ;
364+
365+ logger . info ( `Verifying with fully qualified name: ${ verificationString } ` ) ;
366+ logger . info ( `Using Sourcify API: ${ sourcifyConfig . apiUrl } ` ) ;
367+
368+ await hre . run ( 'verify:sourcify' , {
369+ address : contractAddress ,
370+ constructorArguments,
371+ contract : verificationString
372+ } ) ;
373+ logger . success ( 'Sourcify verification successful!' ) ;
374+ } finally {
375+ hre . config . sourcify = originalConfig ;
376+ }
377+ }
378+
379+ /**
380+ * Attempts a single verification (standard + custom + hedera fallback)
381+ * Returns true if successful, false if should retry, throws if already verified
382+ */
383+ async function attemptVerification (
384+ hre : HardhatRuntimeEnvironment ,
385+ contractAddress : string ,
386+ contractName : string ,
387+ constructorArguments : string [ ]
388+ ) : Promise < boolean > {
389+ // Try sourcify verification if network supports it
390+ try {
391+ if ( await isSourcifyNetwork ( hre ) ) {
392+ await attemptSourcifyVerification (
393+ hre ,
394+ contractAddress ,
395+ contractName ,
396+ constructorArguments
397+ ) ;
398+ return true ; // Success
399+ }
400+ } catch ( sourcifyError : any ) {
401+ if ( isAlreadyVerifiedError ( sourcifyError ) ) {
402+ logger . success ( 'Contract is already verified.' ) ;
403+ throw new Error ( 'ALREADY_VERIFIED' ) ;
404+ }
405+ logger . warn ( `Sourcify verification failed: ${ sourcifyError . message } ` ) ;
406+ return false ; // Should retry
407+ }
408+
409+ // Try standard verification
410+ try {
411+ await attemptStandardVerification (
412+ hre ,
413+ contractAddress ,
414+ contractName ,
415+ constructorArguments
416+ ) ;
417+ return true ; // Success
418+ } catch ( standardError : any ) {
419+ if ( isAlreadyVerifiedError ( standardError ) ) {
420+ logger . success ( 'Contract is already verified.' ) ;
421+ throw new Error ( 'ALREADY_VERIFIED' ) ;
422+ }
423+
424+ logger . warn ( `Standard verifier failed: ${ standardError . message } ` ) ;
425+ }
426+
427+ // Try custom verification as fallback
428+ try {
429+ await attemptCustomVerification (
430+ hre ,
431+ contractAddress ,
432+ contractName ,
433+ constructorArguments
434+ ) ;
435+ return true ; // Success
436+ } catch ( customError : any ) {
437+ if ( isAlreadyVerifiedError ( customError ) ) {
438+ logger . success ( 'Contract is already verified.' ) ;
439+ throw new Error ( 'ALREADY_VERIFIED' ) ; // Special error to indicate success
440+ }
441+
442+ logger . warn ( `Custom verifier fallback also failed: ${ customError . message } ` ) ;
443+ }
444+
445+ return false ; // Should retry
446+ }
447+
217448/**
218449 * Waits for contract confirmation and then verifies it on a block explorer.
219- * It first tries the standard Hardhat verifier and falls back to a custom verifier if the first one fails.
220- * The entire process is wrapped in a retry loop.
450+ * Uses standard Hardhat verifier, custom verifier, and Sourcify verification.
221451 */
222452export async function waitAndVerify (
223453 hre : HardhatRuntimeEnvironment ,
224454 contract : BaseContract ,
225455 contractName : string ,
226456 constructorArguments : string [ ] = [ ]
227- ) {
457+ ) : Promise < void > {
228458 if ( ! hre ) {
229459 const errorMsg = 'Hardhat Runtime Environment (hre) is not defined.' ;
230460 logger . error ( errorMsg ) ;
231461 throw new Error ( errorMsg ) ;
232462 }
233463
234- const confirmationCount = 5 ;
235- logger . info (
236- `Waiting for ${ confirmationCount } block confirmations for ${ contractName } ...`
237- ) ;
238- const artifact = await hre . artifacts . readArtifact ( contractName ) ;
239- const verificationString = `${ artifact . sourceName } :${ artifact . contractName } ` ;
240- console . log ( `Verification string: ${ verificationString } ` ) ;
241-
242- const deployTx = contract . deploymentTransaction ( ) ;
243- await deployTx ?. wait ( confirmationCount ) ;
244-
245- logger . success (
246- `Contract ${ contractName } confirmed on the network after ${ confirmationCount } confirmations.`
247- ) ;
248- const contractAddress = await contract . getAddress ( ) ;
249- logger . success ( `Contract confirmed on the network at ${ contractAddress } .` ) ;
464+ // Wait for block confirmations
465+ const contractAddress = await waitForConfirmations ( contract , contractName ) ;
250466
251- const maxRetries = 20 ;
252- const retryDelay = 180000 ; // 180 seconds
467+ // Perform verification with retry logic
468+ for ( let attempt = 1 ; attempt <= VERIFICATION_CONFIG . MAX_RETRIES ; attempt ++ ) {
469+ logger . info ( `Verification attempt #${ attempt } for ${ contractName } ...` ) ;
253470
254- for ( let i = 0 ; i < maxRetries ; i ++ ) {
255- logger . info ( `Verification attempt #${ i + 1 } for ${ contractName } ...` ) ;
256471 try {
257- // --- Primary Attempt: Standard Verifier ---
258- logger . info ( 'Attempting verification with standard Hardhat verifier...' ) ;
259- await hre . run ( 'verify:verify' , {
260- address : contractAddress ,
261- constructorArguments : constructorArguments ,
262- contract : verificationString
263- } ) ;
264- logger . success ( 'Standard verification successful!' ) ;
265- return ; // Success, exit the loop.
266- } catch ( standardError : any ) {
267- logger . warn ( `Standard verifier failed: ${ standardError . message } ` ) ;
268-
269- if ( standardError . message . toLowerCase ( ) . includes ( 'already verified' ) ) {
270- logger . success ( 'Contract is already verified.' ) ;
271- return ;
272- }
472+ const success = await attemptVerification (
473+ hre ,
474+ contractAddress ,
475+ contractName ,
476+ constructorArguments
477+ ) ;
273478
274- // --- Fallback Attempt: Custom Verifier ---
275- logger . info ( 'Falling back to custom verifier...' ) ;
276- try {
277- await verifyOnCustomEtherscan ( {
278- hre,
279- contractAddress : contractAddress , // Use the fetched address
280- contractName : contractName ,
281- constructorArguments : constructorArguments
282- } ) ;
283- logger . success ( 'Custom verifier fallback successful!' ) ;
284- return ; // Success, exit the loop.
285- } catch ( customError : any ) {
286- if ( customError . message . toLowerCase ( ) . includes ( 'already verified' ) ) {
287- logger . success ( 'Contract is already verified.' ) ;
288- return ;
289- }
290-
291- logger . warn (
292- `Custom verifier fallback also failed: ${ customError . message } `
293- ) ;
294- if ( i < maxRetries - 1 ) {
295- logger . info (
296- `Waiting ${
297- retryDelay / 1000
298- } seconds before retrying entire process...`
299- ) ;
300- await new Promise ( ( resolve ) => setTimeout ( resolve , retryDelay ) ) ;
301- } else {
302- logger . error (
303- `All verification retries failed. Please verify manually later.`
304- ) ;
305- }
479+ if ( success ) {
480+ logger . success ( `Verification succeeded on attempt #${ attempt } .` ) ;
481+ return ; // Verification succeeded
482+ }
483+ } catch ( error : any ) {
484+ if ( error . message === 'ALREADY_VERIFIED' ) {
485+ logger . success ( `Contract already verified on attempt #${ attempt } .` ) ;
486+ return ; // Already verified - success
487+ } else {
488+ logger . warn ( `Unexpected error during verification: ${ error . message } ` ) ;
306489 }
307490 }
491+
492+ // If we get here, verification failed and we should retry
493+ if ( attempt < VERIFICATION_CONFIG . MAX_RETRIES ) {
494+ const delaySeconds = VERIFICATION_CONFIG . RETRY_DELAY_MS / 1000 ;
495+ logger . info ( `Waiting ${ delaySeconds } seconds before retrying...` ) ;
496+ await delay ( VERIFICATION_CONFIG . RETRY_DELAY_MS ) ;
497+ }
308498 }
499+
500+ logger . error ( `Verification process failed: Please verify manually later.` ) ;
309501}
0 commit comments