@0xsequence/catapult 1.3.17 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.md +276 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +1 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/index.d.ts +1 -0
  6. package/dist/commands/index.d.ts.map +1 -1
  7. package/dist/commands/index.js +1 -0
  8. package/dist/commands/index.js.map +1 -1
  9. package/dist/commands/list.d.ts.map +1 -1
  10. package/dist/commands/list.js +12 -0
  11. package/dist/commands/list.js.map +1 -1
  12. package/dist/commands/provenance.d.ts +3 -0
  13. package/dist/commands/provenance.d.ts.map +1 -0
  14. package/dist/commands/provenance.js +138 -0
  15. package/dist/commands/provenance.js.map +1 -0
  16. package/dist/lib/__tests__/deployer.spec.js +118 -1
  17. package/dist/lib/__tests__/deployer.spec.js.map +1 -1
  18. package/dist/lib/__tests__/network-loader.spec.js.map +1 -1
  19. package/dist/lib/__tests__/provenance.spec.d.ts +2 -0
  20. package/dist/lib/__tests__/provenance.spec.d.ts.map +1 -0
  21. package/dist/lib/__tests__/provenance.spec.js +205 -0
  22. package/dist/lib/__tests__/provenance.spec.js.map +1 -0
  23. package/dist/lib/contracts/__tests__/repository.spec.js +243 -0
  24. package/dist/lib/contracts/__tests__/repository.spec.js.map +1 -1
  25. package/dist/lib/contracts/repository.d.ts +9 -1
  26. package/dist/lib/contracts/repository.d.ts.map +1 -1
  27. package/dist/lib/contracts/repository.js +93 -7
  28. package/dist/lib/contracts/repository.js.map +1 -1
  29. package/dist/lib/core/__tests__/assert-action.spec.d.ts +2 -0
  30. package/dist/lib/core/__tests__/assert-action.spec.d.ts.map +1 -0
  31. package/dist/lib/core/__tests__/assert-action.spec.js +377 -0
  32. package/dist/lib/core/__tests__/assert-action.spec.js.map +1 -0
  33. package/dist/lib/core/__tests__/engine.spec.js +80 -0
  34. package/dist/lib/core/__tests__/engine.spec.js.map +1 -1
  35. package/dist/lib/core/__tests__/loader.spec.js +29 -0
  36. package/dist/lib/core/__tests__/loader.spec.js.map +1 -1
  37. package/dist/lib/core/__tests__/resolver.spec.js +405 -0
  38. package/dist/lib/core/__tests__/resolver.spec.js.map +1 -1
  39. package/dist/lib/core/__tests__/sign-actions.spec.d.ts +2 -0
  40. package/dist/lib/core/__tests__/sign-actions.spec.d.ts.map +1 -0
  41. package/dist/lib/core/__tests__/sign-actions.spec.js +128 -0
  42. package/dist/lib/core/__tests__/sign-actions.spec.js.map +1 -0
  43. package/dist/lib/core/__tests__/signer.spec.d.ts +2 -0
  44. package/dist/lib/core/__tests__/signer.spec.d.ts.map +1 -0
  45. package/dist/lib/core/__tests__/signer.spec.js +40 -0
  46. package/dist/lib/core/__tests__/signer.spec.js.map +1 -0
  47. package/dist/lib/core/context.d.ts +3 -2
  48. package/dist/lib/core/context.d.ts.map +1 -1
  49. package/dist/lib/core/context.js +3 -2
  50. package/dist/lib/core/context.js.map +1 -1
  51. package/dist/lib/core/engine.d.ts +4 -0
  52. package/dist/lib/core/engine.d.ts.map +1 -1
  53. package/dist/lib/core/engine.js +206 -0
  54. package/dist/lib/core/engine.js.map +1 -1
  55. package/dist/lib/core/loader.d.ts +1 -0
  56. package/dist/lib/core/loader.d.ts.map +1 -1
  57. package/dist/lib/core/loader.js +6 -1
  58. package/dist/lib/core/loader.js.map +1 -1
  59. package/dist/lib/core/resolver.d.ts +2 -0
  60. package/dist/lib/core/resolver.d.ts.map +1 -1
  61. package/dist/lib/core/resolver.js +89 -0
  62. package/dist/lib/core/resolver.js.map +1 -1
  63. package/dist/lib/core/signer.d.ts +7 -0
  64. package/dist/lib/core/signer.d.ts.map +1 -0
  65. package/dist/lib/core/signer.js +60 -0
  66. package/dist/lib/core/signer.js.map +1 -0
  67. package/dist/lib/deployer.d.ts.map +1 -1
  68. package/dist/lib/deployer.js +21 -4
  69. package/dist/lib/deployer.js.map +1 -1
  70. package/dist/lib/index.d.ts +1 -0
  71. package/dist/lib/index.d.ts.map +1 -1
  72. package/dist/lib/index.js +1 -0
  73. package/dist/lib/index.js.map +1 -1
  74. package/dist/lib/parsers/__tests__/job.spec.js +77 -0
  75. package/dist/lib/parsers/__tests__/job.spec.js.map +1 -1
  76. package/dist/lib/parsers/__tests__/source.spec.d.ts +2 -0
  77. package/dist/lib/parsers/__tests__/source.spec.d.ts.map +1 -0
  78. package/dist/lib/parsers/__tests__/source.spec.js +158 -0
  79. package/dist/lib/parsers/__tests__/source.spec.js.map +1 -0
  80. package/dist/lib/parsers/index.d.ts +1 -0
  81. package/dist/lib/parsers/index.d.ts.map +1 -1
  82. package/dist/lib/parsers/index.js +1 -0
  83. package/dist/lib/parsers/index.js.map +1 -1
  84. package/dist/lib/parsers/job.d.ts.map +1 -1
  85. package/dist/lib/parsers/job.js +11 -0
  86. package/dist/lib/parsers/job.js.map +1 -1
  87. package/dist/lib/parsers/source.d.ts +4 -0
  88. package/dist/lib/parsers/source.d.ts.map +1 -0
  89. package/dist/lib/parsers/source.js +107 -0
  90. package/dist/lib/parsers/source.js.map +1 -0
  91. package/dist/lib/provenance.d.ts +34 -0
  92. package/dist/lib/provenance.d.ts.map +1 -0
  93. package/dist/lib/provenance.js +694 -0
  94. package/dist/lib/provenance.js.map +1 -0
  95. package/dist/lib/types/actions.d.ts +42 -2
  96. package/dist/lib/types/actions.d.ts.map +1 -1
  97. package/dist/lib/types/actions.js +4 -0
  98. package/dist/lib/types/actions.js.map +1 -1
  99. package/dist/lib/types/contracts.d.ts +3 -0
  100. package/dist/lib/types/contracts.d.ts.map +1 -1
  101. package/dist/lib/types/definitions.d.ts +1 -0
  102. package/dist/lib/types/definitions.d.ts.map +1 -1
  103. package/dist/lib/types/index.d.ts +1 -0
  104. package/dist/lib/types/index.d.ts.map +1 -1
  105. package/dist/lib/types/index.js +1 -0
  106. package/dist/lib/types/index.js.map +1 -1
  107. package/dist/lib/types/source.d.ts +26 -0
  108. package/dist/lib/types/source.d.ts.map +1 -0
  109. package/dist/lib/types/source.js +3 -0
  110. package/dist/lib/types/source.js.map +1 -0
  111. package/dist/lib/types/values.d.ts +33 -1
  112. package/dist/lib/types/values.d.ts.map +1 -1
  113. package/package.json +4 -1
  114. package/.eslintrc.json +0 -29
  115. package/.github/workflows/ci.yml +0 -181
  116. package/CONCEPT.md +0 -24
  117. package/contracts/checked-call.huff +0 -65
  118. package/eslint.config.js +0 -48
  119. package/examples/jobs/guards-v1.yaml +0 -17
  120. package/examples/jobs/sequence-seq-0001-patch.yaml +0 -59
  121. package/examples/jobs/sequence-v1.yaml +0 -59
  122. package/examples/templates/sequence-factory-v1.yaml +0 -56
  123. package/jest.config.js +0 -25
  124. package/src/cli.ts +0 -17
  125. package/src/commands/common.ts +0 -61
  126. package/src/commands/dry.ts +0 -209
  127. package/src/commands/etherscan.ts +0 -360
  128. package/src/commands/index.ts +0 -5
  129. package/src/commands/list.ts +0 -249
  130. package/src/commands/run.ts +0 -146
  131. package/src/commands/utils.ts +0 -215
  132. package/src/index.ts +0 -67
  133. package/src/lib/__tests__/deployer-events.spec.ts +0 -338
  134. package/src/lib/__tests__/deployer.spec.ts +0 -2093
  135. package/src/lib/__tests__/network-loader.spec.ts +0 -150
  136. package/src/lib/__tests__/network-selection.spec.ts +0 -41
  137. package/src/lib/__tests__/network-utils.spec.ts +0 -230
  138. package/src/lib/artifacts/__tests__/fixtures/contract1.json +0 -19
  139. package/src/lib/artifacts/__tests__/fixtures/contract2.json +0 -19
  140. package/src/lib/artifacts/__tests__/fixtures/duplicate-name.json +0 -19
  141. package/src/lib/artifacts/__tests__/fixtures/nested/nested-contract.json +0 -18
  142. package/src/lib/artifacts/__tests__/fixtures/not-an-artifact.json +0 -8
  143. package/src/lib/artifacts/__tests__/fixtures/readme.txt +0 -2
  144. package/src/lib/contracts/__tests__/repository.spec.ts +0 -344
  145. package/src/lib/contracts/repository.ts +0 -313
  146. package/src/lib/core/__tests__/context.spec.ts +0 -37
  147. package/src/lib/core/__tests__/engine.spec.ts +0 -1889
  148. package/src/lib/core/__tests__/graph.spec.ts +0 -125
  149. package/src/lib/core/__tests__/json-integration.spec.ts +0 -425
  150. package/src/lib/core/__tests__/loader.spec.ts +0 -334
  151. package/src/lib/core/__tests__/multi-platform-verification.spec.ts +0 -406
  152. package/src/lib/core/__tests__/resolver.spec.ts +0 -2053
  153. package/src/lib/core/__tests__/static-action.spec.ts +0 -172
  154. package/src/lib/core/context.ts +0 -127
  155. package/src/lib/core/engine.ts +0 -1782
  156. package/src/lib/core/graph.ts +0 -252
  157. package/src/lib/core/loader.ts +0 -247
  158. package/src/lib/core/resolver.ts +0 -757
  159. package/src/lib/deployer.ts +0 -981
  160. package/src/lib/events/__tests__/event-system.spec.ts +0 -392
  161. package/src/lib/events/cli-adapter.ts +0 -369
  162. package/src/lib/events/emitter.ts +0 -62
  163. package/src/lib/events/index.ts +0 -3
  164. package/src/lib/events/types.ts +0 -520
  165. package/src/lib/index.ts +0 -14
  166. package/src/lib/network-loader.ts +0 -90
  167. package/src/lib/network-selection.ts +0 -73
  168. package/src/lib/network-utils.ts +0 -64
  169. package/src/lib/parsers/__tests__/buildinfo.spec.ts +0 -122
  170. package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-bytecode-buildinfo.json +0 -62
  171. package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-json.txt +0 -2
  172. package/src/lib/parsers/__tests__/fixtures/buildinfo/multi-contract-buildinfo.json +0 -89
  173. package/src/lib/parsers/__tests__/fixtures/buildinfo/no-contracts-buildinfo.json +0 -17
  174. package/src/lib/parsers/__tests__/fixtures/buildinfo/simple-buildinfo.json +0 -63
  175. package/src/lib/parsers/__tests__/fixtures/buildinfo/wrong-format.json +0 -4
  176. package/src/lib/parsers/__tests__/job.spec.ts +0 -358
  177. package/src/lib/parsers/__tests__/template.spec.ts +0 -111
  178. package/src/lib/parsers/artifact/__tests__/artifact.spec.ts +0 -117
  179. package/src/lib/parsers/artifact/__tests__/fixtures/empty-bytecode.json +0 -5
  180. package/src/lib/parsers/artifact/__tests__/fixtures/hardhat-artifact.json +0 -67
  181. package/src/lib/parsers/artifact/__tests__/fixtures/invalid-bytecode.json +0 -5
  182. package/src/lib/parsers/artifact/__tests__/fixtures/invalid-json.txt +0 -11
  183. package/src/lib/parsers/artifact/__tests__/fixtures/minimal-artifact.json +0 -5
  184. package/src/lib/parsers/artifact/__tests__/fixtures/missing-abi.json +0 -4
  185. package/src/lib/parsers/artifact/__tests__/fixtures/missing-bytecode.json +0 -11
  186. package/src/lib/parsers/artifact/__tests__/fixtures/missing-contract-name.json +0 -11
  187. package/src/lib/parsers/artifact/__tests__/fixtures/simple-artifact.json +0 -40
  188. package/src/lib/parsers/artifact/__tests__/fixtures/wrong-types.json +0 -7
  189. package/src/lib/parsers/artifact/foundry-1.2.ts +0 -72
  190. package/src/lib/parsers/artifact/index.ts +0 -27
  191. package/src/lib/parsers/artifact/types.ts +0 -9
  192. package/src/lib/parsers/buildinfo.ts +0 -127
  193. package/src/lib/parsers/constants.ts +0 -56
  194. package/src/lib/parsers/index.ts +0 -5
  195. package/src/lib/parsers/job.ts +0 -148
  196. package/src/lib/parsers/template.ts +0 -135
  197. package/src/lib/std/templates/arachnid-deterministic-deployment-proxy.yaml +0 -68
  198. package/src/lib/std/templates/assured-deployment.yaml +0 -46
  199. package/src/lib/std/templates/era-evm-predeploy.yaml +0 -35
  200. package/src/lib/std/templates/erc-2470.yaml +0 -70
  201. package/src/lib/std/templates/min-balance.yaml +0 -35
  202. package/src/lib/std/templates/nano-universal-deployer.yaml +0 -61
  203. package/src/lib/std/templates/raw-erc-2470.yaml +0 -62
  204. package/src/lib/std/templates/raw-nano-universal-deployer.yaml +0 -54
  205. package/src/lib/std/templates/raw-sequence-universal-deployer-2.yaml +0 -52
  206. package/src/lib/std/templates/sequence-universal-deployer-2.yaml +0 -61
  207. package/src/lib/types/__tests__/json-request-action.spec.ts +0 -243
  208. package/src/lib/types/__tests__/read-json-value.spec.ts +0 -278
  209. package/src/lib/types/__tests__/resolve-json-value.spec.ts +0 -769
  210. package/src/lib/types/actions.ts +0 -127
  211. package/src/lib/types/artifacts.ts +0 -21
  212. package/src/lib/types/buildinfo.ts +0 -116
  213. package/src/lib/types/conditions.ts +0 -50
  214. package/src/lib/types/contracts.ts +0 -23
  215. package/src/lib/types/definitions.ts +0 -70
  216. package/src/lib/types/index.ts +0 -8
  217. package/src/lib/types/network.ts +0 -33
  218. package/src/lib/types/project.ts +0 -9
  219. package/src/lib/types/task.ts +0 -9
  220. package/src/lib/types/values.ts +0 -150
  221. package/src/lib/utils/assertion.ts +0 -24
  222. package/src/lib/utils/validation.ts +0 -116
  223. package/src/lib/validation/contract-references.ts +0 -210
  224. package/src/lib/validation/index.ts +0 -1
  225. package/src/lib/verification/__tests__/etherscan.spec.ts +0 -710
  226. package/src/lib/verification/__tests__/sourcify.spec.ts +0 -288
  227. package/src/lib/verification/etherscan.ts +0 -547
  228. package/src/lib/verification/sourcify.ts +0 -248
  229. package/test_validation/artifacts/TestContract.json +0 -9
  230. package/test_validation/jobs/test-missing.yaml +0 -16
  231. package/test_validation/networks.yaml +0 -3
  232. package/tsconfig.json +0 -36
