@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,344 +0,0 @@
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
- })
@@ -1,313 +0,0 @@
1
- import * as fs from 'fs/promises'
2
- import * as path from 'path'
3
- import { createHash } from 'crypto'
4
- import { Contract } from '../types/contracts'
5
- import { parseArtifact } from '../parsers/artifact'
6
- import { parseBuildInfo, isBuildInfoFile } from '../parsers/buildinfo'
7
-
8
- export class ContractRepository {
9
- private contracts: Map<string, Contract> = new Map()
10
- private referenceMap: Map<string, string[]> = new Map()
11
- private ambiguousReferences: Set<string> = new Set()
12
-
13
- /**
14
- * Main entry point that orchestrates the discovery and hydration process
15
- */
16
- public async loadFrom(projectRoot: string): Promise<void> {
17
- // Step 1: Discover all .json files
18
- const files = await this.findContractFiles(projectRoot)
19
-
20
- // Step 2: Parse and hydrate contracts from all discovered files
21
- for (const filePath of files) {
22
- try {
23
- const content = await fs.readFile(filePath, 'utf-8')
24
- await this.parseAndHydrateFromFile(content, filePath)
25
- } catch (error) {
26
- // Silently ignore files that can't be read or parsed
27
- }
28
- }
29
-
30
- // Step 3: Build reference maps and identify ambiguous references
31
- this.disambiguateReferences()
32
- }
33
-
34
- /**
35
- * Parse a file as both artifact and build-info, then hydrate contracts
36
- */
37
- private async parseAndHydrateFromFile(content: string, filePath: string): Promise<void> {
38
- // Try parsing as build-info file first
39
- if (isBuildInfoFile(filePath)) {
40
- const extractedContracts = parseBuildInfo(content, filePath)
41
- if (extractedContracts) {
42
- for (const extracted of extractedContracts) {
43
- this.hydrateContract({
44
- creationCode: extracted.bytecode,
45
- runtimeBytecode: extracted.deployedBytecode,
46
- abi: extracted.abi,
47
- sourceName: extracted.sourceName,
48
- contractName: extracted.contractName,
49
- source: extracted.source,
50
- compiler: extracted.compiler,
51
- buildInfoId: extracted.buildInfoId,
52
- }, filePath)
53
- }
54
- return
55
- }
56
- }
57
-
58
- // Try parsing as regular artifact
59
- const parsed = parseArtifact(content, filePath)
60
- if (parsed) {
61
- this.hydrateContract({
62
- creationCode: parsed.bytecode,
63
- runtimeBytecode: parsed.deployedBytecode,
64
- abi: parsed.abi,
65
- sourceName: parsed.sourceName,
66
- contractName: parsed.contractName,
67
- source: parsed.source,
68
- compiler: parsed.compiler,
69
- }, filePath)
70
- }
71
- }
72
-
73
- /**
74
- * Hydrates a contract object with data from a source file
75
- */
76
- private hydrateContract(data: {
77
- creationCode: string
78
- runtimeBytecode?: string
79
- abi?: any[]
80
- sourceName?: string
81
- contractName?: string
82
- source?: string
83
- compiler?: any
84
- buildInfoId?: string
85
- }, sourceFilePath: string): void {
86
- // Validate that we have creation code for hashing (but allow empty string)
87
- if (data.creationCode === null || data.creationCode === undefined) {
88
- throw new Error(`Cannot hydrate contract from ${sourceFilePath}: missing creation code`)
89
- }
90
-
91
- // Calculate unique hash based on creation code
92
- const uniqueHash = createHash('sha256').update(data.creationCode).digest('hex')
93
-
94
- // Get existing contract or create new one
95
- let contract = this.contracts.get(uniqueHash)
96
- if (!contract) {
97
- contract = {
98
- uniqueHash,
99
- creationCode: data.creationCode,
100
- _sources: new Set<string>()
101
- }
102
- this.contracts.set(uniqueHash, contract)
103
- }
104
-
105
- // Add source file to tracking
106
- contract._sources.add(sourceFilePath)
107
-
108
- // Hydrate with new information - prefer more complete information
109
- // For build-info sources, prefer their data over artifact data
110
- const isFromBuildInfo = sourceFilePath.includes('/build-info/')
111
-
112
- if (data.runtimeBytecode && (!contract.runtimeBytecode || isFromBuildInfo)) {
113
- contract.runtimeBytecode = data.runtimeBytecode
114
- }
115
- if (data.abi && (!contract.abi || contract.abi.length === 0 || isFromBuildInfo)) {
116
- contract.abi = data.abi
117
- }
118
- if (data.sourceName && (!contract.sourceName || isFromBuildInfo)) {
119
- contract.sourceName = data.sourceName
120
- }
121
- if (data.contractName && (!contract.contractName || isFromBuildInfo)) {
122
- contract.contractName = data.contractName
123
- }
124
- if (data.source && (!contract.source || isFromBuildInfo)) {
125
- contract.source = data.source
126
- }
127
- if (data.compiler && (!contract.compiler || isFromBuildInfo)) {
128
- contract.compiler = data.compiler
129
- }
130
- if (data.buildInfoId && !contract.buildInfoId) {
131
- contract.buildInfoId = data.buildInfoId
132
- }
133
- }
134
-
135
- /**
136
- * Builds reference maps and identifies ambiguous references
137
- */
138
- public disambiguateReferences(): void {
139
- this.referenceMap.clear()
140
- this.ambiguousReferences.clear()
141
-
142
- // Build reference map
143
- for (const contract of this.contracts.values()) {
144
- const references: string[] = []
145
-
146
- // Add contract name reference
147
- if (contract.contractName) {
148
- references.push(contract.contractName)
149
- }
150
-
151
- // Add sourceName:contractName reference
152
- if (contract.sourceName && contract.contractName) {
153
- references.push(`${contract.sourceName}:${contract.contractName}`)
154
- }
155
-
156
- // Add file paths from sources (excluding build-info files since they can contain multiple contracts)
157
- for (const sourcePath of contract._sources) {
158
- // Skip build-info files as they legitimately contain multiple contracts
159
- if (!isBuildInfoFile(sourcePath)) {
160
- references.push(sourcePath)
161
-
162
- // Add relative paths (both forward and backward variants)
163
- const relativePath = path.relative(process.cwd(), sourcePath)
164
- if (relativePath !== sourcePath) {
165
- references.push(relativePath)
166
- }
167
- }
168
- }
169
-
170
- // For each reference, add the contract's uniqueHash to the reference map
171
- for (const ref of references) {
172
- if (!this.referenceMap.has(ref)) {
173
- this.referenceMap.set(ref, [])
174
- }
175
- if (!this.referenceMap.get(ref)!.includes(contract.uniqueHash)) {
176
- this.referenceMap.get(ref)!.push(contract.uniqueHash)
177
- }
178
- }
179
- }
180
-
181
- // Identify ambiguous references
182
- for (const [reference, hashes] of this.referenceMap.entries()) {
183
- if (hashes.length > 1) {
184
- this.ambiguousReferences.add(reference)
185
- }
186
- }
187
- }
188
-
189
- /**
190
- * Lookup a contract by reference
191
- * @param reference The contract reference string
192
- * @param contextPath Optional file path context for resolving relative paths
193
- */
194
- public lookup(reference: string, contextPath?: string): Contract | null {
195
- let resolvedReference = reference
196
-
197
- // Handle relative path resolution if contextPath is provided
198
- if (contextPath && (reference.startsWith('./') || reference.startsWith('../'))) {
199
- resolvedReference = path.resolve(path.dirname(contextPath), reference)
200
- }
201
-
202
- // Handle build-info file:contract references (e.g., "./build-info/file.json:ContractName")
203
- if (resolvedReference.includes(':')) {
204
- const colonIndex = resolvedReference.lastIndexOf(':')
205
- const filePath = resolvedReference.substring(0, colonIndex)
206
- const contractName = resolvedReference.substring(colonIndex + 1)
207
-
208
- // Check if this looks like a build-info file reference
209
- if (isBuildInfoFile(filePath)) {
210
- // Find contract that came from this specific file with this specific contract name
211
- for (const contract of this.contracts.values()) {
212
- if (contract.contractName === contractName && contract._sources.has(filePath)) {
213
- return contract
214
- }
215
- }
216
- // If not found, return null (will be handled by the error in resolver)
217
- return null
218
- }
219
- }
220
-
221
- // Check if reference is ambiguous
222
- if (this.ambiguousReferences.has(resolvedReference)) {
223
- const hashes = this.referenceMap.get(resolvedReference) || []
224
- const conflictingSources = hashes.map(hash => {
225
- const contract = this.contracts.get(hash)
226
- return contract ? Array.from(contract._sources).join(', ') : 'unknown'
227
- })
228
- throw new Error(`Ambiguous contract reference "${resolvedReference}". Found in multiple contracts: ${conflictingSources.join(' | ')}`)
229
- }
230
-
231
- // Check if it's a direct unique hash
232
- if (this.contracts.has(resolvedReference)) {
233
- return this.contracts.get(resolvedReference)!
234
- }
235
-
236
- // Look up in reference map
237
- const hashes = this.referenceMap.get(resolvedReference)
238
- if (hashes && hashes.length === 1) {
239
- return this.contracts.get(hashes[0]) || null
240
- }
241
-
242
- return null
243
- }
244
-
245
- /**
246
- * Get all contracts in the repository
247
- */
248
- public getAll(): Contract[] {
249
- return Array.from(this.contracts.values())
250
- }
251
-
252
- /**
253
- * Get all ambiguous references
254
- */
255
- public getAmbiguousReferences(): string[] {
256
- return Array.from(this.ambiguousReferences)
257
- }
258
-
259
- /**
260
- * Add a contract directly to the repository (for testing purposes)
261
- * @param contractData - Contract data in the old Artifact format for compatibility
262
- */
263
- public addForTesting(contractData: {
264
- contractName: string
265
- abi: any[]
266
- bytecode: string
267
- deployedBytecode?: string
268
- sourceName?: string
269
- source?: string
270
- compiler?: any
271
- buildInfoId?: string
272
- _path: string
273
- _hash: string
274
- }): void {
275
- this.hydrateContract({
276
- creationCode: contractData.bytecode,
277
- runtimeBytecode: contractData.deployedBytecode,
278
- abi: contractData.abi,
279
- sourceName: contractData.sourceName,
280
- contractName: contractData.contractName,
281
- source: contractData.source,
282
- compiler: contractData.compiler,
283
- buildInfoId: contractData.buildInfoId,
284
- }, contractData._path)
285
-
286
- // For testing, immediately disambiguate references after adding
287
- this.disambiguateReferences()
288
- }
289
-
290
- /**
291
- * Recursively finds all files that might contain contracts (e.g., .json files)
292
- */
293
- private async findContractFiles(dir: string, ignoreDirs: Set<string> = new Set(['node_modules', 'dist', '.git', '.idea', '.vscode'])): Promise<string[]> {
294
- let results: string[] = []
295
- try {
296
- const list = await fs.readdir(dir, { withFileTypes: true })
297
-
298
- for (const dirent of list) {
299
- const fullPath = path.resolve(dir, dirent.name)
300
- if (dirent.isDirectory()) {
301
- if (!ignoreDirs.has(dirent.name)) {
302
- results = results.concat(await this.findContractFiles(fullPath, ignoreDirs))
303
- }
304
- } else if (dirent.isFile() && dirent.name.endsWith('.json')) {
305
- results.push(fullPath)
306
- }
307
- }
308
- } catch (err) {
309
- // Ignore errors from trying to read directories we don't have access to
310
- }
311
- return results
312
- }
313
- }
@@ -1,37 +0,0 @@
1
- import { ethers } from 'ethers'
2
- import { ExecutionContext } from '../context'
3
- import { Network } from '../../types'
4
-
5
- describe('ExecutionContext', () => {
6
- const network: Network = {
7
- name: 'test',
8
- chainId: 31337,
9
- rpcUrl: 'http://127.0.0.1:8545'
10
- }
11
-
12
- const contractRepository = {} as any
13
-
14
- it('wraps private-key signers in a NonceManager', async () => {
15
- const context = new ExecutionContext(
16
- network,
17
- '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
18
- contractRepository
19
- )
20
-
21
- const signer = await context.getResolvedSigner()
22
- expect(signer).toBeInstanceOf(ethers.NonceManager)
23
- })
24
-
25
- it('wraps promised signers in a NonceManager when first resolved', async () => {
26
- const getSignerSpy = jest.spyOn(ethers.JsonRpcProvider.prototype, 'getSigner')
27
- getSignerSpy.mockResolvedValue(
28
- ethers.Wallet.createRandom().connect(new ethers.JsonRpcProvider(network.rpcUrl)) as any
29
- )
30
-
31
- const context = new ExecutionContext(network, undefined, contractRepository)
32
-
33
- await expect(context.getResolvedSigner()).resolves.toBeInstanceOf(ethers.NonceManager)
34
-
35
- getSignerSpy.mockRestore()
36
- })
37
- })