gate-evm-tools 1.0.31 → 1.2.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/README.md +34 -20
- package/bin/cli.js +3 -0
- package/bin/delivery.cjs +8 -7
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +26 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/plan/index.d.ts.map +1 -1
- package/dist/commands/plan/index.js +1 -1
- package/dist/commands/plan/index.js.map +1 -1
- package/dist/core/preparation/batch.d.ts +26 -0
- package/dist/core/preparation/batch.d.ts.map +1 -0
- package/dist/core/preparation/batch.js +72 -0
- package/dist/core/preparation/batch.js.map +1 -0
- package/dist/core/preparation/evm.d.ts +23 -4
- package/dist/core/preparation/evm.d.ts.map +1 -1
- package/dist/core/preparation/evm.js +19 -3
- package/dist/core/preparation/evm.js.map +1 -1
- package/dist/core/preparation/evmManifestSync.d.ts +5 -0
- package/dist/core/preparation/evmManifestSync.d.ts.map +1 -1
- package/dist/core/preparation/evmManifestSync.js +15 -7
- package/dist/core/preparation/evmManifestSync.js.map +1 -1
- package/dist/core/preparation/index.d.ts +2 -2
- package/dist/core/preparation/index.d.ts.map +1 -1
- package/dist/core/preparation/manifest.d.ts +2 -0
- package/dist/core/preparation/manifest.d.ts.map +1 -1
- package/dist/core/preparation/manifest.js +2 -2
- package/dist/core/preparation/manifest.js.map +1 -1
- package/dist/core/preparation/normalize.d.ts.map +1 -1
- package/dist/core/preparation/normalize.js +53 -11
- package/dist/core/preparation/normalize.js.map +1 -1
- package/dist/core/preparation/transparent.d.ts +23 -0
- package/dist/core/preparation/transparent.d.ts.map +1 -0
- package/dist/core/preparation/transparent.js +103 -0
- package/dist/core/preparation/transparent.js.map +1 -0
- package/dist/core/preparation/types.d.ts +47 -5
- package/dist/core/preparation/types.d.ts.map +1 -1
- package/dist/core/preparation/zksync.d.ts.map +1 -1
- package/dist/core/preparation/zksync.js +2 -0
- package/dist/core/preparation/zksync.js.map +1 -1
- package/dist/custody/credential.d.ts.map +1 -1
- package/dist/custody/credential.js +1 -6
- package/dist/custody/credential.js.map +1 -1
- package/dist/deployment-evm/index.d.ts +4 -0
- package/dist/deployment-evm/index.d.ts.map +1 -0
- package/dist/deployment-evm/index.js +3 -0
- package/dist/deployment-evm/index.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +5 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow/index.d.ts +4 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist-cjs/core/preparation/batch.js +76 -0
- package/dist-cjs/core/preparation/batch.js.map +1 -0
- package/dist-cjs/core/preparation/evm.js +25 -7
- package/dist-cjs/core/preparation/evm.js.map +1 -1
- package/dist-cjs/core/preparation/evmManifestSync.js +15 -7
- package/dist-cjs/core/preparation/evmManifestSync.js.map +1 -1
- package/dist-cjs/core/preparation/manifest.js +2 -2
- package/dist-cjs/core/preparation/manifest.js.map +1 -1
- package/dist-cjs/core/preparation/normalize.js +53 -11
- package/dist-cjs/core/preparation/normalize.js.map +1 -1
- package/dist-cjs/core/preparation/transparent.js +110 -0
- package/dist-cjs/core/preparation/transparent.js.map +1 -0
- package/dist-cjs/core/preparation/zksync.js +2 -0
- package/dist-cjs/core/preparation/zksync.js.map +1 -1
- package/dist-cjs/custody/credential.js +1 -6
- package/dist-cjs/custody/credential.js.map +1 -1
- package/dist-cjs/deployment-evm/index.js +10 -0
- package/dist-cjs/deployment-evm/index.js.map +1 -0
- package/dist-cjs/sync/index.js +5 -0
- package/dist-cjs/sync/index.js.map +1 -1
- package/dist-cjs/workflow/index.js +11 -1
- package/dist-cjs/workflow/index.js.map +1 -1
- package/dist-runtime/config/hardhatAdapters.js +2 -1
- package/dist-runtime/config/hardhatAdapters.js.map +1 -1
- package/dist-runtime/delivery/aggregate-bootstrap.js +3 -1
- package/dist-runtime/delivery/aggregate-bootstrap.js.map +1 -1
- package/dist-runtime/delivery/aggregate-channel.js +7 -3
- package/dist-runtime/delivery/aggregate-channel.js.map +1 -1
- package/dist-runtime/delivery/aggregate-diagnostics.d.ts +14 -0
- package/dist-runtime/delivery/aggregate-diagnostics.js +73 -0
- package/dist-runtime/delivery/aggregate-diagnostics.js.map +1 -0
- package/dist-runtime/delivery/aggregate-inputs.d.ts +13 -9
- package/dist-runtime/delivery/aggregate-source.js +11 -3
- package/dist-runtime/delivery/aggregate-source.js.map +1 -1
- package/dist-runtime/delivery/aggregate-worker.js +12 -4
- package/dist-runtime/delivery/aggregate-worker.js.map +1 -1
- package/dist-runtime/delivery/aggregate.js +2 -2
- package/dist-runtime/delivery/aggregate.js.map +1 -1
- package/dist-runtime/delivery/business-extension.d.ts +10 -0
- package/dist-runtime/delivery/business-extension.js +38 -0
- package/dist-runtime/delivery/business-extension.js.map +1 -0
- package/dist-runtime/delivery/calldata-archive.d.ts +18 -0
- package/dist-runtime/delivery/calldata-archive.js +31 -0
- package/dist-runtime/delivery/calldata-archive.js.map +1 -0
- package/dist-runtime/delivery/calldata-details.d.ts +47 -0
- package/dist-runtime/delivery/calldata-details.js +94 -0
- package/dist-runtime/delivery/calldata-details.js.map +1 -0
- package/dist-runtime/delivery/calldata-format.d.ts +4 -0
- package/dist-runtime/delivery/calldata-format.js +17 -0
- package/dist-runtime/delivery/calldata-format.js.map +1 -0
- package/dist-runtime/delivery/calldata-preparations.d.ts +13 -0
- package/dist-runtime/delivery/calldata-preparations.js +85 -0
- package/dist-runtime/delivery/calldata-preparations.js.map +1 -0
- package/dist-runtime/delivery/calldata-review.d.ts +44 -0
- package/dist-runtime/delivery/calldata-review.js +131 -0
- package/dist-runtime/delivery/calldata-review.js.map +1 -0
- package/dist-runtime/delivery/codec-pin.d.ts +2 -2
- package/dist-runtime/delivery/codec-pin.js +4 -4
- package/dist-runtime/delivery/codec-pin.js.map +1 -1
- package/dist-runtime/delivery/compiler-files.js +3 -1
- package/dist-runtime/delivery/compiler-files.js.map +1 -1
- package/dist-runtime/delivery/compiler-pins.js +1 -1
- package/dist-runtime/delivery/compiler.js +17 -16
- package/dist-runtime/delivery/compiler.js.map +1 -1
- package/dist-runtime/delivery/config.d.ts +1 -1
- package/dist-runtime/delivery/config.js +27 -2
- package/dist-runtime/delivery/config.js.map +1 -1
- package/dist-runtime/delivery/configuration-definition.d.ts +9 -0
- package/dist-runtime/delivery/configuration-definition.js +33 -6
- package/dist-runtime/delivery/configuration-definition.js.map +1 -1
- package/dist-runtime/delivery/configuration.js +7 -4
- package/dist-runtime/delivery/configuration.js.map +1 -1
- package/dist-runtime/delivery/contract-source.d.ts +14 -0
- package/dist-runtime/delivery/contract-source.js +138 -0
- package/dist-runtime/delivery/contract-source.js.map +1 -0
- package/dist-runtime/delivery/custom-format.js +51 -24
- package/dist-runtime/delivery/custom-format.js.map +1 -1
- package/dist-runtime/delivery/development.d.ts +2 -1
- package/dist-runtime/delivery/development.js +21 -10
- package/dist-runtime/delivery/development.js.map +1 -1
- package/dist-runtime/delivery/eoa.d.ts +1 -0
- package/dist-runtime/delivery/execution-identity.d.ts +15 -0
- package/dist-runtime/delivery/execution-identity.js +33 -0
- package/dist-runtime/delivery/execution-identity.js.map +1 -0
- package/dist-runtime/delivery/existing-code.js +14 -6
- package/dist-runtime/delivery/existing-code.js.map +1 -1
- package/dist-runtime/delivery/history-registration.d.ts +1 -1
- package/dist-runtime/delivery/inputs.js +22 -15
- package/dist-runtime/delivery/inputs.js.map +1 -1
- package/dist-runtime/delivery/journal.js +18 -10
- package/dist-runtime/delivery/journal.js.map +1 -1
- package/dist-runtime/delivery/parameter-defaults.d.ts +10 -0
- package/dist-runtime/delivery/parameter-defaults.js +86 -0
- package/dist-runtime/delivery/parameter-defaults.js.map +1 -0
- package/dist-runtime/delivery/parameters.d.ts +2 -0
- package/dist-runtime/delivery/parameters.js +22 -0
- package/dist-runtime/delivery/parameters.js.map +1 -1
- package/dist-runtime/delivery/planning.d.ts +4 -1
- package/dist-runtime/delivery/planning.js +19 -3
- package/dist-runtime/delivery/planning.js.map +1 -1
- package/dist-runtime/delivery/preparation.js +43 -23
- package/dist-runtime/delivery/preparation.js.map +1 -1
- package/dist-runtime/delivery/production-environment.js +2 -1
- package/dist-runtime/delivery/production-environment.js.map +1 -1
- package/dist-runtime/delivery/production-finalization.js +23 -9
- package/dist-runtime/delivery/production-finalization.js.map +1 -1
- package/dist-runtime/delivery/production-intent.d.ts +2 -0
- package/dist-runtime/delivery/production-intent.js +16 -0
- package/dist-runtime/delivery/production-intent.js.map +1 -0
- package/dist-runtime/delivery/production.d.ts +129 -8
- package/dist-runtime/delivery/production.js +60 -11
- package/dist-runtime/delivery/production.js.map +1 -1
- package/dist-runtime/delivery/project-files.d.ts +3 -3
- package/dist-runtime/delivery/project-files.js +19 -14
- package/dist-runtime/delivery/project-files.js.map +1 -1
- package/dist-runtime/delivery/project-rpc.d.ts +19 -0
- package/dist-runtime/delivery/project-rpc.js +138 -0
- package/dist-runtime/delivery/project-rpc.js.map +1 -0
- package/dist-runtime/delivery/project.d.ts +3 -1
- package/dist-runtime/delivery/project.js +21 -8
- package/dist-runtime/delivery/project.js.map +1 -1
- package/dist-runtime/delivery/public-calldata.d.ts +25 -0
- package/dist-runtime/delivery/public-calldata.js +97 -0
- package/dist-runtime/delivery/public-calldata.js.map +1 -0
- package/dist-runtime/delivery/release-graph.d.ts +7 -3
- package/dist-runtime/delivery/release-graph.js +58 -25
- package/dist-runtime/delivery/release-graph.js.map +1 -1
- package/dist-runtime/delivery/release-history.d.ts +1 -1
- package/dist-runtime/delivery/release-history.js +86 -10
- package/dist-runtime/delivery/release-history.js.map +1 -1
- package/dist-runtime/delivery/release-inputs.d.ts +33 -0
- package/dist-runtime/delivery/release-inputs.js +129 -0
- package/dist-runtime/delivery/release-inputs.js.map +1 -0
- package/dist-runtime/delivery/release.d.ts +38 -14
- package/dist-runtime/delivery/release.js +81 -29
- package/dist-runtime/delivery/release.js.map +1 -1
- package/dist-runtime/delivery/safe.d.ts +1 -0
- package/dist-runtime/delivery/safe.js +13 -2
- package/dist-runtime/delivery/safe.js.map +1 -1
- package/dist-runtime/delivery/same-fork-baseline.d.ts +1 -1
- package/dist-runtime/delivery/same-fork-baseline.js +5 -4
- package/dist-runtime/delivery/same-fork-baseline.js.map +1 -1
- package/dist-runtime/delivery/setup.d.ts +1 -1
- package/dist-runtime/delivery/setup.js +21 -6
- package/dist-runtime/delivery/setup.js.map +1 -1
- package/dist-runtime/delivery/source.d.ts +1 -0
- package/dist-runtime/delivery/source.js +12 -10
- package/dist-runtime/delivery/source.js.map +1 -1
- package/dist-runtime/delivery/task-identity.d.ts +23 -0
- package/dist-runtime/delivery/task-identity.js +109 -0
- package/dist-runtime/delivery/task-identity.js.map +1 -0
- package/dist-runtime/delivery/toolchain.d.ts +3 -0
- package/dist-runtime/delivery/toolchain.js +52 -0
- package/dist-runtime/delivery/toolchain.js.map +1 -0
- package/dist-runtime/delivery/validation.js +7 -2
- package/dist-runtime/delivery/validation.js.map +1 -1
- package/dist-runtime/runtime-identity.json +2 -2
- package/dist-runtime/vendor/plan-codec/index.cjs +97 -20
- package/dist-runtime/vendor/plan-codec/index.d.cts +6 -0
- package/dist-runtime/vendor/plan-codec/provenance.json +9 -8
- package/dist-runtime/workflow/lib/calls.js +1 -0
- package/dist-runtime/workflow/lib/calls.js.map +1 -1
- package/dist-runtime/workflow/lib/checkCodeRunner.js +7 -4
- package/dist-runtime/workflow/lib/checkCodeRunner.js.map +1 -1
- package/dist-runtime/workflow/lib/context.d.ts +1 -0
- package/dist-runtime/workflow/lib/create2.d.ts +4 -26
- package/dist-runtime/workflow/lib/create2.js +2 -67
- package/dist-runtime/workflow/lib/create2.js.map +1 -1
- package/dist-runtime/workflow/lib/deploymentInfo.d.ts +2 -0
- package/dist-runtime/workflow/lib/deploymentInfo.js +6 -0
- package/dist-runtime/workflow/lib/deploymentInfo.js.map +1 -1
- package/dist-runtime/workflow/lib/deploymentRecords.d.ts +2 -0
- package/dist-runtime/workflow/lib/deploymentRecords.js +1 -1
- package/dist-runtime/workflow/lib/deploymentRecords.js.map +1 -1
- package/dist-runtime/workflow/lib/externalExecutionScanner.js +2 -1
- package/dist-runtime/workflow/lib/externalExecutionScanner.js.map +1 -1
- package/dist-runtime/workflow/lib/gateTool.js +2 -2
- package/dist-runtime/workflow/lib/gateTool.js.map +1 -1
- package/dist-runtime/workflow/lib/gateToolSync.d.ts +3 -0
- package/dist-runtime/workflow/lib/gateToolSync.js +5 -0
- package/dist-runtime/workflow/lib/gateToolSync.js.map +1 -1
- package/dist-runtime/workflow/lib/parameters.js +5 -0
- package/dist-runtime/workflow/lib/parameters.js.map +1 -1
- package/dist-runtime/workflow/lib/proxy.d.ts +1 -0
- package/dist-runtime/workflow/lib/proxy.js.map +1 -1
- package/dist-runtime/workflow/run.js +1 -3
- package/dist-runtime/workflow/run.js.map +1 -1
- package/dist-runtime/workflow/steps/deploy.js +53 -0
- package/dist-runtime/workflow/steps/deploy.js.map +1 -1
- package/dist-runtime/workflow/steps/upgrade.js +24 -10
- package/dist-runtime/workflow/steps/upgrade.js.map +1 -1
- package/docs/compiler-qualification.md +8 -2
- package/docs/delivery-aggregate.md +2 -0
- package/docs/delivery-calldata.md +27 -0
- package/docs/delivery-development.md +6 -0
- package/docs/delivery-execution-store.md +1 -1
- package/docs/delivery-inputs.md +55 -6
- package/docs/delivery-parameters.md +1 -1
- package/docs/delivery-release.md +60 -6
- package/docs/delivery-safe.md +7 -4
- package/docs/delivery-setup.md +72 -20
- package/docs/delivery-source.md +8 -8
- package/docs/direct-package-acceptance.md +2 -0
- package/docs/openzeppelin-acceptance.md +86 -0
- package/docs/openzeppelin-baseline.json +27 -0
- package/docs/openzeppelin-integration.md +115 -0
- package/docs/plans/2026-10-28-openzeppelin-toolkit-consolidation.md +396 -0
- package/docs/plans/2026-11-02-transparent-proxy-delivery.md +78 -0
- package/docs/superpowers/plans/2026-08-17-custody-hardhat-signers.md +1 -1
- package/docs/workflow-reference.md +12 -4
- package/docs/workflow-runtime.md +6 -0
- package/package.json +19 -5
- package/runtime/config/hardhatAdapters.ts +2 -1
- package/runtime/delivery/aggregate-bootstrap.ts +3 -1
- package/runtime/delivery/aggregate-channel.ts +6 -3
- package/runtime/delivery/aggregate-diagnostics.ts +63 -0
- package/runtime/delivery/aggregate-source.ts +6 -2
- package/runtime/delivery/aggregate-worker.ts +15 -5
- package/runtime/delivery/aggregate.ts +2 -2
- package/runtime/delivery/business-extension.ts +33 -0
- package/runtime/delivery/calldata-archive.ts +25 -0
- package/runtime/delivery/calldata-details.ts +90 -0
- package/runtime/delivery/calldata-format.ts +14 -0
- package/runtime/delivery/calldata-preparations.ts +76 -0
- package/runtime/delivery/calldata-review.ts +126 -0
- package/runtime/delivery/codec-pin.ts +3 -3
- package/runtime/delivery/compiler-files.ts +3 -1
- package/runtime/delivery/compiler-pins.ts +1 -1
- package/runtime/delivery/compiler.ts +18 -17
- package/runtime/delivery/config.ts +25 -2
- package/runtime/delivery/configuration-definition.ts +34 -7
- package/runtime/delivery/configuration.ts +8 -5
- package/runtime/delivery/contract-source.ts +112 -0
- package/runtime/delivery/custom-format.ts +20 -5
- package/runtime/delivery/development.ts +13 -11
- package/runtime/delivery/execution-identity.ts +32 -0
- package/runtime/delivery/existing-code.ts +7 -6
- package/runtime/delivery/inputs.ts +18 -11
- package/runtime/delivery/journal.ts +14 -10
- package/runtime/delivery/parameter-defaults.ts +75 -0
- package/runtime/delivery/parameters.ts +18 -0
- package/runtime/delivery/planning.ts +19 -5
- package/runtime/delivery/preparation.ts +17 -1
- package/runtime/delivery/production-environment.ts +2 -1
- package/runtime/delivery/production-finalization.ts +19 -10
- package/runtime/delivery/production-intent.ts +14 -0
- package/runtime/delivery/production.ts +51 -11
- package/runtime/delivery/project-files.ts +16 -11
- package/runtime/delivery/project-rpc.ts +116 -0
- package/runtime/delivery/project.ts +19 -7
- package/runtime/delivery/public-calldata.ts +74 -0
- package/runtime/delivery/release-graph.ts +44 -14
- package/runtime/delivery/release-history.ts +66 -8
- package/runtime/delivery/release-inputs.ts +107 -0
- package/runtime/delivery/release.ts +56 -18
- package/runtime/delivery/safe.ts +14 -3
- package/runtime/delivery/same-fork-baseline.ts +5 -4
- package/runtime/delivery/setup.ts +20 -8
- package/runtime/delivery/source.ts +10 -10
- package/runtime/delivery/task-identity.ts +85 -0
- package/runtime/delivery/toolchain.ts +48 -0
- package/runtime/delivery/validation.ts +7 -2
- package/runtime/vendor/plan-codec/index.cjs +97 -20
- package/runtime/vendor/plan-codec/index.d.cts +6 -0
- package/runtime/vendor/plan-codec/provenance.json +9 -8
- package/runtime/workflow/lib/calls.ts +1 -0
- package/runtime/workflow/lib/checkCodeRunner.ts +7 -3
- package/runtime/workflow/lib/context.ts +1 -0
- package/runtime/workflow/lib/create2.ts +7 -108
- package/runtime/workflow/lib/deploymentInfo.ts +8 -0
- package/runtime/workflow/lib/deploymentRecords.ts +3 -1
- package/runtime/workflow/lib/externalExecutionScanner.ts +2 -1
- package/runtime/workflow/lib/gateTool.ts +2 -2
- package/runtime/workflow/lib/gateToolSync.ts +8 -0
- package/runtime/workflow/lib/parameters.ts +4 -0
- package/runtime/workflow/lib/proxy.ts +1 -0
- package/runtime/workflow/run.ts +1 -2
- package/runtime/workflow/steps/deploy.ts +42 -0
- package/runtime/workflow/steps/upgrade.ts +19 -11
- package/bin/workflow.cjs +0 -19
|
@@ -11,6 +11,7 @@ import { getDeployData, type DeployData } from '@openzeppelin/hardhat-upgrades/d
|
|
|
11
11
|
import { withDefaults } from '@openzeppelin/hardhat-upgrades/dist/utils/options';
|
|
12
12
|
import { validate, solcInputOutputDecoder, getContractNameAndRunValidation, getStorageLayout, getVersion, getUnlinkedBytecode, assertUpgradeSafe, assertStorageUpgradeSafe, getImplementationAddress } from '@openzeppelin/upgrades-core';
|
|
13
13
|
import { strictData } from './data';
|
|
14
|
+
import { compilerExecutionInput } from './execution-identity';
|
|
14
15
|
import { deepFreeze, semanticHash } from '../workflow/lib/canonicalData';
|
|
15
16
|
import { CompilerFiles, regular, relative, sha256, type CompilerPackage, type CompilerResolution } from './compiler-files';
|
|
16
17
|
import { compilerTaskPins, compilerDispatcherPin } from './compiler-pins';
|
|
@@ -45,7 +46,7 @@ type SameForkProof = NonNullable<Awaited<ReturnType<NonNullable<GateToolPreparat
|
|
|
45
46
|
type OwnedInitial = SameForkInitialPreparation & {selection:Selection};
|
|
46
47
|
// Resolve the same core manifest reader used by the actual preparation call site.
|
|
47
48
|
const { readRegisteredTargetUpgradeState, resolveTargetManifestDirectory } = require(path.join(path.dirname(require.resolve('gate-evm-tools/workflow')), '../core/preparation/manifest.js')) as {
|
|
48
|
-
readRegisteredTargetUpgradeState(input: {root:string; target:string; chainId:number; proxy:string; currentImplementation:string}): HistoricalObservation['state'];
|
|
49
|
+
readRegisteredTargetUpgradeState(input: {root:string; target:string; chainId:number; proxy:string; currentImplementation:string; proxyKind?:'uups'|'transparent'}): HistoricalObservation['state'];
|
|
49
50
|
resolveTargetManifestDirectory(root:string,target:string):string;
|
|
50
51
|
};
|
|
51
52
|
export interface CompilerEvidence {
|
|
@@ -95,7 +96,7 @@ function projection(sourceName: string, contractName: string, output: Json): Gat
|
|
|
95
96
|
linkReferences: output.evm?.bytecode?.linkReferences ?? {}, deployedLinkReferences: output.evm?.deployedBytecode?.linkReferences ?? {} });
|
|
96
97
|
}
|
|
97
98
|
function stable(e: Omit<CompilerEvidence, 'stableDigest' | 'exactDigest'>): unknown {
|
|
98
|
-
return { version: e.version, adapter: e.adapter, toolchain: e.toolchain,
|
|
99
|
+
return { version: e.version, adapter: e.adapter, toolchain: compilerExecutionInput(e.toolchain),
|
|
99
100
|
jobs: e.jobs.map(j => ({ id: j.id, config: j.config, sources: j.sources, main: j.runs[0] })),
|
|
100
101
|
builds: e.builds, artifacts: e.artifacts, selections: e.selections, baselines: e.baselines.map(({ prior, ...b }) => ({ ...b, prior: { stableDigest: prior.stableDigest, selection: prior.selection } })) };
|
|
101
102
|
}
|
|
@@ -404,9 +405,9 @@ class CompilerSession {
|
|
|
404
405
|
origin = {kind:'target-manifest',manifestPolicy:state.paths.manifestDir,manifestDigest:state.digest,proxy:state.proxyEntry,implementationEntry:persistedOZ(state.implementationEntry)};
|
|
405
406
|
} else {
|
|
406
407
|
const initial = this.#sameForkProofs.get(observation.sameFork);
|
|
407
|
-
if (!initial || request.kind !== 'uups-upgrade' || initial.selection.digest !== prior.selection.digest
|
|
408
|
-
|| !matchesSameForkInitial(initial,request.target,String(chainId),request.proxy,currentImplementation)) throw new Error('Same-fork baseline requires its owned initial preparation and actual deployment observation');
|
|
409
|
-
origin = {kind:'same-fork',manifestPolicy:resolveTargetManifestDirectory(this.hre.config.paths.root,request.target),proxy:{address:request.proxy.toLowerCase(),kind:
|
|
408
|
+
if (!initial || (request.kind !== 'uups-upgrade' && request.kind !== 'transparent-upgrade') || initial.selection.digest !== prior.selection.digest
|
|
409
|
+
|| !matchesSameForkInitial(initial,request.target,String(chainId),request.proxy,currentImplementation,request.proxyKind)) throw new Error('Same-fork baseline requires its owned initial preparation and actual deployment observation');
|
|
410
|
+
origin = {kind:'same-fork',manifestPolicy:resolveTargetManifestDirectory(this.hre.config.paths.root,request.target),proxy:{address:request.proxy.toLowerCase(),kind:request.proxyKind},sameForkBaselineDigest:observation.sameFork.digest,initial:{request:initial.request,plan:initial.plan}};
|
|
410
411
|
}
|
|
411
412
|
const baseline: Baseline = strictData({ ...origin, target: request.target, chainId, selection:selection.digest, currentImplementation: currentImplementation.toLowerCase(), implementationKey: prior.selection.version.linkedWithoutMetadata, oldLayout: prior.selection.layout, prior: this.priorQualification(prior) });
|
|
412
413
|
if (!this.#baselines.some(b => semanticHash(b) === semanticHash(baseline))) this.#baselines.push(baseline);
|
|
@@ -433,7 +434,7 @@ class CompilerSession {
|
|
|
433
434
|
}
|
|
434
435
|
readonly sameForkBaseline: NonNullable<GateToolPreparationValidation['sameForkBaseline']> = async input => {
|
|
435
436
|
this.assertRegistry();
|
|
436
|
-
const matches = [...this.#initialPreparations.values()].filter(p => this.#observedInitials.has(p) && matchesSameForkInitial(p,input.request.target,String(input.chainId),input.request.proxy,input.currentImplementation));
|
|
437
|
+
const matches = [...this.#initialPreparations.values()].filter(p => this.#observedInitials.has(p) && matchesSameForkInitial(p,input.request.target,String(input.chainId),input.request.proxy,input.currentImplementation,input.request.proxyKind));
|
|
437
438
|
if (!matches.length) return undefined;
|
|
438
439
|
if (matches.length !== 1) throw new Error('Ambiguous same-fork initial preparation');
|
|
439
440
|
const actual = await getImplementationAddress(this.#provider,input.request.proxy);
|
|
@@ -460,7 +461,7 @@ class CompilerSession {
|
|
|
460
461
|
}
|
|
461
462
|
};
|
|
462
463
|
preparationSelection(request: Exclude<GateToolPreparationRequestV1, {kind:'create2-deploy'}>, plan: GateToolPreparationPlanV1): Selection {
|
|
463
|
-
const options = persistedOZ(withDefaults({ kind:
|
|
464
|
+
const options = persistedOZ(withDefaults({ kind: request.proxyKind, constructorArgs: request.constructorArgs, ...(request.unsafeAllow ? { unsafeAllow: request.unsafeAllow } : {}) } as Parameters<typeof withDefaults>[0]));
|
|
464
465
|
const matches = [...this.#selections.values()].filter(s => s.fqn === `${plan.artifact.sourceName}:${plan.artifact.contractName}` && semanticHash(s.options) === semanticHash(options));
|
|
465
466
|
if (matches.length !== 1) throw new Error('Preparation reuse requires one prior owned qualified OZ selection');
|
|
466
467
|
return matches[0];
|
|
@@ -469,7 +470,7 @@ class CompilerSession {
|
|
|
469
470
|
async observePreparationPlan(request: GateToolPreparationRequestV1, plan: GateToolPreparationPlanV1): Promise<void> {
|
|
470
471
|
try {
|
|
471
472
|
this.assertRegistry();
|
|
472
|
-
if (request.kind === 'uups-upgrade' && plan.validation.kind === 'uups-upgrade') {
|
|
473
|
+
if ((request.kind === 'uups-upgrade' || request.kind === 'transparent-upgrade') && (plan.validation.kind === 'uups-upgrade' || plan.validation.kind === 'transparent-upgrade')) {
|
|
473
474
|
const selected = this.preparationSelection(request,plan);
|
|
474
475
|
const chainId = Number(BigInt(await this.#provider.send('eth_chainId')));
|
|
475
476
|
if (!Number.isSafeInteger(chainId) || chainId <= 0 || String(chainId) !== plan.chainId) throw new Error('Preparation baseline chain mismatch');
|
|
@@ -480,14 +481,14 @@ class CompilerSession {
|
|
|
480
481
|
if (!sameFork || sameFork.digest !== plan.validation.sameForkBaselineDigest) throw new Error('Preparation same-fork baseline digest mismatch');
|
|
481
482
|
this.captureBaseline(request,selected,{sameFork,currentImplementation,chainId});
|
|
482
483
|
} else {
|
|
483
|
-
const state = readRegisteredTargetUpgradeState({root:this.hre.config.paths.root,target:request.target,chainId,proxy:request.proxy,currentImplementation});
|
|
484
|
+
const state = readRegisteredTargetUpgradeState({root:this.hre.config.paths.root,target:request.target,chainId,proxy:request.proxy,currentImplementation,proxyKind:request.proxyKind});
|
|
484
485
|
if (state.digest !== plan.validation.manifestDigest) throw new Error('Preparation baseline manifest digest mismatch');
|
|
485
486
|
this.assertRegistry();
|
|
486
487
|
this.captureBaseline(request,selected,{state,currentImplementation,chainId});
|
|
487
488
|
}
|
|
488
489
|
}
|
|
489
490
|
this.preparationPlan(request,plan);
|
|
490
|
-
if (request.kind === 'uups-placeholder-deploy') {
|
|
491
|
+
if (request.kind === 'uups-placeholder-deploy' || request.kind === 'transparent-deploy') {
|
|
491
492
|
await validatePreparationSemantics(request,plan,name=>this.hre.artifacts.readArtifact(name));
|
|
492
493
|
const selection = this.preparationSelection(request,plan);
|
|
493
494
|
const initial = deepFreeze({request:normalizePreparationRequest(request),plan:strictData(plan),selection});
|
|
@@ -503,11 +504,11 @@ class CompilerSession {
|
|
|
503
504
|
this.assertRegistry();
|
|
504
505
|
if (request.kind === 'create2-deploy') return;
|
|
505
506
|
const selected = this.preparationSelection(request,plan);
|
|
506
|
-
if (plan.validation.kind === 'uups-upgrade') {
|
|
507
|
-
if (request.kind !== 'uups-upgrade') throw new Error('Preparation baseline request mismatch');
|
|
507
|
+
if (plan.validation.kind === 'uups-upgrade' || plan.validation.kind === 'transparent-upgrade') {
|
|
508
|
+
if ((request.kind !== 'uups-upgrade' && request.kind !== 'transparent-upgrade')) throw new Error('Preparation baseline request mismatch');
|
|
508
509
|
if (sha256(canonicalPreparationJson(selected.layout)) !== plan.validation.newLayoutHash) throw new Error('Preparation selected new layout mismatch');
|
|
509
510
|
const validation = plan.validation;
|
|
510
|
-
const matches = this.#baselines.filter(b => b.target === request.target && String(b.chainId) === plan.chainId && b.proxy.address.toLowerCase() === request.proxy.toLowerCase()
|
|
511
|
+
const matches = this.#baselines.filter(b => b.target === request.target && String(b.chainId) === plan.chainId && b.proxy.address.toLowerCase() === request.proxy.toLowerCase() && b.proxy.kind === request.proxyKind
|
|
511
512
|
&& b.currentImplementation === validation.currentImplementation.toLowerCase() && b.selection === selected.digest
|
|
512
513
|
&& (b.kind === 'target-manifest' ? validation.sameForkBaselineDigest === undefined && b.manifestDigest === validation.manifestDigest
|
|
513
514
|
: validation.manifestDigest === undefined && b.sameForkBaselineDigest === validation.sameForkBaselineDigest));
|
|
@@ -680,20 +681,20 @@ export function parseCompilerEvidence(raw: unknown): CompilerEvidence {
|
|
|
680
681
|
if (prior.baselines.length || prior.selections.length !== 1 || prior.stableDigest !== b.prior.stableDigest || prior.exactDigest !== b.prior.exactDigest || prior.selections[0].digest !== b.prior.selection || prior.selections[0].version.linkedWithoutMetadata !== b.implementationKey) throw new Error('Historical compiler baseline relation mismatch');
|
|
681
682
|
equal(b.oldLayout, prior.selections[0].layout, 'Historical qualified layout');
|
|
682
683
|
assertStorageUpgradeSafe(b.oldLayout as any,selected.layout as any,selected.options as any);
|
|
683
|
-
if (b.proxy.kind !== 'uups' || !Number.isSafeInteger(b.chainId) || b.chainId <= 0) throw new Error('Historical baseline identity mismatch');
|
|
684
|
+
if (selected.options.kind !== b.proxy.kind || prior.selections[0].options.kind !== b.proxy.kind || !['uups','transparent'].includes(b.proxy.kind) || !Number.isSafeInteger(b.chainId) || b.chainId <= 0) throw new Error('Historical baseline identity mismatch');
|
|
684
685
|
if (b.kind === 'target-manifest') {
|
|
685
686
|
equal(b.oldLayout, b.implementationEntry.layout, 'Historical manifest layout');
|
|
686
687
|
if (![b.implementationEntry.address, ...(b.implementationEntry.allAddresses ?? [])].some(a => typeof a === 'string' && a.toLowerCase() === b.currentImplementation)) throw new Error('Historical manifest identity mismatch');
|
|
687
688
|
} else {
|
|
688
689
|
const initial = b.initial, selection = prior.selections[0];
|
|
689
690
|
const layoutHash = sha256(canonicalPreparationJson(b.oldLayout));
|
|
690
|
-
if (!matchesSameForkInitial(initial,b.target,String(b.chainId),b.proxy.address,b.currentImplementation)
|
|
691
|
-
|| sameForkBaselineDigest(initial,layoutHash) !== b.sameForkBaselineDigest || initial.request.kind !== 'uups-placeholder-deploy') throw new Error('Same-fork initial preparation relation mismatch');
|
|
691
|
+
if (!matchesSameForkInitial(initial,b.target,String(b.chainId),b.proxy.address,b.currentImplementation,b.proxy.kind)
|
|
692
|
+
|| sameForkBaselineDigest(initial,layoutHash) !== b.sameForkBaselineDigest || (initial.request.kind !== 'uups-placeholder-deploy' && initial.request.kind !== 'transparent-deploy')) throw new Error('Same-fork initial preparation relation mismatch');
|
|
692
693
|
const artifact = prior.artifacts.find(a=>a.digest===selection.artifactDigest)!.artifact;
|
|
693
694
|
equal(artifactIdentity(artifact,'evm'),initial.plan.artifact,'Same-fork prior artifact');
|
|
694
695
|
const encodedArgs = new ContractFactory(artifact.abi,artifact.bytecode).interface.encodeDeploy(initial.request.constructorArgs);
|
|
695
696
|
if (encodedArgs !== selection.encodedArgs || getCreate2Address(initial.request.factory,initial.request.implementationSalt,keccak256(concat([selection.linkedBytecode,encodedArgs]))).toLowerCase() !== b.currentImplementation) throw new Error('Same-fork prior constructor/implementation mismatch');
|
|
696
|
-
equal(persistedOZ(withDefaults({kind:
|
|
697
|
+
equal(persistedOZ(withDefaults({kind:initial.request.proxyKind,constructorArgs:initial.request.constructorArgs,...(initial.request.unsafeAllow ? {unsafeAllow:initial.request.unsafeAllow}: {})} as Parameters<typeof withDefaults>[0])),selection.options,'Same-fork prior options');
|
|
697
698
|
}
|
|
698
699
|
}
|
|
699
700
|
return deepFreeze(e);
|
|
@@ -52,16 +52,39 @@ export function validateDeliveryTarget(input: unknown): DeliveryTarget {
|
|
|
52
52
|
}
|
|
53
53
|
export function configDocument(root: string): YAML.Document {
|
|
54
54
|
const contents = readFile(root, 'config.yaml');
|
|
55
|
+
if (contents !== undefined) parseInputDocument(contents, 'yaml');
|
|
55
56
|
const doc = contents === undefined ? new YAML.Document({}) : YAML.parseDocument(contents);
|
|
56
57
|
if (doc.errors.length || !YAML.isMap(doc.contents)) throw new Error('config.yaml must be a valid mapping');
|
|
57
58
|
return doc;
|
|
58
59
|
}
|
|
59
|
-
/** Validate
|
|
60
|
+
/** Validate the selected target with its facility defaults, never another network or environment. */
|
|
60
61
|
export function loadDeliveryTarget(root: string, network: string, environment?: DeliveryEnvironment): DeliveryTargetConfig {
|
|
61
62
|
const target = parseSelectedTarget(parseInputDocument(readInputBytes(root, 'config.yaml'), 'yaml'), network, environment);
|
|
62
63
|
confinedFile(root, target.openzeppelin.manifestDir, 'directory');
|
|
63
64
|
return target;
|
|
64
65
|
}
|
|
66
|
+
const FACILITY_FIELDS: Record<string, string[]> = {
|
|
67
|
+
create2: ['scheme', 'factory', 'leadingZeroBytes', 'caller'],
|
|
68
|
+
uups: ['placeholderImplementation'],
|
|
69
|
+
multicall: ['controlledMulticall'],
|
|
70
|
+
};
|
|
71
|
+
/** Only public facilities inherit. Environment, finality, roles and manifest policy remain target-owned. */
|
|
72
|
+
function inheritTargetFacilities(configuration: Record<string, unknown>, target: Record<string, unknown>): Record<string, unknown> {
|
|
73
|
+
const profiles = configuration._profiles === undefined ? {} : object(configuration._profiles, '_profiles', ['baseProfile', 'dev', 'prod']);
|
|
74
|
+
const selected = target.environment === 'dev' || target.environment === 'prod' ? target.environment : undefined;
|
|
75
|
+
const layers = [
|
|
76
|
+
['baseProfile', profiles.baseProfile],
|
|
77
|
+
[selected ?? 'environment', selected ? profiles[selected] : undefined],
|
|
78
|
+
] as const;
|
|
79
|
+
const defaults = layers.map(([name, value]) => value === undefined ? {} : object(value, `_profiles.${name}`, Object.keys(FACILITY_FIELDS)));
|
|
80
|
+
const result = { ...target };
|
|
81
|
+
for (const [facility, fields] of Object.entries(FACILITY_FIELDS)) {
|
|
82
|
+
const sections = [...defaults, target].filter(layer => layer[facility] !== undefined)
|
|
83
|
+
.map(layer => object(layer[facility], facility, fields));
|
|
84
|
+
if (sections.length) result[facility] = Object.assign({}, ...sections);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
65
88
|
function parseSelectedTarget(document: unknown, network: string, environment?: DeliveryEnvironment): DeliveryTargetConfig {
|
|
66
89
|
validateNetworkAlias(network, 'network', false);
|
|
67
90
|
const configuration = object(document, 'config.yaml');
|
|
@@ -70,7 +93,7 @@ function parseSelectedTarget(document: unknown, network: string, environment?: D
|
|
|
70
93
|
if (environment && value.environment !== environment) throw new Error(`Selected target ${network} environment mismatch`);
|
|
71
94
|
const manifest = object(value.openzeppelin, 'openzeppelin');
|
|
72
95
|
validateManifestPolicy(value.environment, manifest.manifestDir, 'delivery');
|
|
73
|
-
const { network: _network, ...validated } = validateDeliveryTarget({ ...value, network });
|
|
96
|
+
const { network: _network, ...validated } = validateDeliveryTarget({ ...inheritTargetFacilities(configuration, value), network });
|
|
74
97
|
return deepFreeze(validated) as DeliveryTargetConfig;
|
|
75
98
|
}
|
|
76
99
|
/** Pure projection from the owner's exact captured buffers; creates no input/receipt authority. */
|
|
@@ -4,10 +4,15 @@ import { parseProjectConfig } from './project';
|
|
|
4
4
|
import { inputDigest } from './input-files';
|
|
5
5
|
import { validateNetworkAlias } from './policy';
|
|
6
6
|
import { deepFreeze } from '../workflow/lib/canonicalData';
|
|
7
|
+
import { projectRpcSyntax, projectRpcOptions, resolveProjectRpc } from './project-rpc';
|
|
8
|
+
// dist-runtime has its own CommonJS boundary; resolve our built helper by location.
|
|
9
|
+
const resolveHardhatAccounts: typeof import('gate-evm-tools/custody').resolveHardhatAccounts =
|
|
10
|
+
require('../../dist-cjs/custody/credential.js').resolveHardhatAccounts;
|
|
7
11
|
|
|
8
12
|
type Data = Record<string, any>;
|
|
9
13
|
export type SecretDefinition = {kind:'literal'; definitionHash:string} | {kind:'env'; name:string}
|
|
10
|
-
| {kind:'fallback'; operator:'||'|'??'; left:SecretDefinition; right:SecretDefinition}
|
|
14
|
+
| {kind:'fallback'; operator:'||'|'??'; left:SecretDefinition; right:SecretDefinition}
|
|
15
|
+
| {kind:'project-rpc'; route:string; useBaseRpc:boolean; base:{kind:'env';name:'BASE_RPC_URI'}; publicFallback:SecretDefinition};
|
|
11
16
|
const fail = (): never => { throw new Error('Unsupported static delivery configuration'); };
|
|
12
17
|
const literalDefinition = (value:string):SecretDefinition => ({kind:'literal',definitionHash:inputDigest(`gate-delivery-secret-definition@1\0${value}`)});
|
|
13
18
|
function unwrap(n:ts.Expression):ts.Expression { while(ts.isParenthesizedExpression(n)||ts.isAsExpression(n)||ts.isSatisfiesExpression(n)) n=n.expression; return n; }
|
|
@@ -45,8 +50,21 @@ function headers(n:ts.Expression,env:NodeJS.ProcessEnv):{value:Data;definition:a
|
|
|
45
50
|
for(const [key,node] of fields(n)){const item=secret(node,env);value[key]=item.value;definition.push({name:literalDefinition(key),value:item.definition});}
|
|
46
51
|
return {value,definition};
|
|
47
52
|
}
|
|
48
|
-
function
|
|
53
|
+
function networkUrl(n:ts.Expression,env:NodeJS.ProcessEnv,helper:boolean):ReturnType<typeof secret> {
|
|
49
54
|
n=unwrap(n);
|
|
55
|
+
if(helper&&ts.isCallExpression(n)){
|
|
56
|
+
const {route,useBaseRpc,publicFallback}=projectRpcOptions(n),fallback=secret(publicFallback,env);
|
|
57
|
+
return {value:resolveProjectRpc(route,fallback.value,useBaseRpc,env),definition:{kind:'project-rpc',route,useBaseRpc,base:{kind:'env',name:'BASE_RPC_URI'},publicFallback:fallback.definition}};
|
|
58
|
+
}
|
|
59
|
+
return secret(n,env);
|
|
60
|
+
}
|
|
61
|
+
function accounts(n:ts.Expression,local:boolean,env:NodeJS.ProcessEnv,credentialResolver:boolean):{value:any;definition:any} {
|
|
62
|
+
n=unwrap(n);
|
|
63
|
+
if(!local&&credentialResolver&&ts.isCallExpression(n)&&ts.isIdentifier(n.expression)&&n.expression.text==='resolveHardhatAccounts'&&n.arguments.length===1&&!n.typeArguments){
|
|
64
|
+
const credential=secret(n.arguments[0],env);
|
|
65
|
+
if(credential.definition.kind!=='env'||credential.definition.name!=='PRIVATE_KEY')return fail();
|
|
66
|
+
return {value:resolveHardhatAccounts(credential.value),definition:{kind:'wallet-credential',credential:credential.definition}};
|
|
67
|
+
}
|
|
50
68
|
if(ts.isStringLiteral(n)&&n.text==='remote'&&!local)return {value:'remote',definition:{kind:'remote'}};
|
|
51
69
|
if(ts.isArrayLiteralExpression(n)){
|
|
52
70
|
const entries=n.elements.map(e=>{
|
|
@@ -71,12 +89,12 @@ function accounts(n:ts.Expression,local:boolean,env:NodeJS.ProcessEnv):{value:an
|
|
|
71
89
|
const common=['chainId','from','gas','gasPrice','gasMultiplier'];
|
|
72
90
|
const localFields=[...common,'initialBaseFeePerGas','hardfork','mining','accounts','blockGasLimit','minGasPrice','throwOnTransactionFailures','throwOnCallFailures','allowUnlimitedContractSize','allowBlocksWithSameTimestamp','initialDate','loggingEnabled','forking','coinbase','chains','enableTransientStorage','enableRip7212'];
|
|
73
91
|
const httpFields=[...common,'url','timeout','httpHeaders','accounts'];
|
|
74
|
-
function network(n:ts.Expression,local:boolean,env:NodeJS.ProcessEnv):{value:Data;definition:Data} {
|
|
92
|
+
function network(n:ts.Expression,local:boolean,env:NodeJS.ProcessEnv,helper:boolean,credentialResolver:boolean):{value:Data;definition:Data} {
|
|
75
93
|
const value:Data={},definition:Data={};
|
|
76
94
|
for(const [key,node] of fields(n)){
|
|
77
95
|
if(!(local?localFields:httpFields).includes(key))return fail();
|
|
78
|
-
if(key==='url'){const s=
|
|
79
|
-
else if(key==='accounts'){const a=accounts(node,local,env);value[key]=a.value;definition[key]=a.definition;}
|
|
96
|
+
if(key==='url'){const s=networkUrl(node,env,helper);value[key]=s.value;definition[key]=s.definition;}
|
|
97
|
+
else if(key==='accounts'){const a=accounts(node,local,env,credentialResolver);value[key]=a.value;definition[key]=a.definition;}
|
|
80
98
|
else if(key==='httpHeaders'){const h=headers(node,env);value[key]=h.value;definition[key]=h.definition;}
|
|
81
99
|
else if(key==='forking'){
|
|
82
100
|
const v:Data={},d:Data={};for(const [k,x] of fields(node)){
|
|
@@ -109,13 +127,22 @@ export function parseConfigurationDefinition(bytes:Buffer,selected:string,env:No
|
|
|
109
127
|
try {
|
|
110
128
|
validateNetworkAlias(selected,'network',false);if(selected==='hardhat')fail();
|
|
111
129
|
const {file,fields:top,networks}=parseProjectConfig(new TextDecoder('utf-8',{fatal:true}).decode(bytes));
|
|
130
|
+
const rpc=projectRpcSyntax(file);
|
|
112
131
|
const plugins:string[]=[];
|
|
132
|
+
let credentialResolver=false;
|
|
113
133
|
const exported=unwrap(file.statements.filter(ts.isExportAssignment)[0].expression);
|
|
114
134
|
for(const statement of file.statements){
|
|
135
|
+
if(rpc.statements.has(statement))continue;
|
|
115
136
|
if(ts.isImportDeclaration(statement)){
|
|
116
137
|
if(!ts.isStringLiteral(statement.moduleSpecifier)||statement.attributes)fail();
|
|
117
138
|
const name=(statement.moduleSpecifier as ts.StringLiteral).text;
|
|
118
|
-
if(statement.importClause){
|
|
139
|
+
if(statement.importClause){
|
|
140
|
+
const clause=statement.importClause;
|
|
141
|
+
if(name==='gate-evm-tools/custody'){
|
|
142
|
+
if(credentialResolver||clause.isTypeOnly||clause.name||!clause.namedBindings||!ts.isNamedImports(clause.namedBindings)||clause.namedBindings.elements.length!==1||clause.namedBindings.elements[0].name.text!=='resolveHardhatAccounts'||clause.namedBindings.elements[0].propertyName||clause.namedBindings.elements[0].isTypeOnly)fail();
|
|
143
|
+
credentialResolver=true;
|
|
144
|
+
}else if(name!=='hardhat/config'||!clause.isTypeOnly||clause.name||!clause.namedBindings||!ts.isNamedImports(clause.namedBindings)||clause.namedBindings.elements.some(e=>e.name.text!=='HardhatUserConfig'||e.propertyName))fail();
|
|
145
|
+
}
|
|
119
146
|
else {if(!['gate-evm-tools/delivery-hardhat','@nomicfoundation/hardhat-ethers','@nomicfoundation/hardhat-chai-matchers','@openzeppelin/hardhat-upgrades'].includes(name)||plugins.includes(name))fail();plugins.push(name);}
|
|
120
147
|
}else if(ts.isVariableStatement(statement)){if(!ts.isIdentifier(exported)||statement.declarationList.declarations[0]?.name.getText(file)!==exported.text||statement.modifiers?.length||statement.declarationList.declarations.length!==1||!(statement.declarationList.flags&ts.NodeFlags.Const)||file.statements.filter(ts.isVariableStatement).length!==1)fail();}
|
|
121
148
|
else if(!ts.isExportAssignment(statement))fail();
|
|
@@ -126,7 +153,7 @@ export function parseConfigurationDefinition(bytes:Buffer,selected:string,env:No
|
|
|
126
153
|
if(!('solidity'in userConfig))fail();compiler(userConfig.solidity);
|
|
127
154
|
if(userConfig.paths){keys(userConfig.paths,['sources','cache','artifacts','tests']);for(const value of Object.values(userConfig.paths))if(typeof value!=='string'||!value||value.startsWith('/')||value.includes('\\')||value.split('/').some(p=>!p||p==='..'))fail();}
|
|
128
155
|
if(userConfig.defaultNetwork!==undefined)validateNetworkAlias(userConfig.defaultNetwork,'defaultNetwork');
|
|
129
|
-
userConfig.networks={};for(const [name,node] of networks){validateNetworkAlias(name,'network');const n=network(node,name==='hardhat',env);userConfig.networks[name]=n.value;definition.networks[name]=n.definition;}
|
|
156
|
+
userConfig.networks={};for(const [name,node] of networks){validateNetworkAlias(name,'network');const n=network(node,name==='hardhat',env,rpc.helper,credentialResolver);userConfig.networks[name]=n.value;definition.networks[name]=n.definition;}
|
|
130
157
|
if(!userConfig.networks[selected])fail();
|
|
131
158
|
return {userConfig,definition:deepFreeze(definition),plugins,explicitDate:Object.hasOwn(userConfig.networks.hardhat??{},'initialDate')};
|
|
132
159
|
}catch{throw new Error('Unsupported static delivery configuration');}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Owned configuration/runtime contributor. It grants no planning, signing or execution authority. */
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {projectRoot,
|
|
3
|
+
import {projectRoot,parseDeliveryProjectMarker} from './project-files';
|
|
4
4
|
import {readInputBytes,inputDigest} from './input-files';
|
|
5
5
|
import {parseConfigurationDefinition} from './configuration-definition';
|
|
6
6
|
import {observeConfigurationHre} from './configuration-hre';
|
|
@@ -8,6 +8,8 @@ import {RuntimeObservation,type RuntimeEvidence} from './configuration-runtime';
|
|
|
8
8
|
import {openPlanCodecObservation,type PlanCodecObservation} from './codec';
|
|
9
9
|
import {deepFreeze,semanticHash,exactObject} from '../workflow/lib/canonicalData';
|
|
10
10
|
import type {DeepReadonly} from './source';
|
|
11
|
+
import {projectRpcEnvironment} from './project-rpc';
|
|
12
|
+
import {runtimeExecutionInput} from './execution-identity';
|
|
11
13
|
|
|
12
14
|
export interface DeliveryConfigurationOptions {workspaceRoot:string;projectRoot:string;network:string}
|
|
13
15
|
export interface DeliveryConfigurationEvidence {
|
|
@@ -34,8 +36,9 @@ export function openDeliveryConfiguration(raw:DeliveryConfigurationOptions):Deli
|
|
|
34
36
|
if(path.resolve(process.cwd())!==root)throw new Error();
|
|
35
37
|
const config=readInputBytes(root,'hardhat.config.ts'),marker=readInputBytes(root,'.gate-template.json');
|
|
36
38
|
// Marker describes generation provenance; current source is independently observed.
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
+
parseDeliveryProjectMarker(marker);
|
|
40
|
+
const parse=(bytes:Buffer)=>parseConfigurationDefinition(bytes,raw.network,projectRpcEnvironment(root,bytes.toString('utf8'),process.env));
|
|
41
|
+
const parsed=parse(config);
|
|
39
42
|
runtime=new RuntimeObservation(root);codec=openPlanCodecObservation();
|
|
40
43
|
const hre=observeConfigurationHre(root,raw.network,parsed,runtime.files);
|
|
41
44
|
const files=[{path:'hardhat.config.ts',digest:inputDigest(config)},{path:'.gate-template.json',digest:inputDigest(marker)}];
|
|
@@ -45,14 +48,14 @@ export function openDeliveryConfiguration(raw:DeliveryConfigurationOptions):Deli
|
|
|
45
48
|
const compiler=ownedDeliveryCompiler(hre.hre)?.evidence();
|
|
46
49
|
const body={version:1 as const,files,configuration:hre.configuration,runtime:runtime!.observe(),codec:codec!.snapshot,
|
|
47
50
|
compiler:compiler?{adapter:compiler.adapter,stableDigest:compiler.stableDigest,exactDigest:compiler.exactDigest}:null};
|
|
48
|
-
return deepFreeze({...body,configurationRuntimeHash:semanticHash({...body,compiler:compiler?{adapter:compiler.adapter,stableDigest:compiler.stableDigest}:null})});
|
|
51
|
+
return deepFreeze({...body,configurationRuntimeHash:semanticHash({...body,runtime:runtimeExecutionInput(body.runtime),compiler:compiler?{adapter:compiler.adapter,stableDigest:compiler.stableDigest}:null})});
|
|
49
52
|
};
|
|
50
53
|
const snapshot=observe();let status:'open'|'sealed'|'failed'|'closed'='open';
|
|
51
54
|
const close=()=>{runtime!.close();codec!.close();};
|
|
52
55
|
const check=()=>{
|
|
53
56
|
const current=readInputBytes(root,'hardhat.config.ts');
|
|
54
57
|
if(inputDigest(current)!==files[0].digest||inputDigest(readInputBytes(root,'.gate-template.json'))!==files[1].digest)throw new Error();
|
|
55
|
-
hre.assertUnchanged(
|
|
58
|
+
hre.assertUnchanged(parse(current));codec!.assertUnchanged();runtime!.assertUnchanged();
|
|
56
59
|
};
|
|
57
60
|
const assertOpen=()=>{if(status!=='open')throw new Error('Delivery configuration session closed');};
|
|
58
61
|
return Object.freeze({snapshot,
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** Bind actual project Solidity inputs to their last source-changing Git commit. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { readInputBytes, inputDigest } from './input-files';
|
|
7
|
+
import { confinedFile } from './project-files';
|
|
8
|
+
import { portablePath } from './protocol';
|
|
9
|
+
import { deepFreeze, semanticHash } from '../workflow/lib/canonicalData';
|
|
10
|
+
import type { DeliveryAggregate } from './aggregate';
|
|
11
|
+
|
|
12
|
+
export interface ContractSourceIdentity {
|
|
13
|
+
version: 1;
|
|
14
|
+
commit: string;
|
|
15
|
+
projectPath: string;
|
|
16
|
+
sourcesDirectory: string;
|
|
17
|
+
files: Array<{ path: string; digest: string }>;
|
|
18
|
+
sourceHash: string;
|
|
19
|
+
}
|
|
20
|
+
type TreeEntry = { mode: string; oid: string };
|
|
21
|
+
const portable = (value: string) => value.split(path.sep).join('/');
|
|
22
|
+
function git(root: string, args: string[]): string {
|
|
23
|
+
// These reads must inspect this worktree, including its own index.
|
|
24
|
+
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith('GIT_')));
|
|
25
|
+
const result = spawnSync('git', ['--no-optional-locks', '-c', 'core.fsmonitor=false', ...args], {
|
|
26
|
+
cwd: root, env, encoding: 'utf8', timeout: 15000, maxBuffer: 32 * 1024 * 1024,
|
|
27
|
+
});
|
|
28
|
+
if (result.error || result.status !== 0) throw Error('Deployment release requires a Git repository with committed contract sources');
|
|
29
|
+
return result.stdout;
|
|
30
|
+
}
|
|
31
|
+
function sourceFiles(root: string, directory: string): string[] {
|
|
32
|
+
const files: string[] = [];
|
|
33
|
+
const visit = (relative: string) => {
|
|
34
|
+
const absolute = relative === '.' ? root : confinedFile(root, relative, 'directory');
|
|
35
|
+
if (!fs.existsSync(absolute)) return;
|
|
36
|
+
for (const entry of fs.readdirSync(absolute, { withFileTypes: true })) {
|
|
37
|
+
if (['.git', 'node_modules', '.gate-delivery'].includes(entry.name)) continue;
|
|
38
|
+
const file = relative === '.' ? entry.name : `${relative}/${entry.name}`;
|
|
39
|
+
if (entry.isSymbolicLink()) throw Error('Contract source directory cannot contain symlinks');
|
|
40
|
+
if (entry.isDirectory()) visit(file);
|
|
41
|
+
else if (entry.isFile() && file.endsWith('.sol')) files.push(file);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
visit(directory);
|
|
45
|
+
return files;
|
|
46
|
+
}
|
|
47
|
+
function tree(root: string, commit: string, scopes: string[], wanted: (file: string) => boolean): Map<string, TreeEntry> {
|
|
48
|
+
const entries = new Map<string, TreeEntry>();
|
|
49
|
+
for (const row of git(root, ['ls-tree', '-r', '-z', '--full-tree', commit, '--', ...scopes]).split('\0').filter(Boolean)) {
|
|
50
|
+
const tab = row.indexOf('\t'), file = row.slice(tab + 1), [mode, kind, oid] = row.slice(0, tab).split(' ');
|
|
51
|
+
if (!wanted(file)) continue;
|
|
52
|
+
if (kind !== 'blob' || !['100644', '100755'].includes(mode)) throw Error('Contract sources must be regular committed files');
|
|
53
|
+
entries.set(file, { mode, oid });
|
|
54
|
+
}
|
|
55
|
+
return entries;
|
|
56
|
+
}
|
|
57
|
+
/** Called only with the collector's aggregate; no caller-selected Git reference is accepted. */
|
|
58
|
+
export function captureCommittedContractSource(root: string, aggregate: DeliveryAggregate): Readonly<ContractSourceIdentity> {
|
|
59
|
+
root = fs.realpathSync(root);
|
|
60
|
+
const configurations = aggregate.inputs.targets.map(target => target.configuration.configuration.paths?.sources);
|
|
61
|
+
const directory = configurations[0];
|
|
62
|
+
if (typeof directory !== 'string' || configurations.some(value => value !== directory)) throw Error('Missing or inconsistent compiled contract source directory');
|
|
63
|
+
if (directory !== '.') portablePath(directory, 'contract sources directory');
|
|
64
|
+
const compiled = new Map<string, string>();
|
|
65
|
+
for (const target of aggregate.inputs.targets) for (const job of target.compiler.jobs) for (const source of job.sources) {
|
|
66
|
+
if (source.package !== null) continue;
|
|
67
|
+
portablePath(source.path, 'compiled contract source');
|
|
68
|
+
if (compiled.has(source.path) && compiled.get(source.path) !== source.digest) throw Error('Conflicting compiled contract sources');
|
|
69
|
+
compiled.set(source.path, source.digest);
|
|
70
|
+
}
|
|
71
|
+
if (!compiled.size) throw Error('Deployment release requires compiled project contract sources');
|
|
72
|
+
const repo = fs.realpathSync(git(root, ['rev-parse', '--show-toplevel']).trim());
|
|
73
|
+
const relative = path.relative(repo, root);
|
|
74
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw Error('Project is outside its contract Git repository');
|
|
75
|
+
const projectPath = portable(relative) || '.', prefix = relative ? `${portable(relative)}/` : '';
|
|
76
|
+
const sourceScope = directory === '.' ? prefix.slice(0, -1) || '.' : `${prefix}${directory}`;
|
|
77
|
+
const paths = new Set([...sourceFiles(root, directory), ...compiled.keys()]);
|
|
78
|
+
const explicit = new Set([...compiled.keys()].map(file => prefix + file));
|
|
79
|
+
const wanted = (file: string) => explicit.has(file) || file.endsWith('.sol') && (sourceScope === '.' || file.startsWith(sourceScope + '/'));
|
|
80
|
+
const scopes = [...new Set([sourceScope, ...explicit])].map(file => `:(literal)${file}`);
|
|
81
|
+
const committed = tree(repo, 'HEAD', scopes, wanted);
|
|
82
|
+
const index = new Map<string, TreeEntry>();
|
|
83
|
+
for (const row of git(repo, ['ls-files', '--stage', '-z', '--', ...scopes]).split('\0').filter(Boolean)) {
|
|
84
|
+
const tab = row.indexOf('\t'), file = row.slice(tab + 1), [mode, oid, stage] = row.slice(0, tab).split(' ');
|
|
85
|
+
if (!wanted(file)) continue;
|
|
86
|
+
if (stage !== '0') throw Error('Contract sources have unresolved Git conflicts');
|
|
87
|
+
index.set(file, { mode, oid });
|
|
88
|
+
}
|
|
89
|
+
const uncommitted = () => { throw Error('Contract sources have uncommitted, staged, untracked or deleted files; commit contract changes before freezing a deployment release'); };
|
|
90
|
+
if (committed.size !== paths.size || index.size !== committed.size) uncommitted();
|
|
91
|
+
const format = git(repo, ['rev-parse', '--show-object-format']).trim();
|
|
92
|
+
if (!['sha1', 'sha256'].includes(format)) throw Error('Unsupported contract Git object format');
|
|
93
|
+
const files = [...paths].sort().map(file => {
|
|
94
|
+
const entry = committed.get(prefix + file), staged = index.get(prefix + file);
|
|
95
|
+
if (!entry || !staged || entry.mode !== staged.mode || entry.oid !== staged.oid) uncommitted();
|
|
96
|
+
let bytes: Buffer;
|
|
97
|
+
try { bytes = readInputBytes(root, file); } catch { return uncommitted(); }
|
|
98
|
+
const oid = createHash(format).update(`blob ${bytes.length}\0`).update(bytes).digest('hex');
|
|
99
|
+
if (oid !== entry!.oid) uncommitted();
|
|
100
|
+
const digest = inputDigest(bytes);
|
|
101
|
+
if (compiled.has(file) && compiled.get(file) !== digest) throw Error('Contract source changed after deployment qualification');
|
|
102
|
+
return { path: file, digest };
|
|
103
|
+
});
|
|
104
|
+
// Ignore script/documentation commits, while retaining source additions and deletions.
|
|
105
|
+
const glob = sourceScope === '.' ? '**/*.sol' : `${sourceScope}/**/*.sol`;
|
|
106
|
+
const commit = git(repo, ['log', '-1', '--format=%H', '--first-parent', '--full-history', 'HEAD', '--', `:(glob)${glob}`, ...[...explicit].map(file => `:(literal)${file}`)]).trim();
|
|
107
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(commit)) throw Error('No committed contract source version found');
|
|
108
|
+
const version = tree(repo, commit, scopes, wanted);
|
|
109
|
+
if (version.size !== committed.size || [...committed].some(([file, entry]) => version.get(file)?.oid !== entry.oid)) throw Error('Contract commit does not reproduce current contract sources');
|
|
110
|
+
return deepFreeze({ version: 1 as const, commit, projectPath, sourcesDirectory: directory, files,
|
|
111
|
+
sourceHash: semanticHash({ sourcesDirectory: directory, files }) });
|
|
112
|
+
}
|
|
@@ -94,13 +94,16 @@ function proxy(v: unknown, deploying: boolean): void {
|
|
|
94
94
|
"initializer",
|
|
95
95
|
"unsafeAllow",
|
|
96
96
|
"constructorArgs",
|
|
97
|
+
"adminOwner",
|
|
97
98
|
...(deploying ? [] : ["address", "name", "contract"]),
|
|
98
99
|
],
|
|
99
100
|
[],
|
|
100
101
|
"proxy"
|
|
101
102
|
);
|
|
102
|
-
if (p.kind !== undefined && p.kind !== "uups")
|
|
103
|
-
throw new Error("
|
|
103
|
+
if (p.kind !== undefined && p.kind !== "uups" && p.kind !== "transparent")
|
|
104
|
+
throw new Error("Unsupported proxy kind");
|
|
105
|
+
if(p.kind === "transparent") {if(p.adminOwner === undefined)throw Error("Transparent proxy requires explicit adminOwner");address(p.adminOwner,"proxy.adminOwner");}
|
|
106
|
+
else if(p.adminOwner !== undefined)throw Error("Only Transparent proxy accepts adminOwner");
|
|
104
107
|
if (p.initializer !== undefined && p.initializer !== false)
|
|
105
108
|
string(p.initializer, "initializer");
|
|
106
109
|
if (p.constructorArgs !== undefined)
|
|
@@ -130,6 +133,8 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
130
133
|
[
|
|
131
134
|
"id",
|
|
132
135
|
"kind",
|
|
136
|
+
"name",
|
|
137
|
+
"description",
|
|
133
138
|
"contract",
|
|
134
139
|
"abi",
|
|
135
140
|
"address",
|
|
@@ -159,6 +164,8 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
159
164
|
const keys = [
|
|
160
165
|
"id",
|
|
161
166
|
"kind",
|
|
167
|
+
"name",
|
|
168
|
+
"description",
|
|
162
169
|
"contract",
|
|
163
170
|
...(kind === "deploy"
|
|
164
171
|
? [
|
|
@@ -175,6 +182,7 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
175
182
|
: ["abi", "address", "deployment", "saveAs", "calls"]),
|
|
176
183
|
];
|
|
177
184
|
record(base, keys, ["id", "kind", "contract"], "operation");
|
|
185
|
+
for (const key of ["name", "description"]) if (base[key] !== undefined) string(base[key], key);
|
|
178
186
|
refs(base);
|
|
179
187
|
for (const key of ["abi", "deployment", "saveAs"])
|
|
180
188
|
if (base[key] !== undefined) string(base[key], key);
|
|
@@ -220,6 +228,10 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
220
228
|
if (base.args !== undefined) array(base.args, "constructor args");
|
|
221
229
|
if (base.proxy !== undefined) {
|
|
222
230
|
proxy(base.proxy, true);
|
|
231
|
+
if((base.proxy as Record<string,unknown>).kind === 'transparent'){
|
|
232
|
+
const p=base.proxy as Record<string,unknown>;
|
|
233
|
+
if(base.upgradeableStrategy!=='transparent-proxy'||base.firstUpgrade!==undefined||p.initializer===undefined)throw Error('Transparent deployment requires transparent-proxy strategy, explicit initializer and no firstUpgrade');
|
|
234
|
+
} else {
|
|
223
235
|
if (
|
|
224
236
|
(base.proxy as Record<string, unknown>).initializer !== false ||
|
|
225
237
|
base.upgradeableStrategy !== "uups-placeholder-proxy"
|
|
@@ -251,6 +263,7 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
251
263
|
)
|
|
252
264
|
throw new Error("Invalid unsafeAllow");
|
|
253
265
|
if (first.call !== undefined) upgradeCall(first.call);
|
|
266
|
+
}
|
|
254
267
|
} else if (
|
|
255
268
|
base.firstUpgrade !== undefined ||
|
|
256
269
|
base.upgradeableStrategy !== undefined
|
|
@@ -261,8 +274,9 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
261
274
|
if (base.proxy !== undefined) proxy(base.proxy, false);
|
|
262
275
|
else if (base.address === undefined)
|
|
263
276
|
throw new Error("Upgrade requires proxy");
|
|
264
|
-
if (base.proxyKind !== undefined && base.proxyKind !== "uups")
|
|
265
|
-
throw new Error("
|
|
277
|
+
if (base.proxyKind !== undefined && base.proxyKind !== "uups" && base.proxyKind !== "transparent")
|
|
278
|
+
throw new Error("Unsupported proxy upgrade kind");
|
|
279
|
+
if(base.proxyKind === "transparent" && (!base.proxy || typeof base.proxy !== "object" || (base.proxy as Record<string,unknown>).kind!=="transparent"))throw Error("Transparent upgrade requires explicit proxy object and adminOwner");
|
|
266
280
|
if (base.constructorArgs !== undefined)
|
|
267
281
|
array(base.constructorArgs, "constructorArgs");
|
|
268
282
|
if (base.call !== undefined) upgradeCall(base.call);
|
|
@@ -275,12 +289,13 @@ export function parseNativeOperation(raw: unknown): WorkflowStep {
|
|
|
275
289
|
kind === "check"
|
|
276
290
|
? ["method", "args", "expect"]
|
|
277
291
|
: kind === "call"
|
|
278
|
-
? ["method", "args", "value"]
|
|
292
|
+
? ["method", "args", "value", "name", "description"]
|
|
279
293
|
: ["method", "args"],
|
|
280
294
|
kind === "check" ? ["method", "expect"] : ["method"],
|
|
281
295
|
"call"
|
|
282
296
|
);
|
|
283
297
|
method(c.method);
|
|
298
|
+
for (const key of ["name", "description"]) if (c[key] !== undefined) string(c[key], key);
|
|
284
299
|
if (c.args !== undefined) array(c.args, "call args");
|
|
285
300
|
if (c.value !== undefined) quantity(c.value);
|
|
286
301
|
}
|