@@ -1,547 +0,0 @@
1
- import { Network } from '../types/network'
2
- import { BuildInfo } from '../types/buildinfo'
3
- import { Contract } from '../types/contracts'
4
- import { DeploymentEventEmitter } from '../events/emitter'
5
-
6
- // Generic verification platform interface
7
- export interface VerificationPlatform {
8
- /**
9
- * The name of this verification platform (e.g., 'etherscan_v2', 'sourcify')
10
- */
11
- readonly name: string
12
-
13
- /**
14
- * Check if this platform supports verification on the given network
15
- */
16
- supportsNetwork(network: Network): boolean
17
-
18
- /**
19
- * Check if the required configuration (API keys, etc.) is available
20
- */
21
- isConfigured(): boolean
22
-
23
- /**
24
- * Get a description of what configuration is missing (for error messages)
25
- */
26
- getConfigurationRequirements(): string
27
-
28
- /**
29
- * Check if a contract is already verified on this platform
30
- */
31
- isContractAlreadyVerified(address: string, network: Network): Promise<boolean>
32
-
33
- /**
34
- * Submit a contract for verification
35
- */
36
- verifyContract(request: VerificationRequest): Promise<VerificationResult>
37
- }
38
-
39
- export interface VerificationRequest {
40
- contract: Contract // Contract object
41
- buildInfo: BuildInfo
42
- address: string
43
- constructorArguments?: string // Hex encoded constructor args
44
- network: Network
45
- maxRetries?: number // Number of retries for "contract not found" errors
46
- retryDelayMs?: number // Delay between retries in milliseconds
47
- }
48
-
49
- export interface VerificationResult {
50
- success: boolean
51
- guid?: string
52
- message: string
53
- isAlreadyVerified?: boolean // Indicates if verification was skipped because already verified
54
- }
55
-
56
- export interface VerificationStatus {
57
- isComplete: boolean
58
- isSuccess: boolean
59
- message: string
60
- }
61
-
62
- /**
63
- * Checks if an error message indicates that the contract code was not found
64
- */
65
- function isContractNotFoundError(message: string): boolean {
66
- return message.toLowerCase().includes('unable to locate contractcode') ||
67
- message.toLowerCase().includes('contract source code not verified') ||
68
- message.toLowerCase().includes('contract not found')
69
- }
70
-
71
- /**
72
- * Checks if an error message indicates that the contract is already verified
73
- */
74
- function isAlreadyVerifiedError(message: string): boolean {
75
- return message.toLowerCase().includes('already verified') ||
76
- message.toLowerCase().includes('contract source code already verified')
77
- }
78
-
79
- /**
80
- * Extracts the full compiler version with commit hash from contract metadata
81
- */
82
- function getFullCompilerVersion(buildInfo: BuildInfo): string {
83
- // Try to extract from any contract's metadata
84
- for (const [sourceName, contracts] of Object.entries(buildInfo.output.contracts)) {
85
- for (const [contractName, contract] of Object.entries(contracts)) {
86
- if (contract.metadata) {
87
- try {
88
- const metadata = JSON.parse(contract.metadata)
89
- if (metadata.compiler?.version) {
90
- return metadata.compiler.version
91
- }
92
- } catch (error) {
93
- // Continue to next contract if metadata parsing fails
94
- continue
95
- }
96
- }
97
- }
98
- }
99
-
100
- // Fallback to the basic version if metadata extraction fails
101
- // Use solcLongVersion if available, otherwise fallback to solcVersion
102
- return buildInfo.solcLongVersion || buildInfo.solcVersion
103
- }
104
-
105
- /**
106
- * Gets the Etherscan v2 API URL (unified endpoint for all chains)
107
- */
108
- function getEtherscanApiUrl(chainId: number): string {
109
- return `https://api.etherscan.io/v2/api?chainid=${chainId}`
110
- }
111
-
112
- /**
113
- * Checks if a contract is already verified on Etherscan using the v2 API
114
- */
115
- export async function isContractAlreadyVerified(
116
- address: string,
117
- apiKey: string,
118
- network: Network
119
- ): Promise<boolean> {
120
- const apiUrl = getEtherscanApiUrl(network.chainId)
121
-
122
- const params = new URLSearchParams({
123
- module: 'contract',
124
- action: 'getsourcecode',
125
- address: address,
126
- apikey: apiKey
127
- })
128
-
129
- try {
130
- const response = await fetch(`${apiUrl}&${params.toString()}`, {
131
- method: 'GET',
132
- signal: AbortSignal.timeout(15000), // 15 second timeout
133
- })
134
-
135
- if (!response.ok) {
136
- throw new Error(`HTTP ${response.status}: ${response.statusText}`)
137
- }
138
-
139
- const data = await response.json() as { status: string; result: any }
140
-
141
- // If status is "1" and result contains source code, the contract is verified
142
- if (data.status === '1' && Array.isArray(data.result) && data.result.length > 0) {
143
- const sourceCode = data.result[0]?.SourceCode
144
- return !!(sourceCode && sourceCode.length > 0)
145
- }
146
-
147
- return false
148
- } catch (error) {
149
- // If we can't determine the verification status, assume it's not verified
150
- // and let the verification attempt proceed (which will handle any errors)
151
- console.warn(`Failed to check verification status for ${address}: ${error instanceof Error ? error.message : String(error)}`)
152
- return false
153
- }
154
- }
155
-
156
- /**
157
- * Internal function to perform a single verification attempt
158
- */
159
- async function submitVerificationAttempt(request: VerificationRequest, apiKey: string): Promise<VerificationResult> {
160
- const apiUrl = getEtherscanApiUrl(request.network.chainId)
161
-
162
- // Extract the fully qualified contract name from the contract object
163
- const contractName = `${request.contract.sourceName}:${request.contract.contractName}`
164
-
165
- // Clean the input to only include standard Solidity compiler input format keys
166
- const cleanedInput = {
167
- language: request.buildInfo.input.language,
168
- sources: request.buildInfo.input.sources,
169
- settings: {
170
- // Only include standard settings that Etherscan supports
171
- ...(request.buildInfo.input.settings.optimizer && { optimizer: request.buildInfo.input.settings.optimizer }),
172
- ...(request.buildInfo.input.settings.evmVersion && { evmVersion: request.buildInfo.input.settings.evmVersion }),
173
- ...(request.buildInfo.input.settings.remappings && { remappings: request.buildInfo.input.settings.remappings }),
174
- ...(request.buildInfo.input.settings.viaIR && { viaIR: request.buildInfo.input.settings.viaIR }),
175
- ...(request.buildInfo.input.settings.libraries && { libraries: request.buildInfo.input.settings.libraries }),
176
- outputSelection: request.buildInfo.input.settings.outputSelection,
177
- ...(request.buildInfo.input.settings.metadata && { metadata: request.buildInfo.input.settings.metadata })
178
- }
179
- }
180
-
181
- const sourceCode = JSON.stringify(cleanedInput)
182
-
183
- // Extract the full compiler version with commit hash from contract metadata
184
- const fullCompilerVersion = getFullCompilerVersion(request.buildInfo)
185
-
186
- const formData = new URLSearchParams({
187
- module: 'contract',
188
- action: 'verifysourcecode',
189
- codeformat: 'solidity-standard-json-input',
190
- sourceCode,
191
- contractaddress: request.address,
192
- contractname: contractName,
193
- compilerversion: `v${fullCompilerVersion}`,
194
- apikey: apiKey,
195
- })
196
-
197
- if (request.constructorArguments) {
198
- // Remove 0x prefix if present
199
- const constructorArgs = request.constructorArguments.startsWith('0x')
200
- ? request.constructorArguments.slice(2)
201
- : request.constructorArguments
202
- formData.append('constructorArguements', constructorArgs) // Note: Etherscan API has this typo
203
- }
204
-
205
- const response = await fetch(apiUrl, {
206
- method: 'POST',
207
- headers: {
208
- 'Content-Type': 'application/x-www-form-urlencoded'
209
- },
210
- body: formData.toString(),
211
- signal: AbortSignal.timeout(30000), // 30 second timeout
212
- })
213
-
214
- if (!response.ok) {
215
- throw new Error(`HTTP ${response.status}: ${response.statusText}`)
216
- }
217
-
218
- const data = await response.json() as { status: string; result: string }
219
-
220
- if (data.status === '1') {
221
- return {
222
- success: true,
223
- guid: data.result,
224
- message: 'Verification submitted successfully'
225
- }
226
- } else {
227
- const errorMessage = data.result || 'Unknown error occurred'
228
-
229
- // Treat "Already Verified" as a success case
230
- if (isAlreadyVerifiedError(errorMessage)) {
231
- return {
232
- success: true,
233
- message: 'Contract is already verified'
234
- }
235
- }
236
-
237
- return {
238
- success: false,
239
- message: errorMessage
240
- }
241
- }
242
- }
243
-
244
- /**
245
- * Submits a contract for verification to Etherscan using the v2 API with retry logic
246
- */
247
- export async function submitVerification(
248
- request: VerificationRequest,
249
- apiKey: string,
250
- eventEmitter?: DeploymentEventEmitter
251
- ): Promise<VerificationResult> {
252
- const maxRetries = request.maxRetries ?? 3
253
- const retryDelayMs = request.retryDelayMs ?? 5000 // 5 seconds default
254
-
255
- let lastError: string = ''
256
-
257
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
258
- try {
259
- const result = await submitVerificationAttempt(request, apiKey)
260
-
261
- // If successful or if it's not a "contract not found" error, return immediately
262
- if (result.success || !isContractNotFoundError(result.message)) {
263
- return result
264
- }
265
-
266
- // Store the error message for potential retry
267
- lastError = result.message
268
-
269
- // If this is the last attempt, don't wait
270
- if (attempt === maxRetries) {
271
- break
272
- }
273
-
274
- // Emit retry event if emitter is available
275
- if (eventEmitter) {
276
- eventEmitter.emitEvent({
277
- type: 'verification_retry',
278
- level: 'info',
279
- data: {
280
- platform: 'etherscan_v2',
281
- attempt: attempt + 1,
282
- maxRetries: maxRetries + 1,
283
- error: lastError
284
- }
285
- })
286
- }
287
-
288
- // Wait before retrying
289
- await new Promise(resolve => setTimeout(resolve, retryDelayMs))
290
-
291
- } catch (error) {
292
- const errorMessage = error instanceof Error ? error.message : String(error)
293
-
294
- // If it's a "contract not found" type error and we have retries left, continue
295
- if (isContractNotFoundError(errorMessage) && attempt < maxRetries) {
296
- lastError = errorMessage
297
- await new Promise(resolve => setTimeout(resolve, retryDelayMs))
298
- continue
299
- }
300
-
301
- // For other errors or if we're out of retries, return the error
302
- return {
303
- success: false,
304
- message: `API request failed: ${errorMessage}`
305
- }
306
- }
307
- }
308
-
309
- // All retries exhausted
310
- return {
311
- success: false,
312
- message: `Verification failed after ${maxRetries + 1} attempts. Last error: ${lastError}`
313
- }
314
- }
315
-
316
- /**
317
- * Checks the verification status of a submitted contract
318
- */
319
- export async function checkVerificationStatus(
320
- guid: string,
321
- apiKey: string,
322
- network: Network
323
- ): Promise<VerificationStatus> {
324
- const apiUrl = getEtherscanApiUrl(network.chainId)
325
-
326
- const params = new URLSearchParams({
327
- module: 'contract',
328
- action: 'checkverifystatus',
329
- guid,
330
- apikey: apiKey
331
- })
332
-
333
- try {
334
- const response = await fetch(`${apiUrl}&${params.toString()}`, {
335
- method: 'GET',
336
- signal: AbortSignal.timeout(15000), // 15 second timeout
337
- })
338
-
339
- if (!response.ok) {
340
- throw new Error(`HTTP ${response.status}: ${response.statusText}`)
341
- }
342
-
343
- const data = await response.json() as { status: string; result: string }
344
-
345
- if (data.status === '1') {
346
- return {
347
- isComplete: true,
348
- isSuccess: true,
349
- message: 'Verification successful'
350
- }
351
- } else if (data.status === '0') {
352
- const result = data.result || ''
353
- if (result.includes('Pending')) {
354
- return {
355
- isComplete: false,
356
- isSuccess: false,
357
- message: 'Verification pending'
358
- }
359
- } else if (isAlreadyVerifiedError(result)) {
360
- // Treat "Already Verified" as success during status check
361
- return {
362
- isComplete: true,
363
- isSuccess: true,
364
- message: 'Contract is already verified'
365
- }
366
- } else {
367
- return {
368
- isComplete: true,
369
- isSuccess: false,
370
- message: result || 'Verification failed'
371
- }
372
- }
373
- } else {
374
- return {
375
- isComplete: true,
376
- isSuccess: false,
377
- message: data.result || 'Unknown verification status'
378
- }
379
- }
380
- } catch (error) {
381
- throw new Error(`Failed to check verification status: ${error instanceof Error ? error.message : String(error)}`)
382
- }
383
- }
384
-
385
- /**
386
- * Polls verification status until completion or timeout
387
- */
388
- export async function waitForVerification(
389
- guid: string,
390
- apiKey: string,
391
- network: Network,
392
- timeoutMs: number = 300000 // 5 minute default timeout
393
- ): Promise<VerificationStatus> {
394
- const startTime = Date.now()
395
- const pollInterval = 5000 // Poll every 5 seconds
396
-
397
- while (Date.now() - startTime < timeoutMs) {
398
- const status = await checkVerificationStatus(guid, apiKey, network)
399
-
400
- if (status.isComplete) {
401
- return status
402
- }
403
-
404
- // Wait before polling again
405
- await new Promise(resolve => setTimeout(resolve, pollInterval))
406
- }
407
-
408
- throw new Error(`Verification timed out after ${timeoutMs / 1000} seconds`)
409
- }
410
-
411
- /**
412
- * Etherscan verification platform implementation
413
- */
414
- export class EtherscanVerificationPlatform implements VerificationPlatform {
415
- readonly name = 'etherscan_v2'
416
- private apiKey?: string
417
-
418
- constructor(apiKey?: string) {
419
- this.apiKey = apiKey
420
- }
421
-
422
- supportsNetwork(network: Network): boolean {
423
- // Only support networks that explicitly include this platform in their supports list
424
- return Array.isArray(network.supports) && network.supports.includes(this.name)
425
- }
426
-
427
- isConfigured(): boolean {
428
- return !!this.apiKey
429
- }
430
-
431
- getConfigurationRequirements(): string {
432
- return 'Etherscan API key is required. Set --etherscan-api-key or ETHERSCAN_API_KEY environment variable.'
433
- }
434
-
435
- async isContractAlreadyVerified(address: string, network: Network): Promise<boolean> {
436
- if (!this.apiKey) {
437
- throw new Error('Etherscan API key not configured')
438
- }
439
- return isContractAlreadyVerified(address, this.apiKey, network)
440
- }
441
-
442
- async verifyContract(request: VerificationRequest): Promise<VerificationResult> {
443
- if (!this.apiKey) {
444
- throw new Error('Etherscan API key not configured')
445
- }
446
-
447
- // Check if already verified first
448
- const alreadyVerified = await this.isContractAlreadyVerified(request.address, request.network)
449
- if (alreadyVerified) {
450
- return {
451
- success: true,
452
- message: 'Contract was already verified (checked before attempting verification)',
453
- isAlreadyVerified: true
454
- }
455
- }
456
-
457
- // Submit verification with API key
458
- const verificationResult = await submitVerification(request, this.apiKey)
459
-
460
- if (!verificationResult.success) {
461
- return verificationResult
462
- }
463
-
464
- // If we have a guid, wait for verification to complete
465
- if (verificationResult.guid) {
466
- const verificationStatus = await waitForVerification(verificationResult.guid, this.apiKey, request.network)
467
-
468
- if (!verificationStatus.isSuccess) {
469
- return {
470
- success: false,
471
- message: `Verification failed: ${verificationStatus.message}`
472
- }
473
- }
474
-
475
- return {
476
- success: true,
477
- guid: verificationResult.guid,
478
- message: 'Contract verified successfully'
479
- }
480
- } else {
481
- // Contract was already verified during submission
482
- return {
483
- success: true,
484
- message: 'Contract was already verified',
485
- isAlreadyVerified: true
486
- }
487
- }
488
- }
489
- }
490
-
491
- /**
492
- * Registry for verification platforms
493
- */
494
- export class VerificationPlatformRegistry {
495
- private platforms = new Map<string, VerificationPlatform>()
496
-
497
- /**
498
- * Register a verification platform
499
- */
500
- register(platform: VerificationPlatform): void {
501
- this.platforms.set(platform.name, platform)
502
- }
503
-
504
- /**
505
- * Get a verification platform by name
506
- */
507
- get(platformName: string): VerificationPlatform | undefined {
508
- return this.platforms.get(platformName)
509
- }
510
-
511
- /**
512
- * Get all available platforms
513
- */
514
- getAll(): VerificationPlatform[] {
515
- return Array.from(this.platforms.values())
516
- }
517
-
518
- /**
519
- * Get all platforms that support the given network
520
- */
521
- getSupportedPlatforms(network: Network): VerificationPlatform[] {
522
- return this.getAll().filter(platform => platform.supportsNetwork(network))
523
- }
524
-
525
- /**
526
- * Get all configured platforms that support the given network
527
- */
528
- getConfiguredPlatforms(network: Network): VerificationPlatform[] {
529
- return this.getSupportedPlatforms(network).filter(platform => platform.isConfigured())
530
- }
531
- }
532
-
533
- /**
534
- * Default verification platform registry instance
535
- */
536
- export function createDefaultVerificationRegistry(etherscanApiKey?: string): VerificationPlatformRegistry {
537
- const registry = new VerificationPlatformRegistry()
538
-
539
- // Register Etherscan platform
540
- registry.register(new EtherscanVerificationPlatform(etherscanApiKey))
541
-
542
- // Register Sourcify platform
543
- const { SourcifyVerificationPlatform } = require('./sourcify')
544
- registry.register(new SourcifyVerificationPlatform())
545
-
546
- return registry
547
- }