@0xsequence/catapult 1.1.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 (393) hide show
  1. package/.eslintrc.json +29 -0
  2. package/.github/workflows/ci.yml +181 -0
  3. package/CONCEPT.md +24 -0
  4. package/README.md +772 -0
  5. package/contracts/checked-call.huff +65 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +16 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/commands/common.d.ts +11 -0
  11. package/dist/commands/common.d.ts.map +1 -0
  12. package/dist/commands/common.js +73 -0
  13. package/dist/commands/common.js.map +1 -0
  14. package/dist/commands/dry.d.ts +3 -0
  15. package/dist/commands/dry.d.ts.map +1 -0
  16. package/dist/commands/dry.js +171 -0
  17. package/dist/commands/dry.js.map +1 -0
  18. package/dist/commands/etherscan.d.ts +3 -0
  19. package/dist/commands/etherscan.d.ts.map +1 -0
  20. package/dist/commands/etherscan.js +323 -0
  21. package/dist/commands/etherscan.js.map +1 -0
  22. package/dist/commands/index.d.ts +6 -0
  23. package/dist/commands/index.d.ts.map +1 -0
  24. package/dist/commands/index.js +22 -0
  25. package/dist/commands/index.js.map +1 -0
  26. package/dist/commands/list.d.ts +3 -0
  27. package/dist/commands/list.d.ts.map +1 -0
  28. package/dist/commands/list.js +259 -0
  29. package/dist/commands/list.js.map +1 -0
  30. package/dist/commands/run.d.ts +3 -0
  31. package/dist/commands/run.d.ts.map +1 -0
  32. package/dist/commands/run.js +96 -0
  33. package/dist/commands/run.js.map +1 -0
  34. package/dist/commands/utils.d.ts +3 -0
  35. package/dist/commands/utils.d.ts.map +1 -0
  36. package/dist/commands/utils.js +46 -0
  37. package/dist/commands/utils.js.map +1 -0
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +58 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/lib/__tests__/deployer-events.spec.d.ts +2 -0
  43. package/dist/lib/__tests__/deployer-events.spec.d.ts.map +1 -0
  44. package/dist/lib/__tests__/deployer-events.spec.js +260 -0
  45. package/dist/lib/__tests__/deployer-events.spec.js.map +1 -0
  46. package/dist/lib/__tests__/deployer.spec.d.ts +2 -0
  47. package/dist/lib/__tests__/deployer.spec.d.ts.map +1 -0
  48. package/dist/lib/__tests__/deployer.spec.js +884 -0
  49. package/dist/lib/__tests__/deployer.spec.js.map +1 -0
  50. package/dist/lib/__tests__/network-utils.spec.d.ts +2 -0
  51. package/dist/lib/__tests__/network-utils.spec.d.ts.map +1 -0
  52. package/dist/lib/__tests__/network-utils.spec.js +140 -0
  53. package/dist/lib/__tests__/network-utils.spec.js.map +1 -0
  54. package/dist/lib/contracts/__tests__/repository.spec.d.ts +2 -0
  55. package/dist/lib/contracts/__tests__/repository.spec.d.ts.map +1 -0
  56. package/dist/lib/contracts/__tests__/repository.spec.js +321 -0
  57. package/dist/lib/contracts/__tests__/repository.spec.js.map +1 -0
  58. package/dist/lib/contracts/repository.d.ts +27 -0
  59. package/dist/lib/contracts/repository.d.ts.map +1 -0
  60. package/dist/lib/contracts/repository.js +241 -0
  61. package/dist/lib/contracts/repository.js.map +1 -0
  62. package/dist/lib/core/__tests__/engine.spec.d.ts +2 -0
  63. package/dist/lib/core/__tests__/engine.spec.d.ts.map +1 -0
  64. package/dist/lib/core/__tests__/engine.spec.js +1212 -0
  65. package/dist/lib/core/__tests__/engine.spec.js.map +1 -0
  66. package/dist/lib/core/__tests__/graph.spec.d.ts +2 -0
  67. package/dist/lib/core/__tests__/graph.spec.d.ts.map +1 -0
  68. package/dist/lib/core/__tests__/graph.spec.js +116 -0
  69. package/dist/lib/core/__tests__/graph.spec.js.map +1 -0
  70. package/dist/lib/core/__tests__/json-integration.spec.d.ts +2 -0
  71. package/dist/lib/core/__tests__/json-integration.spec.d.ts.map +1 -0
  72. package/dist/lib/core/__tests__/json-integration.spec.js +300 -0
  73. package/dist/lib/core/__tests__/json-integration.spec.js.map +1 -0
  74. package/dist/lib/core/__tests__/loader.spec.d.ts +2 -0
  75. package/dist/lib/core/__tests__/loader.spec.d.ts.map +1 -0
  76. package/dist/lib/core/__tests__/loader.spec.js +288 -0
  77. package/dist/lib/core/__tests__/loader.spec.js.map +1 -0
  78. package/dist/lib/core/__tests__/multi-platform-verification.spec.d.ts +2 -0
  79. package/dist/lib/core/__tests__/multi-platform-verification.spec.d.ts.map +1 -0
  80. package/dist/lib/core/__tests__/multi-platform-verification.spec.js +342 -0
  81. package/dist/lib/core/__tests__/multi-platform-verification.spec.js.map +1 -0
  82. package/dist/lib/core/__tests__/resolver.spec.d.ts +2 -0
  83. package/dist/lib/core/__tests__/resolver.spec.d.ts.map +1 -0
  84. package/dist/lib/core/__tests__/resolver.spec.js +1367 -0
  85. package/dist/lib/core/__tests__/resolver.spec.js.map +1 -0
  86. package/dist/lib/core/__tests__/static-action.spec.d.ts +2 -0
  87. package/dist/lib/core/__tests__/static-action.spec.d.ts.map +1 -0
  88. package/dist/lib/core/__tests__/static-action.spec.js +136 -0
  89. package/dist/lib/core/__tests__/static-action.spec.js.map +1 -0
  90. package/dist/lib/core/context.d.ts +29 -0
  91. package/dist/lib/core/context.d.ts.map +1 -0
  92. package/dist/lib/core/context.js +88 -0
  93. package/dist/lib/core/context.js.map +1 -0
  94. package/dist/lib/core/engine.d.ts +25 -0
  95. package/dist/lib/core/engine.d.ts.map +1 -0
  96. package/dist/lib/core/engine.js +1191 -0
  97. package/dist/lib/core/engine.js.map +1 -0
  98. package/dist/lib/core/graph.d.ts +18 -0
  99. package/dist/lib/core/graph.d.ts.map +1 -0
  100. package/dist/lib/core/graph.js +158 -0
  101. package/dist/lib/core/graph.js.map +1 -0
  102. package/dist/lib/core/loader.d.ts +25 -0
  103. package/dist/lib/core/loader.d.ts.map +1 -0
  104. package/dist/lib/core/loader.js +248 -0
  105. package/dist/lib/core/loader.js.map +1 -0
  106. package/dist/lib/core/resolver.d.ts +20 -0
  107. package/dist/lib/core/resolver.d.ts.map +1 -0
  108. package/dist/lib/core/resolver.js +307 -0
  109. package/dist/lib/core/resolver.js.map +1 -0
  110. package/dist/lib/deployer.d.ts +39 -0
  111. package/dist/lib/deployer.d.ts.map +1 -0
  112. package/dist/lib/deployer.js +533 -0
  113. package/dist/lib/deployer.js.map +1 -0
  114. package/dist/lib/events/__tests__/event-system.spec.d.ts +2 -0
  115. package/dist/lib/events/__tests__/event-system.spec.d.ts.map +1 -0
  116. package/dist/lib/events/__tests__/event-system.spec.js +256 -0
  117. package/dist/lib/events/__tests__/event-system.spec.js.map +1 -0
  118. package/dist/lib/events/cli-adapter.d.ts +13 -0
  119. package/dist/lib/events/cli-adapter.d.ts.map +1 -0
  120. package/dist/lib/events/cli-adapter.js +244 -0
  121. package/dist/lib/events/cli-adapter.js.map +1 -0
  122. package/dist/lib/events/emitter.d.ts +11 -0
  123. package/dist/lib/events/emitter.d.ts.map +1 -0
  124. package/dist/lib/events/emitter.js +29 -0
  125. package/dist/lib/events/emitter.js.map +1 -0
  126. package/dist/lib/events/index.d.ts +4 -0
  127. package/dist/lib/events/index.d.ts.map +1 -0
  128. package/dist/lib/events/index.js +20 -0
  129. package/dist/lib/events/index.js.map +1 -0
  130. package/dist/lib/events/types.d.ts +368 -0
  131. package/dist/lib/events/types.d.ts.map +1 -0
  132. package/dist/lib/events/types.js +3 -0
  133. package/dist/lib/events/types.js.map +1 -0
  134. package/dist/lib/index.d.ts +5 -0
  135. package/dist/lib/index.d.ts.map +1 -0
  136. package/dist/lib/index.js +44 -0
  137. package/dist/lib/index.js.map +1 -0
  138. package/dist/lib/network-loader.d.ts +3 -0
  139. package/dist/lib/network-loader.d.ts.map +1 -0
  140. package/dist/lib/network-loader.js +80 -0
  141. package/dist/lib/network-loader.js.map +1 -0
  142. package/dist/lib/network-match.d.ts +3 -0
  143. package/dist/lib/network-match.d.ts.map +1 -0
  144. package/dist/lib/network-match.js +62 -0
  145. package/dist/lib/network-match.js.map +1 -0
  146. package/dist/lib/network-utils.d.ts +4 -0
  147. package/dist/lib/network-utils.d.ts.map +1 -0
  148. package/dist/lib/network-utils.js +39 -0
  149. package/dist/lib/network-utils.js.map +1 -0
  150. package/dist/lib/parsers/__tests__/buildinfo.spec.d.ts +2 -0
  151. package/dist/lib/parsers/__tests__/buildinfo.spec.d.ts.map +1 -0
  152. package/dist/lib/parsers/__tests__/buildinfo.spec.js +132 -0
  153. package/dist/lib/parsers/__tests__/buildinfo.spec.js.map +1 -0
  154. package/dist/lib/parsers/__tests__/job.spec.d.ts +2 -0
  155. package/dist/lib/parsers/__tests__/job.spec.d.ts.map +1 -0
  156. package/dist/lib/parsers/__tests__/job.spec.js +318 -0
  157. package/dist/lib/parsers/__tests__/job.spec.js.map +1 -0
  158. package/dist/lib/parsers/__tests__/template.spec.d.ts +2 -0
  159. package/dist/lib/parsers/__tests__/template.spec.d.ts.map +1 -0
  160. package/dist/lib/parsers/__tests__/template.spec.js +126 -0
  161. package/dist/lib/parsers/__tests__/template.spec.js.map +1 -0
  162. package/dist/lib/parsers/artifact/__tests__/artifact.spec.d.ts +2 -0
  163. package/dist/lib/parsers/artifact/__tests__/artifact.spec.d.ts.map +1 -0
  164. package/dist/lib/parsers/artifact/__tests__/artifact.spec.js +128 -0
  165. package/dist/lib/parsers/artifact/__tests__/artifact.spec.js.map +1 -0
  166. package/dist/lib/parsers/artifact/foundry-1.2.d.ts +3 -0
  167. package/dist/lib/parsers/artifact/foundry-1.2.d.ts.map +1 -0
  168. package/dist/lib/parsers/artifact/foundry-1.2.js +82 -0
  169. package/dist/lib/parsers/artifact/foundry-1.2.js.map +1 -0
  170. package/dist/lib/parsers/artifact/index.d.ts +3 -0
  171. package/dist/lib/parsers/artifact/index.d.ts.map +1 -0
  172. package/dist/lib/parsers/artifact/index.js +17 -0
  173. package/dist/lib/parsers/artifact/index.js.map +1 -0
  174. package/dist/lib/parsers/artifact/types.d.ts +3 -0
  175. package/dist/lib/parsers/artifact/types.d.ts.map +1 -0
  176. package/dist/lib/parsers/artifact/types.js +3 -0
  177. package/dist/lib/parsers/artifact/types.js.map +1 -0
  178. package/dist/lib/parsers/buildinfo.d.ts +5 -0
  179. package/dist/lib/parsers/buildinfo.d.ts.map +1 -0
  180. package/dist/lib/parsers/buildinfo.js +85 -0
  181. package/dist/lib/parsers/buildinfo.js.map +1 -0
  182. package/dist/lib/parsers/constants.d.ts +4 -0
  183. package/dist/lib/parsers/constants.d.ts.map +1 -0
  184. package/dist/lib/parsers/constants.js +45 -0
  185. package/dist/lib/parsers/constants.js.map +1 -0
  186. package/dist/lib/parsers/index.d.ts +5 -0
  187. package/dist/lib/parsers/index.d.ts.map +1 -0
  188. package/dist/lib/parsers/index.js +21 -0
  189. package/dist/lib/parsers/index.js.map +1 -0
  190. package/dist/lib/parsers/job.d.ts +3 -0
  191. package/dist/lib/parsers/job.d.ts.map +1 -0
  192. package/dist/lib/parsers/job.js +74 -0
  193. package/dist/lib/parsers/job.js.map +1 -0
  194. package/dist/lib/parsers/template.d.ts +3 -0
  195. package/dist/lib/parsers/template.d.ts.map +1 -0
  196. package/dist/lib/parsers/template.js +91 -0
  197. package/dist/lib/parsers/template.js.map +1 -0
  198. package/dist/lib/std/templates/assured-deployment.yaml +45 -0
  199. package/dist/lib/std/templates/erc-2470.yaml +67 -0
  200. package/dist/lib/std/templates/min-balance.yaml +32 -0
  201. package/dist/lib/std/templates/nano-universal-deployer.yaml +59 -0
  202. package/dist/lib/std/templates/raw-erc-2470.yaml +59 -0
  203. package/dist/lib/std/templates/raw-nano-universal-deployer.yaml +51 -0
  204. package/dist/lib/std/templates/raw-sequence-universal-deployer-2.yaml +48 -0
  205. package/dist/lib/std/templates/sequence-universal-deployer-2.yaml +57 -0
  206. package/dist/lib/types/__tests__/json-request-action.spec.d.ts +2 -0
  207. package/dist/lib/types/__tests__/json-request-action.spec.d.ts.map +1 -0
  208. package/dist/lib/types/__tests__/json-request-action.spec.js +219 -0
  209. package/dist/lib/types/__tests__/json-request-action.spec.js.map +1 -0
  210. package/dist/lib/types/__tests__/read-json-value.spec.d.ts +2 -0
  211. package/dist/lib/types/__tests__/read-json-value.spec.d.ts.map +1 -0
  212. package/dist/lib/types/__tests__/read-json-value.spec.js +233 -0
  213. package/dist/lib/types/__tests__/read-json-value.spec.js.map +1 -0
  214. package/dist/lib/types/actions.d.ts +74 -0
  215. package/dist/lib/types/actions.d.ts.map +1 -0
  216. package/dist/lib/types/actions.js +18 -0
  217. package/dist/lib/types/actions.js.map +1 -0
  218. package/dist/lib/types/artifacts.d.ts +15 -0
  219. package/dist/lib/types/artifacts.d.ts.map +1 -0
  220. package/dist/lib/types/artifacts.js +3 -0
  221. package/dist/lib/types/artifacts.js.map +1 -0
  222. package/dist/lib/types/buildinfo.d.ts +112 -0
  223. package/dist/lib/types/buildinfo.d.ts.map +1 -0
  224. package/dist/lib/types/buildinfo.js +3 -0
  225. package/dist/lib/types/buildinfo.js.map +1 -0
  226. package/dist/lib/types/conditions.d.ts +17 -0
  227. package/dist/lib/types/conditions.d.ts.map +1 -0
  228. package/dist/lib/types/conditions.js +21 -0
  229. package/dist/lib/types/conditions.js.map +1 -0
  230. package/dist/lib/types/contracts.d.ts +14 -0
  231. package/dist/lib/types/contracts.d.ts.map +1 -0
  232. package/dist/lib/types/contracts.js +3 -0
  233. package/dist/lib/types/contracts.js.map +1 -0
  234. package/dist/lib/types/definitions.d.ts +51 -0
  235. package/dist/lib/types/definitions.d.ts.map +1 -0
  236. package/dist/lib/types/definitions.js +3 -0
  237. package/dist/lib/types/definitions.js.map +1 -0
  238. package/dist/lib/types/index.d.ts +9 -0
  239. package/dist/lib/types/index.d.ts.map +1 -0
  240. package/dist/lib/types/index.js +25 -0
  241. package/dist/lib/types/index.js.map +1 -0
  242. package/dist/lib/types/network.d.ts +9 -0
  243. package/dist/lib/types/network.d.ts.map +1 -0
  244. package/dist/lib/types/network.js +3 -0
  245. package/dist/lib/types/network.js.map +1 -0
  246. package/dist/lib/types/project.d.ts +5 -0
  247. package/dist/lib/types/project.d.ts.map +1 -0
  248. package/dist/lib/types/project.js +3 -0
  249. package/dist/lib/types/project.js.map +1 -0
  250. package/dist/lib/types/task.d.ts +9 -0
  251. package/dist/lib/types/task.d.ts.map +1 -0
  252. package/dist/lib/types/task.js +3 -0
  253. package/dist/lib/types/task.js.map +1 -0
  254. package/dist/lib/types/values.d.ts +78 -0
  255. package/dist/lib/types/values.d.ts.map +1 -0
  256. package/dist/lib/types/values.js +3 -0
  257. package/dist/lib/types/values.js.map +1 -0
  258. package/dist/lib/utils/validation.d.ts +5 -0
  259. package/dist/lib/utils/validation.d.ts.map +1 -0
  260. package/dist/lib/utils/validation.js +77 -0
  261. package/dist/lib/utils/validation.js.map +1 -0
  262. package/dist/lib/validation/contract-references.d.ts +12 -0
  263. package/dist/lib/validation/contract-references.d.ts.map +1 -0
  264. package/dist/lib/validation/contract-references.js +112 -0
  265. package/dist/lib/validation/contract-references.js.map +1 -0
  266. package/dist/lib/validation/index.d.ts +1 -0
  267. package/dist/lib/validation/index.d.ts.map +1 -0
  268. package/dist/lib/validation/index.js +2 -0
  269. package/dist/lib/validation/index.js.map +1 -0
  270. package/dist/lib/verification/__tests__/etherscan.spec.d.ts +2 -0
  271. package/dist/lib/verification/__tests__/etherscan.spec.d.ts.map +1 -0
  272. package/dist/lib/verification/__tests__/etherscan.spec.js +565 -0
  273. package/dist/lib/verification/__tests__/etherscan.spec.js.map +1 -0
  274. package/dist/lib/verification/__tests__/sourcify.spec.d.ts +2 -0
  275. package/dist/lib/verification/__tests__/sourcify.spec.d.ts.map +1 -0
  276. package/dist/lib/verification/__tests__/sourcify.spec.js +212 -0
  277. package/dist/lib/verification/__tests__/sourcify.spec.js.map +1 -0
  278. package/dist/lib/verification/etherscan.d.ts +56 -0
  279. package/dist/lib/verification/etherscan.d.ts.map +1 -0
  280. package/dist/lib/verification/etherscan.js +340 -0
  281. package/dist/lib/verification/etherscan.js.map +1 -0
  282. package/dist/lib/verification/sourcify.d.ts +12 -0
  283. package/dist/lib/verification/sourcify.d.ts.map +1 -0
  284. package/dist/lib/verification/sourcify.js +227 -0
  285. package/dist/lib/verification/sourcify.js.map +1 -0
  286. package/eslint.config.js +48 -0
  287. package/examples/jobs/guards-v1.yaml +17 -0
  288. package/examples/jobs/sequence-seq-0001-patch.yaml +59 -0
  289. package/examples/jobs/sequence-v1.yaml +59 -0
  290. package/examples/templates/sequence-factory-v1.yaml +56 -0
  291. package/jest.config.js +25 -0
  292. package/package.json +68 -0
  293. package/src/cli.ts +17 -0
  294. package/src/commands/common.ts +61 -0
  295. package/src/commands/dry.ts +208 -0
  296. package/src/commands/etherscan.ts +360 -0
  297. package/src/commands/index.ts +5 -0
  298. package/src/commands/list.ts +249 -0
  299. package/src/commands/run.ts +136 -0
  300. package/src/commands/utils.ts +52 -0
  301. package/src/index.ts +67 -0
  302. package/src/lib/__tests__/deployer-events.spec.ts +338 -0
  303. package/src/lib/__tests__/deployer.spec.ts +1204 -0
  304. package/src/lib/__tests__/network-utils.spec.ts +181 -0
  305. package/src/lib/artifacts/__tests__/fixtures/contract1.json +19 -0
  306. package/src/lib/artifacts/__tests__/fixtures/contract2.json +19 -0
  307. package/src/lib/artifacts/__tests__/fixtures/duplicate-name.json +19 -0
  308. package/src/lib/artifacts/__tests__/fixtures/nested/nested-contract.json +18 -0
  309. package/src/lib/artifacts/__tests__/fixtures/not-an-artifact.json +8 -0
  310. package/src/lib/artifacts/__tests__/fixtures/readme.txt +2 -0
  311. package/src/lib/contracts/__tests__/repository.spec.ts +344 -0
  312. package/src/lib/contracts/repository.ts +313 -0
  313. package/src/lib/core/__tests__/engine.spec.ts +1514 -0
  314. package/src/lib/core/__tests__/graph.spec.ts +125 -0
  315. package/src/lib/core/__tests__/json-integration.spec.ts +360 -0
  316. package/src/lib/core/__tests__/loader.spec.ts +334 -0
  317. package/src/lib/core/__tests__/multi-platform-verification.spec.ts +406 -0
  318. package/src/lib/core/__tests__/resolver.spec.ts +1693 -0
  319. package/src/lib/core/__tests__/static-action.spec.ts +172 -0
  320. package/src/lib/core/context.ts +127 -0
  321. package/src/lib/core/engine.ts +1531 -0
  322. package/src/lib/core/graph.ts +252 -0
  323. package/src/lib/core/loader.ts +263 -0
  324. package/src/lib/core/resolver.ts +498 -0
  325. package/src/lib/deployer.ts +768 -0
  326. package/src/lib/events/__tests__/event-system.spec.ts +343 -0
  327. package/src/lib/events/cli-adapter.ts +325 -0
  328. package/src/lib/events/emitter.ts +62 -0
  329. package/src/lib/events/index.ts +3 -0
  330. package/src/lib/events/types.ts +469 -0
  331. package/src/lib/index.ts +14 -0
  332. package/src/lib/network-loader.ts +59 -0
  333. package/src/lib/network-utils.ts +64 -0
  334. package/src/lib/parsers/__tests__/buildinfo.spec.ts +122 -0
  335. package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-bytecode-buildinfo.json +62 -0
  336. package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-json.txt +2 -0
  337. package/src/lib/parsers/__tests__/fixtures/buildinfo/multi-contract-buildinfo.json +89 -0
  338. package/src/lib/parsers/__tests__/fixtures/buildinfo/no-contracts-buildinfo.json +17 -0
  339. package/src/lib/parsers/__tests__/fixtures/buildinfo/simple-buildinfo.json +63 -0
  340. package/src/lib/parsers/__tests__/fixtures/buildinfo/wrong-format.json +4 -0
  341. package/src/lib/parsers/__tests__/job.spec.ts +335 -0
  342. package/src/lib/parsers/__tests__/template.spec.ts +111 -0
  343. package/src/lib/parsers/artifact/__tests__/artifact.spec.ts +117 -0
  344. package/src/lib/parsers/artifact/__tests__/fixtures/empty-bytecode.json +5 -0
  345. package/src/lib/parsers/artifact/__tests__/fixtures/hardhat-artifact.json +67 -0
  346. package/src/lib/parsers/artifact/__tests__/fixtures/invalid-bytecode.json +5 -0
  347. package/src/lib/parsers/artifact/__tests__/fixtures/invalid-json.txt +11 -0
  348. package/src/lib/parsers/artifact/__tests__/fixtures/minimal-artifact.json +5 -0
  349. package/src/lib/parsers/artifact/__tests__/fixtures/missing-abi.json +4 -0
  350. package/src/lib/parsers/artifact/__tests__/fixtures/missing-bytecode.json +11 -0
  351. package/src/lib/parsers/artifact/__tests__/fixtures/missing-contract-name.json +11 -0
  352. package/src/lib/parsers/artifact/__tests__/fixtures/simple-artifact.json +40 -0
  353. package/src/lib/parsers/artifact/__tests__/fixtures/wrong-types.json +7 -0
  354. package/src/lib/parsers/artifact/foundry-1.2.ts +72 -0
  355. package/src/lib/parsers/artifact/index.ts +27 -0
  356. package/src/lib/parsers/artifact/types.ts +9 -0
  357. package/src/lib/parsers/buildinfo.ts +127 -0
  358. package/src/lib/parsers/constants.ts +56 -0
  359. package/src/lib/parsers/index.ts +5 -0
  360. package/src/lib/parsers/job.ts +101 -0
  361. package/src/lib/parsers/template.ts +131 -0
  362. package/src/lib/std/templates/assured-deployment.yaml +45 -0
  363. package/src/lib/std/templates/erc-2470.yaml +67 -0
  364. package/src/lib/std/templates/min-balance.yaml +32 -0
  365. package/src/lib/std/templates/nano-universal-deployer.yaml +59 -0
  366. package/src/lib/std/templates/raw-erc-2470.yaml +59 -0
  367. package/src/lib/std/templates/raw-nano-universal-deployer.yaml +51 -0
  368. package/src/lib/std/templates/raw-sequence-universal-deployer-2.yaml +48 -0
  369. package/src/lib/std/templates/sequence-universal-deployer-2.yaml +57 -0
  370. package/src/lib/types/__tests__/json-request-action.spec.ts +243 -0
  371. package/src/lib/types/__tests__/read-json-value.spec.ts +264 -0
  372. package/src/lib/types/actions.ts +127 -0
  373. package/src/lib/types/artifacts.ts +21 -0
  374. package/src/lib/types/buildinfo.ts +116 -0
  375. package/src/lib/types/conditions.ts +50 -0
  376. package/src/lib/types/contracts.ts +23 -0
  377. package/src/lib/types/definitions.ts +68 -0
  378. package/src/lib/types/index.ts +8 -0
  379. package/src/lib/types/network.ts +22 -0
  380. package/src/lib/types/project.ts +9 -0
  381. package/src/lib/types/task.ts +9 -0
  382. package/src/lib/types/values.ts +116 -0
  383. package/src/lib/utils/validation.ts +116 -0
  384. package/src/lib/validation/contract-references.ts +210 -0
  385. package/src/lib/validation/index.ts +1 -0
  386. package/src/lib/verification/__tests__/etherscan.spec.ts +710 -0
  387. package/src/lib/verification/__tests__/sourcify.spec.ts +288 -0
  388. package/src/lib/verification/etherscan.ts +546 -0
  389. package/src/lib/verification/sourcify.ts +248 -0
  390. package/test_validation/artifacts/TestContract.json +9 -0
  391. package/test_validation/jobs/test-missing.yaml +16 -0
  392. package/test_validation/networks.yaml +3 -0
  393. package/tsconfig.json +36 -0
