@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,181 @@
1
+ import { detectNetworkFromRpc, isValidRpcUrl } from '../network-utils'
2
+ import { Network } from '../types'
3
+
4
+ // Mock ethers.JsonRpcProvider
5
+ jest.mock('ethers', () => ({
6
+ ...jest.requireActual('ethers'),
7
+ ethers: {
8
+ ...jest.requireActual('ethers').ethers,
9
+ JsonRpcProvider: jest.fn().mockImplementation(() => ({
10
+ getNetwork: jest.fn()
11
+ }))
12
+ }
13
+ }))
14
+
15
+ describe('Network Utils', () => {
16
+ describe('isValidRpcUrl', () => {
17
+ it('should validate valid HTTP RPC URLs', () => {
18
+ expect(isValidRpcUrl('http://localhost:8545')).toBe(true)
19
+ expect(isValidRpcUrl('https://mainnet.infura.io/v3/abc123')).toBe(true)
20
+ })
21
+
22
+ it('should validate valid WebSocket RPC URLs', () => {
23
+ expect(isValidRpcUrl('ws://localhost:8545')).toBe(true)
24
+ expect(isValidRpcUrl('wss://mainnet.infura.io/v3/abc123')).toBe(true)
25
+ })
26
+
27
+ it('should reject invalid URLs', () => {
28
+ expect(isValidRpcUrl('invalid-url')).toBe(false)
29
+ expect(isValidRpcUrl('ftp://example.com')).toBe(false)
30
+ expect(isValidRpcUrl('')).toBe(false)
31
+ })
32
+
33
+ it('should reject URLs without hostname', () => {
34
+ expect(isValidRpcUrl('http://')).toBe(false)
35
+ })
36
+ })
37
+
38
+ describe('detectNetworkFromRpc', () => {
39
+ let mockGetNetwork: jest.Mock
40
+
41
+ beforeEach(() => {
42
+ // Reset mocks
43
+ jest.clearAllMocks()
44
+
45
+ // Mock the JsonRpcProvider constructor and getNetwork method
46
+ const { ethers } = require('ethers')
47
+ mockGetNetwork = jest.fn()
48
+
49
+ // Mock the provider's getNetwork method
50
+ ethers.JsonRpcProvider.mockImplementation(() => ({
51
+ getNetwork: mockGetNetwork
52
+ }))
53
+ })
54
+
55
+ it('should detect network successfully', async () => {
56
+ const mockNetwork = {
57
+ name: 'mainnet',
58
+ chainId: 1
59
+ }
60
+
61
+ mockGetNetwork.mockResolvedValue(mockNetwork)
62
+
63
+ const result = await detectNetworkFromRpc('https://mainnet.infura.io/v3/abc123')
64
+
65
+ expect(result).toEqual({
66
+ name: 'mainnet',
67
+ chainId: 1,
68
+ rpcUrl: 'https://mainnet.infura.io/v3/abc123'
69
+ })
70
+
71
+ // Verify provider was created with correct URL
72
+ const { ethers } = require('ethers')
73
+ expect(ethers.JsonRpcProvider).toHaveBeenCalledWith('https://mainnet.infura.io/v3/abc123')
74
+ })
75
+
76
+ it('should handle network with unknown name', async () => {
77
+ const mockNetwork = {
78
+ name: 'unknown',
79
+ chainId: 31337
80
+ }
81
+
82
+ mockGetNetwork.mockResolvedValue(mockNetwork)
83
+
84
+ const result = await detectNetworkFromRpc('http://localhost:8545')
85
+
86
+ expect(result).toEqual({
87
+ name: 'unknown',
88
+ chainId: 31337,
89
+ rpcUrl: 'http://localhost:8545'
90
+ })
91
+ })
92
+
93
+ it('should handle connection errors', async () => {
94
+ mockGetNetwork.mockRejectedValue(new Error('Connection failed'))
95
+
96
+ await expect(detectNetworkFromRpc('http://localhost:8545'))
97
+ .rejects.toThrow('Failed to detect network from RPC URL "http://localhost:8545": Connection failed')
98
+ })
99
+
100
+ it('should handle network detection errors', async () => {
101
+ mockGetNetwork.mockRejectedValue(new Error('Network not supported'))
102
+
103
+ await expect(detectNetworkFromRpc('http://invalid-rpc.com'))
104
+ .rejects.toThrow('Failed to detect network from RPC URL "http://invalid-rpc.com": Network not supported')
105
+ })
106
+ })
107
+
108
+ describe('Integration with Run Command', () => {
109
+ it('should create a complete Network object from detected information', async () => {
110
+ const { ethers } = require('ethers')
111
+
112
+ // Mock successful network detection
113
+ const mockNetwork = {
114
+ name: 'sepolia',
115
+ chainId: 11155111
116
+ }
117
+
118
+ const getNetworkMock = jest.fn().mockResolvedValue(mockNetwork)
119
+ ethers.JsonRpcProvider.mockImplementation(() => ({
120
+ getNetwork: getNetworkMock
121
+ }))
122
+
123
+ const detectedInfo = await detectNetworkFromRpc('https://sepolia.infura.io/v3/abc123')
124
+
125
+ // Simulate what the run command does
126
+ const customNetwork: Network = {
127
+ name: detectedInfo.name || `custom-${detectedInfo.chainId}`,
128
+ chainId: detectedInfo.chainId!,
129
+ rpcUrl: 'https://sepolia.infura.io/v3/abc123',
130
+ supports: detectedInfo.supports || [],
131
+ gasLimit: detectedInfo.gasLimit,
132
+ testnet: detectedInfo.testnet
133
+ }
134
+
135
+ expect(customNetwork).toEqual({
136
+ name: 'sepolia',
137
+ chainId: 11155111,
138
+ rpcUrl: 'https://sepolia.infura.io/v3/abc123',
139
+ supports: [],
140
+ gasLimit: undefined,
141
+ testnet: undefined
142
+ })
143
+ })
144
+
145
+ it('should handle partial network information gracefully', async () => {
146
+ const { ethers } = require('ethers')
147
+
148
+ // Mock network with minimal information
149
+ const mockNetwork = {
150
+ name: 'unknown',
151
+ chainId: 42
152
+ }
153
+
154
+ const getNetworkMock = jest.fn().mockResolvedValue(mockNetwork)
155
+ ethers.JsonRpcProvider.mockImplementation(() => ({
156
+ getNetwork: getNetworkMock
157
+ }))
158
+
159
+ const detectedInfo = await detectNetworkFromRpc('http://custom-network:8545')
160
+
161
+ // Simulate what the run command does
162
+ const customNetwork: Network = {
163
+ name: detectedInfo.name || `custom-${detectedInfo.chainId}`,
164
+ chainId: detectedInfo.chainId!,
165
+ rpcUrl: 'http://custom-network:8545',
166
+ supports: detectedInfo.supports || [],
167
+ gasLimit: detectedInfo.gasLimit,
168
+ testnet: detectedInfo.testnet
169
+ }
170
+
171
+ expect(customNetwork).toEqual({
172
+ name: 'unknown',
173
+ chainId: 42,
174
+ rpcUrl: 'http://custom-network:8545',
175
+ supports: [],
176
+ gasLimit: undefined,
177
+ testnet: undefined
178
+ })
179
+ })
180
+ })
181
+ })
@@ -0,0 +1,19 @@
1
+ {
2
+ "contractName": "TestContract1",
3
+ "sourceName": "contracts/TestContract1.sol",
4
+ "abi": [
5
+ {
6
+ "type": "function",
7
+ "name": "getValue",
8
+ "inputs": [],
9
+ "outputs": [
10
+ {
11
+ "name": "",
12
+ "type": "uint256"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "bytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806320965255146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b0000005b6000806000fefe",
18
+ "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806320965255146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b6000fefe"
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "contractName": "TestContract2",
3
+ "sourceName": "contracts/TestContract2.sol",
4
+ "abi": [
5
+ {
6
+ "type": "function",
7
+ "name": "setValue",
8
+ "inputs": [
9
+ {
10
+ "name": "value",
11
+ "type": "uint256"
12
+ }
13
+ ],
14
+ "outputs": []
15
+ }
16
+ ],
17
+ "bytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806355241077146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b6000fefe",
18
+ "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806355241077146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b6000fefe"
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "contractName": "TestContract1",
3
+ "sourceName": "contracts/DuplicateTestContract1.sol",
4
+ "abi": [
5
+ {
6
+ "type": "function",
7
+ "name": "differentFunction",
8
+ "inputs": [],
9
+ "outputs": [
10
+ {
11
+ "name": "",
12
+ "type": "string"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "bytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806320965255146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b0000005b6000806000fefe",
18
+ "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806320965255146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b6000fefe"
19
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "contractName": "NestedContract",
3
+ "sourceName": "contracts/nested/NestedContract.sol",
4
+ "abi": [
5
+ {
6
+ "type": "function",
7
+ "name": "nestedFunction",
8
+ "inputs": [],
9
+ "outputs": [
10
+ {
11
+ "name": "",
12
+ "type": "bool"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "bytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806320965255146100365780636d4ce63c14610040575b600080fd5b610040610058565b005b610048610062565b6040516100579190610078565b60405180910390f35b0000005b6000806000fefe"
18
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "NotAnArtifact",
3
+ "data": {
4
+ "some": "random",
5
+ "json": "data"
6
+ },
7
+ "version": "1.0.0"
8
+ }
@@ -0,0 +1,2 @@
1
+ This is just a text file that should be ignored during artifact scanning.
2
+ It has no JSON content and should not interfere with the test.
@@ -0,0 +1,344 @@
1
+ import * as fs from 'fs/promises'
2
+ import * as path from 'path'
3
+ import { ContractRepository } from '../repository'
4
+ import { Contract } from '../../types/contracts'
5
+
6
+ describe('ContractRepository', () => {
7
+ let repository: ContractRepository
8
+ let tempDir: string
9
+
10
+ beforeEach(async () => {
11
+ repository = new ContractRepository()
12
+
13
+ // Create a temporary directory for test files
14
+ tempDir = path.join(__dirname, 'temp-test-files')
15
+ await fs.mkdir(tempDir, { recursive: true })
16
+ })
17
+
18
+ afterEach(async () => {
19
+ // Clean up temporary files
20
+ try {
21
+ await fs.rm(tempDir, { recursive: true, force: true })
22
+ } catch (error) {
23
+ // Ignore cleanup errors
24
+ }
25
+ })
26
+
27
+ describe('loadFrom method', () => {
28
+ it('should find and load standard artifact files', async () => {
29
+ const artifactContent = JSON.stringify({
30
+ contractName: 'TestContract',
31
+ abi: [{ type: 'function', name: 'test' }],
32
+ bytecode: '0x608060405234801561001057600080fd5b50',
33
+ deployedBytecode: '0x608060405234801561001057600080fd5b506004361061003957600080fd5b50'
34
+ })
35
+
36
+ const artifactPath = path.join(tempDir, 'TestContract.json')
37
+ await fs.writeFile(artifactPath, artifactContent)
38
+
39
+ await repository.loadFrom(tempDir)
40
+
41
+ const contracts = repository.getAll()
42
+ expect(contracts).toHaveLength(1)
43
+
44
+ const contract = contracts[0]
45
+ expect(contract.contractName).toBe('TestContract')
46
+ expect(contract.creationCode).toBe('0x608060405234801561001057600080fd5b50')
47
+ expect(contract.runtimeBytecode).toBe('0x608060405234801561001057600080fd5b506004361061003957600080fd5b50')
48
+ expect(contract.abi).toEqual([{ type: 'function', name: 'test' }])
49
+ expect(contract._sources.has(artifactPath)).toBe(true)
50
+ })
51
+
52
+ it('should find and load build-info files', async () => {
53
+ const buildInfoContent = JSON.stringify({
54
+ _format: 'hh-sol-build-info-1',
55
+ id: 'test-build-id',
56
+ solcVersion: '0.8.0',
57
+ solcLongVersion: '0.8.0+commit.c7dfd78e',
58
+ input: {
59
+ language: 'Solidity',
60
+ sources: {
61
+ 'src/TestContract.sol': {
62
+ content: 'contract TestContract { function test() public {} }'
63
+ }
64
+ },
65
+ settings: {
66
+ outputSelection: {
67
+ '*': {
68
+ '*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']
69
+ }
70
+ }
71
+ }
72
+ },
73
+ output: {
74
+ contracts: {
75
+ 'src/TestContract.sol': {
76
+ TestContract: {
77
+ abi: [{ type: 'function', name: 'test' }],
78
+ evm: {
79
+ bytecode: {
80
+ object: '0x608060405234801561001057600080fd5b50'
81
+ },
82
+ deployedBytecode: {
83
+ object: '0x608060405234801561001057600080fd5b506004361061003939600080fd5b50'
84
+ }
85
+ }
86
+ }
87
+ }
88
+ },
89
+ sources: {}
90
+ }
91
+ })
92
+
93
+ const buildInfoDir = path.join(tempDir, 'build-info')
94
+ await fs.mkdir(buildInfoDir, { recursive: true })
95
+ const buildInfoPath = path.join(buildInfoDir, 'test-buildinfo.json')
96
+ await fs.writeFile(buildInfoPath, buildInfoContent)
97
+
98
+ await repository.loadFrom(tempDir)
99
+
100
+ const contracts = repository.getAll()
101
+ expect(contracts).toHaveLength(1)
102
+
103
+ const contract = contracts[0]
104
+ expect(contract.contractName).toBe('TestContract')
105
+ expect(contract.sourceName).toBe('src/TestContract.sol')
106
+ expect(contract.creationCode).toBe('0x608060405234801561001057600080fd5b50')
107
+ expect(contract.runtimeBytecode).toBe('0x608060405234801561001057600080fd5b506004361061003939600080fd5b50')
108
+ expect(contract.abi).toEqual([{ type: 'function', name: 'test' }])
109
+ expect(contract.buildInfoId).toBe('test-build-id')
110
+ expect(contract.source).toBe('contract TestContract { function test() public {} }')
111
+ expect(contract._sources.has(buildInfoPath)).toBe(true)
112
+ })
113
+
114
+ it('should hydrate contracts from multiple source files', async () => {
115
+ // Create a basic artifact file (minimal info, will be hydrated by build-info)
116
+ const artifactContent = JSON.stringify({
117
+ contractName: 'TestContract',
118
+ abi: [],
119
+ bytecode: '0x608060405234801561001057600080fd5b50'
120
+ })
121
+ const artifactPath = path.join(tempDir, 'TestContract.json')
122
+ await fs.writeFile(artifactPath, artifactContent)
123
+
124
+ // Create a build-info file with the same bytecode but more complete information
125
+ const buildInfoContent = JSON.stringify({
126
+ _format: 'hh-sol-build-info-1',
127
+ id: 'test-build-id',
128
+ solcVersion: '0.8.0',
129
+ solcLongVersion: '0.8.0+commit.c7dfd78e',
130
+ input: {
131
+ language: 'Solidity',
132
+ sources: {
133
+ 'src/TestContract.sol': {
134
+ content: 'contract TestContract { function test() public {} }'
135
+ }
136
+ },
137
+ settings: {
138
+ outputSelection: {
139
+ '*': {
140
+ '*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']
141
+ }
142
+ }
143
+ }
144
+ },
145
+ output: {
146
+ contracts: {
147
+ 'src/TestContract.sol': {
148
+ TestContract: {
149
+ abi: [{ type: 'function', name: 'test' }],
150
+ evm: {
151
+ bytecode: {
152
+ object: '0x608060405234801561001057600080fd5b50'
153
+ },
154
+ deployedBytecode: {
155
+ object: '0x608060405234801561001057600080fd5b506004361061003939600080fd5b50'
156
+ }
157
+ }
158
+ }
159
+ }
160
+ },
161
+ sources: {}
162
+ }
163
+ })
164
+
165
+ const buildInfoDir = path.join(tempDir, 'build-info')
166
+ await fs.mkdir(buildInfoDir, { recursive: true })
167
+ const buildInfoPath = path.join(buildInfoDir, 'test-buildinfo.json')
168
+ await fs.writeFile(buildInfoPath, buildInfoContent)
169
+
170
+ await repository.loadFrom(tempDir)
171
+
172
+ const contracts = repository.getAll()
173
+ expect(contracts).toHaveLength(1)
174
+
175
+ const contract = contracts[0]
176
+ // Should have information from both sources
177
+ expect(contract.contractName).toBe('TestContract')
178
+ expect(contract.sourceName).toBe('src/TestContract.sol')
179
+ expect(contract.abi).toEqual([{ type: 'function', name: 'test' }])
180
+ expect(contract.buildInfoId).toBe('test-build-id')
181
+ expect(contract.source).toBe('contract TestContract { function test() public {} }')
182
+ expect(contract._sources.has(artifactPath)).toBe(true)
183
+ expect(contract._sources.has(buildInfoPath)).toBe(true)
184
+ })
185
+ })
186
+
187
+ describe('disambiguateReferences method', () => {
188
+ beforeEach(async () => {
189
+ // Create test files with deliberate name collisions
190
+ const artifact1Content = JSON.stringify({
191
+ contractName: 'MyToken',
192
+ abi: [],
193
+ bytecode: '0x608060405234801561001057600080fd5b50111111'
194
+ })
195
+ const artifact1Path = path.join(tempDir, 'contracts', 'MyToken.json')
196
+ await fs.mkdir(path.dirname(artifact1Path), { recursive: true })
197
+ await fs.writeFile(artifact1Path, artifact1Content)
198
+
199
+ const artifact2Content = JSON.stringify({
200
+ contractName: 'MyToken',
201
+ abi: [],
202
+ bytecode: '0x608060405234801561001057600080fd5b50222222'
203
+ })
204
+ const artifact2Path = path.join(tempDir, 'legacy', 'MyToken.json')
205
+ await fs.mkdir(path.dirname(artifact2Path), { recursive: true })
206
+ await fs.writeFile(artifact2Path, artifact2Content)
207
+
208
+ await repository.loadFrom(tempDir)
209
+ })
210
+
211
+ it('should identify ambiguous references correctly', () => {
212
+ const ambiguousRefs = repository.getAmbiguousReferences()
213
+ expect(ambiguousRefs).toContain('MyToken')
214
+ })
215
+
216
+ it('should allow lookup by unique hash', () => {
217
+ const contracts = repository.getAll()
218
+ const contract1 = contracts.find(c => c.creationCode.includes('111111'))
219
+ const contract2 = contracts.find(c => c.creationCode.includes('222222'))
220
+
221
+ expect(contract1).toBeDefined()
222
+ expect(contract2).toBeDefined()
223
+
224
+ const lookupResult1 = repository.lookup(contract1!.uniqueHash)
225
+ const lookupResult2 = repository.lookup(contract2!.uniqueHash)
226
+
227
+ expect(lookupResult1).toBe(contract1)
228
+ expect(lookupResult2).toBe(contract2)
229
+ })
230
+
231
+ it('should allow lookup by unambiguous path', () => {
232
+ const contracts = repository.getAll()
233
+ const contract1 = contracts.find(c => c.creationCode.includes('111111'))
234
+
235
+ const lookupResult = repository.lookup(path.join(tempDir, 'contracts', 'MyToken.json'))
236
+ expect(lookupResult).toBe(contract1)
237
+ })
238
+ })
239
+
240
+ describe('lookup method', () => {
241
+ beforeEach(async () => {
242
+ const artifactContent = JSON.stringify({
243
+ contractName: 'UniqueContract',
244
+ abi: [{ type: 'function', name: 'test' }],
245
+ bytecode: '0x608060405234801561001057600080fd5b50'
246
+ })
247
+ const artifactPath = path.join(tempDir, 'UniqueContract.json')
248
+ await fs.writeFile(artifactPath, artifactContent)
249
+
250
+ await repository.loadFrom(tempDir)
251
+ })
252
+
253
+ it('should successfully lookup by contract name', () => {
254
+ const contract = repository.lookup('UniqueContract')
255
+ expect(contract).not.toBeNull()
256
+ expect(contract!.contractName).toBe('UniqueContract')
257
+ })
258
+
259
+ it('should successfully lookup by unique hash', () => {
260
+ const contracts = repository.getAll()
261
+ const testContract = contracts[0]
262
+
263
+ const contract = repository.lookup(testContract.uniqueHash)
264
+ expect(contract).toBe(testContract)
265
+ })
266
+
267
+ it('should successfully lookup by file path', () => {
268
+ const artifactPath = path.join(tempDir, 'UniqueContract.json')
269
+ const contract = repository.lookup(artifactPath)
270
+ expect(contract).not.toBeNull()
271
+ expect(contract!.contractName).toBe('UniqueContract')
272
+ })
273
+
274
+ it('should return null for non-existent references', () => {
275
+ const contract = repository.lookup('NonExistentContract')
276
+ expect(contract).toBeNull()
277
+ })
278
+
279
+ it('should throw error for ambiguous references', async () => {
280
+ // Add another contract with the same name
281
+ const artifact2Content = JSON.stringify({
282
+ contractName: 'UniqueContract',
283
+ abi: [],
284
+ bytecode: '0x608060405234801561001057600080fd5b50222222'
285
+ })
286
+ const artifact2Path = path.join(tempDir, 'other', 'UniqueContract.json')
287
+ await fs.mkdir(path.dirname(artifact2Path), { recursive: true })
288
+ await fs.writeFile(artifact2Path, artifact2Content)
289
+
290
+ // Reload to pick up the new file
291
+ repository = new ContractRepository()
292
+ await repository.loadFrom(tempDir)
293
+
294
+ expect(() => {
295
+ repository.lookup('UniqueContract')
296
+ }).toThrow(/Ambiguous contract reference/)
297
+ })
298
+ })
299
+
300
+ describe('edge cases', () => {
301
+ it('should handle directories with no contract files', async () => {
302
+ const emptyDir = path.join(tempDir, 'empty')
303
+ await fs.mkdir(emptyDir, { recursive: true })
304
+
305
+ await repository.loadFrom(emptyDir)
306
+
307
+ const contracts = repository.getAll()
308
+ expect(contracts).toHaveLength(0)
309
+ })
310
+
311
+ it('should ignore invalid JSON files', async () => {
312
+ const invalidJsonPath = path.join(tempDir, 'invalid.json')
313
+ await fs.writeFile(invalidJsonPath, 'invalid json content')
314
+
315
+ const validArtifactContent = JSON.stringify({
316
+ contractName: 'ValidContract',
317
+ abi: [],
318
+ bytecode: '0x608060405234801561001057600080fd5b50'
319
+ })
320
+ const validArtifactPath = path.join(tempDir, 'valid.json')
321
+ await fs.writeFile(validArtifactPath, validArtifactContent)
322
+
323
+ await repository.loadFrom(tempDir)
324
+
325
+ const contracts = repository.getAll()
326
+ expect(contracts).toHaveLength(1)
327
+ expect(contracts[0].contractName).toBe('ValidContract')
328
+ })
329
+
330
+ it('should ignore files that are not artifacts or build-info', async () => {
331
+ const nonArtifactContent = JSON.stringify({
332
+ name: 'not an artifact',
333
+ value: 'some data'
334
+ })
335
+ const nonArtifactPath = path.join(tempDir, 'notartifact.json')
336
+ await fs.writeFile(nonArtifactPath, nonArtifactContent)
337
+
338
+ await repository.loadFrom(tempDir)
339
+
340
+ const contracts = repository.getAll()
341
+ expect(contracts).toHaveLength(0)
342
+ })
343
+ })
344
+ })