gate-evm-tools 1.0.31 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/README.md +34 -20
  2. package/bin/cli.js +3 -0
  3. package/bin/delivery.cjs +8 -7
  4. package/dist/commands/check.d.ts.map +1 -1
  5. package/dist/commands/check.js +26 -2
  6. package/dist/commands/check.js.map +1 -1
  7. package/dist/commands/plan/index.d.ts.map +1 -1
  8. package/dist/commands/plan/index.js +1 -1
  9. package/dist/commands/plan/index.js.map +1 -1
  10. package/dist/core/preparation/batch.d.ts +26 -0
  11. package/dist/core/preparation/batch.d.ts.map +1 -0
  12. package/dist/core/preparation/batch.js +72 -0
  13. package/dist/core/preparation/batch.js.map +1 -0
  14. package/dist/core/preparation/evm.d.ts +23 -4
  15. package/dist/core/preparation/evm.d.ts.map +1 -1
  16. package/dist/core/preparation/evm.js +19 -3
  17. package/dist/core/preparation/evm.js.map +1 -1
  18. package/dist/core/preparation/evmManifestSync.d.ts +5 -0
  19. package/dist/core/preparation/evmManifestSync.d.ts.map +1 -1
  20. package/dist/core/preparation/evmManifestSync.js +15 -7
  21. package/dist/core/preparation/evmManifestSync.js.map +1 -1
  22. package/dist/core/preparation/index.d.ts +2 -2
  23. package/dist/core/preparation/index.d.ts.map +1 -1
  24. package/dist/core/preparation/manifest.d.ts +2 -0
  25. package/dist/core/preparation/manifest.d.ts.map +1 -1
  26. package/dist/core/preparation/manifest.js +2 -2
  27. package/dist/core/preparation/manifest.js.map +1 -1
  28. package/dist/core/preparation/normalize.d.ts.map +1 -1
  29. package/dist/core/preparation/normalize.js +53 -11
  30. package/dist/core/preparation/normalize.js.map +1 -1
  31. package/dist/core/preparation/transparent.d.ts +23 -0
  32. package/dist/core/preparation/transparent.d.ts.map +1 -0
  33. package/dist/core/preparation/transparent.js +103 -0
  34. package/dist/core/preparation/transparent.js.map +1 -0
  35. package/dist/core/preparation/types.d.ts +47 -5
  36. package/dist/core/preparation/types.d.ts.map +1 -1
  37. package/dist/core/preparation/zksync.d.ts.map +1 -1
  38. package/dist/core/preparation/zksync.js +2 -0
  39. package/dist/core/preparation/zksync.js.map +1 -1
  40. package/dist/custody/credential.d.ts.map +1 -1
  41. package/dist/custody/credential.js +1 -6
  42. package/dist/custody/credential.js.map +1 -1
  43. package/dist/deployment-evm/index.d.ts +4 -0
  44. package/dist/deployment-evm/index.d.ts.map +1 -0
  45. package/dist/deployment-evm/index.js +3 -0
  46. package/dist/deployment-evm/index.js.map +1 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +4 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/sync/index.d.ts.map +1 -1
  51. package/dist/sync/index.js +5 -0
  52. package/dist/sync/index.js.map +1 -1
  53. package/dist/types.d.ts +3 -0
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/workflow/index.d.ts +4 -1
  56. package/dist/workflow/index.d.ts.map +1 -1
  57. package/dist/workflow/index.js +2 -0
  58. package/dist/workflow/index.js.map +1 -1
  59. package/dist-cjs/core/preparation/batch.js +76 -0
  60. package/dist-cjs/core/preparation/batch.js.map +1 -0
  61. package/dist-cjs/core/preparation/evm.js +25 -7
  62. package/dist-cjs/core/preparation/evm.js.map +1 -1
  63. package/dist-cjs/core/preparation/evmManifestSync.js +15 -7
  64. package/dist-cjs/core/preparation/evmManifestSync.js.map +1 -1
  65. package/dist-cjs/core/preparation/manifest.js +2 -2
  66. package/dist-cjs/core/preparation/manifest.js.map +1 -1
  67. package/dist-cjs/core/preparation/normalize.js +53 -11
  68. package/dist-cjs/core/preparation/normalize.js.map +1 -1
  69. package/dist-cjs/core/preparation/transparent.js +110 -0
  70. package/dist-cjs/core/preparation/transparent.js.map +1 -0
  71. package/dist-cjs/core/preparation/zksync.js +2 -0
  72. package/dist-cjs/core/preparation/zksync.js.map +1 -1
  73. package/dist-cjs/custody/credential.js +1 -6
  74. package/dist-cjs/custody/credential.js.map +1 -1
  75. package/dist-cjs/deployment-evm/index.js +10 -0
  76. package/dist-cjs/deployment-evm/index.js.map +1 -0
  77. package/dist-cjs/sync/index.js +5 -0
  78. package/dist-cjs/sync/index.js.map +1 -1
  79. package/dist-cjs/workflow/index.js +11 -1
  80. package/dist-cjs/workflow/index.js.map +1 -1
  81. package/dist-runtime/config/hardhatAdapters.js +2 -1
  82. package/dist-runtime/config/hardhatAdapters.js.map +1 -1
  83. package/dist-runtime/delivery/aggregate-bootstrap.js +3 -1
  84. package/dist-runtime/delivery/aggregate-bootstrap.js.map +1 -1
  85. package/dist-runtime/delivery/aggregate-channel.js +7 -3
  86. package/dist-runtime/delivery/aggregate-channel.js.map +1 -1
  87. package/dist-runtime/delivery/aggregate-diagnostics.d.ts +14 -0
  88. package/dist-runtime/delivery/aggregate-diagnostics.js +73 -0
  89. package/dist-runtime/delivery/aggregate-diagnostics.js.map +1 -0
  90. package/dist-runtime/delivery/aggregate-inputs.d.ts +13 -9
  91. package/dist-runtime/delivery/aggregate-source.js +11 -3
  92. package/dist-runtime/delivery/aggregate-source.js.map +1 -1
  93. package/dist-runtime/delivery/aggregate-worker.js +12 -4
  94. package/dist-runtime/delivery/aggregate-worker.js.map +1 -1
  95. package/dist-runtime/delivery/aggregate.js +2 -2
  96. package/dist-runtime/delivery/aggregate.js.map +1 -1
  97. package/dist-runtime/delivery/business-extension.d.ts +10 -0
  98. package/dist-runtime/delivery/business-extension.js +38 -0
  99. package/dist-runtime/delivery/business-extension.js.map +1 -0
  100. package/dist-runtime/delivery/calldata-archive.d.ts +18 -0
  101. package/dist-runtime/delivery/calldata-archive.js +31 -0
  102. package/dist-runtime/delivery/calldata-archive.js.map +1 -0
  103. package/dist-runtime/delivery/calldata-details.d.ts +47 -0
  104. package/dist-runtime/delivery/calldata-details.js +94 -0
  105. package/dist-runtime/delivery/calldata-details.js.map +1 -0
  106. package/dist-runtime/delivery/calldata-format.d.ts +4 -0
  107. package/dist-runtime/delivery/calldata-format.js +17 -0
  108. package/dist-runtime/delivery/calldata-format.js.map +1 -0
  109. package/dist-runtime/delivery/calldata-preparations.d.ts +13 -0
  110. package/dist-runtime/delivery/calldata-preparations.js +85 -0
  111. package/dist-runtime/delivery/calldata-preparations.js.map +1 -0
  112. package/dist-runtime/delivery/calldata-review.d.ts +44 -0
  113. package/dist-runtime/delivery/calldata-review.js +131 -0
  114. package/dist-runtime/delivery/calldata-review.js.map +1 -0
  115. package/dist-runtime/delivery/codec-pin.d.ts +2 -2
  116. package/dist-runtime/delivery/codec-pin.js +4 -4
  117. package/dist-runtime/delivery/codec-pin.js.map +1 -1
  118. package/dist-runtime/delivery/compiler-files.js +3 -1
  119. package/dist-runtime/delivery/compiler-files.js.map +1 -1
  120. package/dist-runtime/delivery/compiler-pins.js +1 -1
  121. package/dist-runtime/delivery/compiler.js +17 -16
  122. package/dist-runtime/delivery/compiler.js.map +1 -1
  123. package/dist-runtime/delivery/config.d.ts +1 -1
  124. package/dist-runtime/delivery/config.js +27 -2
  125. package/dist-runtime/delivery/config.js.map +1 -1
  126. package/dist-runtime/delivery/configuration-definition.d.ts +9 -0
  127. package/dist-runtime/delivery/configuration-definition.js +33 -6
  128. package/dist-runtime/delivery/configuration-definition.js.map +1 -1
  129. package/dist-runtime/delivery/configuration.js +7 -4
  130. package/dist-runtime/delivery/configuration.js.map +1 -1
  131. package/dist-runtime/delivery/contract-source.d.ts +14 -0
  132. package/dist-runtime/delivery/contract-source.js +138 -0
  133. package/dist-runtime/delivery/contract-source.js.map +1 -0
  134. package/dist-runtime/delivery/custom-format.js +51 -24
  135. package/dist-runtime/delivery/custom-format.js.map +1 -1
  136. package/dist-runtime/delivery/development-inputs.d.ts +14 -0
  137. package/dist-runtime/delivery/development-inputs.js +76 -0
  138. package/dist-runtime/delivery/development-inputs.js.map +1 -0
  139. package/dist-runtime/delivery/development.d.ts +3 -1
  140. package/dist-runtime/delivery/development.js +24 -10
  141. package/dist-runtime/delivery/development.js.map +1 -1
  142. package/dist-runtime/delivery/eoa.d.ts +1 -0
  143. package/dist-runtime/delivery/execution-identity.d.ts +15 -0
  144. package/dist-runtime/delivery/execution-identity.js +33 -0
  145. package/dist-runtime/delivery/execution-identity.js.map +1 -0
  146. package/dist-runtime/delivery/existing-code.js +14 -6
  147. package/dist-runtime/delivery/existing-code.js.map +1 -1
  148. package/dist-runtime/delivery/history-package.d.ts +2 -0
  149. package/dist-runtime/delivery/history-package.js +70 -0
  150. package/dist-runtime/delivery/history-package.js.map +1 -0
  151. package/dist-runtime/delivery/history-registration.d.ts +1 -1
  152. package/dist-runtime/delivery/inputs.js +22 -15
  153. package/dist-runtime/delivery/inputs.js.map +1 -1
  154. package/dist-runtime/delivery/journal.js +18 -10
  155. package/dist-runtime/delivery/journal.js.map +1 -1
  156. package/dist-runtime/delivery/parameter-defaults.d.ts +10 -0
  157. package/dist-runtime/delivery/parameter-defaults.js +86 -0
  158. package/dist-runtime/delivery/parameter-defaults.js.map +1 -0
  159. package/dist-runtime/delivery/parameters.d.ts +2 -0
  160. package/dist-runtime/delivery/parameters.js +22 -0
  161. package/dist-runtime/delivery/parameters.js.map +1 -1
  162. package/dist-runtime/delivery/planning.d.ts +4 -1
  163. package/dist-runtime/delivery/planning.js +19 -3
  164. package/dist-runtime/delivery/planning.js.map +1 -1
  165. package/dist-runtime/delivery/preparation.js +43 -23
  166. package/dist-runtime/delivery/preparation.js.map +1 -1
  167. package/dist-runtime/delivery/production-environment.js +2 -1
  168. package/dist-runtime/delivery/production-environment.js.map +1 -1
  169. package/dist-runtime/delivery/production-finalization.js +23 -9
  170. package/dist-runtime/delivery/production-finalization.js.map +1 -1
  171. package/dist-runtime/delivery/production-intent.d.ts +2 -0
  172. package/dist-runtime/delivery/production-intent.js +16 -0
  173. package/dist-runtime/delivery/production-intent.js.map +1 -0
  174. package/dist-runtime/delivery/production.d.ts +129 -8
  175. package/dist-runtime/delivery/production.js +60 -11
  176. package/dist-runtime/delivery/production.js.map +1 -1
  177. package/dist-runtime/delivery/project-files.d.ts +3 -3
  178. package/dist-runtime/delivery/project-files.js +19 -14
  179. package/dist-runtime/delivery/project-files.js.map +1 -1
  180. package/dist-runtime/delivery/project-rpc.d.ts +19 -0
  181. package/dist-runtime/delivery/project-rpc.js +138 -0
  182. package/dist-runtime/delivery/project-rpc.js.map +1 -0
  183. package/dist-runtime/delivery/project.d.ts +3 -1
  184. package/dist-runtime/delivery/project.js +21 -8
  185. package/dist-runtime/delivery/project.js.map +1 -1
  186. package/dist-runtime/delivery/public-calldata.d.ts +25 -0
  187. package/dist-runtime/delivery/public-calldata.js +97 -0
  188. package/dist-runtime/delivery/public-calldata.js.map +1 -0
  189. package/dist-runtime/delivery/release-graph.d.ts +7 -3
  190. package/dist-runtime/delivery/release-graph.js +58 -25
  191. package/dist-runtime/delivery/release-graph.js.map +1 -1
  192. package/dist-runtime/delivery/release-history-capture.js +22 -26
  193. package/dist-runtime/delivery/release-history-capture.js.map +1 -1
  194. package/dist-runtime/delivery/release-history.d.ts +3 -2
  195. package/dist-runtime/delivery/release-history.js +97 -50
  196. package/dist-runtime/delivery/release-history.js.map +1 -1
  197. package/dist-runtime/delivery/release-inputs.d.ts +33 -0
  198. package/dist-runtime/delivery/release-inputs.js +129 -0
  199. package/dist-runtime/delivery/release-inputs.js.map +1 -0
  200. package/dist-runtime/delivery/release.d.ts +38 -14
  201. package/dist-runtime/delivery/release.js +81 -29
  202. package/dist-runtime/delivery/release.js.map +1 -1
  203. package/dist-runtime/delivery/safe.d.ts +1 -0
  204. package/dist-runtime/delivery/safe.js +13 -2
  205. package/dist-runtime/delivery/safe.js.map +1 -1
  206. package/dist-runtime/delivery/same-fork-baseline.d.ts +1 -1
  207. package/dist-runtime/delivery/same-fork-baseline.js +5 -4
  208. package/dist-runtime/delivery/same-fork-baseline.js.map +1 -1
  209. package/dist-runtime/delivery/setup.d.ts +1 -1
  210. package/dist-runtime/delivery/setup.js +21 -6
  211. package/dist-runtime/delivery/setup.js.map +1 -1
  212. package/dist-runtime/delivery/source.d.ts +1 -0
  213. package/dist-runtime/delivery/source.js +12 -10
  214. package/dist-runtime/delivery/source.js.map +1 -1
  215. package/dist-runtime/delivery/task-identity.d.ts +23 -0
  216. package/dist-runtime/delivery/task-identity.js +109 -0
  217. package/dist-runtime/delivery/task-identity.js.map +1 -0
  218. package/dist-runtime/delivery/toolchain.d.ts +3 -0
  219. package/dist-runtime/delivery/toolchain.js +52 -0
  220. package/dist-runtime/delivery/toolchain.js.map +1 -0
  221. package/dist-runtime/delivery/validation.js +7 -2
  222. package/dist-runtime/delivery/validation.js.map +1 -1
  223. package/dist-runtime/runtime-identity.json +2 -2
  224. package/dist-runtime/vendor/plan-codec/index.cjs +97 -20
  225. package/dist-runtime/vendor/plan-codec/index.d.cts +6 -0
  226. package/dist-runtime/vendor/plan-codec/provenance.json +9 -8
  227. package/dist-runtime/workflow/lib/calls.js +1 -0
  228. package/dist-runtime/workflow/lib/calls.js.map +1 -1
  229. package/dist-runtime/workflow/lib/checkCodeRunner.js +7 -4
  230. package/dist-runtime/workflow/lib/checkCodeRunner.js.map +1 -1
  231. package/dist-runtime/workflow/lib/context.d.ts +1 -0
  232. package/dist-runtime/workflow/lib/create2.d.ts +4 -26
  233. package/dist-runtime/workflow/lib/create2.js +2 -67
  234. package/dist-runtime/workflow/lib/create2.js.map +1 -1
  235. package/dist-runtime/workflow/lib/deploymentInfo.d.ts +2 -0
  236. package/dist-runtime/workflow/lib/deploymentInfo.js +6 -0
  237. package/dist-runtime/workflow/lib/deploymentInfo.js.map +1 -1
  238. package/dist-runtime/workflow/lib/deploymentRecords.d.ts +2 -0
  239. package/dist-runtime/workflow/lib/deploymentRecords.js +1 -1
  240. package/dist-runtime/workflow/lib/deploymentRecords.js.map +1 -1
  241. package/dist-runtime/workflow/lib/externalExecutionScanner.js +2 -1
  242. package/dist-runtime/workflow/lib/externalExecutionScanner.js.map +1 -1
  243. package/dist-runtime/workflow/lib/gateTool.js +2 -2
  244. package/dist-runtime/workflow/lib/gateTool.js.map +1 -1
  245. package/dist-runtime/workflow/lib/gateToolSync.d.ts +3 -0
  246. package/dist-runtime/workflow/lib/gateToolSync.js +5 -0
  247. package/dist-runtime/workflow/lib/gateToolSync.js.map +1 -1
  248. package/dist-runtime/workflow/lib/parameters.js +5 -0
  249. package/dist-runtime/workflow/lib/parameters.js.map +1 -1
  250. package/dist-runtime/workflow/lib/proxy.d.ts +1 -0
  251. package/dist-runtime/workflow/lib/proxy.js.map +1 -1
  252. package/dist-runtime/workflow/run.js +1 -3
  253. package/dist-runtime/workflow/run.js.map +1 -1
  254. package/dist-runtime/workflow/steps/deploy.js +53 -0
  255. package/dist-runtime/workflow/steps/deploy.js.map +1 -1
  256. package/dist-runtime/workflow/steps/upgrade.js +24 -10
  257. package/dist-runtime/workflow/steps/upgrade.js.map +1 -1
  258. package/docs/compiler-qualification.md +8 -2
  259. package/docs/delivery-aggregate.md +2 -0
  260. package/docs/delivery-calldata.md +27 -0
  261. package/docs/delivery-development.md +6 -0
  262. package/docs/delivery-execution-store.md +1 -1
  263. package/docs/delivery-inputs.md +55 -6
  264. package/docs/delivery-parameters.md +1 -1
  265. package/docs/delivery-release.md +77 -7
  266. package/docs/delivery-safe.md +7 -4
  267. package/docs/delivery-setup.md +72 -20
  268. package/docs/delivery-source.md +8 -8
  269. package/docs/direct-package-acceptance.md +2 -0
  270. package/docs/openzeppelin-acceptance.md +86 -0
  271. package/docs/openzeppelin-baseline.json +27 -0
  272. package/docs/openzeppelin-integration.md +115 -0
  273. package/docs/plans/2026-10-28-openzeppelin-toolkit-consolidation.md +396 -0
  274. package/docs/plans/2026-11-02-transparent-proxy-delivery.md +78 -0
  275. package/docs/superpowers/plans/2026-08-17-custody-hardhat-signers.md +1 -1
  276. package/docs/workflow-reference.md +12 -4
  277. package/docs/workflow-runtime.md +6 -0
  278. package/package.json +19 -5
  279. package/runtime/config/hardhatAdapters.ts +2 -1
  280. package/runtime/delivery/aggregate-bootstrap.ts +3 -1
  281. package/runtime/delivery/aggregate-channel.ts +6 -3
  282. package/runtime/delivery/aggregate-diagnostics.ts +63 -0
  283. package/runtime/delivery/aggregate-source.ts +6 -2
  284. package/runtime/delivery/aggregate-worker.ts +15 -5
  285. package/runtime/delivery/aggregate.ts +2 -2
  286. package/runtime/delivery/business-extension.ts +33 -0
  287. package/runtime/delivery/calldata-archive.ts +25 -0
  288. package/runtime/delivery/calldata-details.ts +90 -0
  289. package/runtime/delivery/calldata-format.ts +14 -0
  290. package/runtime/delivery/calldata-preparations.ts +76 -0
  291. package/runtime/delivery/calldata-review.ts +126 -0
  292. package/runtime/delivery/codec-pin.ts +3 -3
  293. package/runtime/delivery/compiler-files.ts +3 -1
  294. package/runtime/delivery/compiler-pins.ts +1 -1
  295. package/runtime/delivery/compiler.ts +18 -17
  296. package/runtime/delivery/config.ts +25 -2
  297. package/runtime/delivery/configuration-definition.ts +34 -7
  298. package/runtime/delivery/configuration.ts +8 -5
  299. package/runtime/delivery/contract-source.ts +112 -0
  300. package/runtime/delivery/custom-format.ts +20 -5
  301. package/runtime/delivery/development-inputs.ts +42 -0
  302. package/runtime/delivery/development.ts +14 -11
  303. package/runtime/delivery/execution-identity.ts +32 -0
  304. package/runtime/delivery/existing-code.ts +7 -6
  305. package/runtime/delivery/history-package.ts +50 -0
  306. package/runtime/delivery/inputs.ts +18 -11
  307. package/runtime/delivery/journal.ts +14 -10
  308. package/runtime/delivery/parameter-defaults.ts +75 -0
  309. package/runtime/delivery/parameters.ts +18 -0
  310. package/runtime/delivery/planning.ts +19 -5
  311. package/runtime/delivery/preparation.ts +17 -1
  312. package/runtime/delivery/production-environment.ts +2 -1
  313. package/runtime/delivery/production-finalization.ts +19 -10
  314. package/runtime/delivery/production-intent.ts +14 -0
  315. package/runtime/delivery/production.ts +51 -11
  316. package/runtime/delivery/project-files.ts +16 -11
  317. package/runtime/delivery/project-rpc.ts +116 -0
  318. package/runtime/delivery/project.ts +19 -7
  319. package/runtime/delivery/public-calldata.ts +74 -0
  320. package/runtime/delivery/release-graph.ts +44 -14
  321. package/runtime/delivery/release-history-capture.ts +19 -9
  322. package/runtime/delivery/release-history.ts +76 -22
  323. package/runtime/delivery/release-inputs.ts +107 -0
  324. package/runtime/delivery/release.ts +56 -18
  325. package/runtime/delivery/safe.ts +14 -3
  326. package/runtime/delivery/same-fork-baseline.ts +5 -4
  327. package/runtime/delivery/setup.ts +20 -8
  328. package/runtime/delivery/source.ts +10 -10
  329. package/runtime/delivery/task-identity.ts +85 -0
  330. package/runtime/delivery/toolchain.ts +48 -0
  331. package/runtime/delivery/validation.ts +7 -2
  332. package/runtime/vendor/plan-codec/index.cjs +97 -20
  333. package/runtime/vendor/plan-codec/index.d.cts +6 -0
  334. package/runtime/vendor/plan-codec/provenance.json +9 -8
  335. package/runtime/workflow/lib/calls.ts +1 -0
  336. package/runtime/workflow/lib/checkCodeRunner.ts +7 -3
  337. package/runtime/workflow/lib/context.ts +1 -0
  338. package/runtime/workflow/lib/create2.ts +7 -108
  339. package/runtime/workflow/lib/deploymentInfo.ts +8 -0
  340. package/runtime/workflow/lib/deploymentRecords.ts +3 -1
  341. package/runtime/workflow/lib/externalExecutionScanner.ts +2 -1
  342. package/runtime/workflow/lib/gateTool.ts +2 -2
  343. package/runtime/workflow/lib/gateToolSync.ts +8 -0
  344. package/runtime/workflow/lib/parameters.ts +4 -0
  345. package/runtime/workflow/lib/proxy.ts +1 -0
  346. package/runtime/workflow/run.ts +1 -2
  347. package/runtime/workflow/steps/deploy.ts +42 -0
  348. package/runtime/workflow/steps/upgrade.ts +19 -11
  349. package/bin/workflow.cjs +0 -19