@@ -0,0 +1,710 @@
1
+ import { submitVerification, checkVerificationStatus, waitForVerification, isContractAlreadyVerified } from '../etherscan'
2
+ import { Network } from '../../types/network'
3
+ import { BuildInfo } from '../../types/buildinfo'
4
+
5
+ // Mock global fetch
6
+ global.fetch = jest.fn()
7
+ const mockedFetch = fetch as jest.MockedFunction<typeof fetch>
8
+
9
+ describe('Etherscan Verification', () => {
10
+ const mockNetwork: Network = {
11
+ name: 'Ethereum Mainnet',
12
+ chainId: 1,
13
+ rpcUrl: 'https://mainnet.infura.io/v3/test',
14
+ supports: ['etherscan_v2']
15
+ }
16
+
17
+ const mockBuildInfo: BuildInfo = {
18
+ _format: 'hh-sol-build-info-1',
19
+ id: 'test-build-id',
20
+ solcVersion: 'v0.8.25+commit.b61c2a91',
21
+ solcLongVersion: '0.8.25+commit.b61c2a91.Linux.gcc',
22
+ input: {
23
+ language: 'Solidity',
24
+ sources: {
25
+ 'contracts/MyToken.sol': {
26
+ content: 'pragma solidity ^0.8.0; contract MyToken { }'
27
+ }
28
+ },
29
+ settings: {
30
+ optimizer: {
31
+ enabled: true,
32
+ runs: 200
33
+ },
34
+ outputSelection: {
35
+ '*': {
36
+ '*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']
37
+ }
38
+ }
39
+ }
40
+ },
41
+ output: {
42
+ contracts: {
43
+ 'contracts/MyToken.sol': {
44
+ MyToken: {
45
+ abi: [],
46
+ evm: {
47
+ bytecode: { object: '0x608060405234801561001057600080fd5b50' },
48
+ deployedBytecode: { object: '0x6080604052348015600f57600080fd5b50' }
49
+ }
50
+ }
51
+ }
52
+ },
53
+ sources: {
54
+ 'contracts/MyToken.sol': { id: 0 }
55
+ }
56
+ }
57
+ }
58
+
59
+ const mockContract = {
60
+ contractName: 'MyToken',
61
+ sourceName: 'contracts/MyToken.sol',
62
+ abi: [],
63
+ creationCode: '0x608060405234801561001057600080fd5b50',
64
+ uniqueHash: 'test-hash',
65
+ _sources: new Set(['/test/path'])
66
+ } as any
67
+
68
+ const createMockResponse = (data: any, ok = true, status = 200) => ({
69
+ ok,
70
+ status,
71
+ statusText: ok ? 'OK' : 'Error',
72
+ json: jest.fn().mockResolvedValue(data)
73
+ } as any)
74
+
75
+ beforeEach(() => {
76
+ jest.clearAllMocks()
77
+ })
78
+
79
+ describe('submitVerification', () => {
80
+ it('should submit verification successfully', async () => {
81
+ const mockResponseData = {
82
+ status: '1',
83
+ result: 'test-guid-123'
84
+ }
85
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
86
+
87
+
88
+
89
+ const result = await submitVerification({
90
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
91
+ buildInfo: mockBuildInfo,
92
+ contract: mockContract,
93
+ network: mockNetwork
94
+ }, 'test-api-key')
95
+
96
+ expect(result.success).toBe(true)
97
+ expect(result.guid).toBe('test-guid-123')
98
+ expect(result.message).toBe('Verification submitted successfully')
99
+
100
+ expect(mockedFetch).toHaveBeenCalledWith(
101
+ 'https://api.etherscan.io/v2/api?chainid=1',
102
+ expect.objectContaining({
103
+ method: 'POST',
104
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
105
+ body: expect.any(String)
106
+ })
107
+ )
108
+ })
109
+
110
+ it('should handle verification submission failure', async () => {
111
+ const mockResponseData = {
112
+ status: '0',
113
+ result: 'Invalid contract address'
114
+ }
115
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
116
+
117
+ const result = await submitVerification({
118
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
119
+ buildInfo: mockBuildInfo,
120
+ contract: mockContract,
121
+ network: mockNetwork
122
+ }, 'test-api-key')
123
+
124
+ expect(result.success).toBe(false)
125
+ expect(result.message).toBe('Invalid contract address')
126
+ expect(result.guid).toBeUndefined()
127
+ })
128
+
129
+ it('should include constructor arguments when provided', async () => {
130
+ const mockResponseData = {
131
+ status: '1',
132
+ result: 'test-guid-456'
133
+ }
134
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
135
+
136
+ await submitVerification({
137
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
138
+ buildInfo: mockBuildInfo,
139
+ contract: mockContract,
140
+ constructorArguments: '0x000000000000000000000000742d35cc6596c743b2c8d12cd84d5b8fba4f3c',
141
+ network: mockNetwork
142
+ }, 'test-api-key')
143
+
144
+ const fetchCall = mockedFetch.mock.calls[0]
145
+ const requestBody = fetchCall[1]?.body as string
146
+ expect(requestBody).toContain('constructorArguements=000000000000000000000000742d35cc6596c743b2c8d12cd84d5b8fba4f3c')
147
+ })
148
+
149
+ it('should handle network request errors', async () => {
150
+ mockedFetch.mockRejectedValueOnce(new Error('Network error'))
151
+
152
+ const result = await submitVerification({
153
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
154
+ buildInfo: mockBuildInfo,
155
+ contract: mockContract,
156
+ network: mockNetwork
157
+ }, 'test-api-key')
158
+
159
+ expect(result.success).toBe(false)
160
+ expect(result.message).toContain('API request failed: Network error')
161
+ })
162
+
163
+ it('should use correct API URL for different networks', async () => {
164
+ const sepoliaNetwork: Network = {
165
+ name: 'Sepolia',
166
+ chainId: 11155111,
167
+ rpcUrl: 'https://sepolia.infura.io/v3/test'
168
+ }
169
+
170
+ const mockResponseData = {
171
+ status: '1',
172
+ result: 'test-guid-sepolia'
173
+ }
174
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
175
+
176
+ await submitVerification({
177
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
178
+ buildInfo: mockBuildInfo,
179
+ contract: mockContract,
180
+ network: sepoliaNetwork
181
+ }, 'test-api-key')
182
+
183
+ expect(mockedFetch).toHaveBeenCalledWith(
184
+ 'https://api.etherscan.io/v2/api?chainid=11155111',
185
+ expect.any(Object)
186
+ )
187
+ })
188
+
189
+ it('should use v2 API format for any network', async () => {
190
+ const customNetwork: Network = {
191
+ name: 'Custom Network',
192
+ chainId: 999999,
193
+ rpcUrl: 'https://custom.rpc'
194
+ }
195
+
196
+ const mockResponseData = {
197
+ status: '0',
198
+ result: 'Invalid chain ID'
199
+ }
200
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
201
+
202
+ const result = await submitVerification({
203
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
204
+ buildInfo: mockBuildInfo,
205
+ contract: mockContract,
206
+ network: customNetwork
207
+ }, 'test-api-key')
208
+
209
+ expect(result.success).toBe(false)
210
+ expect(result.message).toBe('Invalid chain ID')
211
+ expect(mockedFetch).toHaveBeenCalledWith(
212
+ 'https://api.etherscan.io/v2/api?chainid=999999',
213
+ expect.any(Object)
214
+ )
215
+ })
216
+
217
+ it('should treat "Already Verified" as success', async () => {
218
+ const mockResponseData = {
219
+ status: '0',
220
+ result: 'Already Verified'
221
+ }
222
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
223
+
224
+ const result = await submitVerification({
225
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
226
+ buildInfo: mockBuildInfo,
227
+ contract: mockContract,
228
+ network: mockNetwork
229
+ }, 'test-api-key')
230
+
231
+ expect(result.success).toBe(true)
232
+ expect(result.message).toBe('Contract is already verified')
233
+ expect(result.guid).toBeUndefined()
234
+ })
235
+
236
+ it('should treat "Contract source code already verified" as success', async () => {
237
+ const mockResponseData = {
238
+ status: '0',
239
+ result: 'Contract source code already verified'
240
+ }
241
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
242
+
243
+ const result = await submitVerification({
244
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
245
+ buildInfo: mockBuildInfo,
246
+ contract: mockContract,
247
+ network: mockNetwork
248
+ }, 'test-api-key')
249
+
250
+ expect(result.success).toBe(true)
251
+ expect(result.message).toBe('Contract is already verified')
252
+ expect(result.guid).toBeUndefined()
253
+ })
254
+
255
+ describe('retry logic', () => {
256
+ beforeEach(() => {
257
+ // Mock console.log to avoid noise in test output
258
+ jest.spyOn(console, 'log').mockImplementation(() => {})
259
+ // Mock setTimeout to make tests run faster
260
+ jest.spyOn(global, 'setTimeout').mockImplementation((callback: any) => {
261
+ callback()
262
+ return {} as any
263
+ })
264
+ })
265
+
266
+ afterEach(() => {
267
+ jest.restoreAllMocks()
268
+ })
269
+
270
+ it('should retry for "unable to locate contractcode" error', async () => {
271
+ const contractNotFoundResponse = {
272
+ status: '0',
273
+ result: 'Unable to locate ContractCode at 0x123...'
274
+ }
275
+ const successResponse = {
276
+ status: '1',
277
+ result: 'test-guid-retry'
278
+ }
279
+
280
+ mockedFetch
281
+ .mockResolvedValueOnce(createMockResponse(contractNotFoundResponse))
282
+ .mockResolvedValueOnce(createMockResponse(successResponse))
283
+
284
+ const result = await submitVerification({
285
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
286
+ buildInfo: mockBuildInfo,
287
+ contract: mockContract,
288
+ network: mockNetwork,
289
+ maxRetries: 3,
290
+ retryDelayMs: 100
291
+ }, 'test-api-key')
292
+
293
+ expect(result.success).toBe(true)
294
+ expect(result.guid).toBe('test-guid-retry')
295
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
296
+ })
297
+
298
+ it('should retry for "contract source code not verified" error', async () => {
299
+ const contractNotFoundResponse = {
300
+ status: '0',
301
+ result: 'Contract source code not verified'
302
+ }
303
+ const successResponse = {
304
+ status: '1',
305
+ result: 'test-guid-retry-2'
306
+ }
307
+
308
+ mockedFetch
309
+ .mockResolvedValueOnce(createMockResponse(contractNotFoundResponse))
310
+ .mockResolvedValueOnce(createMockResponse(successResponse))
311
+
312
+ const result = await submitVerification({
313
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
314
+ buildInfo: mockBuildInfo,
315
+ contract: mockContract,
316
+ network: mockNetwork,
317
+ maxRetries: 2
318
+ }, 'test-api-key')
319
+
320
+ expect(result.success).toBe(true)
321
+ expect(result.guid).toBe('test-guid-retry-2')
322
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
323
+ })
324
+
325
+ it('should retry for "contract not found" error', async () => {
326
+ const contractNotFoundResponse = {
327
+ status: '0',
328
+ result: 'Contract not found'
329
+ }
330
+ const successResponse = {
331
+ status: '1',
332
+ result: 'test-guid-retry-3'
333
+ }
334
+
335
+ mockedFetch
336
+ .mockResolvedValueOnce(createMockResponse(contractNotFoundResponse))
337
+ .mockResolvedValueOnce(createMockResponse(successResponse))
338
+
339
+ const result = await submitVerification({
340
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
341
+ buildInfo: mockBuildInfo,
342
+ contract: mockContract,
343
+ network: mockNetwork
344
+ }, 'test-api-key')
345
+
346
+ expect(result.success).toBe(true)
347
+ expect(result.guid).toBe('test-guid-retry-3')
348
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
349
+ })
350
+
351
+ it('should not retry for non-contract-not-found errors', async () => {
352
+ const invalidResponse = {
353
+ status: '0',
354
+ result: 'Invalid API key'
355
+ }
356
+
357
+ mockedFetch.mockResolvedValueOnce(createMockResponse(invalidResponse))
358
+
359
+ const result = await submitVerification({
360
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
361
+ buildInfo: mockBuildInfo,
362
+ contract: mockContract,
363
+ network: mockNetwork,
364
+ maxRetries: 3
365
+ }, 'test-api-key')
366
+
367
+ expect(result.success).toBe(false)
368
+ expect(result.message).toBe('Invalid API key')
369
+ expect(mockedFetch).toHaveBeenCalledTimes(1) // No retries
370
+ })
371
+
372
+ it('should exhaust all retries and return failure message', async () => {
373
+ const contractNotFoundResponse = {
374
+ status: '0',
375
+ result: 'Unable to locate ContractCode'
376
+ }
377
+
378
+ mockedFetch.mockResolvedValue(createMockResponse(contractNotFoundResponse))
379
+
380
+ const result = await submitVerification({
381
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
382
+ buildInfo: mockBuildInfo,
383
+ contract: mockContract,
384
+ network: mockNetwork,
385
+ maxRetries: 2,
386
+ retryDelayMs: 10
387
+ }, 'test-api-key')
388
+
389
+ expect(result.success).toBe(false)
390
+ expect(result.message).toBe('Verification failed after 3 attempts. Last error: Unable to locate ContractCode')
391
+ expect(mockedFetch).toHaveBeenCalledTimes(3) // Initial + 2 retries
392
+ })
393
+
394
+ it('should use default retry settings when not specified', async () => {
395
+ const contractNotFoundResponse = {
396
+ status: '0',
397
+ result: 'Contract not found'
398
+ }
399
+
400
+ mockedFetch.mockResolvedValue(createMockResponse(contractNotFoundResponse))
401
+
402
+ const result = await submitVerification({
403
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
404
+ buildInfo: mockBuildInfo,
405
+ contract: mockContract,
406
+ network: mockNetwork
407
+ // No maxRetries or retryDelayMs specified - should use defaults
408
+ }, 'test-api-key')
409
+
410
+ expect(result.success).toBe(false)
411
+ expect(result.message).toBe('Verification failed after 4 attempts. Last error: Contract not found')
412
+ expect(mockedFetch).toHaveBeenCalledTimes(4) // Initial + 3 default retries
413
+ })
414
+
415
+ it('should retry for network errors with contract not found message', async () => {
416
+ const contractNotFoundError = new Error('Unable to locate ContractCode')
417
+ const successResponse = {
418
+ status: '1',
419
+ result: 'test-guid-network-retry'
420
+ }
421
+
422
+ mockedFetch
423
+ .mockRejectedValueOnce(contractNotFoundError)
424
+ .mockResolvedValueOnce(createMockResponse(successResponse))
425
+
426
+ const result = await submitVerification({
427
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
428
+ buildInfo: mockBuildInfo,
429
+ contract: mockContract,
430
+ network: mockNetwork,
431
+ maxRetries: 2
432
+ }, 'test-api-key')
433
+
434
+ expect(result.success).toBe(true)
435
+ expect(result.guid).toBe('test-guid-network-retry')
436
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
437
+ })
438
+
439
+ it('should not retry for network errors without contract not found message', async () => {
440
+ const networkError = new Error('Network timeout')
441
+
442
+ mockedFetch.mockRejectedValueOnce(networkError)
443
+
444
+ const result = await submitVerification({
445
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
446
+ buildInfo: mockBuildInfo,
447
+ contract: mockContract,
448
+ network: mockNetwork,
449
+ maxRetries: 3
450
+ }, 'test-api-key')
451
+
452
+ expect(result.success).toBe(false)
453
+ expect(result.message).toBe('API request failed: Network timeout')
454
+ expect(mockedFetch).toHaveBeenCalledTimes(1) // No retries
455
+ })
456
+
457
+ it('should exhaust retries for network errors with contract not found message', async () => {
458
+ const contractNotFoundError = new Error('Contract source code not verified')
459
+
460
+ mockedFetch.mockRejectedValue(contractNotFoundError)
461
+
462
+ const result = await submitVerification({
463
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
464
+ buildInfo: mockBuildInfo,
465
+ contract: mockContract,
466
+ network: mockNetwork,
467
+ maxRetries: 1,
468
+ retryDelayMs: 10
469
+ }, 'test-api-key')
470
+
471
+ expect(result.success).toBe(false)
472
+ expect(result.message).toBe('API request failed: Contract source code not verified')
473
+ expect(mockedFetch).toHaveBeenCalledTimes(2) // Initial + 1 retry
474
+ })
475
+
476
+ it('should handle case-insensitive error message matching', async () => {
477
+ const contractNotFoundResponse = {
478
+ status: '0',
479
+ result: 'UNABLE TO LOCATE CONTRACTCODE'
480
+ }
481
+ const successResponse = {
482
+ status: '1',
483
+ result: 'test-guid-case-insensitive'
484
+ }
485
+
486
+ mockedFetch
487
+ .mockResolvedValueOnce(createMockResponse(contractNotFoundResponse))
488
+ .mockResolvedValueOnce(createMockResponse(successResponse))
489
+
490
+ const result = await submitVerification({
491
+ address: '0x742d35Cc6596C743B2c8d12Cd84d5B8FbA4F3C',
492
+ buildInfo: mockBuildInfo,
493
+ contract: mockContract,
494
+ network: mockNetwork,
495
+ maxRetries: 1
496
+ }, 'test-api-key')
497
+
498
+ expect(result.success).toBe(true)
499
+ expect(result.guid).toBe('test-guid-case-insensitive')
500
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
501
+ })
502
+ })
503
+ })
504
+
505
+ describe('checkVerificationStatus', () => {
506
+ it('should return success status', async () => {
507
+ const mockResponseData = {
508
+ status: '1',
509
+ result: 'Pass - Verified'
510
+ }
511
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
512
+
513
+ const status = await checkVerificationStatus('test-guid', 'test-api-key', mockNetwork)
514
+
515
+ expect(status.isComplete).toBe(true)
516
+ expect(status.isSuccess).toBe(true)
517
+ expect(status.message).toBe('Verification successful')
518
+ })
519
+
520
+ it('should return pending status', async () => {
521
+ const mockResponseData = {
522
+ status: '0',
523
+ result: 'Pending in queue'
524
+ }
525
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
526
+
527
+ const status = await checkVerificationStatus('test-guid', 'test-api-key', mockNetwork)
528
+
529
+ expect(status.isComplete).toBe(false)
530
+ expect(status.isSuccess).toBe(false)
531
+ expect(status.message).toBe('Verification pending')
532
+ })
533
+
534
+ it('should return failure status', async () => {
535
+ const mockResponseData = {
536
+ status: '0',
537
+ result: 'Fail - Unable to verify'
538
+ }
539
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
540
+
541
+ const status = await checkVerificationStatus('test-guid', 'test-api-key', mockNetwork)
542
+
543
+ expect(status.isComplete).toBe(true)
544
+ expect(status.isSuccess).toBe(false)
545
+ expect(status.message).toBe('Fail - Unable to verify')
546
+ })
547
+
548
+ it('should treat "Already Verified" as success in status check', async () => {
549
+ const mockResponseData = {
550
+ status: '0',
551
+ result: 'Already Verified'
552
+ }
553
+ mockedFetch.mockResolvedValueOnce(createMockResponse(mockResponseData))
554
+
555
+ const status = await checkVerificationStatus('test-guid', 'test-api-key', mockNetwork)
556
+
557
+ expect(status.isComplete).toBe(true)
558
+ expect(status.isSuccess).toBe(true)
559
+ expect(status.message).toBe('Contract is already verified')
560
+ })
561
+ })
562
+
563
+ describe('waitForVerification', () => {
564
+ it('should return when verification completes successfully', async () => {
565
+ mockedFetch
566
+ .mockResolvedValueOnce(createMockResponse({
567
+ status: '0', result: 'Pending in queue'
568
+ }))
569
+ .mockResolvedValueOnce(createMockResponse({
570
+ status: '1', result: 'Pass - Verified'
571
+ }))
572
+
573
+ const status = await waitForVerification('test-guid', 'test-api-key', mockNetwork, 10000)
574
+
575
+ expect(status.isComplete).toBe(true)
576
+ expect(status.isSuccess).toBe(true)
577
+ expect(mockedFetch).toHaveBeenCalledTimes(2)
578
+ })
579
+
580
+ it('should timeout after specified duration', async () => {
581
+ mockedFetch.mockResolvedValue(createMockResponse({
582
+ status: '0', result: 'Pending in queue'
583
+ }))
584
+
585
+ await expect(
586
+ waitForVerification('test-guid', 'test-api-key', mockNetwork, 1000)
587
+ ).rejects.toThrow('Verification timed out after 1 seconds')
588
+
589
+ expect(mockedFetch).toHaveBeenCalledTimes(1)
590
+ })
591
+ })
592
+
593
+ describe('isContractAlreadyVerified', () => {
594
+ const testAddress = '0x1234567890123456789012345678901234567890'
595
+ const testApiKey = 'test-api-key'
596
+
597
+ beforeEach(() => {
598
+ mockedFetch.mockClear()
599
+ })
600
+
601
+ it('should return true when contract is verified', async () => {
602
+ mockedFetch.mockResolvedValueOnce(createMockResponse({
603
+ status: '1',
604
+ result: [{
605
+ SourceCode: 'pragma solidity ^0.8.0; contract MyToken { }'
606
+ }]
607
+ }))
608
+
609
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
610
+
611
+ expect(result).toBe(true)
612
+ expect(mockedFetch).toHaveBeenCalledWith(
613
+ expect.stringContaining('chainid=1'),
614
+ expect.objectContaining({
615
+ method: 'GET'
616
+ })
617
+ )
618
+ })
619
+
620
+ it('should return false when contract is not verified (empty source code)', async () => {
621
+ mockedFetch.mockResolvedValueOnce(createMockResponse({
622
+ status: '1',
623
+ result: [{
624
+ SourceCode: ''
625
+ }]
626
+ }))
627
+
628
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
629
+
630
+ expect(result).toBe(false)
631
+ })
632
+
633
+ it('should return false when API returns status 0', async () => {
634
+ mockedFetch.mockResolvedValueOnce(createMockResponse({
635
+ status: '0',
636
+ result: 'Contract source code not verified'
637
+ }))
638
+
639
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
640
+
641
+ expect(result).toBe(false)
642
+ })
643
+
644
+ it('should return false when result array is empty', async () => {
645
+ mockedFetch.mockResolvedValueOnce(createMockResponse({
646
+ status: '1',
647
+ result: []
648
+ }))
649
+
650
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
651
+
652
+ expect(result).toBe(false)
653
+ })
654
+
655
+ it('should return false and log warning when API request fails', async () => {
656
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
657
+ mockedFetch.mockRejectedValueOnce(new Error('Network error'))
658
+
659
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
660
+
661
+ expect(result).toBe(false)
662
+ expect(consoleSpy).toHaveBeenCalledWith(
663
+ expect.stringContaining(`Failed to check verification status for ${testAddress}`)
664
+ )
665
+
666
+ consoleSpy.mockRestore()
667
+ })
668
+
669
+ it('should return false when HTTP response is not ok', async () => {
670
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
671
+ mockedFetch.mockResolvedValueOnce({
672
+ ok: false,
673
+ status: 500,
674
+ statusText: 'Internal Server Error'
675
+ } as Response)
676
+
677
+ const result = await isContractAlreadyVerified(testAddress, testApiKey, mockNetwork)
678
+
679
+ expect(result).toBe(false)
680
+ expect(consoleSpy).toHaveBeenCalledWith(
681
+ expect.stringContaining('Failed to check verification status')
682
+ )
683
+
684
+ consoleSpy.mockRestore()
685
+ })
686
+
687
+ it('should use correct chainId in API call for different networks', async () => {
688
+ const arbitrumNetwork: Network = {
689
+ name: 'Arbitrum One',
690
+ chainId: 42161,
691
+ rpcUrl: 'https://arb1.arbitrum.io/rpc',
692
+ supports: ['etherscan_v2']
693
+ }
694
+
695
+ mockedFetch.mockResolvedValueOnce(createMockResponse({
696
+ status: '1',
697
+ result: [{
698
+ SourceCode: 'contract code'
699
+ }]
700
+ }))
701
+
702
+ await isContractAlreadyVerified(testAddress, testApiKey, arbitrumNetwork)
703
+
704
+ expect(mockedFetch).toHaveBeenCalledWith(
705
+ expect.stringContaining('chainid=42161'),
706
+ expect.any(Object)
707
+ )
708
+ })
709
+ })
710
+ })