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
|
@@ -6,8 +6,9 @@ import ts from 'typescript';
|
|
|
6
6
|
import {existingCodeCoverage,requiredExistingAddresses} from './existing-code';
|
|
7
7
|
import {yieldCompilerIo} from './compiler-io';
|
|
8
8
|
import {openDeliveryConfiguration} from './configuration';
|
|
9
|
+
import {aggregateInputHash} from './execution-identity';
|
|
9
10
|
import {getCreate2Address} from 'ethers';
|
|
10
|
-
import {artifactIdentity,BytecodeChecker,prepareEvmManifestCandidate,mergeEvmManifestCandidate,parseTargetManifest,hashStorageLayout,resolveTargetManifestPaths} from 'gate-evm-tools/workflow';
|
|
11
|
+
import {TRANSPARENT_PROXY_ARTIFACT,verifyTransparentAdmin,artifactIdentity,BytecodeChecker,prepareEvmManifestCandidate,mergeEvmManifestCandidate,parseTargetManifest,hashStorageLayout,resolveTargetManifestPaths} from 'gate-evm-tools/workflow';
|
|
11
12
|
import {canonicalData,canonicalJson,deepFreeze,semanticHash} from '../workflow/lib/canonicalData';
|
|
12
13
|
import {typedValue,parseTypedValue} from '../workflow/lib/typedValue';
|
|
13
14
|
import type {VerificationObservation,TypedValue} from '../workflow/lib/evidencePorts';
|
|
@@ -68,7 +69,7 @@ export function expectedDevelopmentAssertions(collection:Pick<DeliveryCollection
|
|
|
68
69
|
export function mergeDevelopmentRegistration(input:{
|
|
69
70
|
registry:unknown;metadata:unknown;base:{registry:ContractInfo;metadata:DeploymentInfo};
|
|
70
71
|
target:string;deploymentId:string;executionId:string;recordPath:string;updatedAt:string;
|
|
71
|
-
changes:readonly (DeploymentChange&{address:string;proxyKind?:'uups'})[];preparations:readonly PreparationEntry[];
|
|
72
|
+
changes:readonly (DeploymentChange&{address:string;proxyKind?:'uups'|'transparent'})[];preparations:readonly PreparationEntry[];
|
|
72
73
|
}):{registry:ContractInfo;metadata:DeploymentInfo} {
|
|
73
74
|
const {base,target}=input,registry=validateContractInfo(input.registry),metadata=validateDeploymentInfo(input.metadata);
|
|
74
75
|
registry[target]??={};metadata.networks[target]??={};
|
|
@@ -78,14 +79,14 @@ export function mergeDevelopmentRegistration(input:{
|
|
|
78
79
|
const previous=resolveDeployment(registry,target,c.instanceId);
|
|
79
80
|
if(previous&&previous.key!==c.contractInfoKey){
|
|
80
81
|
const entry=input.preparations.find(p=>p.stepId===c.stepId),request=entry?.prepared.request;
|
|
81
|
-
if(c.kind!=='upgrade'
|
|
82
|
+
if(c.kind!=='upgrade'||!['uups','transparent'].includes(c.proxyKind??'')||entry?.change.kind!=='upgrade'||!request||!(request.kind==='uups-upgrade'||request.kind==='transparent-upgrade')||entry.prepared.plan.kind!==request.kind
|
|
82
83
|
||entry.change.instanceId!==c.instanceId||entry.change.contractInfoKey!==c.contractInfoKey||entry.change.actualContract!==c.actualContract
|
|
83
84
|
||previous.address.toLowerCase()!==request.proxy.toLowerCase()||previous.address.toLowerCase()!==c.address.toLowerCase()||c.proxyAddress?.toLowerCase()!==request.proxy.toLowerCase())throw Error('Contract candidate key conflict');
|
|
84
85
|
delete registry[target][previous.key];
|
|
85
86
|
}
|
|
86
87
|
if(previous&&previous.address.toLowerCase()!==c.address.toLowerCase()&&c.previousAddress?.toLowerCase()!==previous.address.toLowerCase())throw Error('Contract candidate address conflict');
|
|
87
88
|
registry[target][c.contractInfoKey]=c.address;
|
|
88
|
-
metadata.networks[target][c.instanceId]={contractInfoKey:c.contractInfoKey,address:c.address,actualContract:c.actualContract,...(c.proxyKind?{proxyKind:c.proxyKind,implementationAddress:c.implementationAddress}:{}),source:{kind:'deployment',deploymentId:input.deploymentId,executionId:input.executionId,recordPath:input.recordPath},updatedAt:input.updatedAt};
|
|
89
|
+
metadata.networks[target][c.instanceId]={contractInfoKey:c.contractInfoKey,address:c.address,actualContract:c.actualContract,...(c.proxyKind?{proxyKind:c.proxyKind,implementationAddress:c.implementationAddress,...(c.proxyKind==='transparent'?{proxyAdminAddress:c.proxyAdminAddress,proxyAdminOwner:c.proxyAdminOwner}:{})}:{}),source:{kind:'deployment',deploymentId:input.deploymentId,executionId:input.executionId,recordPath:input.recordPath},updatedAt:input.updatedAt};
|
|
89
90
|
}
|
|
90
91
|
return {registry:validateContractInfo(registry),metadata:validateDeploymentInfo(metadata)};
|
|
91
92
|
}
|
|
@@ -107,7 +108,7 @@ export async function createDevelopmentDelivery(options:DevelopmentDeliveryOptio
|
|
|
107
108
|
same(preparations.map(p=>({stepId:p.stepId,preparationHash:p.preparationHash,transactionIds:p.mappings.map(m=>m.transactionId),derivedKeys:p.derivedKeys})),plan.deploymentBindings,'Sealed preparation bindings');
|
|
108
109
|
if(!plan.transactions.length)throw Error('Development acceptance requires actual transactions');
|
|
109
110
|
const rows=aggregate.inputs.targets;
|
|
110
|
-
const computed=
|
|
111
|
+
const computed=aggregateInputHash(aggregate);
|
|
111
112
|
same(plan.deploymentId,aggregate.inputs.business.deploymentId,'Business deployment identity');same(computed,aggregate.inputsHash,'Aggregate input hash');same(plan.inputsHash,computed,'Plan inputs');same(plan.sourceDefinitionHash,aggregate.sourceDefinitionHash,'Plan source');same(semanticHash(aggregate.inputs.sourceDefinitions),aggregate.sourceDefinitionHash,'Source hash');
|
|
112
113
|
const hre=options.hre,provider={request:(method:string,params:readonly unknown[])=>hre.network.provider.request({method,params:[...params]})};
|
|
113
114
|
if(options.execution.context.finality.kind==='confirmations'&&BigInt(options.execution.context.finality.depth)<BigInt(Math.max(1,target.finality.confirmations)))throw Error('Development finality below configured policy');
|
|
@@ -160,6 +161,7 @@ export async function createDevelopmentDelivery(options:DevelopmentDeliveryOptio
|
|
|
160
161
|
if(preparations.length)return;
|
|
161
162
|
const coverage=pureCoverage(),checker=new BytecodeChecker(hre,{},'evm');
|
|
162
163
|
for(const row of coverage.expected){const code=await hre.ethers.provider.getCode(row.address),local=await checker.getLocalBytecode(row.contract);if(code==='0x'||!checker.compareBytecode(code,local.bytecode,local.abi,local.immutableReferences).matches)throw Error('Existing development code mismatch');}
|
|
164
|
+
for(const alias of coverage.aliases){const m=base.metadata.networks[plan.target]?.[alias];if(m?.proxyKind==='transparent'){if(!m.proxyAdminAddress||!m.proxyAdminOwner)throw Error('Missing frozen existing Transparent admin');await verifyTransparentAdmin({hre:hre as any,proxy:m.address,admin:m.proxyAdminAddress,owner:m.proxyAdminOwner});}}
|
|
163
165
|
for(const m of coverage.manifests){if(byteHash(readInputBytes(root,m.file))!==m.hash)throw Error('Existing UUPS manifest changed');const storage=await provider.request('eth_getStorageAt',[m.proxy,'0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc','latest']);if(typeof storage!=='string'||storage.slice(-40).toLowerCase()!==m.implementation.slice(2))throw Error('Existing UUPS implementation changed');}
|
|
164
166
|
}
|
|
165
167
|
await assertArtifacts();await assertExistingCode();
|
|
@@ -183,16 +185,16 @@ export async function createDevelopmentDelivery(options:DevelopmentDeliveryOptio
|
|
|
183
185
|
for(const deployment of p.deployments){
|
|
184
186
|
if(deployment.initCodeHash&&'factory' in r&&getCreate2Address(r.factory,deployment.salt,deployment.initCodeHash).toLowerCase()!==deployment.address.toLowerCase())throw Error('Prepared CREATE2 address mismatch');
|
|
185
187
|
const code=await hre.ethers.provider.getCode(deployment.address);if(code==='0x')throw Error('Prepared deployment has no actual code');
|
|
186
|
-
const name=deployment.role==='proxy'?'@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy':p.contract;
|
|
188
|
+
const name=deployment.role==='proxy'?(p.proxyKind==='transparent'?TRANSPARENT_PROXY_ARTIFACT:'@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy'):p.contract;
|
|
187
189
|
const local=await checker.getLocalBytecode(name),comparison=checker.compareBytecode(code,local.bytecode,local.abi,local.immutableReferences);if(!comparison.matches)throw Error(`Prepared deployed code mismatch: ${name}`);
|
|
188
190
|
}
|
|
189
191
|
const deployed=p.deployments.find(d=>d.role==='proxy')?.address??('proxy' in r?r.proxy:p.deployments.find(d=>d.role==='contract')?.address);
|
|
190
192
|
if(!deployed)throw Error('Prepared deployment address missing');
|
|
191
|
-
const change={...entry.change,address:deployed,...(p.proxyKind
|
|
193
|
+
const change={...entry.change,address:deployed,...(p.proxyKind?{proxyAddress:deployed,proxyKind:p.proxyKind}:{})};changes.set(change.instanceId,change);
|
|
192
194
|
}
|
|
193
|
-
for(const change of changes.values())if(change.proxyKind==='uups'){
|
|
195
|
+
for(const change of changes.values())if(change.proxyKind==='uups'||change.proxyKind==='transparent'){
|
|
194
196
|
const entry=[...preparations].reverse().find(p=>p.change.instanceId===change.instanceId)!;
|
|
195
|
-
const candidate=await prepareEvmManifestCandidate({root,scheme:'evm',network:plan.target,target:plan.target,proxy:change.address,contract:entry.prepared.plan.contract,constructorArgs:change.constructorArgs??[],skipTxHash:true,hre,compile:false});
|
|
197
|
+
const candidate=await prepareEvmManifestCandidate({root,scheme:'evm',network:plan.target,target:plan.target,proxy:change.address,proxyKind:change.proxyKind,proxyAdminAddress:change.proxyAdminAddress,proxyAdminOwner:change.proxyAdminOwner,contract:entry.prepared.plan.contract,constructorArgs:change.constructorArgs??[],skipTxHash:true,hre,compile:false});
|
|
196
198
|
const expectedImplementation=entry.prepared.plan.deployments.find(d=>d.role==='implementation')?.address??change.implementationAddress;
|
|
197
199
|
if(!expectedImplementation||candidate.implementation.toLowerCase()!==expectedImplementation.toLowerCase())throw Error('Final UUPS implementation mismatch');
|
|
198
200
|
same(candidate.artifact,entry.prepared.plan.artifact,'UUPS artifact');change.implementationAddress=candidate.implementation;candidates.push(candidate);
|
|
@@ -225,7 +227,7 @@ export async function createDevelopmentDelivery(options:DevelopmentDeliveryOptio
|
|
|
225
227
|
}
|
|
226
228
|
files.push(...manifests.values());return commitDevelopmentFilesLocked({root,executionId:plan.executionId,identity,files},options.onFileCommitted);
|
|
227
229
|
});
|
|
228
|
-
for(const candidate of state.candidates){const manifest=parseTargetManifest(fs.readFileSync(candidate.paths.file)),entry=manifest.impls[candidate.versionKey];if(!entry||![entry.address,...(entry.allAddresses??[])].some(a=>a.toLowerCase()===candidate.implementation)||hashStorageLayout(entry.layout)!==candidate.layoutHash||!manifest.proxies.some(p=>p.address.toLowerCase()===candidate.proxy&&p.kind===
|
|
230
|
+
for(const candidate of state.candidates){const manifest=parseTargetManifest(fs.readFileSync(candidate.paths.file)),entry=manifest.impls[candidate.versionKey];if(!entry||![entry.address,...(entry.allAddresses??[])].some(a=>a.toLowerCase()===candidate.implementation)||hashStorageLayout(entry.layout)!==candidate.layoutHash||!manifest.proxies.some(p=>p.address.toLowerCase()===candidate.proxy&&p.kind===candidate.proxyKind))throw Error('Committed target manifest mismatch');}
|
|
229
231
|
return {journal:result,changes:state.changes,manifests:!preparations.length?pureCoverage().manifests:state.candidates.map(c=>({file:path.relative(root,c.paths.file),hash:byteHash(fs.readFileSync(c.paths.file)),layoutHash:c.layoutHash,proxy:c.proxy,implementation:c.implementation}))};
|
|
230
232
|
}
|
|
231
233
|
return Object.freeze({plan,
|
|
@@ -242,7 +244,7 @@ export async function createDevelopmentDelivery(options:DevelopmentDeliveryOptio
|
|
|
242
244
|
const assertions=await verifyBusiness(),finalized=result.snapshot.transactions.map(t=>t.observation!);
|
|
243
245
|
const materialization=await materialize(finalized,assertions);
|
|
244
246
|
const registry=fileBytes(root,'contractInfo.json')!,metadata=fileBytes(root,'deploymentInfo.json')!,effective:Record<string,Record<string,string>>={[plan.target]:{}},expectedCode:ExpectedDevelopmentCode[]=[];
|
|
245
|
-
for(const c of materialization.changes){effective[plan.target][c.contractInfoKey]=c.address;const alias=c.contractInfoKey.includes(':')?c.contractInfoKey.split(':')[0]:c.contractInfoKey;expectedCode.push({key:alias,contract:c.actualContract,address:c.implementationAddress??c.address});if(c.proxyKind
|
|
247
|
+
for(const c of materialization.changes){effective[plan.target][c.contractInfoKey]=c.address;const alias=c.contractInfoKey.includes(':')?c.contractInfoKey.split(':')[0]:c.contractInfoKey;expectedCode.push({key:alias,contract:c.actualContract,address:c.implementationAddress??c.address});if(c.proxyKind)expectedCode.push({key:`${alias}_Proxy`,contract:c.proxyKind==='transparent'?'TransparentUpgradeableProxy':'ERC1967Proxy',address:c.address});if(c.proxyKind==='transparent')expectedCode.push({key:`${alias}_ProxyAdmin`,contract:'ProxyAdmin',address:c.proxyAdminAddress});}
|
|
246
248
|
if(!preparations.length){const coverage=pureCoverage();Object.assign(effective,coverage.effective);expectedCode.push(...coverage.expected);}
|
|
247
249
|
const acceptancePath=`.gate-delivery/development/${plan.executionId}.acceptance.json`,priorAcceptance=fileBytes(root,acceptancePath);
|
|
248
250
|
if(priorAcceptance!==null){
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Environment labels are evidence; actual source, dependency and compiler inputs remain binding. */
|
|
2
|
+
import type { RuntimeEvidence } from './configuration-runtime';
|
|
3
|
+
import { parseCustomInputClosure, type CustomInputClosure } from './closure-format';
|
|
4
|
+
import { semanticHash } from '../workflow/lib/canonicalData';
|
|
5
|
+
import type { DeliveryAggregate } from './aggregate';
|
|
6
|
+
|
|
7
|
+
export function runtimeExecutionInput(runtime: RuntimeEvidence): Omit<RuntimeEvidence, 'node'> {
|
|
8
|
+
const { node: _environment, ...inputs } = runtime;
|
|
9
|
+
return inputs;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function compilerExecutionInput<T extends { node: string; platform: string; arch: string; abi: string }>(toolchain: T): Omit<T, 'node' | 'platform' | 'arch' | 'abi'> {
|
|
13
|
+
const { node: _node, platform: _platform, arch: _arch, abi: _abi, ...inputs } = toolchain;
|
|
14
|
+
return inputs;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Only resolver version and its derived exact hash are omitted; all actual edges/emitted bytes stay. */
|
|
18
|
+
export function customExecutionInput(raw: CustomInputClosure | null): unknown {
|
|
19
|
+
if (raw === null) return null;
|
|
20
|
+
const { closureHash: _exactHash, resolver, ...inputs } = parseCustomInputClosure(raw);
|
|
21
|
+
const { version: _nodeVersion, ...policy } = resolver;
|
|
22
|
+
return { ...inputs, resolver: policy };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Collection, dev execution and historical validation share the same preimage. */
|
|
26
|
+
export function aggregateInputHash(a: Pick<DeliveryAggregate, 'inputs'>): string {
|
|
27
|
+
return semanticHash({ version: 1, business: a.inputs.business, sourceDefinitions: a.inputs.sourceDefinitions,
|
|
28
|
+
runtime: runtimeExecutionInput(a.inputs.runtime), files: a.inputs.files,
|
|
29
|
+
targets: a.inputs.targets.map(row => ({ target: row.target, configuration: row.configuration.configurationRuntimeHash,
|
|
30
|
+
sourceConfiguration: row.sourceConfiguration.configurationRuntimeHash, compiler: row.compiler.stableDigest,
|
|
31
|
+
custom: customExecutionInput(row.custom) })) });
|
|
32
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Pure-call coverage from the accepted registration and owned compiler witness. No deployments are invented. */
|
|
2
|
-
import {artifactIdentity,parseTargetManifest,hashStorageLayout} from 'gate-evm-tools/workflow';
|
|
2
|
+
import {TRANSPARENT_PROXY_ARTIFACT,PROXY_ADMIN_ARTIFACT,transparentAdminAddress,artifactIdentity,parseTargetManifest,hashStorageLayout} from 'gate-evm-tools/workflow';
|
|
3
3
|
import {canonicalJson,semanticHash} from '../workflow/lib/canonicalData';
|
|
4
4
|
import {validateContractInfo} from '../workflow/lib/deployments';
|
|
5
5
|
import {validateDeploymentInfo} from '../workflow/lib/deploymentInfo';
|
|
@@ -26,10 +26,11 @@ export function existingCodeCoverage(input:{target:string;addresses:string[];reg
|
|
|
26
26
|
const [key]=matches[0],alias=key.split(':')[0],m=metadata[alias],contract=m?.actualContract??key.split(':').at(-1)!;
|
|
27
27
|
if(m&&(m.contractInfoKey!==key||m.address.toLowerCase()!==address))throw Error('Existing code metadata registration mismatch');
|
|
28
28
|
aliases.push(alias);effective[input.target][key]=address;
|
|
29
|
-
if(m?.proxyKind&&m.proxyKind!=='uups')throw Error('Unsupported existing proxy kind');
|
|
30
|
-
if(m?.proxyKind==='uups'){
|
|
31
|
-
const implementation=m.implementationAddress!.toLowerCase();add(alias,contract,implementation);add(`${alias}_Proxy`,'ERC1967Proxy',address);
|
|
32
|
-
|
|
29
|
+
if(m?.proxyKind&&m.proxyKind!=='uups'&&m.proxyKind!=='transparent')throw Error('Unsupported existing proxy kind');
|
|
30
|
+
if(m?.proxyKind==='uups'||m?.proxyKind==='transparent'){
|
|
31
|
+
const implementation=m.implementationAddress!.toLowerCase();add(alias,contract,implementation);add(`${alias}_Proxy`,m.proxyKind==='transparent'?TRANSPARENT_PROXY_ARTIFACT:'ERC1967Proxy',address);
|
|
32
|
+
if(m.proxyKind==='transparent'){if(m.proxyAdminAddress?.toLowerCase()!==transparentAdminAddress(address)||!m.proxyAdminOwner)throw Error('Missing existing Transparent admin identity');add(`${alias}_ProxyAdmin`,PROXY_ADMIN_ARTIFACT,m.proxyAdminAddress);}
|
|
33
|
+
const owned=input.manifests.flatMap(file=>{const manifest=parseTargetManifest(Buffer.from(file.contents));const proxies=manifest.proxies.filter(p=>p.address.toLowerCase()===address),impls=Object.entries(manifest.impls).filter(([,v])=>v&&[v.address,...(v.allAddresses??[])].some(a=>a.toLowerCase()===implementation));return proxies.length===1&&proxies[0].kind===m.proxyKind&&impls.length===1?[{file:file.path,hash:byteHash(file.contents),layoutHash:hashStorageLayout(impls[0][1]!.layout),proxy:address,implementation}]:[];});
|
|
33
34
|
if(owned.length!==1)throw Error('Missing unique sealed existing UUPS manifest');manifests.push(owned[0]);
|
|
34
35
|
}else add(alias,contract,address);
|
|
35
36
|
}
|
|
@@ -39,6 +40,6 @@ export function existingCodeCoverage(input:{target:string;addresses:string[];reg
|
|
|
39
40
|
/** Called only by the owned worker while the actual compiler artifact reader is installed. */
|
|
40
41
|
export async function collectExistingCodeArtifacts(input:{target:string;addresses:string[];registry:unknown;metadata:unknown;readArtifact(name:string):Promise<unknown>}){
|
|
41
42
|
const registry=validateContractInfo(input.registry)[input.target]??{},metadata=validateDeploymentInfo(input.metadata).networks[input.target]??{},names=new Set<string>();
|
|
42
|
-
for(const address of new Set(input.addresses.map(a=>a.toLowerCase()))){const entries=Object.entries(registry).filter(([,a])=>a.toLowerCase()===address);if(entries.length!==1)throw Error('Existing code target requires unique frozen registration');const [key]=entries[0],m=metadata[key.split(':')[0]];names.add(m?.actualContract??key.split(':').at(-1)!);if(m?.proxyKind==='uups')names.add('@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy');}
|
|
43
|
+
for(const address of new Set(input.addresses.map(a=>a.toLowerCase()))){const entries=Object.entries(registry).filter(([,a])=>a.toLowerCase()===address);if(entries.length!==1)throw Error('Existing code target requires unique frozen registration');const [key]=entries[0],m=metadata[key.split(':')[0]];names.add(m?.actualContract??key.split(':').at(-1)!);if(m?.proxyKind==='uups'||m?.proxyKind==='transparent'){names.add(m.proxyKind==='transparent'?TRANSPARENT_PROXY_ARTIFACT:'@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy');if(m.proxyKind==='transparent')names.add(PROXY_ADMIN_ARTIFACT);}}
|
|
43
44
|
for(const name of names)await input.readArtifact(name);
|
|
44
45
|
}
|
|
@@ -11,6 +11,8 @@ import { resolveDeliveryParameters, consumeDeliveryParameters, type ResolvedDeli
|
|
|
11
11
|
import { validateDeploySaveAs, type WorkflowStep } from '../workflow/lib/parameters';
|
|
12
12
|
import { canonicalJson, deepFreeze, semanticHash, exactObject, nonempty } from '../workflow/lib/canonicalData';
|
|
13
13
|
import type { DeepReadonly } from './source';
|
|
14
|
+
import { parseDeploymentRequirementRef } from './task-identity';
|
|
15
|
+
import { resolveParameterTargets } from './parameter-defaults';
|
|
14
16
|
|
|
15
17
|
export interface DeliveryInputOptions {
|
|
16
18
|
workspaceRoot: string;
|
|
@@ -83,20 +85,29 @@ export function openDeliveryInputs(raw: DeliveryInputOptions): DeliveryInputHand
|
|
|
83
85
|
files.push({ path: relative, digest: inputDigest(bytes) });
|
|
84
86
|
return parseInputDocument(bytes, format);
|
|
85
87
|
};
|
|
86
|
-
const task =
|
|
88
|
+
const task = object(read('task.yaml', 'yaml'), 'task.yaml', ['version', 'id', 'developmentNetwork', 'releaseTargetNetworks', 'requirementRef', 'productionRequirementRef', 'referenceDeploymentId']);
|
|
87
89
|
if (task.version !== 1 || task.id !== deploymentId) throw new Error('Task version/deployment identity mismatch');
|
|
90
|
+
same(parseDeploymentRequirementRef(task.requirementRef), scope.requirementRef, 'Task requirementRef');
|
|
91
|
+
same(task.referenceDeploymentId ?? null, scope.referenceDeploymentId ?? null, 'Task referenceDeploymentId');
|
|
88
92
|
same(task.developmentNetwork, scope.developmentNetwork, 'Task developmentNetwork');
|
|
89
|
-
|
|
93
|
+
const release = task.releaseTargetNetworks as string[];
|
|
94
|
+
if (!Array.isArray(release) || new Set(release).size !== release.length) throw Error('Invalid task releaseTargetNetworks');
|
|
95
|
+
for (const network of release) if(typeof network !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(network) || ['__proto__','prototype','constructor'].includes(network)) throw Error('Invalid release target');
|
|
96
|
+
if (input.request.environment === 'dev') {
|
|
97
|
+
if (!(scope.releaseTargetNetworks as string[]).every(network => release.includes(network))) throw Error('Task removed a development-declared release target');
|
|
98
|
+
} else {
|
|
99
|
+
same(release, scope.releaseTargetNetworks, 'Task releaseTargetNetworks');
|
|
100
|
+
same(task.productionRequirementRef === undefined ? null : parseDeploymentRequirementRef(task.productionRequirementRef), scope.productionRequirementRef ?? null, 'Task productionRequirementRef');
|
|
101
|
+
}
|
|
90
102
|
const manifest = object(read('manifest.yaml', 'yaml'), 'manifest.yaml', ['id', 'description', 'steps']);
|
|
91
103
|
if (manifest.id !== deploymentId) throw new Error('Manifest deployment identity mismatch');
|
|
92
104
|
if (manifest.description !== undefined) nonempty(manifest.description, 'manifest description');
|
|
93
105
|
const steps = parseSteps(manifest.steps);
|
|
94
106
|
const schema = object(read('parameters.schema.json', 'json'), 'parameters schema');
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const definitions = object(provenance.producers, 'producers'), observations = object(provenance.targets, 'provenance targets');
|
|
107
|
+
const dev = scope.developmentNetwork as string;
|
|
108
|
+
const all = [dev, ...release];
|
|
109
|
+
const { params, observations, definitions } = resolveParameterTargets(
|
|
110
|
+
read('parameters.yaml', 'yaml'), read('parameters.provenance.json', 'json'), all);
|
|
100
111
|
for (const [id, raw] of Object.entries(definitions)) {
|
|
101
112
|
safeId(id, 'producer ID');
|
|
102
113
|
const definition = exactObject(raw, ['version', 'module'], 'producer');
|
|
@@ -104,10 +115,6 @@ export function openDeliveryInputs(raw: DeliveryInputOptions): DeliveryInputHand
|
|
|
104
115
|
const module = portablePath(definition.module, 'producer module');
|
|
105
116
|
if (!module.startsWith(`${businessRoot}/`)) throw new Error('Producer module is outside deployment business root');
|
|
106
117
|
}
|
|
107
|
-
const dev = scope.developmentNetwork as string, release = scope.releaseTargetNetworks as string[];
|
|
108
|
-
const all = [dev, ...release];
|
|
109
|
-
for (const name of [...Object.keys(params), ...Object.keys(observations)]) if (!all.includes(name)) throw new Error('Unknown parameter target');
|
|
110
|
-
for (const value of Object.values(observations)) exactObject(value, ['manual', 'computed'], 'target provenance');
|
|
111
118
|
const selected = input.selection === 'development' ? [dev] : input.selection === 'release' ? release : all;
|
|
112
119
|
// Both the digest and every public projection use these exact buffers. Reopening
|
|
113
120
|
// for projection would permit an A→B→A edit to bind B's values to A's digest.
|
|
@@ -14,7 +14,7 @@ import type { DerivedBindings } from './bindings';
|
|
|
14
14
|
import { matchesSameForkInitial, sameForkBaselineDigest } from './same-fork-baseline';
|
|
15
15
|
export interface PreparationEntry extends PreparationInput { requestHash: string; gateToolPlanHash: string; mappings: PreparationMapping[]; preparationHash: string }
|
|
16
16
|
export interface JournalIdentity { target: string; chainId: string; expectedStepIds: readonly string[] }
|
|
17
|
-
const addressKeys = ['address', 'proxyAddress', 'implementationAddress', 'preparedImplementationAddress', 'placeholderImplementationAddress', 'factory', 'multicall', 'expectedAddress', 'predictedAddress', 'previousAddress'];
|
|
17
|
+
const addressKeys = ['address', 'proxyAddress', 'proxyAdminAddress', 'proxyAdminOwner', 'implementationAddress', 'preparedImplementationAddress', 'placeholderImplementationAddress', 'factory', 'multicall', 'expectedAddress', 'predictedAddress', 'previousAddress'];
|
|
18
18
|
const stringKeys = ['stepId', 'instanceId', 'actualContract', 'contractInfoKey', 'strategy', 'proxyKind', 'implementationSalt', 'salt', 'redeployReason'];
|
|
19
19
|
// Prepared changes cannot carry runtime reuse observations, receipts, candidate lifecycle, sync or success markers.
|
|
20
20
|
const changeKeys = [...addressKeys, ...stringKeys, 'kind', 'constructorArgs', 'leadingZeroBytes', 'gateTool'];
|
|
@@ -42,10 +42,10 @@ function normalizeInput(raw: unknown, identity: JournalIdentity): PreparationInp
|
|
|
42
42
|
if (!requestPath.endsWith(`/${stepId}-request.json`) || !planPath.endsWith(`/${stepId}-plan.json`)) throw new Error('Preparation step/ref mismatch');
|
|
43
43
|
if (request.scheme !== 'evm' || plan.scheme !== 'evm') throw new Error('Delivery preparation must use EVM');
|
|
44
44
|
if (plan.requestHash !== hashPreparationRequest(request) || plan.kind !== request.kind || plan.network !== request.network || plan.target !== request.target || plan.contract !== request.contract || plan.target !== identity.target || plan.chainId !== identity.chainId) throw new Error('Preparation request/plan identity mismatch');
|
|
45
|
-
if (change.stepId !== stepId || (change.kind === 'upgrade') !== (plan.kind === 'uups-upgrade') || change.actualContract !== plan.artifact.contractName || (plan.contract.includes(':') && plan.contract !== `${plan.artifact.sourceName}:${plan.artifact.contractName}`)) throw new Error('Preparation change/step/artifact identity mismatch');
|
|
45
|
+
if (change.stepId !== stepId || (change.kind === 'upgrade') !== (plan.kind === 'uups-upgrade' || plan.kind === 'transparent-upgrade') || change.actualContract !== plan.artifact.contractName || (plan.contract.includes(':') && plan.contract !== `${plan.artifact.sourceName}:${plan.artifact.contractName}`)) throw new Error('Preparation change/step/artifact identity mismatch');
|
|
46
46
|
if (canonicalJson(plan.transactions.map(t => t.purpose)) !== canonicalJson(expectedTransactionPurposes(plan))) throw new Error('Preparation transaction purposes/order mismatch');
|
|
47
47
|
if (!sameAddress(change.factory, request.factory) || change.contractInfoKey !== contractInfoKey(change.instanceId, change.actualContract)) throw new Error('Prepared factory/registry identity mismatch');
|
|
48
|
-
if (change.strategy !== (plan.kind === 'uups-upgrade' ? 'gate-tool' : 'create2')) throw new Error('Invalid prepared strategy');
|
|
48
|
+
if (change.strategy !== ((plan.kind === 'uups-upgrade' || plan.kind === 'transparent-upgrade') ? 'gate-tool' : 'create2')) throw new Error('Invalid prepared strategy');
|
|
49
49
|
const role = (name: string) => { const matches = plan.deployments.filter(d => d.role === name); if (matches.length !== 1) throw new Error(`Missing/duplicate preparation ${name}`); return matches[0]; };
|
|
50
50
|
const optionalAddress = (key: keyof DeploymentChange, expected: string) => {
|
|
51
51
|
if (Object.hasOwn(change, key) && !sameAddress(change[key], expected)) throw new Error(`Prepared ${key} does not match its canonical address`);
|
|
@@ -61,17 +61,21 @@ function normalizeInput(raw: unknown, identity: JournalIdentity): PreparationInp
|
|
|
61
61
|
if (Object.hasOwn(change, 'constructorArgs') && canonicalJson(change.constructorArgs) !== canonicalJson(request.constructorArgs)) throw new Error('Prepared constructorArgs differ from canonical request');
|
|
62
62
|
if (request.kind === 'create2-deploy') {
|
|
63
63
|
const deployment = role('contract');
|
|
64
|
-
rejectFields('proxyAddress', 'implementationAddress', 'preparedImplementationAddress', 'placeholderImplementationAddress', 'implementationSalt');
|
|
64
|
+
rejectFields('proxyAddress', 'implementationAddress', 'preparedImplementationAddress', 'placeholderImplementationAddress', 'implementationSalt', 'proxyAdminAddress', 'proxyAdminOwner');
|
|
65
65
|
if (change.proxyKind !== undefined || deployment.salt !== request.salt || change.salt !== request.salt || !sameAddress(change.predictedAddress, deployment.address)) throw new Error('Prepared CREATE2 request/deployment mismatch');
|
|
66
66
|
optionalAddress('address', deployment.address);
|
|
67
67
|
deploymentPolicy(request.addressPolicy, deployment.address);
|
|
68
68
|
} else {
|
|
69
69
|
const implementation = role('implementation');
|
|
70
|
-
if (change.proxyKind !==
|
|
70
|
+
if (change.proxyKind !== request.proxyKind || !sameAddress(change.implementationAddress, implementation.address) || implementation.salt !== request.implementationSalt) throw new Error('Prepared implementation mismatch');
|
|
71
71
|
optionalAddress('preparedImplementationAddress', implementation.address);
|
|
72
|
-
if
|
|
72
|
+
if(request.proxyKind==='transparent'){
|
|
73
|
+
if(!sameAddress(change.proxyAdminAddress,plan.proxyAdmin?.address)||!sameAddress(change.proxyAdminOwner,request.proxyAdminOwner)||!sameAddress(plan.proxyAdmin?.owner,request.proxyAdminOwner))throw Error('Prepared Transparent ProxyAdmin mismatch');
|
|
74
|
+
}else rejectFields('proxyAdminAddress','proxyAdminOwner');
|
|
75
|
+
if (request.kind === 'uups-placeholder-deploy' || request.kind === 'transparent-deploy') {
|
|
73
76
|
const proxy = role('proxy');
|
|
74
|
-
if (proxy.salt !== request.proxySalt || change.salt !== request.proxySalt || !sameAddress(change.predictedAddress, proxy.address) ||
|
|
77
|
+
if (proxy.salt !== request.proxySalt || change.salt !== request.proxySalt || !sameAddress(change.predictedAddress, proxy.address) || (request.kind==='uups-placeholder-deploy'&&!sameAddress(change.placeholderImplementationAddress, request.placeholderImplementation))) throw new Error('Prepared proxy mismatch');
|
|
78
|
+
if(request.kind==='transparent-deploy')rejectFields('placeholderImplementationAddress');
|
|
75
79
|
optionalAddress('address', proxy.address);
|
|
76
80
|
optionalAddress('proxyAddress', proxy.address);
|
|
77
81
|
deploymentPolicy(request.proxyAddressPolicy, proxy.address);
|
|
@@ -132,9 +136,9 @@ export function parsePreparationJournal(raw: unknown, transactions: readonly Rel
|
|
|
132
136
|
if (canonicalJson(entries.map(e => e.stepId)) !== canonicalJson(identity.expectedStepIds)) throw new Error('missing, extra or duplicate preparation steps');
|
|
133
137
|
for (const [index, entry] of entries.entries()) {
|
|
134
138
|
const {request,plan} = entry.prepared;
|
|
135
|
-
if (request.kind === 'uups-upgrade' && plan.validation.kind === 'uups-upgrade' && plan.validation.sameForkBaselineDigest !== undefined) {
|
|
139
|
+
if ((request.kind === 'uups-upgrade' || request.kind === 'transparent-upgrade') && (plan.validation.kind === 'uups-upgrade' || plan.validation.kind === 'transparent-upgrade') && plan.validation.sameForkBaselineDigest !== undefined) {
|
|
136
140
|
const validation = plan.validation;
|
|
137
|
-
const prior = entries.slice(0,index).filter(e => matchesSameForkInitial(e.prepared,request.target,plan.chainId,request.proxy,validation.currentImplementation));
|
|
141
|
+
const prior = entries.slice(0,index).filter(e => matchesSameForkInitial(e.prepared,request.target,plan.chainId,request.proxy,validation.currentImplementation,request.proxyKind));
|
|
138
142
|
if (prior.length !== 1 || sameForkBaselineDigest(prior[0].prepared,validation.oldLayoutHash) !== validation.sameForkBaselineDigest) throw new Error('Same-fork upgrade requires its exact prior initial preparation');
|
|
139
143
|
}
|
|
140
144
|
}
|
|
@@ -189,7 +193,7 @@ export class PreparationJournal implements PreparationSink {
|
|
|
189
193
|
assertUpgradeBaseline(proxy: string): boolean {
|
|
190
194
|
const matches = this.inputs.filter(i => matchesSameForkInitial(i.prepared,this.identity.target,this.identity.chainId,proxy));
|
|
191
195
|
if (!matches.length) return false;
|
|
192
|
-
if (matches.length !== 1 || !this.qualifiedSameFork?.(matches[0].prepared)) throw new Error('Same-fork
|
|
196
|
+
if (matches.length !== 1 || !this.qualifiedSameFork?.(matches[0].prepared)) throw new Error('Same-fork proxy upgrade requires a complete validated immutable OZ layout baseline; unsupported without that evidence');
|
|
193
197
|
return true;
|
|
194
198
|
}
|
|
195
199
|
seal(transactions: readonly ReleaseExecutionTransaction[], derived: DerivedBindings): PreparationEntry[] {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Expand task-owned defaults before schema/provenance validation. Never a production override port. */
|
|
2
|
+
import { ownPath, pointerPart } from './data';
|
|
3
|
+
import { object } from './protocol';
|
|
4
|
+
import { canonicalJson, exactObject } from '../workflow/lib/canonicalData';
|
|
5
|
+
|
|
6
|
+
type Observations = { manual: Record<string, unknown>; computed: Record<string, unknown> };
|
|
7
|
+
const record = (value: unknown): value is Record<string, unknown> =>
|
|
8
|
+
value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
9
|
+
function observations(raw: unknown): Observations {
|
|
10
|
+
const value = exactObject(raw, ['manual', 'computed'], 'target provenance');
|
|
11
|
+
return { manual: object(value.manual, 'manual observations'), computed: object(value.computed, 'computed observations') };
|
|
12
|
+
}
|
|
13
|
+
function leaves(value: unknown, path = '', result = new Map<string, unknown>()): Map<string, unknown> {
|
|
14
|
+
const entries = value !== null && typeof value === 'object' ? Object.entries(value) : [];
|
|
15
|
+
if (!entries.length) result.set(path, value);
|
|
16
|
+
else for (const [key, child] of entries) leaves(child, `${path}/${pointerPart(key)}`, result);
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
function merge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> {
|
|
20
|
+
return Object.fromEntries([...new Set([...Object.keys(base), ...Object.keys(override)])].map(key => [key,
|
|
21
|
+
!Object.hasOwn(override, key) ? base[key]
|
|
22
|
+
: Object.hasOwn(base, key) && record(base[key]) && record(override[key]) ? merge(base[key], override[key])
|
|
23
|
+
: override[key],
|
|
24
|
+
]));
|
|
25
|
+
}
|
|
26
|
+
/** Only leaves actually inherited from defaults may inherit default observations. Arrays replace as a unit. */
|
|
27
|
+
function inheritedLeaves(base: unknown, override: unknown, path = '', result = new Set<string>()): Set<string> {
|
|
28
|
+
if (!record(base) || !record(override)) return result;
|
|
29
|
+
for (const [key, value] of Object.entries(base)) {
|
|
30
|
+
const child = `${path}/${pointerPart(key)}`;
|
|
31
|
+
if (!Object.hasOwn(override, key)) for (const pointer of leaves(value, child).keys()) result.add(pointer);
|
|
32
|
+
else if (record(value) && record(override[key])) inheritedLeaves(value, override[key], child, result);
|
|
33
|
+
}
|
|
34
|
+
// The empty root/container is itself a schema leaf.
|
|
35
|
+
if (!Object.keys(base).length && !Object.keys(override).length) result.add(path);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveParameterTargets(rawValues: unknown, rawProvenance: unknown, networks: readonly string[]): {
|
|
40
|
+
params: Record<string, unknown>; observations: Record<string, Observations>; definitions: Record<string, unknown>;
|
|
41
|
+
} {
|
|
42
|
+
const values = object(rawValues, 'parameters.yaml', ['defaults', 'params']);
|
|
43
|
+
const params = object(ownPath(values, ['params'], 'target parameters'), 'target parameters');
|
|
44
|
+
const provenance = object(rawProvenance, 'parameters provenance', ['version', 'producers', 'defaults', 'targets']);
|
|
45
|
+
if (provenance.version !== 1) throw new Error('Unsupported provenance version');
|
|
46
|
+
const definitions = object(provenance.producers, 'producers'), targets = object(provenance.targets, 'provenance targets');
|
|
47
|
+
for (const name of [...Object.keys(params), ...Object.keys(targets)])
|
|
48
|
+
if (!networks.includes(name)) throw new Error('Unknown parameter target');
|
|
49
|
+
const observed = Object.fromEntries(Object.entries(targets).map(([name, value]) => [name, observations(value)]));
|
|
50
|
+
if (!Object.hasOwn(values, 'defaults')) {
|
|
51
|
+
if (Object.hasOwn(provenance, 'defaults')) throw new Error('Default provenance requires parameter defaults');
|
|
52
|
+
return { params, observations: observed, definitions };
|
|
53
|
+
}
|
|
54
|
+
const defaults = object(values.defaults, 'parameter defaults');
|
|
55
|
+
const shared = Object.hasOwn(provenance, 'defaults') ? observations(provenance.defaults) : { manual: {}, computed: {} };
|
|
56
|
+
const defaultLeaves = leaves(defaults);
|
|
57
|
+
for (const kind of ['manual', 'computed'] as const) for (const [path, raw] of Object.entries(shared[kind])) {
|
|
58
|
+
if (!defaultLeaves.has(path)) throw new Error(`Unused default parameter observation at ${path}`);
|
|
59
|
+
const observation = exactObject(raw, kind === 'manual' ? ['source', 'value'] : ['producer', 'version', 'inputs', 'output'], 'default observation');
|
|
60
|
+
if (canonicalJson(observation[kind === 'manual' ? 'value' : 'output']) !== canonicalJson(defaultLeaves.get(path)))
|
|
61
|
+
throw new Error(`Default observation mismatch at ${path}`);
|
|
62
|
+
}
|
|
63
|
+
const effective = Object.fromEntries(networks.map(name => {
|
|
64
|
+
const override = Object.hasOwn(params, name) ? object(params[name], 'network parameter overrides') : {};
|
|
65
|
+
return [name, merge(defaults, override)];
|
|
66
|
+
}));
|
|
67
|
+
const effectiveObservations = Object.fromEntries(networks.map(name => {
|
|
68
|
+
const override = Object.hasOwn(params, name) ? params[name] : {};
|
|
69
|
+
const inherited = inheritedLeaves(defaults, override), local = Object.hasOwn(observed, name) ? observed[name] : { manual: {}, computed: {} };
|
|
70
|
+
return [name, Object.fromEntries((['manual', 'computed'] as const).map(kind => [kind, {
|
|
71
|
+
...Object.fromEntries(Object.entries(shared[kind]).filter(([path]) => inherited.has(path))), ...local[kind],
|
|
72
|
+
}])) as Observations];
|
|
73
|
+
}));
|
|
74
|
+
return { params: effective, observations: effectiveObservations, definitions };
|
|
75
|
+
}
|
|
@@ -324,6 +324,24 @@ export function resolveDeliveryParameters(
|
|
|
324
324
|
const body = { version: 1 as const, ...input, provenance };
|
|
325
325
|
return deepFreeze({ ...body, identity: semanticHash(body) });
|
|
326
326
|
}
|
|
327
|
+
/** Read-only migration check, never a producer receipt or production authority. */
|
|
328
|
+
export function validateHistoricalParameterExtension(previous: ResolvedDeliveryParameters, current: ParameterInputs): ResolvedDeliveryParameters {
|
|
329
|
+
consumeDeliveryParameters(previous, previous.identity);
|
|
330
|
+
const input = strictData({schema: current.schema, target: current.target, values: current.values,
|
|
331
|
+
sources: current.sources ?? {}, manual: current.manual ?? {}, computed: current.computed ?? {}});
|
|
332
|
+
if (input.target !== previous.target) throw Error('Historical parameter target changed');
|
|
333
|
+
// A historical consumer cannot rerun or grant authority to a newly introduced producer.
|
|
334
|
+
for (const [pointer, observation] of Object.entries(input.computed)) {
|
|
335
|
+
if (canonicalJson(observation) !== canonicalJson(previous.computed[pointer] ?? null)) throw Error('Historical computed parameter changed; new development acceptance required');
|
|
336
|
+
}
|
|
337
|
+
const provenance = attest(input);
|
|
338
|
+
for (const leaf of previous.provenance) {
|
|
339
|
+
const next = provenance.find(candidate => candidate.path === leaf.path);
|
|
340
|
+
if (!next || canonicalJson(next) !== canonicalJson(leaf)) throw Error(`Historical parameter value/provenance changed: ${leaf.path}`);
|
|
341
|
+
}
|
|
342
|
+
const body = {version: 1 as const, ...input, provenance};
|
|
343
|
+
return deepFreeze({...body, identity: semanticHash(body)});
|
|
344
|
+
}
|
|
327
345
|
/** Consume a previously trusted identity; no fill-in, override, or producer invocation. */
|
|
328
346
|
export function consumeDeliveryParameters(
|
|
329
347
|
raw: ResolvedDeliveryParameters,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { yieldCompilerIo } from './compiler-io';
|
|
2
|
+
import { createCalldataInvocation, reviewTransaction, parseCalldataReviews, type CalldataTransactionReview } from './calldata-review';
|
|
3
|
+
import { preparationCalldataReviews } from './calldata-preparations';
|
|
2
4
|
import {assertOwnedTargetWorker} from './aggregate-bootstrap';
|
|
3
5
|
import type { ReferenceObservation } from "./references";
|
|
4
6
|
import { createDeliveryValidation } from "./validation";
|
|
@@ -67,6 +69,7 @@ export interface DeliveryRuntimeEvidence {
|
|
|
67
69
|
}
|
|
68
70
|
export interface DeliveryCollection {
|
|
69
71
|
plan: DeliveryPlan;
|
|
72
|
+
calldata: CalldataTransactionReview[];
|
|
70
73
|
preparations: PreparationEntry[];
|
|
71
74
|
verification: VerificationObservation[];
|
|
72
75
|
runtimeEvidence: DeliveryRuntimeEvidence;
|
|
@@ -95,14 +98,14 @@ export interface DeliveryPlanningOptions {
|
|
|
95
98
|
identities: PlanningIdentityPort;
|
|
96
99
|
steps: readonly WorkflowStep[];
|
|
97
100
|
derivationSeed: string;
|
|
98
|
-
expected?: Pick<DeliveryCollection, "plan" | "preparations" | "verification"
|
|
101
|
+
expected?: Pick<DeliveryCollection, "plan" | "preparations" | "verification"> & Partial<Pick<DeliveryCollection, 'calldata'>>;
|
|
99
102
|
completedTransactions?: CompletedExecutionTransaction[];
|
|
100
103
|
customSession?: CustomPlanningInputSession;
|
|
101
104
|
}
|
|
102
105
|
export interface StagedDeliveryCollection {
|
|
103
106
|
readonly payload: Omit<DeliveryPlanBody,'inputsHash'>;
|
|
104
107
|
readonly invariantHash:string;
|
|
105
|
-
readonly snapshot: {payload:Omit<DeliveryPlanBody,'inputsHash'>;preparations:PreparationEntry[];verification:VerificationObservation[];runtimeEvidence:Omit<DeliveryRuntimeEvidence,'forkAudit'>&{forkAudit:Omit<ForkAuditEvidence,'planHash'|'evidenceHash'>}};
|
|
108
|
+
readonly snapshot: {payload:Omit<DeliveryPlanBody,'inputsHash'>;calldata:CalldataTransactionReview[];preparations:PreparationEntry[];verification:VerificationObservation[];runtimeEvidence:Omit<DeliveryRuntimeEvidence,'forkAudit'>&{forkAudit:Omit<ForkAuditEvidence,'planHash'|'evidenceHash'>}};
|
|
106
109
|
assertUnchanged(): Promise<void>;
|
|
107
110
|
bind(inputsHash:string): DeliveryCollection;
|
|
108
111
|
close():void;
|
|
@@ -224,6 +227,7 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
224
227
|
});
|
|
225
228
|
const verification = new VerificationJournal([]);
|
|
226
229
|
const pendingObservations: DeliveryRuntimeEvidence["pendingUupsReuse"] = [];
|
|
230
|
+
const callReviews = new Map<string, CalldataTransactionReview>();
|
|
227
231
|
const operationIds = new DeliveryOperationIdentities();
|
|
228
232
|
const references: DeliveryRuntimeEvidence["references"] = [];
|
|
229
233
|
const customBindings: CustomEvidence[] = [],
|
|
@@ -249,6 +253,10 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
249
253
|
bindings,
|
|
250
254
|
preparations,
|
|
251
255
|
verification,
|
|
256
|
+
calldataReview: { record(tx, intent) {
|
|
257
|
+
if (callReviews.has(tx.transactionId)) throw Error('Duplicate calldata ABI intent');
|
|
258
|
+
callReviews.set(tx.transactionId, reviewTransaction(tx, createCalldataInvocation({ ...intent, data: tx.data })));
|
|
259
|
+
} },
|
|
252
260
|
executionPlanner: planner,
|
|
253
261
|
transactionIdentity: operationIds,
|
|
254
262
|
transactionObserver: audit,
|
|
@@ -326,6 +334,12 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
326
334
|
derivedBindings = bindings.seal();
|
|
327
335
|
const prepared = preparations.seal(transactions, derivedBindings),
|
|
328
336
|
observations = verification.seal();
|
|
337
|
+
for (const review of await preparationCalldataReviews(prepared, transactions, context.runtime.hre.artifacts)) {
|
|
338
|
+
if (callReviews.has(review.transactionId)) throw Error('Duplicate calldata preparation intent');
|
|
339
|
+
callReviews.set(review.transactionId, review);
|
|
340
|
+
}
|
|
341
|
+
const calldata = parseCalldataReviews(transactions.map(tx => callReviews.get(tx.transactionId)), transactions);
|
|
342
|
+
if (input.expected?.calldata && canonicalJson(parseCalldataReviews(input.expected.calldata, transactions)) !== canonicalJson(calldata)) throw Error('Replayed calldata ABI intent differs');
|
|
329
343
|
const {inputsHash:knownHash,...base}=header;
|
|
330
344
|
const payload = deepFreeze({
|
|
331
345
|
...base,
|
|
@@ -359,7 +373,7 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
359
373
|
throw new Error("Replayed verification evidence differs");
|
|
360
374
|
session?.closeReads();
|
|
361
375
|
const interval=await audit.capture({transactions,completedTransactions:input.completedTransactions??[]});
|
|
362
|
-
const stagedSnapshot=deepFreeze({payload,preparations:prepared,verification:observations,runtimeEvidence:{pendingUupsReuse:pendingObservations,forkAudit:interval.snapshot,references}});
|
|
376
|
+
const stagedSnapshot=deepFreeze({payload,calldata,preparations:prepared,verification:observations,runtimeEvidence:{pendingUupsReuse:pendingObservations,forkAudit:interval.snapshot,references}});
|
|
363
377
|
const invariantHash=semanticHash(stagedSnapshot);
|
|
364
378
|
let state:'staged'|'bound'|'failed'|'closed'='staged';
|
|
365
379
|
const open=()=>{if(state!=='staged')throw new Error('Staged collection closed or already bound');};
|
|
@@ -368,7 +382,7 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
368
382
|
const plan=sealDeliveryPlan({...payload,inputsHash});
|
|
369
383
|
if(expected&&plan.planHash!==expected.planHash)throw new Error('Replayed delivery plan differs from expected plan');
|
|
370
384
|
const forkAudit=interval.bind(plan.planHash);
|
|
371
|
-
const result=deepFreeze(canonicalData({plan,preparations:prepared,verification:observations,
|
|
385
|
+
const result=deepFreeze(canonicalData({plan,calldata,preparations:prepared,verification:observations,
|
|
372
386
|
runtimeEvidence:{pendingUupsReuse:pendingObservations,forkAudit,references}}) as unknown as DeliveryCollection);
|
|
373
387
|
if(collectionInvariantHash(result)!==invariantHash)throw new Error('Binding changed staged collection payload');
|
|
374
388
|
state='bound';return result;
|
|
@@ -393,5 +407,5 @@ async function collectOwned(input:DeliveryPlanningOptions,staging:boolean):Promi
|
|
|
393
407
|
export function collectionInvariantHash(collection:DeliveryCollection):string {
|
|
394
408
|
const {inputsHash:_,planHash:__,...payload}=collection.plan;
|
|
395
409
|
const {planHash:___,evidenceHash:____,...forkAudit}=collection.runtimeEvidence.forkAudit;
|
|
396
|
-
return semanticHash({payload,preparations:collection.preparations,verification:collection.verification,runtimeEvidence:{...collection.runtimeEvidence,forkAudit}});
|
|
410
|
+
return semanticHash({payload,calldata:collection.calldata,preparations:collection.preparations,verification:collection.verification,runtimeEvidence:{...collection.runtimeEvidence,forkAudit}});
|
|
397
411
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Interface, concat, getCreate2Address } from "ethers";
|
|
3
3
|
import {
|
|
4
4
|
artifactIdentity,
|
|
5
|
+
TRANSPARENT_PROXY_ARTIFACT, PROXY_ADMIN_ARTIFACT, PROXY_ADMIN_INTERFACE, transparentAdminAddress,
|
|
5
6
|
type GateToolArtifact,
|
|
6
7
|
type GateToolPreparationPlanV1,
|
|
7
8
|
type GateToolPreparationRequestV1,
|
|
@@ -173,10 +174,24 @@ export async function validatePreparationSemantics(
|
|
|
173
174
|
artifact,
|
|
174
175
|
request.constructorArgs,
|
|
175
176
|
request.implementationSalt,
|
|
176
|
-
request.kind === "uups-upgrade"
|
|
177
|
+
(request.kind === "uups-upgrade" || request.kind === "transparent-upgrade")
|
|
177
178
|
? request.implementationAddressPolicy
|
|
178
179
|
: undefined,
|
|
179
180
|
);
|
|
181
|
+
if(request.kind === 'transparent-deploy' || request.kind === 'transparent-upgrade'){
|
|
182
|
+
if(request.call)validateAbiArguments(artifact.abi,request.call.method,request.call.args);
|
|
183
|
+
const data=request.call?new Interface(artifact.abi).encodeFunctionData(request.call.method,request.call.args):'0x';
|
|
184
|
+
await read(PROXY_ADMIN_ARTIFACT);
|
|
185
|
+
const proxy=request.kind==='transparent-deploy'
|
|
186
|
+
?role('proxy',deliveryArtifact(await read(TRANSPARENT_PROXY_ARTIFACT)),[implementation,request.proxyAdminOwner,data],request.proxySalt,request.proxyAddressPolicy)
|
|
187
|
+
:request.proxy.toLowerCase();
|
|
188
|
+
const admin=transparentAdminAddress(proxy);
|
|
189
|
+
if(plan.proxyKind!=='transparent'||plan.proxyAdmin?.address!==admin||plan.proxyAdmin?.owner!==request.proxyAdminOwner.toLowerCase()
|
|
190
|
+
||(request.kind==='transparent-upgrade'&&request.proxyAdmin.toLowerCase()!==admin))throw Error('Actual Transparent admin identity differs from preparation');
|
|
191
|
+
if(request.kind==='transparent-upgrade')transactions.push({id:'upgrade-proxy',purpose:'upgrade-proxy',to:admin,value:'0',operation:0,
|
|
192
|
+
data:PROXY_ADMIN_INTERFACE.encodeFunctionData('upgradeAndCall',[proxy,implementation,data]).toLowerCase()});
|
|
193
|
+
if(request.kind==='transparent-deploy'&&deployments.find(d=>d.role==='proxy')?.status==='reused'&&deployments.some(d=>d.status==='required'))throw Error('Invalid actual Transparent reuse roles');
|
|
194
|
+
} else {
|
|
180
195
|
const proxy =
|
|
181
196
|
request.kind === "uups-placeholder-deploy"
|
|
182
197
|
? role(
|
|
@@ -215,6 +230,7 @@ export async function validatePreparationSemantics(
|
|
|
215
230
|
});
|
|
216
231
|
else if (deployments.some((d) => d.status === "required"))
|
|
217
232
|
throw new Error("Invalid actual UUPS reuse roles");
|
|
233
|
+
}
|
|
218
234
|
}
|
|
219
235
|
if (
|
|
220
236
|
canonicalJson(deployments) !== canonicalJson(plan.deployments) ||
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Remove signing authority, retaining independent model/RPC API configuration. */
|
|
2
2
|
export function productionChildEnvironment(input:NodeJS.ProcessEnv):NodeJS.ProcessEnv {
|
|
3
3
|
const out={...input};
|
|
4
|
-
|
|
4
|
+
// Also discard the retired alias if it remains in a caller's environment; it is never a signer input.
|
|
5
|
+
for(const key of Object.keys(out))if(/(^|_)(PRIVATE_KEY|WALLET_CREDENTIAL|MNEMONIC|SEED_PHRASE)$/.test(key)||key==='CUSTODY_API_BASE_URL'||/^GATEFLOW_(OPERATOR_TOKEN|PRODUCTION_|MAC_SECURE_SIGNER_)/.test(key)||/^GATE_(CUSTODY|SIGNER)_/.test(key))delete out[key];
|
|
5
6
|
return out;
|
|
6
7
|
}
|