@@ -2,7 +2,7 @@
2
2
  import path from 'node:path';
3
3
  import {getCreate2Address,Interface} from 'ethers';
4
4
  import {withDefaults} from '@openzeppelin/hardhat-upgrades/dist/utils/options';
5
- import {BytecodeChecker,artifactIdentity,hashStorageLayout,mergeEvmManifestCandidate,parseTargetManifest,resolveTargetManifestPaths} from 'gate-evm-tools/workflow';
5
+ import {TRANSPARENT_PROXY_ARTIFACT,PROXY_ADMIN_ARTIFACT,ERC1967_ADMIN_SLOT,PROXY_ADMIN_INTERFACE,transparentAdminAddress,assertTransparentAdminImmutable,BytecodeChecker,artifactIdentity,hashStorageLayout,mergeEvmManifestCandidate,parseTargetManifest,resolveTargetManifestPaths} from 'gate-evm-tools/workflow';
6
6
  import {canonicalJson,deepFreeze,semanticHash} from '../workflow/lib/canonicalData';
7
7
  import {validateContractInfo,resolveDeployment} from '../workflow/lib/deployments';
8
8
  import {validateDeploymentInfo} from '../workflow/lib/deploymentInfo';
@@ -67,14 +67,14 @@ export async function finalizeProductionExecution(input:{root:string;ready:Produ
67
67
  const p=entry.prepared.plan,r=entry.prepared.request;const compiled=local(p.contract);same(artifactIdentity(compiled.artifact,'evm'),p.artifact,'Prepared sealed artifact');
68
68
  for(const deployment of p.deployments){
69
69
  if(deployment.initCodeHash&&getCreate2Address(r.factory,deployment.salt,deployment.initCodeHash).toLowerCase()!==deployment.address.toLowerCase())throw Error('Production CREATE2 address mismatch');
70
- await compare(deployment.address,deployment.role==='proxy'?'@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy':p.contract,`${entry.change.instanceId}:${deployment.role}`);
70
+ await compare(deployment.address,deployment.role==='proxy'?(p.proxyKind==='transparent'?TRANSPARENT_PROXY_ARTIFACT:'@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy'):p.contract,`${entry.change.instanceId}:${deployment.role}`);
71
71
  }
72
72
  const address=p.deployments.find(d=>d.role==='proxy')?.address??('proxy' in r?r.proxy:p.deployments.find(d=>d.role==='contract')?.address);
73
73
  if(!address)throw Error('Production prepared address missing');
74
- changes.set(entry.change.instanceId,{...entry.change,address,...(p.proxyKind==='uups'?{proxyAddress:address,proxyKind:'uups'}:{})});
74
+ changes.set(entry.change.instanceId,{...entry.change,address,...(p.proxyKind?{proxyAddress:address,proxyKind:p.proxyKind}:{})});
75
75
  }
76
76
  const candidates:any[]=[],expected:ExpectedDevelopmentCode[]=[],effective:Record<string,Record<string,string>>={[plan.target]:{}},checked=new Map<string,{address:string;contract:string;key:string}>();
77
- function expect(address:string,contract:string,key:string){const row={key,contract,address:address.toLowerCase()},old=checked.get(key);if(old)same(old,row,'Production CheckCode key');else{checked.set(key,row);expected.push(row);}}
77
+ function expect(address:string,contract:string,key:string){const row={key,contract:local(contract).artifact.contractName,address:address.toLowerCase()},old=checked.get(key);if(old)same(old,row,'Production CheckCode key');else{checked.set(key,row);expected.push(row);}}
78
78
  const deployed=[...changes.values()],unchangedAliases=new Set<string>();
79
79
  const registrationContext={base,target:plan.target,deploymentId:plan.deploymentId,executionId:plan.executionId,recordPath:recordPath(ready),updatedAt:new Date(Number(BigInt(anchor.timestamp))*1000).toISOString(),changes:deployed,preparations};
80
80
  // Apply the same validated upgrade replacement before resolving code coverage.
@@ -84,11 +84,20 @@ export async function finalizeProductionExecution(input:{root:string;ready:Produ
84
84
  const rows=Object.entries(registry).filter(([,a])=>a.toLowerCase()===address);if(rows.length!==1)throw Error('Production code target requires unique frozen registration');
85
85
  const [key]=rows[0],alias=key.split(':')[0],m=metadata[alias],contract=m?.actualContract??key.split(':').at(-1)!;
86
86
  effective[plan.target][key]=address;if(!changes.has(alias))unchangedAliases.add(alias);
87
- if(m?.proxyKind&&m.proxyKind!=='uups')throw Error('Unsupported production proxy kind');
88
- if(m?.proxyKind==='uups'){
87
+ if(m?.proxyKind&&m.proxyKind!=='uups'&&m.proxyKind!=='transparent')throw Error('Unsupported production proxy kind');
88
+ if(m?.proxyKind==='uups'||m?.proxyKind==='transparent'){
89
89
  const storage=await rpc('eth_getStorageAt',[address,slot,block]);if(typeof storage!=='string'||!/^0x0{24}[a-fA-F0-9]{40}$/.test(storage))throw Error('Invalid finalized UUPS implementation slot');
90
90
  const implementation='0x'+storage.slice(-40).toLowerCase();if(implementation!==m.implementationAddress?.toLowerCase())throw Error('Final production UUPS implementation mismatch');
91
- expect(implementation,contract,alias);expect(address,'ERC1967Proxy',`${alias}_Proxy`);
91
+ expect(implementation,contract,alias);expect(address,m.proxyKind==='transparent'?TRANSPARENT_PROXY_ARTIFACT:'ERC1967Proxy',`${alias}_Proxy`);
92
+ if(m.proxyKind==='transparent'){
93
+ const admin=m.proxyAdminAddress?.toLowerCase();if(!admin||admin!==transparentAdminAddress(address)||!m.proxyAdminOwner)throw Error('Missing frozen Transparent admin identity');
94
+ const value=await rpc('eth_getStorageAt',[address,ERC1967_ADMIN_SLOT,block]);if(typeof value!=='string'||!/^0x0{24}[a-fA-F0-9]{40}$/.test(value)||'0x'+value.slice(-40).toLowerCase()!==admin)throw Error('Final production Transparent admin mismatch');
95
+ assertTransparentAdminImmutable(await rpc('eth_getCode',[address,block]) as string,local(TRANSPARENT_PROXY_ARTIFACT).immutableReferences,admin);
96
+ const owner=PROXY_ADMIN_INTERFACE.decodeFunctionResult('owner',await rpc('eth_call',[{to:admin,data:PROXY_ADMIN_INTERFACE.encodeFunctionData('owner')},block]) as string)[0];
97
+ const version=PROXY_ADMIN_INTERFACE.decodeFunctionResult('UPGRADE_INTERFACE_VERSION',await rpc('eth_call',[{to:admin,data:PROXY_ADMIN_INTERFACE.encodeFunctionData('UPGRADE_INTERFACE_VERSION')},block]) as string)[0];
98
+ if(owner.toLowerCase()!==m.proxyAdminOwner.toLowerCase()||version!=='5.0.0')throw Error('Final production ProxyAdmin owner/version mismatch');
99
+ expect(admin,PROXY_ADMIN_ARTIFACT,`${alias}_ProxyAdmin`);
100
+ }
92
101
  const artifact=local(contract).entry;
93
102
  const paths=resolveTargetManifestPaths(root,plan.target,Number(plan.chainId),{}),manifestPath=path.relative(root,paths.file).split(path.sep).join('/');
94
103
  if(paths.file!==paths.fallbackFile&&fileBytes(root,path.relative(root,paths.fallbackFile))!==null)throw Error('Noncanonical manifest fallback requires explicit migration');
@@ -98,7 +107,7 @@ export async function finalizeProductionExecution(input:{root:string;ready:Produ
98
107
  if(!request||request.kind==='create2-deploy')throw Error('Missing UUPS preparation selection request');
99
108
  // Match the compiler's preparationSelection identity. Canonical request data
100
109
  // contains no undefined values; omit official optional top-level safety flags.
101
- const options=Object.fromEntries(Object.entries(withDefaults({kind:'uups',constructorArgs:request.constructorArgs,...(request.unsafeAllow?{unsafeAllow:request.unsafeAllow}: {})} as Parameters<typeof withDefaults>[0])).filter(([,value])=>value!==undefined));
110
+ const options=Object.fromEntries(Object.entries(withDefaults({kind:request.proxyKind,constructorArgs:request.constructorArgs,...(request.unsafeAllow?{unsafeAllow:request.unsafeAllow}: {})} as Parameters<typeof withDefaults>[0])).filter(([,value])=>value!==undefined));
102
111
  const encodedArgs=new Interface(artifact.artifact.abi).encodeDeploy(request.constructorArgs),optionsHash=semanticHash(options);
103
112
  const selections=compiler.selections.filter(s=>s.fqn===artifact.fqn&&s.artifactDigest===artifact.digest&&s.encodedArgs===encodedArgs&&semanticHash(s.options)===optionsHash);
104
113
  if(selections.length!==1)throw Error('Missing unique frozen OZ implementation selection');
@@ -108,11 +117,11 @@ export async function finalizeProductionExecution(input:{root:string;ready:Produ
108
117
  // regardless of selections made for other instances of the same artifact.
109
118
  const frozen=configuration.manifests?.filter(f=>f.path===manifestPath);if(frozen?.length!==1||frozen[0].contents===null)throw Error('Missing frozen existing UUPS manifest');
110
119
  const manifest=parseTargetManifest(Buffer.from(frozen[0].contents)),proxies=manifest.proxies.filter(p=>p.address.toLowerCase()===address),implementations=Object.entries(manifest.impls).filter(([,v])=>v&&[v.address,...(v.allAddresses??[])].some(a=>a.toLowerCase()===implementation));
111
- if(proxies.length!==1||proxies[0].kind!=='uups'||implementations.length!==1)throw Error('Invalid frozen existing UUPS manifest registration');
120
+ if(proxies.length!==1||proxies[0].kind!==m.proxyKind||implementations.length!==1)throw Error('Invalid frozen existing UUPS manifest registration');
112
121
  versionKey=implementations[0][0];layout=implementations[0][1]!.layout;
113
122
  }
114
123
  if(typeof versionKey!=='string'||!/^[a-f0-9]{64}$/.test(versionKey))throw Error('Invalid frozen OZ version');
115
- candidates.push({path:manifestPath,proxy:address,implementation,versionKey,layout,layoutHash:hashStorageLayout(layout)});
124
+ candidates.push({path:manifestPath,proxy:address,proxyKind:m.proxyKind,implementation,versionKey,layout,layoutHash:hashStorageLayout(layout)});
116
125
  }else expect(address,contract,alias);
117
126
  }
118
127
  if(!expected.length)throw Error('Empty production CheckCode coverage');
@@ -0,0 +1,14 @@
1
+ /** Re-simulation may change operator routing, but cannot replace released transaction intent. */
2
+ import { canonicalJson } from '../workflow/lib/canonicalData';
3
+ import { parseCalldataReviews } from './calldata-review';
4
+ import type { DeliveryCollection } from './planning';
5
+
6
+ export function assertReleasedCalldataIntent(actual: DeliveryCollection, released: DeliveryCollection): void {
7
+ const current = parseCalldataReviews(actual.calldata, actual.plan.transactions);
8
+ const frozen = parseCalldataReviews(released.calldata, released.plan.transactions);
9
+ if (canonicalJson(current) !== canonicalJson(frozen))
10
+ throw Error('Final simulation changed released calldata ABI intent');
11
+ for (const key of ['derivationSeed', 'values'] as const)
12
+ if (canonicalJson(actual.plan.derivedBindings[key]) !== canonicalJson(released.plan.derivedBindings[key]))
13
+ throw Error('Final simulation changed released derivation');
14
+ }
@@ -1,5 +1,7 @@
1
1
  /** Public release-only production boundary. Host capabilities never enter JSON options. */
2
2
  import fs from 'node:fs';
3
+ import {customExecutionInput} from './execution-identity';
4
+ import {assertReleasedCalldataIntent} from './production-intent';
3
5
  import os from 'node:os';
4
6
  import path from 'node:path';
5
7
  import { randomUUID } from 'node:crypto';
@@ -16,6 +18,10 @@ import { canonicalJson, deepFreeze, exactObject, semanticHash } from '../workflo
16
18
  import { createDeliveryEoaExecution, type EoaExecutionOptions, type EoaHashReferences } from './eoa';
17
19
  import type { ReleaseGraphOptions } from './release-graph';
18
20
  import type { DeliveryCollection } from './planning';
21
+ import { parseCalldataReviews } from './calldata-review';
22
+ import { projectDeliveryCalls, mergeDeliveryCalls } from './public-calldata';
23
+ import { archiveDeliveryCalls } from './calldata-archive';
24
+ import { serializeDeliveryCalls } from './calldata-format';
19
25
  import { finalizeProductionExecution, retainedProductionFinalizationAnchor, type FinalizedAnchor } from './production-finalization';
20
26
  export { productionChildEnvironment } from './production-environment';
21
27
  export interface ProductionOptions extends ReleaseGraphOptions {
@@ -58,9 +64,12 @@ export function inspectDeliveryProduction(raw: ProductionOptions, command: Produ
58
64
  if (record.schema !== 'gate-delivery-production' || record.version !== 1 || record.status !== 'READY' || record.generation !== 'complete' || semanticHash(body) !== artifactHash)
59
65
  throw Error('Invalid production READY artifact');
60
66
  const plan = parseDeliveryPlan(record.collection.plan);
67
+ parseCalldataReviews(record.collection.calldata, plan.transactions);
68
+ const deliveryCalls=projectDeliveryCalls({plan,calldata:record.collection.calldata,operations:current.release.operations as any[],preparations:record.collection.preparations});
69
+ if(canonicalJson(deliveryCalls)!==canonicalJson(record.deliveryCalls))throw Error('Frozen production public projection mismatch');
61
70
  if (record.releaseHash !== current.releaseHash || plan.inputsHash !== current.release.inputsHash || plan.sourceDefinitionHash !== current.release.sourceDefinitionHash || plan.executionId !== current.input.executionId || plan.target !== current.input.target || plan.operator !== current.input.operator.toLowerCase() || plan.environment !== 'prod' || plan.chainId !== String(current.target.chainId))
62
71
  throw Error('Production artifact context mismatch');
63
- return deepFreeze({ status: 'ready' as const, plan, collection: record.collection as DeliveryCollection, finalization: record.finalization, releaseHash: current.releaseHash, artifactHash, sha256: byteHash(bytes), path: artifactPath(current.input.executionId), ...(current.target.safe ? { safeTarget: current.target.safe } : {}) });
72
+ return deepFreeze({ status: 'ready' as const, plan, collection: record.collection as DeliveryCollection, deliveryCalls, operations: current.release.operations as any[], finalization: record.finalization, releaseHash: current.releaseHash, artifactHash, sha256: byteHash(bytes), path: artifactPath(current.input.executionId), ...(current.target.safe ? { safeTarget: current.target.safe } : {}) });
64
73
  }
65
74
  /** Instantiate the delivered business operations, never accept replacement operations or parameters. */
66
75
  export async function prepareDeliveryProduction(raw: ProductionOptions) {
@@ -91,7 +100,16 @@ export async function prepareDeliveryProduction(raw: ProductionOptions) {
91
100
  const parameter = release.parameters.find((p: any) => p.target === input.target);
92
101
  if (!parameter)
93
102
  throw Error('Release parameters missing');
94
- const staged = await worker.request('stage', { ...common, role: 'target', handshake: ready.handshake, target: current.target, params: parameter.resolved.values, steps: release.operations, deploymentId: input.deploymentId, businessRoot: `scripts/tasks/${input.deploymentId}`, executionId: input.executionId, sourceDefinitionHash: release.sourceDefinitionHash });
103
+ // Production consumes the released CREATE2 derivation, while its execution
104
+ // identity and durable progress remain local to this execution.
105
+ const candidate = JSON.parse(fs.readFileSync(path.join(root, release.candidate.path), 'utf8'));
106
+ const qualification = candidate.aggregate.collections.find((c: any) => c.plan.target === input.target);
107
+ if (!qualification) throw Error('Released target qualification missing');
108
+ const qualificationPlan = parseDeliveryPlan(qualification.plan);
109
+ if (qualificationPlan.inputsHash !== release.inputsHash || qualificationPlan.target !== input.target)
110
+ throw Error('Released derivation context mismatch');
111
+ const derivationSeed = qualificationPlan.derivedBindings.derivationSeed;
112
+ const staged = await worker.request('stage', { ...common, role: 'target', handshake: ready.handshake, target: current.target, params: parameter.resolved.values, steps: release.operations, deploymentId: input.deploymentId, businessRoot: `scripts/tasks/${input.deploymentId}`, executionId: input.executionId, derivationSeed, sourceDefinitionHash: release.sourceDefinitionHash });
95
113
  check();
96
114
  if (staged.ready !== true)
97
115
  throw Error('Production generation not READY');
@@ -99,15 +117,15 @@ export async function prepareDeliveryProduction(raw: ProductionOptions) {
99
117
  check();
100
118
  const sourceChecked = await source.request('check');
101
119
  check();
102
- const candidate = JSON.parse(fs.readFileSync(path.join(root, release.candidate.path), 'utf8'));
103
120
  const expected = candidate.aggregate.inputs.targets.find((t: any) => t.target === input.target);
104
- for (const [actual, wanted] of [[checked.compiler.stableDigest, expected.compiler.stableDigest], [checked.custom, expected.custom], [checked.configuration.configurationRuntimeHash, expected.configuration.configurationRuntimeHash], [sourceChecked.configuration.configurationRuntimeHash, expected.sourceConfiguration.configurationRuntimeHash]])
121
+ for (const [actual, wanted] of [[checked.compiler.stableDigest, expected.compiler.stableDigest], [customExecutionInput(checked.custom), customExecutionInput(expected.custom)], [checked.configuration.configurationRuntimeHash, expected.configuration.configurationRuntimeHash], [sourceChecked.configuration.configurationRuntimeHash, expected.sourceConfiguration.configurationRuntimeHash]])
105
122
  if (canonicalJson(actual) !== canonicalJson(wanted))
106
123
  throw Error('Final simulation changed released input closure');
107
124
  const collection = await worker.request('bind', { inputsHash: release.inputsHash }) as DeliveryCollection;
108
125
  check();
126
+ assertReleasedCalldataIntent(collection, qualification);
109
127
  expectedDevelopmentAssertions(collection, release.operations);
110
- if (collection.plan.executionId !== input.executionId || collection.plan.operator !== input.operator.toLowerCase())
128
+ if (collection.plan.executionId !== input.executionId || collection.plan.operator !== input.operator.toLowerCase() || collection.plan.derivedBindings.derivationSeed !== derivationSeed)
111
129
  throw Error('Final simulation context mismatch');
112
130
  await worker.request('close');
113
131
  await source.request('close');
@@ -118,7 +136,8 @@ export async function prepareDeliveryProduction(raw: ProductionOptions) {
118
136
  if (paths.file !== paths.fallbackFile && fileBytes(root, path.relative(root, paths.fallbackFile)) !== null)
119
137
  throw Error('Noncanonical manifest fallback requires explicit migration');
120
138
  const finalization = { compiler: checked.compiler, registration: { registry: JSON.parse(fileBytes(root, 'contractInfo.json') ?? '{}'), metadata: JSON.parse(fileBytes(root, 'deploymentInfo.json') ?? '{"version":1,"networks":{}}') }, manifests: [{ path: manifestPath, contents: fileBytes(root, manifestPath) }] };
121
- const body = { schema: 'gate-delivery-production', version: 1, status: 'READY', generation: 'complete', releaseHash: current.releaseHash, collection, finalization }, record = { ...body, artifactHash: semanticHash(body) };
139
+ const deliveryCalls=projectDeliveryCalls({plan:collection.plan,calldata:collection.calldata,operations:release.operations,preparations:collection.preparations});
140
+ const body = { schema: 'gate-delivery-production', version: 1, status: 'READY', generation: 'complete', releaseHash: current.releaseHash, collection, deliveryCalls, finalization }, record = { ...body, artifactHash: semanticHash(body) };
122
141
  const prior = fileBytes(root, artifactPath(input.executionId));
123
142
  if (prior !== null && prior !== encode(record))
124
143
  throw Error('Execution ID already has immutable final simulation');
@@ -160,7 +179,7 @@ export async function runDeliveryProduction(command: Exclude<ProductionCommand,
160
179
  throw Error('PRODUCTION_SIGNER_UNAVAILABLE: trusted host required');
161
180
  if (command !== 'export-calldata')
162
181
  throw Error('Trusted host observation provider required');
163
- return renderProductionExport(ready);
182
+ return persistProductionExport(input,ready,renderProductionExport(ready));
164
183
  }
165
184
  const { guard, request, store, finality, signer, approval } = ports;
166
185
  const check = () => { guard(); const current = inspectDeliveryProduction(input, command); if (current.status !== 'ready' || current.artifactHash !== ready.artifactHash)
@@ -175,7 +194,7 @@ export async function runDeliveryProduction(command: Exclude<ProductionCommand,
175
194
  const result = command === 'execute' ? await kernel.execute(captured?.unsigned) : command === 'export-calldata' ? await kernel.export() : await kernel.reconcile(captured?.hashes ?? {});
176
195
  check();
177
196
  if (command === 'export-calldata')
178
- return renderProductionExport(ready, result as Awaited<ReturnType<typeof kernel.export>>);
197
+ return persistProductionExport(input,ready,renderProductionExport(ready, result as Awaited<ReturnType<typeof kernel.export>>));
179
198
  if (command === 'verify' && (result as any).status === 'complete') {
180
199
  try {
181
200
  const root = projectRoot(input.workspaceRoot, input.projectRoot), priorAnchor = retainedProductionFinalizationAnchor(root, ready);
@@ -193,14 +212,35 @@ export async function runDeliveryProduction(command: Exclude<ProductionCommand,
193
212
  return result;
194
213
  }
195
214
  import { renderDeliveryExport } from './export';
215
+ async function persistProductionExport(input:ProductionOptions,ready:Extract<ReturnType<typeof inspectDeliveryProduction>,{status:'ready'}>,result:ReturnType<typeof renderProductionExport>){
216
+ const exported=result.status==='preparation-required'?result.export:result;
217
+ const deliveryFile=await archiveDeliveryCalls({...input,calls:JSON.parse(exported.json),provenance:{releaseRef:input.releaseRef,sources:[{planHash:ready.plan.planHash,chainId:ready.plan.chainId,artifactHash:ready.artifactHash,releaseHash:ready.releaseHash,executionId:ready.plan.executionId}]},assertCurrent(){const now=inspectDeliveryProduction(input,'export-calldata');if(now.status!=='ready'||now.artifactHash!==ready.artifactHash||now.releaseHash!==ready.releaseHash)throw Error('Production changed during calldata publication');}});
218
+ const artifact=deepFreeze({...exported,deliveryFile});
219
+ return result.status==='preparation-required'?deepFreeze({...result,export:artifact}):artifact;
220
+ }
221
+
222
+ /** Each network is validated independently before one combined immutable JSON is published. */
223
+ export async function exportProductionCalldata(productions:readonly ProductionOptions[]){
224
+ if(!productions.length)throw Error('Production targets required');
225
+ const inputs=productions.map(p=>deepFreeze(strictData(p))),first=inputs[0];
226
+ for(const p of inputs)if(canonicalJson([p.workspaceRoot,p.projectRoot,p.taskId,p.deploymentId,p.releaseRef])!==canonicalJson([first.workspaceRoot,first.projectRoot,first.taskId,first.deploymentId,first.releaseRef]))throw Error('Multi-network delivery must belong to one deployment release');
227
+ const ready=inputs.map(input=>{const r=inspectDeliveryProduction(input,'export-calldata');if(r.status!=='ready')throw Error('Production calldata generation is pending');return r;});
228
+ const calls=mergeDeliveryCalls(ready.map(r=>({plan:r.plan,calldata:r.collection.calldata,operations:r.operations,preparations:r.collection.preparations})));
229
+ const deliveryFile=await archiveDeliveryCalls({...first,calls,provenance:{releaseRef:first.releaseRef,sources:ready.map(r=>({planHash:r.plan.planHash,chainId:r.plan.chainId,artifactHash:r.artifactHash,releaseHash:r.releaseHash,executionId:r.plan.executionId}))},assertCurrent(){inputs.forEach((input,i)=>{const now=inspectDeliveryProduction(input,'export-calldata');if(now.status!=='ready'||now.artifactHash!==ready[i].artifactHash||now.releaseHash!==ready[i].releaseHash)throw Error('Multi-network production changed during publication');});}});
230
+ return deepFreeze({status:'artifact-delivered' as const,json:serializeDeliveryCalls(calls),deliveryFile});
231
+ }
196
232
  export function renderProductionExport(ready: Extract<ReturnType<typeof inspectDeliveryProduction>, {
197
233
  status: 'ready';
198
234
  }>, exported = renderDeliveryExport(ready.plan)) {
235
+ if (canonicalJson(exported.model.plan) !== canonicalJson(ready.plan)) throw Error('Exported plan differs from frozen production plan');
236
+ const calldataReview = { version: 1, planHash: ready.plan.planHash, chainId: ready.plan.chainId,
237
+ transactions: parseCalldataReviews(ready.collection.calldata, ready.plan.transactions), check: 'matches-frozen-intent' };
199
238
  const start = exported.model.completed.length, active = ready.plan.transactions[start], frozen = (exported.model as any).safeEnvelopes ?? [];
200
239
  const needsPreparation = !!ready.safeTarget && active?.route === 'external' && !frozen.some((x: any) => x.envelope.start === start);
201
- const model = deepFreeze({ ...exported.model, ...(ready.safeTarget ? { safePreparation: needsPreparation ? 'preparation-required' : active?.route === 'external' ? 'ready' : 'not-applicable', futureSafeEnvelopes: 'pending until their segment becomes executable' } : {}), releaseHash: ready.releaseHash, artifactHash: ready.artifactHash });
202
- const json = canonicalJson(model);
203
- const artifact = deepFreeze({ status: 'artifact-delivered' as const, model, json, markdown: `# Production calldata\n\nRelease: ${ready.releaseHash}\nExecution: ${ready.plan.executionId}\n\n\`\`\`json\n${json}\n\`\`\`\n` });
240
+ const deliveryContext = { operations: ready.operations, preparations: ready.collection.preparations };
241
+ const model = deepFreeze({ ...exported.model, calldataReview, deliveryContext, ...(ready.safeTarget ? { safePreparation: needsPreparation ? 'preparation-required' : active?.route === 'external' ? 'ready' : 'not-applicable', futureSafeEnvelopes: 'pending until their segment becomes executable' } : {}), releaseHash: ready.releaseHash, artifactHash: ready.artifactHash });
242
+ const json = serializeDeliveryCalls(projectDeliveryCalls({ plan: ready.plan, calldata: ready.collection.calldata, operations: ready.operations, preparations: ready.collection.preparations }));
243
+ const artifact = deepFreeze({ status: 'artifact-delivered' as const, model, json });
204
244
  return needsPreparation ? deepFreeze({ status: 'preparation-required' as const, export: artifact }) : artifact;
205
245
  }
206
246
  import { parseConfigurationDefinition } from './configuration-definition';
@@ -34,25 +34,30 @@ export function readFile(root: string, relative: string): string | undefined {
34
34
  const file = confinedFile(root, relative);
35
35
  return stat(file) ? fs.readFileSync(file, 'utf8') : undefined;
36
36
  }
37
- export function coreMarker(root: string): void {
38
- parseCoreMarker(readFile(root, '.gate-template.json') ?? 'null');
37
+ export function deliveryProjectMarker(root: string): void {
38
+ parseDeliveryProjectMarker(readFile(root, '.gate-template.json') ?? 'null');
39
39
  }
40
- /** Validate the same captured marker bytes whose digest is being bound. */
41
- export function parseCoreMarker(bytes: string | Buffer): void {
40
+ /** Validate the same captured marker bytes whose digest is bound to current inputs. */
41
+ export function parseDeliveryProjectMarker(bytes: string | Buffer): void {
42
42
  const marker = JSON.parse(bytes.toString());
43
- if (!marker || marker.template !== 'gateflow-evm-core@1' || marker.templateVersion !== 1 || marker.profile !== 'core') throw new Error('Unsupported core template; no legacy migration is performed');
43
+ if (!marker || marker.profile !== 'full' || marker.templateVersion !== 1
44
+ || marker.template !== `gateflow-evm-${marker.profile}@1`) throw new Error('Unsupported EVM template; no legacy migration is performed');
44
45
  if (marker.generator?.name !== 'gate-evm-hardhat-foundry' || typeof marker.generator?.version !== 'string'
45
46
  || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(marker.generator.version)
46
- || !marker.generation?.inputs || !marker.generation?.files || !Array.isArray(marker.generation?.preserved)) throw new Error('Invalid core generator provenance');
47
- if (marker.generation.state !== 'complete') throw new Error('Core generation is pending or invalid');
48
- const inputs = object(marker.generation.inputs, 'core generation provenance inputs');
49
- const files = object(marker.generation.files, 'core generation provenance files');
47
+ || !marker.generation?.inputs || !marker.generation?.files || !Array.isArray(marker.generation?.preserved)) throw new Error('Invalid EVM generator provenance');
48
+ if (marker.generation.state !== 'complete') throw new Error('EVM generation is pending or invalid');
49
+ const inputs = object(marker.generation.inputs, 'EVM generation provenance inputs', ['projectName', 'networks', 'examples']);
50
+ const files = object(marker.generation.files, 'EVM generation provenance files');
50
51
  const preserved = marker.generation.preserved as unknown[];
51
52
  const optional = ['README.md', 'AGENTS.md', '.gitignore'];
52
- const assets = ['package.json', 'hardhat.config.ts', 'tsconfig.json', ...optional, 'contracts/.gitkeep', 'test/.gitkeep'];
53
+ const assets = ['package.json', 'package-lock.json', 'hardhat.config.ts', 'rpc.env', '.env.example', 'tsconfig.json', ...optional, 'contracts/.gitkeep', 'test/.gitkeep',
54
+ 'foundry.toml', 'config.yaml',
55
+ ...(Object.hasOwn(files, 'vendor/gate-evm-tools-1.2.0.tgz') ? ['vendor/gate-evm-tools-1.2.0.tgz'] : []),
56
+ ...(inputs.examples === true ? ['contracts/Counter.sol', 'test/Counter.ts', 'test/Counter.t.sol'] : [])];
53
57
  if (typeof inputs.projectName !== 'string' || !inputs.projectName || !Array.isArray(inputs.networks)
58
+ || typeof inputs.examples !== 'boolean'
54
59
  || preserved.some(file => typeof file !== 'string' || !optional.includes(file))
55
60
  || new Set(preserved).size !== preserved.length
56
61
  || Object.keys(files).sort().join('\n') !== assets.filter(file => !preserved.includes(file)).sort().join('\n')
57
- || Object.values(files).some(hash => typeof hash !== 'string' || !/^[a-f0-9]{64}$/.test(hash))) throw new Error('Invalid core generation provenance');
62
+ || Object.values(files).some(hash => typeof hash !== 'string' || !/^[a-f0-9]{64}$/.test(hash))) throw new Error('Invalid EVM generation provenance');
58
63
  }
@@ -0,0 +1,116 @@
1
+ /** Fixed template RPC syntax. Inspection reads local env data without evaluating project code. */
2
+ import ts from 'typescript';
3
+ import { parseEnv } from 'node:util';
4
+ import { readFile } from './project-files';
5
+
6
+ export const PROJECT_ENV_BOOTSTRAP = `for (const file of ["rpc.env", ".env"]) {
7
+ const envFile = join(__dirname, file);
8
+ if (existsSync(envFile)) {
9
+ try {
10
+ process.loadEnvFile(envFile);
11
+ } catch (error) {
12
+ if (file !== ".env" || !["ENOENT", "EPERM", "EACCES"].includes((error as NodeJS.ErrnoException).code ?? "")) throw error;
13
+ console.warn("Project credentials are unavailable; compilation and public checks can continue. Use the application host for credential-bearing delivery operations.");
14
+ }
15
+ }
16
+ }`;
17
+ export const PROJECT_RPC_HELPER = [
18
+ "function rpcUrl(options: { route: string; publicFallback: string | undefined; useBaseRpc: boolean }): string {",
19
+ " const fallback = options.publicFallback?.trim() || \"\";",
20
+ " const base = process.env.BASE_RPC_URI?.trim();",
21
+ " if (!options.useBaseRpc || !base) return fallback;",
22
+ " return `${base.replace(/\\/+$/, \"\")}/${options.route}/`;",
23
+ "}",
24
+ ].join('\n');
25
+ const printer = ts.createPrinter({ removeComments: true });
26
+ function syntax(node: ts.Node, file: ts.SourceFile): string {
27
+ return printer.printNode(ts.EmitHint.Unspecified, node, file);
28
+ }
29
+ function statement(source: string): string {
30
+ const file = ts.createSourceFile('rpc.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
31
+ return syntax(file.statements[0], file);
32
+ }
33
+ const bootstrapSyntax = statement(PROJECT_ENV_BOOTSTRAP), helperSyntax = statement(PROJECT_RPC_HELPER);
34
+
35
+ export function projectRpcSyntax(file: ts.SourceFile): { statements: Set<ts.Statement>; bootstrap: boolean; helper: boolean } {
36
+ const statements = new Set<ts.Statement>();
37
+ let bootstrap = false, helper = false;
38
+ const imports = new Set<string>();
39
+ for (const node of file.statements) {
40
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)
41
+ && ['node:fs', 'node:path'].includes(node.moduleSpecifier.text)) {
42
+ const name = node.moduleSpecifier.text, clause = node.importClause;
43
+ const wanted = name === 'node:fs' ? 'existsSync' : 'join';
44
+ if (imports.has(name) || node.attributes || !clause || clause.name || clause.isTypeOnly
45
+ || !clause.namedBindings || !ts.isNamedImports(clause.namedBindings)
46
+ || clause.namedBindings.elements.length !== 1 || clause.namedBindings.elements[0].name.text !== wanted
47
+ || clause.namedBindings.elements[0].propertyName) throw Error('Unsupported project RPC import');
48
+ imports.add(name); statements.add(node);
49
+ } else if (ts.isForOfStatement(node) && syntax(node, file) === bootstrapSyntax) {
50
+ if (bootstrap) throw Error('Duplicate project RPC loader');
51
+ bootstrap = true; statements.add(node);
52
+ } else if (ts.isFunctionDeclaration(node) && node.name?.text === 'rpcUrl') {
53
+ if (helper || syntax(node, file) !== helperSyntax) throw Error('Unsupported project RPC helper');
54
+ helper = true; statements.add(node);
55
+ }
56
+ }
57
+ if (bootstrap !== (imports.size === 2) || (!bootstrap && imports.size)) throw Error('Incomplete project RPC loader');
58
+ const config = file.statements.findIndex(node => ts.isVariableStatement(node) || ts.isExportAssignment(node));
59
+ if (bootstrap && config >= 0 && [...statements].some(node => ts.isForOfStatement(node) && file.statements.indexOf(node) > config))
60
+ throw Error('Project RPC loader must precede configuration');
61
+ return { statements, bootstrap, helper };
62
+ }
63
+
64
+ export function projectRpcOptions(node: ts.CallExpression): { route: string; publicFallback: ts.Expression; useBaseRpc: boolean } {
65
+ if (!ts.isIdentifier(node.expression) || node.expression.text !== 'rpcUrl' || node.arguments.length !== 1 || node.typeArguments)
66
+ throw Error('Unsupported project RPC call');
67
+ const options = node.arguments[0];
68
+ if (!ts.isObjectLiteralExpression(options)) throw Error('Unsupported project RPC options');
69
+ const fields = new Map<string, ts.Expression>();
70
+ for (const property of options.properties) {
71
+ if (!ts.isPropertyAssignment(property) || (!ts.isIdentifier(property.name) && !ts.isStringLiteral(property.name)))
72
+ throw Error('Unsupported project RPC option');
73
+ const name = property.name.text;
74
+ if (!['route', 'publicFallback', 'useBaseRpc'].includes(name) || fields.has(name)) throw Error('Unsupported project RPC option');
75
+ fields.set(name, property.initializer);
76
+ }
77
+ const route = fields.get('route'), useBaseRpc = fields.get('useBaseRpc'), publicFallback = fields.get('publicFallback');
78
+ if (!route || !ts.isStringLiteral(route) || !/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(route.text)) throw Error('Unsupported project RPC route');
79
+ if (!publicFallback || !useBaseRpc || ![ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword].includes(useBaseRpc.kind))
80
+ throw Error('Project RPC requires a literal useBaseRpc boolean and publicFallback');
81
+ return { route: route.text, publicFallback, useBaseRpc: useBaseRpc.kind === ts.SyntaxKind.TrueKeyword };
82
+ }
83
+
84
+ export function resolveProjectRpc(route: string, publicFallback: string | undefined, useBaseRpc: boolean, env: NodeJS.ProcessEnv): string {
85
+ const base = env.BASE_RPC_URI?.trim();
86
+ return useBaseRpc && base ? `${base.replace(/\/+$/, '')}/${route}/` : publicFallback?.trim() || '';
87
+ }
88
+
89
+ function projectEnvironment(root: string, source: string, env: NodeJS.ProcessEnv, files: readonly string[]): NodeJS.ProcessEnv {
90
+ const file = ts.createSourceFile('hardhat.config.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
91
+ if (!projectRpcSyntax(file).bootstrap) return env;
92
+ const effective = { ...env };
93
+ for (const name of files) {
94
+ try {
95
+ const contents = readFile(root, name);
96
+ if (contents === undefined) continue;
97
+ for (const [key, value] of Object.entries(parseEnv(contents))) if (effective[key] === undefined) effective[key] = value;
98
+ } catch (error) {
99
+ if (name === '.env' && ['EPERM', 'EACCES'].includes((error as NodeJS.ErrnoException).code ?? '')) {
100
+ throw Error('Project credential environment is protected; run credential-bearing delivery operations through the trusted application host. Configure public RPCs in rpc.env.');
101
+ }
102
+ throw Error(`Cannot read local project RPC environment (${name})`);
103
+ }
104
+ }
105
+ return effective;
106
+ }
107
+
108
+ /** Static diagnostics never access the credential file, even when it is readable. */
109
+ export function projectPublicRpcEnvironment(root: string, source: string, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
110
+ return projectEnvironment(root, source, env, ['rpc.env']);
111
+ }
112
+
113
+ /** Actual runtime observation must retain the same environment semantics as Hardhat. */
114
+ export function projectRpcEnvironment(root: string, source: string, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
115
+ return projectEnvironment(root, source, env, ['rpc.env', '.env']);
116
+ }
@@ -3,8 +3,9 @@ import ts from 'typescript';
3
3
  import { positiveInteger, type ProjectNetworkSnapshot } from './protocol';
4
4
  import { validateNetworkAlias } from './policy';
5
5
 
6
- export { stat, confinedFile, projectRoot, readFile, coreMarker } from './project-files';
6
+ export { stat, confinedFile, projectRoot, readFile, deliveryProjectMarker } from './project-files';
7
7
  import { confinedFile, readFile } from './project-files';
8
+ import { projectRpcSyntax, projectRpcOptions, resolveProjectRpc, projectRpcEnvironment, projectPublicRpcEnvironment } from './project-rpc';
8
9
 
9
10
  function unwrap(node: ts.Expression): ts.Expression {
10
11
  while (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node)) node = node.expression;
@@ -63,7 +64,7 @@ export function projectDefaultNetwork(root: string): string {
63
64
  if (!ts.isStringLiteral(network)) throw new Error('Project defaultNetwork must be a static string for delivery routing');
64
65
  return validateNetworkAlias(network.text, 'defaultNetwork');
65
66
  }
66
- function rpcValue(node: ts.Expression, env: NodeJS.ProcessEnv): string | undefined {
67
+ function rpcValue(node: ts.Expression, env: NodeJS.ProcessEnv, helper: boolean): string | undefined {
67
68
  node = unwrap(node);
68
69
  if (ts.isStringLiteral(node)) return node.text;
69
70
  if (ts.isPropertyAccessExpression(node) && ts.isPropertyAccessExpression(node.expression)
@@ -73,19 +74,30 @@ function rpcValue(node: ts.Expression, env: NodeJS.ProcessEnv): string | undefin
73
74
  && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === 'process'
74
75
  && node.expression.name.text === 'env' && ts.isStringLiteral(node.argumentExpression)) return env[node.argumentExpression.text];
75
76
  if (ts.isBinaryExpression(node) && [ts.SyntaxKind.BarBarToken, ts.SyntaxKind.QuestionQuestionToken].includes(node.operatorToken.kind)) {
76
- const left = rpcValue(node.left, env);
77
+ const left = rpcValue(node.left, env, helper);
77
78
  return node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken
78
- ? left ?? rpcValue(node.right, env) : left || rpcValue(node.right, env);
79
+ ? left ?? rpcValue(node.right, env, helper) : left || rpcValue(node.right, env, helper);
80
+ }
81
+ if (helper && ts.isCallExpression(node)) {
82
+ const options = projectRpcOptions(node);
83
+ return resolveProjectRpc(options.route, rpcValue(options.publicFallback, env, false), options.useBaseRpc, env);
79
84
  }
80
85
  throw new Error('Selected network URL must be a literal or process.env reference');
81
86
  }
82
87
  /** Read the project-owned definitions without evaluating the config, plugins or HRE. */
83
88
  export function readProjectNetworkSnapshots(root: string, aliases: string[], env: NodeJS.ProcessEnv = process.env): ProjectNetworkSnapshot[] {
84
- return parseProjectNetworkSnapshots(readFile(root, 'hardhat.config.ts') ?? '', aliases, env);
89
+ const source = readFile(root, 'hardhat.config.ts') ?? '';
90
+ return parseProjectNetworkSnapshots(source, aliases, projectRpcEnvironment(root, source, env));
91
+ }
92
+ /** Public preflight only: RPCs must be in rpc.env or the supplied environment, never .env. */
93
+ export function readPublicProjectNetworkSnapshots(root: string, aliases: string[], env: NodeJS.ProcessEnv = process.env): ProjectNetworkSnapshot[] {
94
+ const source = readFile(root, 'hardhat.config.ts') ?? '';
95
+ return parseProjectNetworkSnapshots(source, aliases, projectPublicRpcEnvironment(root, source, env));
85
96
  }
86
97
  /** Parse one captured project definition without rereading files or evaluating plugins/HRE. */
87
98
  export function parseProjectNetworkSnapshots(source: string, aliases: string[], env: NodeJS.ProcessEnv = process.env): ProjectNetworkSnapshot[] {
88
- const { networks } = parseProjectConfig(source);
99
+ const { file, networks } = parseProjectConfig(source);
100
+ const { helper } = projectRpcSyntax(file);
89
101
  return aliases.map(network => {
90
102
  validateNetworkAlias(network, 'network', false);
91
103
  const selected = networks.get(network);
@@ -96,7 +108,7 @@ export function parseProjectNetworkSnapshots(source: string, aliases: string[],
96
108
  if (fields.has('zksync') && fields.get('zksync')!.kind !== ts.SyntaxKind.FalseKeyword) throw new Error('Delivery requires an EVM network');
97
109
  const url = fields.get('url');
98
110
  if (!url) throw new Error(`Selected network ${network} requires an RPC URL definition`);
99
- return { network, chainId: positiveInteger(Number(chainId.text), 'network chainId'), url: rpcValue(url, env) ?? '' };
111
+ return { network, chainId: positiveInteger(Number(chainId.text), 'network chainId'), url: rpcValue(url, env, helper) ?? '' };
100
112
  });
101
113
  }
102
114
  export function integratedConfig(source: string): string {
@@ -0,0 +1,74 @@
1
+ /** Public business projection. Internal provenance and runtime progress stay separate. */
2
+ import { immutableDeliveryPlan } from './export';
3
+ import { parseCalldataReviews } from './calldata-review';
4
+ import type { PreparationEntry } from './journal';
5
+ import { expandDeliveryInvocation, readableInvocationAbi, describeDeliveryInvocation, type ExpandedDetails } from './calldata-details';
6
+ import { nonempty, deepFreeze, canonicalJson, semanticHash } from '../workflow/lib/canonicalData';
7
+ import type { WorkflowStep } from '../workflow/lib/parameters';
8
+
9
+ export { archiveDeliveryCalls } from './calldata-archive';
10
+ export { serializeDeliveryCalls, deliveryCalldataPath } from './calldata-format';
11
+
12
+ export interface DeliveryCall {
13
+ chains: string[]; executor: string; to: string; name: string; description: string;
14
+ abi: string[]; calldata: string; value?: string;
15
+ details?: ExpandedDetails;
16
+ }
17
+ export interface PublicCalldataInput { plan: unknown; calldata: unknown; operations: readonly WorkflowStep[]; preparations?: unknown }
18
+ /** Frozen parameters independently re-encode and compare before any public projection. */
19
+ export function projectDeliveryCalls(input: PublicCalldataInput): readonly DeliveryCall[] {
20
+ const plan = immutableDeliveryPlan(input.plan);
21
+ const reviews = parseCalldataReviews(input.calldata, plan.transactions);
22
+ const journal=input.preparations??[];
23
+ const preparations: PreparationEntry[] = Array.isArray(journal)&&!journal.length&&!plan.deploymentBindings.length?[]
24
+ : (require('./journal') as typeof import('./journal')).parsePreparationJournal(journal, plan.transactions, plan.derivedBindings, {target:plan.target,chainId:plan.chainId,expectedStepIds:plan.deploymentBindings.map(d=>d.stepId)});
25
+ return deepFreeze(plan.transactions.map((tx, index) => {
26
+ if (tx.operation !== 0) throw Error('Public calldata supports ordinary CALL only');
27
+ const binding = plan.transactionBindings[index], operation = plan.operationBindings.find(o => o.stepId === binding.stepId);
28
+ if (!operation) throw Error('Public calldata operation binding missing');
29
+ const source = operation.operationId === null ? input.operations.find(s => s.id === operation.sourceStepId)
30
+ : plan.customBindings.find(s => s.sourceStepId === operation.sourceStepId)?.operations.find(s => s.id === operation.operationId);
31
+ if (!source) throw Error('Frozen operation intent missing');
32
+ const call = binding.callIndex === null ? undefined : (source.calls as any[] | undefined)?.[binding.callIndex];
33
+ const name = nonempty(call?.name ?? source.name, 'operation name');
34
+ const description = nonempty(call?.description ?? source.description, 'operation description');
35
+ const invocation = reviews[index].invocation;
36
+ if (invocation.kind !== 'function') throw Error('Outer public transaction requires function ABI');
37
+ const entry=preparations.find(p=>p.mappings.some(m=>m.transactionId===tx.transactionId));
38
+ const details=expandDeliveryInvocation(invocation,tx.to,{name,description},entry);
39
+ return { chains: [plan.chainId], executor: tx.executor, to: tx.to, name, description:describeDeliveryInvocation(description,invocation),
40
+ abi: readableInvocationAbi(invocation), calldata: tx.data, ...(BigInt(tx.value) === 0n ? {} : { value: tx.value }),...(details?{details}:{}) };
41
+ }));
42
+ }
43
+
44
+ /** Merge matching logical occurrences, never globally deduplicate calldata. */
45
+ export function mergeDeliveryCalls(inputs: readonly PublicCalldataInput[]): readonly DeliveryCall[] {
46
+ if(!inputs.length)throw Error('At least one independently frozen network is required');
47
+ const chains=new Set<string>(), sequences:Array<{chain:string;calls:readonly DeliveryCall[];keys:string[]}>=[];
48
+ const nodes=new Map<string,{call:DeliveryCall;next:Set<string>;incoming:number}>();
49
+ for(const input of inputs){
50
+ const plan=immutableDeliveryPlan(input.plan),chain=plan.chainId,calls=projectDeliveryCalls(input);
51
+ if(chains.has(chain))throw Error('Duplicate chain projection');chains.add(chain);
52
+ const keys=calls.map((call,index)=>{
53
+ const binding=plan.transactionBindings[index],operation=plan.operationBindings.find(o=>o.stepId===binding.stepId)!;
54
+ const {chains:_,...content}=call;
55
+ const key=semanticHash({logical:[operation.sourceStepId,operation.operationId,binding.role,binding.callIndex],content});
56
+ const existing=nodes.get(key);
57
+ if(existing){if(existing.call.chains.includes(chain))throw Error('Duplicate logical occurrence on one chain');existing.call.chains.push(chain);}
58
+ else nodes.set(key,{call:{...call,chains:[chain]},next:new Set(),incoming:0});
59
+ return key;
60
+ });
61
+ sequences.push({chain,calls,keys});
62
+ for(let i=1;i<keys.length;i++){const a=nodes.get(keys[i-1])!,b=nodes.get(keys[i])!;if(!a.next.has(keys[i])){a.next.add(keys[i]);b.incoming++;}}
63
+ }
64
+ const queue=[...nodes].filter(([,n])=>n.incoming===0).map(([key])=>key),ordered:DeliveryCall[]=[];
65
+ for(let at=0;at<queue.length;at++){
66
+ const node=nodes.get(queue[at])!;ordered.push(node.call);
67
+ for(const key of node.next){const next=nodes.get(key)!;if(--next.incoming===0)queue.push(key);}
68
+ }
69
+ // Conflicting cross-chain ordering cannot share occurrences; keep exact per-chain sequences.
70
+ const result=ordered.length===nodes.size?ordered:sequences.flatMap(s=>s.calls.map(call=>({...call,chains:[s.chain]})));
71
+ const content=(call:DeliveryCall)=>{const {chains:_,...rest}=call;return rest;};
72
+ for(const sequence of sequences)if(canonicalJson(result.filter(c=>c.chains.includes(sequence.chain)).map(content))!==canonicalJson(sequence.calls.map(content)))throw Error('Merged calldata changed per-chain order or coverage');
73
+ return deepFreeze(result);
74
+ }