@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.
- package/.eslintrc.json +29 -0
- package/.github/workflows/ci.yml +181 -0
- package/CONCEPT.md +24 -0
- package/README.md +772 -0
- package/contracts/checked-call.huff +65 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/common.d.ts +11 -0
- package/dist/commands/common.d.ts.map +1 -0
- package/dist/commands/common.js +73 -0
- package/dist/commands/common.js.map +1 -0
- package/dist/commands/dry.d.ts +3 -0
- package/dist/commands/dry.d.ts.map +1 -0
- package/dist/commands/dry.js +171 -0
- package/dist/commands/dry.js.map +1 -0
- package/dist/commands/etherscan.d.ts +3 -0
- package/dist/commands/etherscan.d.ts.map +1 -0
- package/dist/commands/etherscan.js +323 -0
- package/dist/commands/etherscan.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +22 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +259 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +96 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/utils.d.ts +3 -0
- package/dist/commands/utils.d.ts.map +1 -0
- package/dist/commands/utils.js +46 -0
- package/dist/commands/utils.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/__tests__/deployer-events.spec.d.ts +2 -0
- package/dist/lib/__tests__/deployer-events.spec.d.ts.map +1 -0
- package/dist/lib/__tests__/deployer-events.spec.js +260 -0
- package/dist/lib/__tests__/deployer-events.spec.js.map +1 -0
- package/dist/lib/__tests__/deployer.spec.d.ts +2 -0
- package/dist/lib/__tests__/deployer.spec.d.ts.map +1 -0
- package/dist/lib/__tests__/deployer.spec.js +884 -0
- package/dist/lib/__tests__/deployer.spec.js.map +1 -0
- package/dist/lib/__tests__/network-utils.spec.d.ts +2 -0
- package/dist/lib/__tests__/network-utils.spec.d.ts.map +1 -0
- package/dist/lib/__tests__/network-utils.spec.js +140 -0
- package/dist/lib/__tests__/network-utils.spec.js.map +1 -0
- package/dist/lib/contracts/__tests__/repository.spec.d.ts +2 -0
- package/dist/lib/contracts/__tests__/repository.spec.d.ts.map +1 -0
- package/dist/lib/contracts/__tests__/repository.spec.js +321 -0
- package/dist/lib/contracts/__tests__/repository.spec.js.map +1 -0
- package/dist/lib/contracts/repository.d.ts +27 -0
- package/dist/lib/contracts/repository.d.ts.map +1 -0
- package/dist/lib/contracts/repository.js +241 -0
- package/dist/lib/contracts/repository.js.map +1 -0
- package/dist/lib/core/__tests__/engine.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/engine.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/engine.spec.js +1212 -0
- package/dist/lib/core/__tests__/engine.spec.js.map +1 -0
- package/dist/lib/core/__tests__/graph.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/graph.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/graph.spec.js +116 -0
- package/dist/lib/core/__tests__/graph.spec.js.map +1 -0
- package/dist/lib/core/__tests__/json-integration.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/json-integration.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/json-integration.spec.js +300 -0
- package/dist/lib/core/__tests__/json-integration.spec.js.map +1 -0
- package/dist/lib/core/__tests__/loader.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/loader.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/loader.spec.js +288 -0
- package/dist/lib/core/__tests__/loader.spec.js.map +1 -0
- package/dist/lib/core/__tests__/multi-platform-verification.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/multi-platform-verification.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/multi-platform-verification.spec.js +342 -0
- package/dist/lib/core/__tests__/multi-platform-verification.spec.js.map +1 -0
- package/dist/lib/core/__tests__/resolver.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/resolver.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/resolver.spec.js +1367 -0
- package/dist/lib/core/__tests__/resolver.spec.js.map +1 -0
- package/dist/lib/core/__tests__/static-action.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/static-action.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/static-action.spec.js +136 -0
- package/dist/lib/core/__tests__/static-action.spec.js.map +1 -0
- package/dist/lib/core/context.d.ts +29 -0
- package/dist/lib/core/context.d.ts.map +1 -0
- package/dist/lib/core/context.js +88 -0
- package/dist/lib/core/context.js.map +1 -0
- package/dist/lib/core/engine.d.ts +25 -0
- package/dist/lib/core/engine.d.ts.map +1 -0
- package/dist/lib/core/engine.js +1191 -0
- package/dist/lib/core/engine.js.map +1 -0
- package/dist/lib/core/graph.d.ts +18 -0
- package/dist/lib/core/graph.d.ts.map +1 -0
- package/dist/lib/core/graph.js +158 -0
- package/dist/lib/core/graph.js.map +1 -0
- package/dist/lib/core/loader.d.ts +25 -0
- package/dist/lib/core/loader.d.ts.map +1 -0
- package/dist/lib/core/loader.js +248 -0
- package/dist/lib/core/loader.js.map +1 -0
- package/dist/lib/core/resolver.d.ts +20 -0
- package/dist/lib/core/resolver.d.ts.map +1 -0
- package/dist/lib/core/resolver.js +307 -0
- package/dist/lib/core/resolver.js.map +1 -0
- package/dist/lib/deployer.d.ts +39 -0
- package/dist/lib/deployer.d.ts.map +1 -0
- package/dist/lib/deployer.js +533 -0
- package/dist/lib/deployer.js.map +1 -0
- package/dist/lib/events/__tests__/event-system.spec.d.ts +2 -0
- package/dist/lib/events/__tests__/event-system.spec.d.ts.map +1 -0
- package/dist/lib/events/__tests__/event-system.spec.js +256 -0
- package/dist/lib/events/__tests__/event-system.spec.js.map +1 -0
- package/dist/lib/events/cli-adapter.d.ts +13 -0
- package/dist/lib/events/cli-adapter.d.ts.map +1 -0
- package/dist/lib/events/cli-adapter.js +244 -0
- package/dist/lib/events/cli-adapter.js.map +1 -0
- package/dist/lib/events/emitter.d.ts +11 -0
- package/dist/lib/events/emitter.d.ts.map +1 -0
- package/dist/lib/events/emitter.js +29 -0
- package/dist/lib/events/emitter.js.map +1 -0
- package/dist/lib/events/index.d.ts +4 -0
- package/dist/lib/events/index.d.ts.map +1 -0
- package/dist/lib/events/index.js +20 -0
- package/dist/lib/events/index.js.map +1 -0
- package/dist/lib/events/types.d.ts +368 -0
- package/dist/lib/events/types.d.ts.map +1 -0
- package/dist/lib/events/types.js +3 -0
- package/dist/lib/events/types.js.map +1 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +44 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/network-loader.d.ts +3 -0
- package/dist/lib/network-loader.d.ts.map +1 -0
- package/dist/lib/network-loader.js +80 -0
- package/dist/lib/network-loader.js.map +1 -0
- package/dist/lib/network-match.d.ts +3 -0
- package/dist/lib/network-match.d.ts.map +1 -0
- package/dist/lib/network-match.js +62 -0
- package/dist/lib/network-match.js.map +1 -0
- package/dist/lib/network-utils.d.ts +4 -0
- package/dist/lib/network-utils.d.ts.map +1 -0
- package/dist/lib/network-utils.js +39 -0
- package/dist/lib/network-utils.js.map +1 -0
- package/dist/lib/parsers/__tests__/buildinfo.spec.d.ts +2 -0
- package/dist/lib/parsers/__tests__/buildinfo.spec.d.ts.map +1 -0
- package/dist/lib/parsers/__tests__/buildinfo.spec.js +132 -0
- package/dist/lib/parsers/__tests__/buildinfo.spec.js.map +1 -0
- package/dist/lib/parsers/__tests__/job.spec.d.ts +2 -0
- package/dist/lib/parsers/__tests__/job.spec.d.ts.map +1 -0
- package/dist/lib/parsers/__tests__/job.spec.js +318 -0
- package/dist/lib/parsers/__tests__/job.spec.js.map +1 -0
- package/dist/lib/parsers/__tests__/template.spec.d.ts +2 -0
- package/dist/lib/parsers/__tests__/template.spec.d.ts.map +1 -0
- package/dist/lib/parsers/__tests__/template.spec.js +126 -0
- package/dist/lib/parsers/__tests__/template.spec.js.map +1 -0
- package/dist/lib/parsers/artifact/__tests__/artifact.spec.d.ts +2 -0
- package/dist/lib/parsers/artifact/__tests__/artifact.spec.d.ts.map +1 -0
- package/dist/lib/parsers/artifact/__tests__/artifact.spec.js +128 -0
- package/dist/lib/parsers/artifact/__tests__/artifact.spec.js.map +1 -0
- package/dist/lib/parsers/artifact/foundry-1.2.d.ts +3 -0
- package/dist/lib/parsers/artifact/foundry-1.2.d.ts.map +1 -0
- package/dist/lib/parsers/artifact/foundry-1.2.js +82 -0
- package/dist/lib/parsers/artifact/foundry-1.2.js.map +1 -0
- package/dist/lib/parsers/artifact/index.d.ts +3 -0
- package/dist/lib/parsers/artifact/index.d.ts.map +1 -0
- package/dist/lib/parsers/artifact/index.js +17 -0
- package/dist/lib/parsers/artifact/index.js.map +1 -0
- package/dist/lib/parsers/artifact/types.d.ts +3 -0
- package/dist/lib/parsers/artifact/types.d.ts.map +1 -0
- package/dist/lib/parsers/artifact/types.js +3 -0
- package/dist/lib/parsers/artifact/types.js.map +1 -0
- package/dist/lib/parsers/buildinfo.d.ts +5 -0
- package/dist/lib/parsers/buildinfo.d.ts.map +1 -0
- package/dist/lib/parsers/buildinfo.js +85 -0
- package/dist/lib/parsers/buildinfo.js.map +1 -0
- package/dist/lib/parsers/constants.d.ts +4 -0
- package/dist/lib/parsers/constants.d.ts.map +1 -0
- package/dist/lib/parsers/constants.js +45 -0
- package/dist/lib/parsers/constants.js.map +1 -0
- package/dist/lib/parsers/index.d.ts +5 -0
- package/dist/lib/parsers/index.d.ts.map +1 -0
- package/dist/lib/parsers/index.js +21 -0
- package/dist/lib/parsers/index.js.map +1 -0
- package/dist/lib/parsers/job.d.ts +3 -0
- package/dist/lib/parsers/job.d.ts.map +1 -0
- package/dist/lib/parsers/job.js +74 -0
- package/dist/lib/parsers/job.js.map +1 -0
- package/dist/lib/parsers/template.d.ts +3 -0
- package/dist/lib/parsers/template.d.ts.map +1 -0
- package/dist/lib/parsers/template.js +91 -0
- package/dist/lib/parsers/template.js.map +1 -0
- package/dist/lib/std/templates/assured-deployment.yaml +45 -0
- package/dist/lib/std/templates/erc-2470.yaml +67 -0
- package/dist/lib/std/templates/min-balance.yaml +32 -0
- package/dist/lib/std/templates/nano-universal-deployer.yaml +59 -0
- package/dist/lib/std/templates/raw-erc-2470.yaml +59 -0
- package/dist/lib/std/templates/raw-nano-universal-deployer.yaml +51 -0
- package/dist/lib/std/templates/raw-sequence-universal-deployer-2.yaml +48 -0
- package/dist/lib/std/templates/sequence-universal-deployer-2.yaml +57 -0
- package/dist/lib/types/__tests__/json-request-action.spec.d.ts +2 -0
- package/dist/lib/types/__tests__/json-request-action.spec.d.ts.map +1 -0
- package/dist/lib/types/__tests__/json-request-action.spec.js +219 -0
- package/dist/lib/types/__tests__/json-request-action.spec.js.map +1 -0
- package/dist/lib/types/__tests__/read-json-value.spec.d.ts +2 -0
- package/dist/lib/types/__tests__/read-json-value.spec.d.ts.map +1 -0
- package/dist/lib/types/__tests__/read-json-value.spec.js +233 -0
- package/dist/lib/types/__tests__/read-json-value.spec.js.map +1 -0
- package/dist/lib/types/actions.d.ts +74 -0
- package/dist/lib/types/actions.d.ts.map +1 -0
- package/dist/lib/types/actions.js +18 -0
- package/dist/lib/types/actions.js.map +1 -0
- package/dist/lib/types/artifacts.d.ts +15 -0
- package/dist/lib/types/artifacts.d.ts.map +1 -0
- package/dist/lib/types/artifacts.js +3 -0
- package/dist/lib/types/artifacts.js.map +1 -0
- package/dist/lib/types/buildinfo.d.ts +112 -0
- package/dist/lib/types/buildinfo.d.ts.map +1 -0
- package/dist/lib/types/buildinfo.js +3 -0
- package/dist/lib/types/buildinfo.js.map +1 -0
- package/dist/lib/types/conditions.d.ts +17 -0
- package/dist/lib/types/conditions.d.ts.map +1 -0
- package/dist/lib/types/conditions.js +21 -0
- package/dist/lib/types/conditions.js.map +1 -0
- package/dist/lib/types/contracts.d.ts +14 -0
- package/dist/lib/types/contracts.d.ts.map +1 -0
- package/dist/lib/types/contracts.js +3 -0
- package/dist/lib/types/contracts.js.map +1 -0
- package/dist/lib/types/definitions.d.ts +51 -0
- package/dist/lib/types/definitions.d.ts.map +1 -0
- package/dist/lib/types/definitions.js +3 -0
- package/dist/lib/types/definitions.js.map +1 -0
- package/dist/lib/types/index.d.ts +9 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/dist/lib/types/index.js +25 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/lib/types/network.d.ts +9 -0
- package/dist/lib/types/network.d.ts.map +1 -0
- package/dist/lib/types/network.js +3 -0
- package/dist/lib/types/network.js.map +1 -0
- package/dist/lib/types/project.d.ts +5 -0
- package/dist/lib/types/project.d.ts.map +1 -0
- package/dist/lib/types/project.js +3 -0
- package/dist/lib/types/project.js.map +1 -0
- package/dist/lib/types/task.d.ts +9 -0
- package/dist/lib/types/task.d.ts.map +1 -0
- package/dist/lib/types/task.js +3 -0
- package/dist/lib/types/task.js.map +1 -0
- package/dist/lib/types/values.d.ts +78 -0
- package/dist/lib/types/values.d.ts.map +1 -0
- package/dist/lib/types/values.js +3 -0
- package/dist/lib/types/values.js.map +1 -0
- package/dist/lib/utils/validation.d.ts +5 -0
- package/dist/lib/utils/validation.d.ts.map +1 -0
- package/dist/lib/utils/validation.js +77 -0
- package/dist/lib/utils/validation.js.map +1 -0
- package/dist/lib/validation/contract-references.d.ts +12 -0
- package/dist/lib/validation/contract-references.d.ts.map +1 -0
- package/dist/lib/validation/contract-references.js +112 -0
- package/dist/lib/validation/contract-references.js.map +1 -0
- package/dist/lib/validation/index.d.ts +1 -0
- package/dist/lib/validation/index.d.ts.map +1 -0
- package/dist/lib/validation/index.js +2 -0
- package/dist/lib/validation/index.js.map +1 -0
- package/dist/lib/verification/__tests__/etherscan.spec.d.ts +2 -0
- package/dist/lib/verification/__tests__/etherscan.spec.d.ts.map +1 -0
- package/dist/lib/verification/__tests__/etherscan.spec.js +565 -0
- package/dist/lib/verification/__tests__/etherscan.spec.js.map +1 -0
- package/dist/lib/verification/__tests__/sourcify.spec.d.ts +2 -0
- package/dist/lib/verification/__tests__/sourcify.spec.d.ts.map +1 -0
- package/dist/lib/verification/__tests__/sourcify.spec.js +212 -0
- package/dist/lib/verification/__tests__/sourcify.spec.js.map +1 -0
- package/dist/lib/verification/etherscan.d.ts +56 -0
- package/dist/lib/verification/etherscan.d.ts.map +1 -0
- package/dist/lib/verification/etherscan.js +340 -0
- package/dist/lib/verification/etherscan.js.map +1 -0
- package/dist/lib/verification/sourcify.d.ts +12 -0
- package/dist/lib/verification/sourcify.d.ts.map +1 -0
- package/dist/lib/verification/sourcify.js +227 -0
- package/dist/lib/verification/sourcify.js.map +1 -0
- package/eslint.config.js +48 -0
- package/examples/jobs/guards-v1.yaml +17 -0
- package/examples/jobs/sequence-seq-0001-patch.yaml +59 -0
- package/examples/jobs/sequence-v1.yaml +59 -0
- package/examples/templates/sequence-factory-v1.yaml +56 -0
- package/jest.config.js +25 -0
- package/package.json +68 -0
- package/src/cli.ts +17 -0
- package/src/commands/common.ts +61 -0
- package/src/commands/dry.ts +208 -0
- package/src/commands/etherscan.ts +360 -0
- package/src/commands/index.ts +5 -0
- package/src/commands/list.ts +249 -0
- package/src/commands/run.ts +136 -0
- package/src/commands/utils.ts +52 -0
- package/src/index.ts +67 -0
- package/src/lib/__tests__/deployer-events.spec.ts +338 -0
- package/src/lib/__tests__/deployer.spec.ts +1204 -0
- package/src/lib/__tests__/network-utils.spec.ts +181 -0
- package/src/lib/artifacts/__tests__/fixtures/contract1.json +19 -0
- package/src/lib/artifacts/__tests__/fixtures/contract2.json +19 -0
- package/src/lib/artifacts/__tests__/fixtures/duplicate-name.json +19 -0
- package/src/lib/artifacts/__tests__/fixtures/nested/nested-contract.json +18 -0
- package/src/lib/artifacts/__tests__/fixtures/not-an-artifact.json +8 -0
- package/src/lib/artifacts/__tests__/fixtures/readme.txt +2 -0
- package/src/lib/contracts/__tests__/repository.spec.ts +344 -0
- package/src/lib/contracts/repository.ts +313 -0
- package/src/lib/core/__tests__/engine.spec.ts +1514 -0
- package/src/lib/core/__tests__/graph.spec.ts +125 -0
- package/src/lib/core/__tests__/json-integration.spec.ts +360 -0
- package/src/lib/core/__tests__/loader.spec.ts +334 -0
- package/src/lib/core/__tests__/multi-platform-verification.spec.ts +406 -0
- package/src/lib/core/__tests__/resolver.spec.ts +1693 -0
- package/src/lib/core/__tests__/static-action.spec.ts +172 -0
- package/src/lib/core/context.ts +127 -0
- package/src/lib/core/engine.ts +1531 -0
- package/src/lib/core/graph.ts +252 -0
- package/src/lib/core/loader.ts +263 -0
- package/src/lib/core/resolver.ts +498 -0
- package/src/lib/deployer.ts +768 -0
- package/src/lib/events/__tests__/event-system.spec.ts +343 -0
- package/src/lib/events/cli-adapter.ts +325 -0
- package/src/lib/events/emitter.ts +62 -0
- package/src/lib/events/index.ts +3 -0
- package/src/lib/events/types.ts +469 -0
- package/src/lib/index.ts +14 -0
- package/src/lib/network-loader.ts +59 -0
- package/src/lib/network-utils.ts +64 -0
- package/src/lib/parsers/__tests__/buildinfo.spec.ts +122 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-bytecode-buildinfo.json +62 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/invalid-json.txt +2 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/multi-contract-buildinfo.json +89 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/no-contracts-buildinfo.json +17 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/simple-buildinfo.json +63 -0
- package/src/lib/parsers/__tests__/fixtures/buildinfo/wrong-format.json +4 -0
- package/src/lib/parsers/__tests__/job.spec.ts +335 -0
- package/src/lib/parsers/__tests__/template.spec.ts +111 -0
- package/src/lib/parsers/artifact/__tests__/artifact.spec.ts +117 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/empty-bytecode.json +5 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/hardhat-artifact.json +67 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/invalid-bytecode.json +5 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/invalid-json.txt +11 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/minimal-artifact.json +5 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/missing-abi.json +4 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/missing-bytecode.json +11 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/missing-contract-name.json +11 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/simple-artifact.json +40 -0
- package/src/lib/parsers/artifact/__tests__/fixtures/wrong-types.json +7 -0
- package/src/lib/parsers/artifact/foundry-1.2.ts +72 -0
- package/src/lib/parsers/artifact/index.ts +27 -0
- package/src/lib/parsers/artifact/types.ts +9 -0
- package/src/lib/parsers/buildinfo.ts +127 -0
- package/src/lib/parsers/constants.ts +56 -0
- package/src/lib/parsers/index.ts +5 -0
- package/src/lib/parsers/job.ts +101 -0
- package/src/lib/parsers/template.ts +131 -0
- package/src/lib/std/templates/assured-deployment.yaml +45 -0
- package/src/lib/std/templates/erc-2470.yaml +67 -0
- package/src/lib/std/templates/min-balance.yaml +32 -0
- package/src/lib/std/templates/nano-universal-deployer.yaml +59 -0
- package/src/lib/std/templates/raw-erc-2470.yaml +59 -0
- package/src/lib/std/templates/raw-nano-universal-deployer.yaml +51 -0
- package/src/lib/std/templates/raw-sequence-universal-deployer-2.yaml +48 -0
- package/src/lib/std/templates/sequence-universal-deployer-2.yaml +57 -0
- package/src/lib/types/__tests__/json-request-action.spec.ts +243 -0
- package/src/lib/types/__tests__/read-json-value.spec.ts +264 -0
- package/src/lib/types/actions.ts +127 -0
- package/src/lib/types/artifacts.ts +21 -0
- package/src/lib/types/buildinfo.ts +116 -0
- package/src/lib/types/conditions.ts +50 -0
- package/src/lib/types/contracts.ts +23 -0
- package/src/lib/types/definitions.ts +68 -0
- package/src/lib/types/index.ts +8 -0
- package/src/lib/types/network.ts +22 -0
- package/src/lib/types/project.ts +9 -0
- package/src/lib/types/task.ts +9 -0
- package/src/lib/types/values.ts +116 -0
- package/src/lib/utils/validation.ts +116 -0
- package/src/lib/validation/contract-references.ts +210 -0
- package/src/lib/validation/index.ts +1 -0
- package/src/lib/verification/__tests__/etherscan.spec.ts +710 -0
- package/src/lib/verification/__tests__/sourcify.spec.ts +288 -0
- package/src/lib/verification/etherscan.ts +546 -0
- package/src/lib/verification/sourcify.ts +248 -0
- package/test_validation/artifacts/TestContract.json +9 -0
- package/test_validation/jobs/test-missing.yaml +16 -0
- package/test_validation/networks.yaml +3 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { loadProject } from './common'
|
|
4
|
+
import { loadNetworks } from '../lib/network-loader'
|
|
5
|
+
import { DependencyGraph } from '../lib/core/graph'
|
|
6
|
+
import { projectOption, noStdOption, verbosityOption } from './common'
|
|
7
|
+
import { validateContractReferences, extractUsedContractReferences } from '../lib/validation/contract-references'
|
|
8
|
+
import { setVerbosity } from '../index'
|
|
9
|
+
import { Template } from '../lib/types'
|
|
10
|
+
|
|
11
|
+
interface DryRunOptions {
|
|
12
|
+
project: string
|
|
13
|
+
std: boolean
|
|
14
|
+
network?: string[]
|
|
15
|
+
verbose: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Extract only constant-like placeholders from a value, using template metadata when available.
|
|
20
|
+
* A placeholder is treated as a constant candidate if:
|
|
21
|
+
* - It is a bare identifier (no dot, no parentheses), AND
|
|
22
|
+
* - It is NOT declared as a template argument in the current template (when template context provided)
|
|
23
|
+
*/
|
|
24
|
+
function extractConstantRefs(value: unknown, refs: string[], templateCtx?: Template) {
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
const m = value.match(/^{{(.*)}}$/)
|
|
27
|
+
if (m) {
|
|
28
|
+
const expr = m[1].trim()
|
|
29
|
+
|
|
30
|
+
// Skip outputs or function-like references
|
|
31
|
+
if (expr.includes('.') || expr.includes('(') || expr.includes(')')) return
|
|
32
|
+
|
|
33
|
+
// If we have a template context, and the expr matches a declared argument, it's NOT a constant
|
|
34
|
+
if (templateCtx?.arguments && Object.prototype.hasOwnProperty.call(templateCtx.arguments, expr)) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Otherwise, treat as a constant candidate
|
|
39
|
+
refs.push(expr)
|
|
40
|
+
}
|
|
41
|
+
} else if (Array.isArray(value)) {
|
|
42
|
+
for (const v of value) extractConstantRefs(v, refs, templateCtx)
|
|
43
|
+
} else if (value && typeof value === 'object') {
|
|
44
|
+
for (const v of Object.values(value)) extractConstantRefs(v, refs, templateCtx)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function makeDryRunCommand(): Command {
|
|
49
|
+
const dryRun = new Command('dry-run')
|
|
50
|
+
.description('Validate project configuration and show execution plan without running transactions')
|
|
51
|
+
.argument('[jobs...]', 'Specific job names to validate (and their dependencies).')
|
|
52
|
+
.option('-n, --network <chainIds...>', 'One or more network chain IDs to simulate running on.')
|
|
53
|
+
|
|
54
|
+
projectOption(dryRun)
|
|
55
|
+
noStdOption(dryRun)
|
|
56
|
+
verbosityOption(dryRun)
|
|
57
|
+
|
|
58
|
+
dryRun.action(async (jobs: string[], options: DryRunOptions) => {
|
|
59
|
+
try {
|
|
60
|
+
// Set verbosity level for logging
|
|
61
|
+
setVerbosity(options.verbose as 0 | 1 | 2 | 3)
|
|
62
|
+
|
|
63
|
+
console.log(chalk.bold.inverse(' DRY-RUN MODE '))
|
|
64
|
+
const projectRoot = options.project
|
|
65
|
+
const loader = await loadProject(projectRoot, {
|
|
66
|
+
loadStdTemplates: options.std !== false
|
|
67
|
+
})
|
|
68
|
+
const allNetworks = await loadNetworks(projectRoot)
|
|
69
|
+
|
|
70
|
+
console.log(chalk.blue('\nBuilding dependency graph...'))
|
|
71
|
+
const graph = new DependencyGraph(loader.jobs, loader.templates)
|
|
72
|
+
const fullOrder = graph.getExecutionOrder()
|
|
73
|
+
console.log(chalk.green(' - Dependency graph built successfully.'))
|
|
74
|
+
|
|
75
|
+
console.log(chalk.blue('\nContract Repository:'))
|
|
76
|
+
console.log(chalk.green(` - Found ${loader.contractRepository.getAll().length} unique contracts.`))
|
|
77
|
+
|
|
78
|
+
// Check for ambiguous references that are actually being used
|
|
79
|
+
const usedRefs = await extractUsedContractReferences(loader)
|
|
80
|
+
const allAmbiguousRefs = loader.contractRepository.getAmbiguousReferences()
|
|
81
|
+
const usedRefNames = usedRefs.map(ref => ref.reference)
|
|
82
|
+
const usedAmbiguousRefs = allAmbiguousRefs.filter(ref => usedRefNames.includes(ref))
|
|
83
|
+
|
|
84
|
+
if (usedAmbiguousRefs.length > 0) {
|
|
85
|
+
console.log(chalk.red('\n - Found ambiguous contract references being used:'))
|
|
86
|
+
for (const ref of usedAmbiguousRefs) {
|
|
87
|
+
console.log(chalk.red(` ✗ "${ref}" could refer to multiple contracts`))
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Found ${usedAmbiguousRefs.length} ambiguous contract reference(s) being used. Please use more specific references to resolve ambiguity.`)
|
|
90
|
+
}
|
|
91
|
+
console.log(chalk.green(' - All used contract references are unambiguous.'))
|
|
92
|
+
|
|
93
|
+
// Validate that all Contract() references point to existing contracts
|
|
94
|
+
console.log(chalk.blue('\nValidating contract references...'))
|
|
95
|
+
const missingRefs = await validateContractReferences(loader)
|
|
96
|
+
if (missingRefs.length > 0) {
|
|
97
|
+
console.log(chalk.red('\n - Found missing contract references:'))
|
|
98
|
+
for (const ref of missingRefs) {
|
|
99
|
+
console.log(chalk.red(` ✗ ${ref.reference} in ${ref.location}`))
|
|
100
|
+
}
|
|
101
|
+
throw new Error(`Found ${missingRefs.length} missing contract reference(s). Please ensure all referenced contracts exist.`)
|
|
102
|
+
}
|
|
103
|
+
console.log(chalk.green(' - All contract references are valid.'))
|
|
104
|
+
|
|
105
|
+
// Validate constant references exist
|
|
106
|
+
console.log(chalk.blue('\nValidating constant references...'))
|
|
107
|
+
const topLevelConstants = loader.constants
|
|
108
|
+
const missingConstantRefs: Array<{ ref: string; location: string }> = []
|
|
109
|
+
|
|
110
|
+
// Check jobs (arguments and outputs within templates are resolved at runtime; here we just check expressions)
|
|
111
|
+
for (const [jobName, job] of loader.jobs.entries()) {
|
|
112
|
+
// Collect refs in job actions
|
|
113
|
+
for (let i = 0; i < job.actions.length; i++) {
|
|
114
|
+
const action = job.actions[i]
|
|
115
|
+
const refs: string[] = []
|
|
116
|
+
extractConstantRefs(action.arguments, refs)
|
|
117
|
+
const jobConstants = job.constants || {}
|
|
118
|
+
for (const r of refs) {
|
|
119
|
+
if (!(r in jobConstants) && !topLevelConstants.has(r)) {
|
|
120
|
+
missingConstantRefs.push({ ref: r, location: `job '${jobName}', action ${i + 1}${action.name ? ` '${action.name}'` : ''}` })
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Check templates (setup/actions/outputs)
|
|
127
|
+
for (const [templateName, template] of loader.templates.entries()) {
|
|
128
|
+
// actions
|
|
129
|
+
for (let i = 0; i < template.actions.length; i++) {
|
|
130
|
+
const action = template.actions[i]
|
|
131
|
+
const refs: string[] = []
|
|
132
|
+
extractConstantRefs(action.arguments, refs, template)
|
|
133
|
+
for (const r of refs) {
|
|
134
|
+
if (!topLevelConstants.has(r)) {
|
|
135
|
+
missingConstantRefs.push({ ref: r, location: `template '${templateName}', action ${i + 1}${action.name ? ` '${action.name}'` : ''}` })
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// setup actions
|
|
140
|
+
if (template.setup?.actions) {
|
|
141
|
+
for (let i = 0; i < (template.setup.actions?.length || 0); i++) {
|
|
142
|
+
const action = template.setup.actions![i]
|
|
143
|
+
const refs: string[] = []
|
|
144
|
+
extractConstantRefs(action.arguments, refs, template)
|
|
145
|
+
for (const r of refs) {
|
|
146
|
+
if (!topLevelConstants.has(r)) {
|
|
147
|
+
missingConstantRefs.push({ ref: r, location: `template '${templateName}' setup, action ${i + 1}${action.name ? ` '${action.name}'` : ''}` })
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// outputs
|
|
153
|
+
if (template.outputs) {
|
|
154
|
+
const refs: string[] = []
|
|
155
|
+
extractConstantRefs(template.outputs, refs, template)
|
|
156
|
+
for (const r of refs) {
|
|
157
|
+
if (!topLevelConstants.has(r)) {
|
|
158
|
+
missingConstantRefs.push({ ref: r, location: `template '${templateName}' outputs` })
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (missingConstantRefs.length > 0) {
|
|
165
|
+
console.log(chalk.red('\n - Found missing constant references:'))
|
|
166
|
+
for (const m of missingConstantRefs) {
|
|
167
|
+
console.log(chalk.red(` ✗ ${m.ref} in ${m.location}`))
|
|
168
|
+
}
|
|
169
|
+
throw new Error(`Found ${missingConstantRefs.length} missing constant reference(s). Ensure they are defined at top-level or in the job's constants.`)
|
|
170
|
+
}
|
|
171
|
+
console.log(chalk.green(' - All constant references are valid.'))
|
|
172
|
+
|
|
173
|
+
const runJobs = jobs.length > 0 ? jobs : undefined
|
|
174
|
+
const runOnNetworks = options.network?.map(Number)
|
|
175
|
+
|
|
176
|
+
const jobsToRun = new Set<string>()
|
|
177
|
+
if (runJobs) {
|
|
178
|
+
for (const jobName of runJobs) {
|
|
179
|
+
if (!loader.jobs.has(jobName)) {
|
|
180
|
+
throw new Error(`Specified job "${jobName}" not found in project.`)
|
|
181
|
+
}
|
|
182
|
+
jobsToRun.add(jobName)
|
|
183
|
+
graph.getDependencies(jobName).forEach(dep => jobsToRun.add(dep))
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
fullOrder.forEach(j => jobsToRun.add(j))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const jobExecutionPlan = fullOrder.filter(jobName => jobsToRun.has(jobName))
|
|
190
|
+
const targetNetworks = runOnNetworks
|
|
191
|
+
? allNetworks.filter(n => runOnNetworks.includes(n.chainId))
|
|
192
|
+
: allNetworks
|
|
193
|
+
|
|
194
|
+
console.log(chalk.blue('\nExecution Plan:'))
|
|
195
|
+
console.log(chalk.gray(` - Target Networks: ${targetNetworks.map(n => `${n.name} (ChainID: ${n.chainId})`).join(', ')}`))
|
|
196
|
+
console.log(chalk.gray(` - Job Execution Order: ${jobExecutionPlan.join(' -> ')}`))
|
|
197
|
+
|
|
198
|
+
console.log(chalk.green.bold('\n✅ Dry run successful. All job and template definitions appear to be valid.'))
|
|
199
|
+
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(chalk.red.bold('\n💥 DRY RUN FAILED!'))
|
|
202
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)))
|
|
203
|
+
process.exit(1)
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
return dryRun
|
|
208
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { loadNetworks } from '../lib/network-loader'
|
|
4
|
+
import { projectOption, verbosityOption } from './common'
|
|
5
|
+
import { setVerbosity } from '../index'
|
|
6
|
+
import * as solc from 'solc'
|
|
7
|
+
import { createHash } from 'crypto'
|
|
8
|
+
|
|
9
|
+
type ApiAction = 'getsourcecode' | 'getabi'
|
|
10
|
+
|
|
11
|
+
interface EtherscanCmdBase {
|
|
12
|
+
project: string
|
|
13
|
+
verbose: number
|
|
14
|
+
etherscanApiKey?: string
|
|
15
|
+
network?: string
|
|
16
|
+
address: string
|
|
17
|
+
raw?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getEtherscanApiUrl(chainId: number): string {
|
|
21
|
+
return `https://api.etherscan.io/v2/api?chainid=${chainId}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type EtherscanSourceEnvelope = {
|
|
25
|
+
rawResult: Record<string, any>
|
|
26
|
+
parsedSource: unknown // standard-json object or flattened string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function fetchFromEtherscan(
|
|
30
|
+
chainId: number,
|
|
31
|
+
apiKey: string,
|
|
32
|
+
address: string,
|
|
33
|
+
action: ApiAction
|
|
34
|
+
): Promise<unknown | EtherscanSourceEnvelope> {
|
|
35
|
+
const apiUrl = getEtherscanApiUrl(chainId)
|
|
36
|
+
const params = new URLSearchParams({
|
|
37
|
+
module: 'contract',
|
|
38
|
+
action,
|
|
39
|
+
apikey: apiKey,
|
|
40
|
+
address
|
|
41
|
+
})
|
|
42
|
+
const resp = await fetch(`${apiUrl}&${params.toString()}`, {
|
|
43
|
+
method: 'GET',
|
|
44
|
+
signal: AbortSignal.timeout(20000)
|
|
45
|
+
})
|
|
46
|
+
if (!resp.ok) {
|
|
47
|
+
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`)
|
|
48
|
+
}
|
|
49
|
+
const data = await resp.json() as {
|
|
50
|
+
status: string
|
|
51
|
+
message?: string
|
|
52
|
+
result:
|
|
53
|
+
| string
|
|
54
|
+
| Array<{
|
|
55
|
+
SourceCode?: string
|
|
56
|
+
ABI?: string
|
|
57
|
+
[key: string]: unknown
|
|
58
|
+
}>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (data.status !== '1') {
|
|
62
|
+
// Etherscan v2 returns status "0" with message in result
|
|
63
|
+
const msg = typeof data.result === 'string' ? data.result : JSON.stringify(data.result)
|
|
64
|
+
throw new Error(msg || 'Unknown Etherscan error')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (action === 'getabi') {
|
|
68
|
+
// data.result is a JSON-encoded string for ABI, parse and return as object
|
|
69
|
+
if (typeof data.result !== 'string') {
|
|
70
|
+
throw new Error('Unexpected ABI result format from Etherscan')
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(data.result as string)
|
|
74
|
+
} catch (_e) {
|
|
75
|
+
throw new Error('Failed to parse ABI JSON returned by Etherscan')
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (action === 'getsourcecode') {
|
|
80
|
+
// data.result[0].SourceCode is a string; when standard-json it is wrapped with a leading and trailing character
|
|
81
|
+
if (!Array.isArray(data.result) || data.result.length === 0) {
|
|
82
|
+
throw new Error('Empty result from Etherscan')
|
|
83
|
+
}
|
|
84
|
+
const first = (data.result as Array<{ SourceCode?: string }>)[0] as Record<string, any>
|
|
85
|
+
const sourceCodeRaw = first?.SourceCode as string
|
|
86
|
+
if (typeof sourceCodeRaw !== 'string' || sourceCodeRaw.length === 0) {
|
|
87
|
+
throw new Error('No SourceCode found on Etherscan')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The SourceCode may be:
|
|
91
|
+
// 1) a raw source (flattened) string
|
|
92
|
+
// 2) a JSON string that may be double-wrapped like: "{...}" or "{{...}}"
|
|
93
|
+
// Try to normalize to a parsed JSON object when possible, otherwise return the raw string.
|
|
94
|
+
const trimmed = sourceCodeRaw.trim()
|
|
95
|
+
// Heuristic: if it starts with '{{' and ends with '}}', strip one layer
|
|
96
|
+
const cleaned = trimmed.startsWith('{{') && trimmed.endsWith('}}')
|
|
97
|
+
? trimmed.slice(1, -1)
|
|
98
|
+
: trimmed
|
|
99
|
+
|
|
100
|
+
// Try to parse JSON; if it fails, return string
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(cleaned)
|
|
103
|
+
return { rawResult: first, parsedSource: parsed }
|
|
104
|
+
} catch {
|
|
105
|
+
// Not JSON, return as-is string
|
|
106
|
+
return { rawResult: first, parsedSource: sourceCodeRaw }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return data.result
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function makeEtherscanCommand(): Command {
|
|
114
|
+
const etherscan = new Command('etherscan')
|
|
115
|
+
.description('Etherscan helper commands (ABI/source fetch)')
|
|
116
|
+
|
|
117
|
+
// Common options builder
|
|
118
|
+
const withCommon = (cmd: Command) => {
|
|
119
|
+
projectOption(cmd)
|
|
120
|
+
verbosityOption(cmd)
|
|
121
|
+
cmd
|
|
122
|
+
.option('--etherscan-api-key <key>', 'Etherscan API key. Can also be set via ETHERSCAN_API_KEY env var.')
|
|
123
|
+
.option('-n, --network <chainId>', 'Target network chain ID (required to select proper Etherscan endpoint)')
|
|
124
|
+
.option('-a, --address <address>', 'Contract address to query', '')
|
|
125
|
+
.option('--raw', 'Print raw response (no pretty JSON). Useful for piping.', false)
|
|
126
|
+
return cmd
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// etherscan abi
|
|
130
|
+
const abi = new Command('abi')
|
|
131
|
+
.description('Fetch contract ABI from Etherscan and print to stdout')
|
|
132
|
+
withCommon(abi)
|
|
133
|
+
abi.action(async (options: EtherscanCmdBase) => {
|
|
134
|
+
try {
|
|
135
|
+
setVerbosity(options.verbose as 0 | 1 | 2 | 3)
|
|
136
|
+
|
|
137
|
+
const apiKey = options.etherscanApiKey || process.env.ETHERSCAN_API_KEY
|
|
138
|
+
if (!apiKey) {
|
|
139
|
+
console.error(chalk.red('Etherscan API key is required. Use --etherscan-api-key or set ETHERSCAN_API_KEY.'))
|
|
140
|
+
process.exit(1)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!options.address) {
|
|
144
|
+
console.error(chalk.red('Missing required --address option'))
|
|
145
|
+
process.exit(1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Determine chainId
|
|
149
|
+
let chainId: number | undefined
|
|
150
|
+
if (options.network) {
|
|
151
|
+
const parsed = Number(options.network)
|
|
152
|
+
if (Number.isNaN(parsed)) {
|
|
153
|
+
console.error(chalk.red('Invalid --network value. Must be a chain ID number.'))
|
|
154
|
+
process.exit(1)
|
|
155
|
+
}
|
|
156
|
+
chainId = parsed
|
|
157
|
+
} else {
|
|
158
|
+
// If network not provided, try to infer: if only one network configured, use it
|
|
159
|
+
const networks = await loadNetworks(options.project)
|
|
160
|
+
if (networks.length === 1) {
|
|
161
|
+
chainId = networks[0].chainId
|
|
162
|
+
} else {
|
|
163
|
+
console.error(chalk.red('Please provide --network <chainId> (multiple or zero networks configured).'))
|
|
164
|
+
process.exit(1)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const result = await fetchFromEtherscan(chainId!, apiKey, options.address, 'getabi')
|
|
169
|
+
|
|
170
|
+
if (options.raw) {
|
|
171
|
+
// raw: output minified JSON
|
|
172
|
+
process.stdout.write(JSON.stringify(result))
|
|
173
|
+
} else {
|
|
174
|
+
// pretty
|
|
175
|
+
console.log(JSON.stringify(result, null, 2))
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error(chalk.red('Error fetching ABI from Etherscan:'), error instanceof Error ? error.message : String(error))
|
|
179
|
+
process.exit(1)
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
// etherscan source
|
|
184
|
+
const source = new Command('source')
|
|
185
|
+
.description('Fetch contract source and emit a self-contained build-info JSON suitable for verification')
|
|
186
|
+
withCommon(source)
|
|
187
|
+
source.action(async (options: EtherscanCmdBase) => {
|
|
188
|
+
try {
|
|
189
|
+
setVerbosity(options.verbose as 0 | 1 | 2 | 3)
|
|
190
|
+
|
|
191
|
+
const apiKey = options.etherscanApiKey || process.env.ETHERSCAN_API_KEY
|
|
192
|
+
if (!apiKey) {
|
|
193
|
+
console.error(chalk.red('Etherscan API key is required. Use --etherscan-api-key or set ETHERSCAN_API_KEY.'))
|
|
194
|
+
process.exit(1)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!options.address) {
|
|
198
|
+
console.error(chalk.red('Missing required --address option'))
|
|
199
|
+
process.exit(1)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Determine chainId
|
|
203
|
+
let chainId: number | undefined
|
|
204
|
+
if (options.network) {
|
|
205
|
+
const parsed = Number(options.network)
|
|
206
|
+
if (Number.isNaN(parsed)) {
|
|
207
|
+
console.error(chalk.red('Invalid --network value. Must be a chain ID number.'))
|
|
208
|
+
process.exit(1)
|
|
209
|
+
}
|
|
210
|
+
chainId = parsed
|
|
211
|
+
} else {
|
|
212
|
+
const networks = await loadNetworks(options.project)
|
|
213
|
+
if (networks.length === 1) {
|
|
214
|
+
chainId = networks[0].chainId
|
|
215
|
+
} else {
|
|
216
|
+
console.error(chalk.red('Please provide --network <chainId> (multiple or zero networks configured).'))
|
|
217
|
+
process.exit(1)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const result = await fetchFromEtherscan(chainId!, apiKey, options.address, 'getsourcecode') as EtherscanSourceEnvelope
|
|
222
|
+
|
|
223
|
+
const raw = result.rawResult
|
|
224
|
+
const parsed = result.parsedSource
|
|
225
|
+
|
|
226
|
+
// Extract compiler version with commit from metadata when available
|
|
227
|
+
const compilerVersion = (raw?.CompilerVersion as string | undefined) || ''
|
|
228
|
+
const optimizationUsed = (raw?.OptimizationUsed as string | undefined) || ''
|
|
229
|
+
const runsStr = (raw?.Runs as string | undefined) || ''
|
|
230
|
+
const evmVersionRaw = (raw?.EVMVersion as string | undefined) || ''
|
|
231
|
+
const isStandardJson = parsed && typeof parsed === 'object' && (parsed as any).language && (parsed as any).sources
|
|
232
|
+
|
|
233
|
+
// If we have a standard JSON input, use it; otherwise build one from flattened source
|
|
234
|
+
let input: any
|
|
235
|
+
if (isStandardJson) {
|
|
236
|
+
input = { ...(parsed as any) }
|
|
237
|
+
// Ensure outputSelection includes required entries to get creation bytecode and metadata
|
|
238
|
+
const currentSel = input.settings?.outputSelection || {}
|
|
239
|
+
const mergedSel = {
|
|
240
|
+
'*': {
|
|
241
|
+
'*': Array.from(new Set([
|
|
242
|
+
...(currentSel?.['*']?.['*'] || []),
|
|
243
|
+
'abi',
|
|
244
|
+
'evm.bytecode',
|
|
245
|
+
'evm.deployedBytecode',
|
|
246
|
+
'metadata',
|
|
247
|
+
'userdoc',
|
|
248
|
+
'devdoc',
|
|
249
|
+
'evm.methodIdentifiers'
|
|
250
|
+
]))
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
input.settings = {
|
|
254
|
+
...(input.settings || {}),
|
|
255
|
+
outputSelection: mergedSel
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
// Build a minimal standard JSON input from flattened source
|
|
259
|
+
const flattened = String(parsed || '')
|
|
260
|
+
input = {
|
|
261
|
+
language: 'Solidity',
|
|
262
|
+
sources: {
|
|
263
|
+
'Flattened.sol': { content: flattened }
|
|
264
|
+
},
|
|
265
|
+
settings: {
|
|
266
|
+
optimizer: {
|
|
267
|
+
enabled: optimizationUsed === '1',
|
|
268
|
+
runs: Number.isFinite(Number(runsStr)) ? Number(runsStr) : 200
|
|
269
|
+
},
|
|
270
|
+
evmVersion: evmVersionRaw && evmVersionRaw !== 'default' ? evmVersionRaw : undefined,
|
|
271
|
+
outputSelection: {
|
|
272
|
+
'*': {
|
|
273
|
+
'*': [
|
|
274
|
+
'abi',
|
|
275
|
+
'evm.bytecode.object',
|
|
276
|
+
'evm.bytecode.sourceMap',
|
|
277
|
+
'evm.bytecode.linkReferences',
|
|
278
|
+
'evm.deployedBytecode.object',
|
|
279
|
+
'evm.deployedBytecode.sourceMap',
|
|
280
|
+
'evm.deployedBytecode.linkReferences',
|
|
281
|
+
'evm.deployedBytecode.immutableReferences',
|
|
282
|
+
'evm.methodIdentifiers',
|
|
283
|
+
'metadata'
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Compile with exact solc version when possible
|
|
292
|
+
const solcInput = JSON.stringify(input)
|
|
293
|
+
const versionTag = compilerVersion && compilerVersion.startsWith('v') ? compilerVersion : (compilerVersion ? `v${compilerVersion}` : '')
|
|
294
|
+
let outputRaw: string
|
|
295
|
+
if (versionTag) {
|
|
296
|
+
outputRaw = await new Promise<string>((resolve, reject) => {
|
|
297
|
+
// @ts-ignore - loadRemoteVersion exists in solc js
|
|
298
|
+
solc.loadRemoteVersion(versionTag, (err: any, specificSolc: any) => {
|
|
299
|
+
if (err || !specificSolc) return reject(err || new Error('Failed to load solc version'))
|
|
300
|
+
try {
|
|
301
|
+
resolve(specificSolc.compile(solcInput))
|
|
302
|
+
} catch (e) {
|
|
303
|
+
reject(e)
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
})
|
|
307
|
+
} else {
|
|
308
|
+
outputRaw = solc.compile(solcInput)
|
|
309
|
+
}
|
|
310
|
+
const output = JSON.parse(outputRaw)
|
|
311
|
+
|
|
312
|
+
// Build build-info id as hex of sha1 of input
|
|
313
|
+
const id = createHash('sha1').update(solcInput).digest('hex')
|
|
314
|
+
|
|
315
|
+
// Determine solc versions
|
|
316
|
+
const solcLongVersion = (output?.compiler?.version as string | undefined) || (compilerVersion ? compilerVersion.replace(/^v/, '') : undefined)
|
|
317
|
+
const solcVersion = (solcLongVersion || '').split('+')[0] || (typeof (solc as any).version === 'function' ? (solc as any).version() : 'unknown')
|
|
318
|
+
|
|
319
|
+
// Augment settings with defaults similar to reference format
|
|
320
|
+
const basePath = process.cwd()
|
|
321
|
+
const includePaths = [basePath]
|
|
322
|
+
const allowPaths = includePaths
|
|
323
|
+
|
|
324
|
+
const buildInfo = {
|
|
325
|
+
id,
|
|
326
|
+
source_id_to_path: Object.fromEntries(Object.keys(input.sources).map((p, i) => [String(i), p])),
|
|
327
|
+
language: input.language,
|
|
328
|
+
_format: 'ethers-rs-sol-build-info-1',
|
|
329
|
+
input: {
|
|
330
|
+
version: solcVersion,
|
|
331
|
+
language: input.language,
|
|
332
|
+
sources: input.sources,
|
|
333
|
+
settings: input.settings,
|
|
334
|
+
evmVersion: input.settings?.evmVersion || 'cancun',
|
|
335
|
+
viaIR: input.settings?.viaIR || false,
|
|
336
|
+
libraries: input.settings?.libraries || {}
|
|
337
|
+
},
|
|
338
|
+
allowPaths,
|
|
339
|
+
basePath,
|
|
340
|
+
includePaths,
|
|
341
|
+
output: {
|
|
342
|
+
contracts: output.contracts || {},
|
|
343
|
+
sources: output.sources || {}
|
|
344
|
+
},
|
|
345
|
+
solcLongVersion: solcLongVersion || solcVersion,
|
|
346
|
+
solcVersion: solcVersion
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Print build-info JSON
|
|
350
|
+
console.log(options.raw ? JSON.stringify(buildInfo) : JSON.stringify(buildInfo, null, 2))
|
|
351
|
+
} catch (error) {
|
|
352
|
+
console.error(chalk.red('Error fetching source from Etherscan:'), error instanceof Error ? error.message : String(error))
|
|
353
|
+
process.exit(1)
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
etherscan.addCommand(abi)
|
|
358
|
+
etherscan.addCommand(source)
|
|
359
|
+
return etherscan
|
|
360
|
+
}
|