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