@eco-incorp/sauce 0.99.0 → 0.99.2

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 (185) hide show
  1. package/LICENSE.md +29 -0
  2. package/README.md +69 -249
  3. package/actions/dist/to-sauce.d.ts.map +1 -1
  4. package/actions/dist/to-sauce.js +4 -5
  5. package/dev-tools/README.md +11 -170
  6. package/docs/README.md +39 -0
  7. package/docs/api/README.md +71 -0
  8. package/docs/api/compiler.md +234 -0
  9. package/docs/api/coverage.md +117 -0
  10. package/docs/api/routes.md +110 -0
  11. package/docs/concepts/architecture.md +134 -0
  12. package/docs/concepts/saucescript.md +172 -0
  13. package/docs/examples/README.md +34 -0
  14. package/docs/examples/compile-program.ts +20 -0
  15. package/docs/examples/evm-execution.ts +59 -0
  16. package/docs/examples/first-intent.ts +56 -0
  17. package/docs/examples/protocol-approval.ts +33 -0
  18. package/docs/guides/builders-and-actions.md +108 -0
  19. package/docs/guides/compiling.md +264 -0
  20. package/docs/guides/intents.md +158 -0
  21. package/docs/guides/nested-intents.md +79 -0
  22. package/docs/guides/protocols-and-tokens.md +116 -0
  23. package/docs/guides/quick-start.md +64 -0
  24. package/docs/guides/solana.md +196 -0
  25. package/docs/guides/verification.md +253 -0
  26. package/package.json +9 -4
  27. package/sdk/dist/artifacts/V12Deployments.json +82 -0
  28. package/sdk/dist/artifacts/V12RuntimeBytecode.json +1 -1
  29. package/sdk/dist/artifacts/svm/engine-devnet.so +0 -0
  30. package/sdk/dist/artifacts/svm/engine-mainnet.so +0 -0
  31. package/sdk/dist/artifacts/svm/engine-wire-devnet.json +3 -3
  32. package/sdk/dist/artifacts/svm/engine-wire-mainnet.json +3 -3
  33. package/sdk/dist/deployments/index.d.ts +15 -39
  34. package/sdk/dist/deployments/index.d.ts.map +1 -1
  35. package/sdk/dist/deployments/index.js +23 -39
  36. package/sdk/dist/deployments/index.js.map +1 -1
  37. package/sdk/dist/deployments/v12-addresses.d.ts +85 -0
  38. package/sdk/dist/deployments/v12-addresses.d.ts.map +1 -0
  39. package/sdk/dist/deployments/v12-addresses.js +51 -0
  40. package/sdk/dist/deployments/v12-addresses.js.map +1 -0
  41. package/sdk/dist/deployments/v12.generated.d.ts +3 -3
  42. package/sdk/dist/deployments/v12.generated.d.ts.map +1 -1
  43. package/sdk/dist/deployments/v12.generated.js +3 -3
  44. package/sdk/dist/deployments/v12.generated.js.map +1 -1
  45. package/sdk/dist/deposit/index.d.ts +28 -102
  46. package/sdk/dist/deposit/index.d.ts.map +1 -1
  47. package/sdk/dist/deposit/index.js.map +1 -1
  48. package/sdk/dist/deposit/params.d.ts +1 -1
  49. package/sdk/dist/deposit/params.js +2 -2
  50. package/sdk/dist/deposit/params.js.map +1 -1
  51. package/sdk/dist/deposit/source.d.ts +1 -1
  52. package/sdk/dist/deposit/source.d.ts.map +1 -1
  53. package/sdk/dist/deposit/source.js +18 -33
  54. package/sdk/dist/deposit/source.js.map +1 -1
  55. package/sdk/dist/deposit/types.d.ts +5 -4
  56. package/sdk/dist/deposit/types.d.ts.map +1 -1
  57. package/sdk/dist/evm/engine.d.ts +32 -0
  58. package/sdk/dist/evm/engine.d.ts.map +1 -1
  59. package/sdk/dist/evm/engine.js +2 -0
  60. package/sdk/dist/evm/engine.js.map +1 -1
  61. package/sdk/dist/index.d.ts +1 -0
  62. package/sdk/dist/index.d.ts.map +1 -1
  63. package/sdk/dist/index.js +2 -0
  64. package/sdk/dist/index.js.map +1 -1
  65. package/sdk/dist/plugin/index.d.ts +16 -41
  66. package/sdk/dist/plugin/index.d.ts.map +1 -1
  67. package/sdk/dist/plugin/index.js +2 -6
  68. package/sdk/dist/plugin/index.js.map +1 -1
  69. package/sdk/dist/recipes/index.js +2 -2
  70. package/sdk/dist/recipes/settle.sauce.ts +1 -1
  71. package/sdk/dist/routes/index.d.ts +3 -3
  72. package/sdk/dist/routes/index.js +3 -3
  73. package/sdk/dist/routes/intent-dsl.d.ts +23 -10
  74. package/sdk/dist/routes/intent-dsl.d.ts.map +1 -1
  75. package/sdk/dist/routes/intent-dsl.js +19 -2
  76. package/sdk/dist/routes/intent-dsl.js.map +1 -1
  77. package/sdk/dist/routes/nest.d.ts +23 -0
  78. package/sdk/dist/routes/nest.d.ts.map +1 -1
  79. package/sdk/dist/routes/nest.js +2 -4
  80. package/sdk/dist/routes/nest.js.map +1 -1
  81. package/sdk/dist/routes/protocol-rewrite.d.ts +2 -2
  82. package/sdk/dist/routes/protocol-rewrite.d.ts.map +1 -1
  83. package/sdk/dist/routes/protocol-rewrite.js +19 -35
  84. package/sdk/dist/routes/protocol-rewrite.js.map +1 -1
  85. package/sdk/dist/routes/sauce-calls.d.ts +7 -13
  86. package/sdk/dist/routes/sauce-calls.d.ts.map +1 -1
  87. package/sdk/dist/routes/sauce-calls.js +6 -11
  88. package/sdk/dist/routes/sauce-calls.js.map +1 -1
  89. package/sdk/dist/routes/sauce-route.d.ts +24 -53
  90. package/sdk/dist/routes/sauce-route.d.ts.map +1 -1
  91. package/sdk/dist/routes/sauce-route.js +5 -6
  92. package/sdk/dist/routes/sauce-route.js.map +1 -1
  93. package/sdk/dist/routes/source-globals.generated.d.ts +931 -0
  94. package/sdk/dist/routes/source-globals.generated.d.ts.map +1 -0
  95. package/sdk/dist/routes/source-globals.generated.js +7 -0
  96. package/sdk/dist/routes/source-globals.generated.js.map +1 -0
  97. package/sdk/dist/std/token/token.svm.js +19 -14
  98. package/sdk/dist/svm/cpi-probe.d.ts +1 -1
  99. package/sdk/dist/svm/cpi-probe.d.ts.map +1 -1
  100. package/sdk/dist/svm/cpi-probe.js +5 -2
  101. package/sdk/dist/svm/cpi-probe.js.map +1 -1
  102. package/sdk/dist/svm/intent.d.ts +12 -40
  103. package/sdk/dist/svm/intent.d.ts.map +1 -1
  104. package/sdk/dist/svm/intent.js +22 -66
  105. package/sdk/dist/svm/intent.js.map +1 -1
  106. package/sdk/dist/svm/venues/byreal/index.d.ts.map +1 -1
  107. package/sdk/dist/svm/venues/byreal/index.js +4 -1
  108. package/sdk/dist/svm/venues/byreal/index.js.map +1 -1
  109. package/sdk/dist/svm/venues/carrot/index.d.ts.map +1 -1
  110. package/sdk/dist/svm/venues/carrot/index.js +4 -0
  111. package/sdk/dist/svm/venues/carrot/index.js.map +1 -1
  112. package/sdk/dist/svm/venues/cropper/index.d.ts +1 -1
  113. package/sdk/dist/svm/venues/cropper/index.js +1 -1
  114. package/sdk/dist/svm/venues/huma/index.d.ts.map +1 -1
  115. package/sdk/dist/svm/venues/huma/index.js +4 -1
  116. package/sdk/dist/svm/venues/huma/index.js.map +1 -1
  117. package/sdk/dist/svm/venues/index.d.ts +1 -0
  118. package/sdk/dist/svm/venues/index.d.ts.map +1 -1
  119. package/sdk/dist/svm/venues/index.js +1 -0
  120. package/sdk/dist/svm/venues/index.js.map +1 -1
  121. package/sdk/dist/svm/venues/math.d.ts +4 -1
  122. package/sdk/dist/svm/venues/math.d.ts.map +1 -1
  123. package/sdk/dist/svm/venues/math.js +4 -1
  124. package/sdk/dist/svm/venues/math.js.map +1 -1
  125. package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.d.ts.map +1 -1
  126. package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.js +4 -1
  127. package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.js.map +1 -1
  128. package/sdk/dist/svm/venues/meteora-damm-v2/index.d.ts.map +1 -1
  129. package/sdk/dist/svm/venues/meteora-damm-v2/index.js +5 -2
  130. package/sdk/dist/svm/venues/meteora-damm-v2/index.js.map +1 -1
  131. package/sdk/dist/svm/venues/obric-v2/index.d.ts.map +1 -1
  132. package/sdk/dist/svm/venues/obric-v2/index.js +16 -5
  133. package/sdk/dist/svm/venues/obric-v2/index.js.map +1 -1
  134. package/sdk/dist/svm/venues/oracle-exponent.d.ts +82 -0
  135. package/sdk/dist/svm/venues/oracle-exponent.d.ts.map +1 -0
  136. package/sdk/dist/svm/venues/oracle-exponent.js +97 -0
  137. package/sdk/dist/svm/venues/oracle-exponent.js.map +1 -0
  138. package/sdk/dist/svm/venues/orca-legacy-token-swap/index.d.ts.map +1 -1
  139. package/sdk/dist/svm/venues/orca-legacy-token-swap/index.js +4 -1
  140. package/sdk/dist/svm/venues/orca-legacy-token-swap/index.js.map +1 -1
  141. package/sdk/dist/svm/venues/pumpswap/index.d.ts.map +1 -1
  142. package/sdk/dist/svm/venues/pumpswap/index.js +19 -13
  143. package/sdk/dist/svm/venues/pumpswap/index.js.map +1 -1
  144. package/sdk/dist/svm/venues/raydium-amm-v4/index.d.ts.map +1 -1
  145. package/sdk/dist/svm/venues/raydium-amm-v4/index.js +4 -1
  146. package/sdk/dist/svm/venues/raydium-amm-v4/index.js.map +1 -1
  147. package/sdk/dist/svm/venues/raydium-clmm/index.d.ts.map +1 -1
  148. package/sdk/dist/svm/venues/raydium-clmm/index.js +4 -1
  149. package/sdk/dist/svm/venues/raydium-clmm/index.js.map +1 -1
  150. package/sdk/dist/svm/venues/raydium-cp-swap/index.d.ts.map +1 -1
  151. package/sdk/dist/svm/venues/raydium-cp-swap/index.js +4 -1
  152. package/sdk/dist/svm/venues/raydium-cp-swap/index.js.map +1 -1
  153. package/sdk/dist/svm/venues/scorch/index.d.ts.map +1 -1
  154. package/sdk/dist/svm/venues/scorch/index.js +4 -1
  155. package/sdk/dist/svm/venues/scorch/index.js.map +1 -1
  156. package/sdk/dist/svm/venues/stabble-common.d.ts +1 -1
  157. package/sdk/dist/svm/venues/stabble-common.js +1 -1
  158. package/sdk/dist/svm/venues/types.d.ts +4 -1
  159. package/sdk/dist/svm/venues/types.d.ts.map +1 -1
  160. package/sdk/dist/svm/venues/woofi/index.d.ts.map +1 -1
  161. package/sdk/dist/svm/venues/woofi/index.js +4 -0
  162. package/sdk/dist/svm/venues/woofi/index.js.map +1 -1
  163. package/sdk/dist/svm/verify.d.ts +27 -133
  164. package/sdk/dist/svm/verify.d.ts.map +1 -1
  165. package/sdk/dist/svm/verify.js +72 -139
  166. package/sdk/dist/svm/verify.js.map +1 -1
  167. package/sdk/dist/swap/index.d.ts +16 -59
  168. package/sdk/dist/swap/index.d.ts.map +1 -1
  169. package/sdk/dist/swap/index.js +16 -59
  170. package/sdk/dist/swap/index.js.map +1 -1
  171. package/sdk/dist/token/source.d.ts.map +1 -1
  172. package/sdk/dist/token/source.js +4 -1
  173. package/sdk/dist/token/source.js.map +1 -1
  174. package/sdk/dist/verify/decode.d.ts +6 -6
  175. package/sdk/dist/verify/decode.js +7 -7
  176. package/sdk/dist/verify/index.js +2 -2
  177. package/sdk/dist/verify/intent.js +2 -2
  178. package/sdk/dist/verify/vectors.d.ts +1 -1
  179. package/sdk/dist/verify/vectors.d.ts.map +1 -1
  180. package/sdk/dist/verify/vectors.js +2 -2
  181. package/sdk/dist/verify/vectors.js.map +1 -1
  182. package/sdk/dist/verify/wire.d.ts +7 -4
  183. package/sdk/dist/verify/wire.d.ts.map +1 -1
  184. package/sdk/dist/verify/wire.js +7 -4
  185. package/sdk/dist/verify/wire.js.map +1 -1
@@ -0,0 +1,64 @@
1
+ # Quick start
2
+
3
+ [Documentation](../README.md) · [Protocols and tokens](protocols-and-tokens.md) · [Intents](intents.md)
4
+
5
+ Use Node.js 24 or newer and install the single public package:
6
+
7
+ ```sh
8
+ pnpm add @eco-incorp/sauce
9
+ ```
10
+
11
+ The Sauce compiler is a dependency of that package. You do not need a compiler checkout or a separate compiler install.
12
+
13
+ ## Compile your first intent
14
+
15
+ This complete TypeScript example builds an approval intent offline. Addresses and the fee are fixtures; the zero reward demonstrates construction only. Before submission, [read the current Kitchen fee and prepare an Executor-owned Pot](intents.md#prepare-the-destination-pot).
16
+
17
+ ```ts
18
+ import "@eco-incorp/sauce";
19
+ import type { routes } from "@eco-incorp/sauce";
20
+
21
+ const executionFee = 1_000n; // Fixture: read the destination Kitchen's executionFee() before use.
22
+ const options: routes.IntentOptions = {
23
+ execution: {
24
+ pot: "0x1111111111111111111111111111111111111111",
25
+ engine: "0x2222222222222222222222222222222222222222",
26
+ value: executionFee,
27
+ },
28
+ nativeAmount: executionFee,
29
+ portal: "0x3333333333333333333333333333333333333333",
30
+ deadline: 2_000_000_000n,
31
+ };
32
+
33
+ const built = Base(() => {
34
+ USDC.approve(Uniswap.UniversalRouter, 1_000_000n);
35
+ }, options).reward({
36
+ source: "ethereum",
37
+ creator: "0x4444444444444444444444444444444444444444",
38
+ prover: "0x5555555555555555555555555555555555555555",
39
+ deadline: 2_000_003_600n,
40
+ nativeAmount: 0n,
41
+ });
42
+
43
+ console.log(built.hash().intentHash);
44
+ ```
45
+
46
+ Importing the root package installs `Base` and the other chain globals. Inside the callback, the SDK resolves `USDC` and `Uniswap.UniversalRouter` for Base, compiles the body with Sauce, and encodes a Pot `cook(engine, program)` call. `.reward(...)` completes the Eco intent. Nothing is submitted to a chain.
47
+
48
+ For execution, deploy the Pot with the destination `Portal.executor()` as owner and pay the current Kitchen fee on every cook. [Intent setup](intents.md#prepare-the-destination-pot) shows the reads and deployment call. Fund and empty that shared Pot within the fulfillment.
49
+
50
+ `USDC` and protocol names have generated TypeScript declarations but are source syntax, not JavaScript clients. The router is registered as `UniswapV4.UniversalRouter`, with `Uniswap.UniversalRouter` as a family alias. `UniswapV3.UniversalRouter` is not a registered name. See [coverage](../api/coverage.md) for which protocols expose these namespaces.
51
+
52
+ The callback captures no outer variables. Pass dynamic scalars through `defines`, or use explicit source strings; see the complete [transfer example](../examples/first-intent.ts). Callbacks must remain recognizable synchronous source after your build tooling transforms them.
53
+
54
+ ## Deliver assets and fund the reward
55
+
56
+ In a transfer intent, the destination assets and source reward are separate. Destination `tokens` reach the Portal Executor. Add a transfer precall to deliver tokens into the Pot before Sauce spends them. Source reward tokens are approved to the source Portal and escrowed through its funding call.
57
+
58
+ The [first-intent.ts example](../examples/first-intent.ts) constructs both sides and returns source transaction requests. Read [creating intents](intents.md) before submitting those requests, and [nested intents](nested-intents.md) to compose subsequent routes.
59
+
60
+ ## Compile a standalone program
61
+
62
+ Use `@eco-incorp/sauce/compiler` when you need raw bytecode, entry schemas, or an SVM account manifest. It exposes the published Rust/Wasm compiler through `compile(options)`; it does not install SDK protocol namespaces into arbitrary compiler input.
63
+
64
+ The [compiler example](../examples/compile-program.ts) compiles a typed SauceScript entry point and appends compact arguments. [Compiling](compiling.md) explains module resolution and the distinction between raw compiler output and the route wrapper.
@@ -0,0 +1,196 @@
1
+ # Solana programs and execution
2
+
3
+ [Documentation](../README.md) · [Compiler](../api/compiler.md) · [Coverage](../api/coverage.md)
4
+
5
+ Solana programs use the `svm` compiler target, explicit account parameters, and a Kitchen that invokes the engine. EVM token/protocol member rewrites such as `USDC.transfer(...)` do not apply to SVM routes.
6
+
7
+ Use `@eco-incorp/sauce/compiler` to retain the compiler's account manifest. `routes.compileSauceRoute()` returns execution calls and a `compiled.bytecode` segment list, but does not expose that manifest; applications resolving account slots should use the direct compiler result.
8
+
9
+ ## Compile an SPL transfer
10
+
11
+ The universal token builder emits account parameters and an SPL `TransferChecked` CPI. Its source needs no imports, so a single-module resolver is sufficient:
12
+
13
+ ```ts
14
+ import { token } from "@eco-incorp/sauce";
15
+ import { compile } from "@eco-incorp/sauce/compiler";
16
+
17
+ export function compileSplTransfer(amount: bigint) {
18
+ const source = token.Token.transfer({
19
+ amount,
20
+ svm: {
21
+ source: "sourceAta",
22
+ mint: "mint",
23
+ dest: "destinationAta",
24
+ owner: "owner",
25
+ tokenProgram: "tokenProgram",
26
+ },
27
+ }).source("svm");
28
+
29
+ return compile({
30
+ target: "svm",
31
+ entry: "main.ts",
32
+ resolve: (id) => (id === "main.ts" ? new TextEncoder().encode(source) : null),
33
+ });
34
+ }
35
+ ```
36
+
37
+ The account references are names, not addresses. `manifest.accounts` records their order and required roles. Resolve them to the mint, source token account, destination token account, authority, and token program before execution. Amounts are smallest-unit integers. The builder reads mint decimals for the checked instruction and defaults to the classic SPL Token program. Set the builder's top-level `tokenProgram: "token-2022"` for a supported Token-2022 operation; `svm.tokenProgram` names the account reference and must resolve to that token program.
38
+
39
+ ## Execute through the Kitchen
40
+
41
+ `createSauceSvmClient` requires an RPC URL, engine program ID, Kitchen program ID, and a Kit transaction signer. Its inline execution path constructs a Kitchen `cook`, includes the required heap-frame instruction, resolves accounts, and builds/signs transactions.
42
+
43
+ Use `v12SvmEngineProgramId()` and `v12SvmKitchenProgramId()` from
44
+ `@eco-incorp/sauce/deployments` for the released program identities, and confirm
45
+ they are deployed on your cluster. The older `v12SvmProgramId` constant identifies
46
+ a legacy engine. The client derives a Pot owned by its `payer` signer; select it
47
+ with `potSalt` when configuring the client.
48
+
49
+ ```ts
50
+ import {
51
+ createSauceSvmClient,
52
+ type AccountResolution,
53
+ type SauceSvmClientConfig,
54
+ } from "@eco-incorp/sauce/svm";
55
+ import type { CompileResult } from "@eco-incorp/sauce/compiler";
56
+
57
+ export async function simulateProgram(
58
+ config: SauceSvmClientConfig,
59
+ compiled: CompileResult,
60
+ accounts: AccountResolution,
61
+ ) {
62
+ if (!compiled.manifest) throw new Error("Expected an SVM account manifest");
63
+ const client = await createSauceSvmClient(config);
64
+ return client.simulate(compiled.bytecode, compiled.manifest, accounts);
65
+ }
66
+ ```
67
+
68
+ For the transfer above, the resolution keys are `sourceAta`, `mint`, `destinationAta`, `owner`, and `tokenProgram`. A non-payer transaction authority should be supplied as `{ address, signer: transactionSigner }`; an address alone cannot provide its signature. A Pot PDA that the Kitchen signs for must be attached with `signer: false` in the transaction resolution. That override represents a signature supplied during invocation, not permission to bypass the program's authority requirement.
69
+
70
+ After successful simulation, `client.execute(bytecode, manifest, resolution, { computeUnitLimit: "auto" })` simulates for compute budgeting and sends the transaction. `maxExecutionFee` in client configuration is the lamport fee ceiling accepted for each cook; its default is zero and fails when the Kitchen charges a positive fee. Lookup-table helpers can create or extend an address lookup table and wait until it is usable.
71
+
72
+ ### Select the released programs and quote the fee
73
+
74
+ The pinned SVM engine **1.0.1** is `8Sgwi8N7JykC3K19ReY8aZzYXmWxKcDTedtQ6r1y6iwH`;
75
+ Kitchen **1.0.0** is `SauceYLdWyabKFwtevSAgsSDoMjCoTKtx1HTb63eJot`.
76
+ Use the deployment helpers and read the Kitchen's fee configuration on the selected
77
+ cluster. This example checks a caller-selected lamport budget before signing:
78
+
79
+ ```ts
80
+ import { createHash } from "node:crypto";
81
+ import {
82
+ address,
83
+ assertAccountExists,
84
+ createSolanaRpc,
85
+ fetchEncodedAccount,
86
+ type TransactionSigner,
87
+ } from "@solana/kit";
88
+ import { v12SvmEngineProgramId, v12SvmKitchenProgramId } from "@eco-incorp/sauce/deployments";
89
+ import { createSauceSvmClient, deriveExecutionFeeConfigPda } from "@eco-incorp/sauce/svm";
90
+
91
+ export async function createReleasedClient(
92
+ rpcUrl: string,
93
+ payer: TransactionSigner,
94
+ feeBudgetLamports: bigint,
95
+ ) {
96
+ const kitchen = address(v12SvmKitchenProgramId());
97
+ const { address: feeConfig } = await deriveExecutionFeeConfigPda(kitchen);
98
+ const account = await fetchEncodedAccount(createSolanaRpc(rpcUrl), feeConfig);
99
+ assertAccountExists(account);
100
+ const discriminator = createHash("sha256")
101
+ .update("account:ExecutionFeeConfig")
102
+ .digest()
103
+ .subarray(0, 8);
104
+ if (
105
+ account.programAddress !== kitchen ||
106
+ account.data.length !== 16 ||
107
+ !discriminator.every((value, index) => account.data[index] === value)
108
+ )
109
+ throw new Error("Unexpected Kitchen fee account");
110
+ const fee = new DataView(
111
+ account.data.buffer,
112
+ account.data.byteOffset,
113
+ account.data.byteLength,
114
+ ).getBigUint64(8, true);
115
+ if (fee > feeBudgetLamports) throw new Error("Kitchen fee exceeds the approved budget");
116
+ return createSauceSvmClient({
117
+ rpcUrl,
118
+ payer,
119
+ kitchen,
120
+ programId: address(v12SvmEngineProgramId()),
121
+ maxExecutionFee: fee,
122
+ });
123
+ }
124
+ ```
125
+
126
+ The payer needs SOL for this per-cook fee, transaction fees, and any rent or program
127
+ spending. The Kitchen charges its current fee up to the signed cap; a fee increase
128
+ above the quoted amount makes the cook fail. Requote before signing a retry.
129
+
130
+ `resolveAccounts` preserves manifest order. The reserved `payer` reference resolves to the fee payer. A manifest ending with `remaining` leaves the final account tail to the caller; do not insert accounts that shift that tail's indices.
131
+
132
+ ## Stage a larger program
133
+
134
+ Staging belongs to the Kitchen. There is no `client.stageBuffer()` convenience method. Build and submit Kitchen instructions in this order:
135
+
136
+ 1. Derive metadata and code addresses with `deriveCodeBufferPda(kitchen, owner, nonce)` and `deriveCodePda(kitchen, codeBuffer)`.
137
+ 2. Allocate with `buildCreateCodeBufferInstruction`. Capacities above `GROWTH_STEP` require additional `buildGrowCodeBufferInstruction` calls.
138
+ 3. Write the bytecode in appropriately sized chunks using `buildWriteCodeBufferInstruction`.
139
+ 4. Finalize with `buildFinalizeCodeBufferInstruction`, supplying the byte length and its SHA-256 digest. Finalization verifies the digest and shrinks the code account to that length.
140
+ 5. Execute with a Kitchen `buildCookFromAccountInstruction`, or the client's `simulateStaged`/`executeStaged` methods.
141
+
142
+ The low-level instruction builders return instructions; the application groups, signs, submits, and confirms them. The two Kitchen cook paths require `buildHeapFramePrepend()` when assembling transactions yourself. A staged client's first argument is the **code-buffer metadata address**; it derives the associated code account.
143
+
144
+ `buildCookFromAccountInstruction` supports a `pin` that the Kitchen checks at execution. The client's `expectedSha256` option is currently rejected; it is not a supported substitute for that low-level `pin`. A finalized buffer's digest and an execution-time caller-selected digest are different guarantees.
145
+
146
+ ## SVM destinations in Eco intents
147
+
148
+ **The SDK's SVM route helpers are incompatible with the released gated engine.**
149
+ For an SVM destination, `Solana(body, { execution, ... }).reward(...)`,
150
+ `routes.compileSauceRoute()`, `buildSauceSvmCall()`, and `buildSauceSvmCalls()` emit
151
+ a legacy `execute_from_account` instruction containing only its 8-byte
152
+ discriminator. Engine 1.0.1 requires another 65 bytes of Pot derivation material
153
+ and a trailing Pot signer supplied by the Kitchen.
154
+
155
+ The [SVM Portal fulfillment implementation](https://github.com/eco/eco-routes-svm/blob/5e544b72d368d9d1f0ee5269e2a1a5d2a9f8c2f2/programs/portal/src/instructions/fulfill.rs#L139-L192)
156
+ forwards the route's instruction bytes to its target unchanged. It signs for its
157
+ Executor PDA; it does not construct a Kitchen call or sign for a Sauce Pot.
158
+ Changing only the helper's engine program ID therefore does not make these routes
159
+ executable. Do not distribute them as executable intents against the pinned release.
160
+
161
+ A Kitchen-targeted Portal integration needs separately constructed cook data and
162
+ accounts, including the owner signature, Pot, fee configuration and payer, engine,
163
+ and staged metadata/code where applicable. The SDK does not currently build or
164
+ validate that complete integration. For standalone execution, use the client or
165
+ Kitchen instruction builders described above.
166
+
167
+ The legacy route's `execution.code` means the finalized **code account**, not its
168
+ metadata address. The helper neither stages nor checks that code against its newly
169
+ compiled bytes, and it drops the compiler account manifest. Keep the direct
170
+ compilation result when inspecting historical routes. EVM-source Portal helpers
171
+ can encode an SVM destination; they do not provide Solana-origin submission.
172
+
173
+ ## Venue accessors
174
+
175
+ The `Solana` global includes the venues registered for runtime access. A venue accessor exposes a program ID, pool configuration loading, quote-source generation, swap CPI construction, and a TypeScript reference quote:
176
+
177
+ ```ts
178
+ import { venue } from "@eco-incorp/sauce/svm";
179
+ import type { AccountLoader, SwapUser } from "@eco-incorp/sauce/svm";
180
+ import type { Address } from "@solana/kit";
181
+
182
+ export async function buildRaydiumSwap(
183
+ load: AccountLoader,
184
+ pool: Address,
185
+ user: SwapUser,
186
+ amount: bigint,
187
+ ) {
188
+ const raydium = venue("raydium-cp-swap");
189
+ const config = await raydium.poolConfig(load, pool);
190
+ return raydium.swap(config, user, amount);
191
+ }
192
+ ```
193
+
194
+ `Solana.RaydiumCpSwap` exposes the same accessor when globals are installed. `poolConfig` uses the account loader you supply; it does not create an RPC client or discover pools. `quoteSource` returns SauceScript source, and `.swap` returns CPI data plus account references, not a transaction.
195
+
196
+ Venue swap builders use a venue-level minimum output of one; the composed program must enforce the user's actual minimum with a post-swap output balance delta. Runtime accessors cover the registered venue set. Other adapters exported from `/svm` do not automatically appear as `Solana.<Venue>`; consult [coverage](../api/coverage.md).
@@ -0,0 +1,253 @@
1
+ # Verifying settlement programs
2
+
3
+ [Documentation](../README.md) · [Intents](intents.md) · [Compiler API](../api/compiler.md)
4
+
5
+ The SDK verifies its canonical settlement programs on EVM and SVM. These helpers
6
+ answer which settlement logic and parameters a payload contains. Applications
7
+ still check the destination, execution target, account identities, and remaining
8
+ intent calls against the operation they intend to authorize.
9
+
10
+ | Surface | Mechanism | Environment |
11
+ | ------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
12
+ | `@eco-incorp/sauce/verify` | Validate the EVM program hash and decode its canonical runtime argument tail | Node, browsers, and edge runtimes; depends on `viem`, not the compiler |
13
+ | `@eco-incorp/sauce/svm/verify` | Recompile SVM settlement with expected parameters, compare bytecode, and inspect attached accounts | Node; loads the compiler |
14
+
15
+ ## Settlement behavior
16
+
17
+ The EVM recipe sweeps the Pot's entire current balance of every listed token to
18
+ one recipient. It checks `minOut` against the balance of `tokens[0]` before the
19
+ first transfer; `minOut: 0n` disables that floor. Existing or donated balances
20
+ count toward the floor and are swept as well. The floor is a balance check, not a
21
+ measurement of the amount produced by an earlier swap.
22
+
23
+ The SVM recipe applies the same pattern to escrow token accounts. It takes an
24
+ escrow count and compile-time `minOut`/`splCount`, then attaches token programs,
25
+ escrows, mints, destination token accounts, and the owner. `splCount` selects how
26
+ the escrows are split between the two token-program slots.
27
+
28
+ ## EVM: validate a complete payload
29
+
30
+ For EVM, a payload is the reusable compiled program followed by ABI-v1 runtime
31
+ arguments. The compiler never sees the argument values.
32
+
33
+ ```ts
34
+ import {
35
+ SETTLE_PROGRAM,
36
+ encodeSettleProgram,
37
+ validateSettleProgram,
38
+ } from "@eco-incorp/sauce/verify";
39
+
40
+ const payload = encodeSettleProgram(
41
+ ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"], // Base USDC
42
+ 1_000_000n,
43
+ "0x1111111111111111111111111111111111111111", // Example recipient
44
+ SETTLE_PROGRAM,
45
+ );
46
+
47
+ const settlement = validateSettleProgram(payload);
48
+ console.log(settlement.tokens, settlement.minOut, settlement.recipient);
49
+ console.log(settlement.floorToken, settlement.programHash);
50
+ ```
51
+
52
+ `validateSettleProgram()` checks the full program hash and the argument encoding.
53
+ The current `SETTLE_WIRE` pin records compiler **2.3.0** and a **356-byte** program.
54
+ Payloads produced before that recompile are 362 bytes under a different hash; verify them by
55
+ passing their historical `{ hash, bytes: 362 }` pin to `validateSettleProgram`.
56
+ Import `SETTLE_WIRE` when code needs those values; avoid copying them into a
57
+ second constant table.
58
+
59
+ The tail contains three 32-byte head words—token-array offset, minimum output,
60
+ recipient—followed by the token count and token addresses in source order. The
61
+ verifier requires the canonical offset, a nonempty token list, a nonzero
62
+ recipient, clean address words, and no trailing data. Some alternate encodings
63
+ execute on an engine but are deliberately rejected here, so a successful decode
64
+ has a unique byte representation.
65
+
66
+ This surface verifies the pinned **ABI-v1** settlement artifact. Recompiling the
67
+ recipe with `compactArgs: true` changes that contract and is not accepted by the
68
+ existing settlement decoder.
69
+
70
+ ### Inspection levels
71
+
72
+ | Helper | Result |
73
+ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
74
+ | `validateSettleProgram(payload, accepted?)` | Hash-pinned program identity and strict argument decode; preferred for validation |
75
+ | `decodeSettleProgram(payload)` | Strict argument shape at the expected program length; does not authenticate program bytes |
76
+ | `parseSettleProgram(payload)` | A non-throwing structural report, including a `fatal` failure when present |
77
+ | `bestEffortDecode(parse)` | Best-effort inspection or `null` when reporting values would be misleading |
78
+ | `encodeSettleProgram(tokens, minOut, recipient, program)` | Canonical payload construction |
79
+
80
+ An arbitrary prefix of the expected length can pass structural decoding. Only a
81
+ hash-pinned validation establishes that it contains the recognized settlement
82
+ program. Validation failures use `SettleDecodeError.code`, including
83
+ `PROGRAM_HASH`, `TOKENS_OFFSET`, `DIRTY_ADDRESS_WORD`, and `ARGS_OVERLONG`.
84
+
85
+ ### Extract a settlement from an intent
86
+
87
+ The intent helpers unwrap `cook` calldata and validate the program they find.
88
+ This reusable check expects exactly one current Pot settlement call:
89
+
90
+ ```ts
91
+ import { extractEvmSettleFromIntent, type IntentLike } from "@eco-incorp/sauce/verify";
92
+ import type { Address } from "viem";
93
+
94
+ export function inspectSingleSettle(
95
+ intent: IntentLike,
96
+ trustedPot: Address,
97
+ trustedEngine: Address,
98
+ ) {
99
+ const result = extractEvmSettleFromIntent(intent);
100
+ if (!result) throw new Error("No recognized settlement");
101
+ if (intent.route.calls.length !== 1 || result.callIndex !== 0) {
102
+ throw new Error("Expected exactly one settlement call");
103
+ }
104
+ if (result.ingredientCount !== 1) throw new Error("Unexpected extra program");
105
+ if (result.target?.toLowerCase() !== trustedPot.toLowerCase()) {
106
+ throw new Error("Unexpected Pot");
107
+ }
108
+ if (result.engine?.toLowerCase() !== trustedEngine.toLowerCase()) {
109
+ throw new Error("Unexpected engine");
110
+ }
111
+ return result; // Compare tokens, minOut, and recipient to application expectations.
112
+ }
113
+ ```
114
+
115
+ For a swap-plus-settle intent, use the expected call count and positions for that
116
+ application and validate every other call. `extractEvmSettleFromIntent()` returns
117
+ the first recognized settlement; it does not approve the whole batch or check
118
+ the intent's destination chain.
119
+
120
+ `decodeSettleCall(data)` examines one cook, and
121
+ `extractEvmSettleFromCalls(calls)` operates without the intent wrapper. The
122
+ decoder also recognizes the historical `cook(bytes[])` wrapper: only its first
123
+ ingredient is inspected. A legacy router executes every ingredient, so check
124
+ `ingredientCount` and interpret an absent `engine` according to that contract.
125
+ Current `Pot.cook(address,bytes)` carries exactly one program and reports the
126
+ engine it names.
127
+
128
+ ### Compiler upgrades and historical pins
129
+
130
+ `validateSettleProgram` accepts an explicit list of program hashes or
131
+ `{ hash, bytes }` `ProgramPin` records. Use the full record for a historical
132
+ program with a different length. Passing an empty list accepts no program; it
133
+ does not fall back to the default pin.
134
+
135
+ Compiler upgrades can change program bytes. When upgrading the SDK or compiler,
136
+ check which program versions your application produces and accepts. Import the
137
+ SDK's settlement pins rather than copying their values. Keep historical pins only
138
+ for program versions your application explicitly accepts.
139
+
140
+ The source is available through `settleSource()` from
141
+ `@eco-incorp/sauce/recipes`, and as the
142
+ `@eco-incorp/sauce/recipes/settle.sauce.ts` asset. `SAUCE_BASE_DIRS` locates its ABI
143
+ dependencies for a reproducing resolver. The verifier itself does not load that
144
+ source or recompile it.
145
+
146
+ ## SVM: verify program and accounts
147
+
148
+ SVM settle parameters are compiled into the program, and account identities live
149
+ outside it. State the expected floor and token-program split, then verify both
150
+ parts.
151
+
152
+ ```ts
153
+ import { compile } from "@eco-incorp/sauce/compiler";
154
+ import { svmSettleSource } from "@eco-incorp/sauce/svm";
155
+ import { verifySvmSettleProgram } from "@eco-incorp/sauce/svm/verify";
156
+
157
+ const expected = { minOut: 1_000_000n, splCount: 1n };
158
+ const source = new TextEncoder().encode(svmSettleSource(1));
159
+ const artifact = compile({
160
+ target: "svm",
161
+ resolve: (path) => (path === "main.js" ? source : undefined),
162
+ defines: [
163
+ ["SETTLE_MIN_OUT", expected.minOut.toString()],
164
+ ["SETTLE_SPL_COUNT", expected.splCount.toString()],
165
+ ],
166
+ });
167
+ if (!artifact.manifest) throw new Error("Expected SVM accounts");
168
+
169
+ const result = verifySvmSettleProgram(artifact.bytecode, artifact.manifest, expected);
170
+ if (!result.genuine) throw new Error(result.mismatch);
171
+ console.log(result.escrowCount, result.refs);
172
+ ```
173
+
174
+ This example demonstrates reproduction. To verify received data, pass the
175
+ received bytecode and manifest instead. The helper infers the escrow count from
176
+ the `3N + 3` account shape, checks canonical slot names, and recompiles the shipped
177
+ source with the expected values. Supported settle generators accept 1–16 escrows.
178
+ The result does not establish that the account addresses attached to an actual
179
+ instruction are the ones the application expects.
180
+
181
+ ### Execution verification
182
+
183
+ `decodeSvmSettleExecution({ instructionData, accounts })` resolves accounts
184
+ positionally against the canonical settlement refs. The default `wireFormat: "gated-v1"` accepts raw **engine CPI instructions** produced by Kitchen 1.0.0 for
185
+ engine 1.0.1:
186
+
187
+ | Instruction | Data | Full CPI account list |
188
+ | ---------------------- | ------------------------------------------------------------------ | -------------------------------------- |
189
+ | `execute` | discriminator (8 bytes), owner (32), salt (32), bump (1), bytecode | settlement accounts, Pot |
190
+ | `execute_from_account` | discriminator (8 bytes), owner (32), salt (32), bump (1) | code account, settlement accounts, Pot |
191
+
192
+ The decoder removes the code account and trailing Pot before resolving the
193
+ `3N + 3` settlement slots. It returns parsed `gate` metadata and the staged
194
+ `codeAccount` when present. It rejects truncated headers, extra staged data,
195
+ invalid account addresses, and incompatible account counts. Labels are diagnostic;
196
+ account positions determine identities. Structural decoding alone cannot identify
197
+ settlement: unrelated programs can use the same account count.
198
+
199
+ Historical 8-byte headers require explicit `wireFormat: "legacy-ungated"`.
200
+ That inspection mode accepts the user account tail or its code-prefixed form;
201
+ it does not make legacy instructions executable on the released engine.
202
+ Kitchen `cook` and `cook_from_account` have different data and account layouts
203
+ and must not be passed directly to this decoder.
204
+
205
+ `verifySvmSettleExecution()` adds `minOut`, `splCount`, and optional `bytecode`
206
+ and `pin` inputs. Check both its `genuine` and `verifiedBy` fields:
207
+
208
+ | `verifiedBy` | What was compared |
209
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
210
+ | `inline-bytecode` | The program inside an `execute` instruction matches the canonical program; supplied bytecode, if any, must match it too |
211
+ | `bytecode` | Supplied staged bytecode matches the canonical program and the supplied pin hashes those bytes |
212
+ | `caller-asserted-pin` | A caller-supplied pin equals the hash of the canonical program; no staged bytes were supplied |
213
+ | `none` | No basis to authenticate the staged program |
214
+
215
+ For staged execution, the pin comes from the **caller**, not from the released
216
+ engine's `execute_from_account` calldata. That instruction has no content-pin
217
+ field. A `bytecode` or `caller-asserted-pin` result therefore depends on the
218
+ caller's evidence connecting that pin to the code account that will execute,
219
+ such as the relevant Kitchen `cook_from_account` instruction and staged account
220
+ contents. The helper does not fetch that evidence. Supplying canonical bytes
221
+ without a pin cannot authenticate a staged execution.
222
+
223
+ Also check the engine program ID and the account identities, roles, mints,
224
+ owners, and destinations required by the application. Parsed gate metadata is
225
+ not proof of a valid Pot derivation or signature. The verifier does not validate
226
+ the Kitchen invocation, account roles, on-chain state, or execution success;
227
+ `genuine` describes the recognized program under the stated pin assumptions.
228
+
229
+ ### Eco Portal envelopes
230
+
231
+ `decodePortalCalldataWithAccounts()` unwraps the SVM Portal's instruction data
232
+ and ordered account metas. It requires the declared account count to match the
233
+ full account list, canonical Borsh flags, and no trailing bytes. Envelope decoding
234
+ alone does not validate the target, program identity, or settlement.
235
+ `extractSvmSettleFromIntent()` and
236
+ `extractSvmSettleFromCalls()` combine envelope extraction with execution
237
+ verification and report the call target. They expect the raw engine format
238
+ above, default to `gated-v1`, and do **not** decode Kitchen cook envelopes. Supply
239
+ expected `minOut`, `splCount`, optional `wireFormat`, and optional `bytecode`
240
+ through their options. When verifying staged code, attach
241
+ the independently obtained `pin` to the relevant input call; pins are per call,
242
+ not shared across the batch.
243
+
244
+ A working Kitchen-targeted route needs separate Kitchen decoding before its
245
+ program and account plan can be checked. For an already executed transaction,
246
+ inspect the recorded inner engine instruction instead. The SDK's legacy SVM
247
+ route builder cannot produce that Kitchen integration; see the
248
+ [Solana guide](solana.md#svm-destinations-in-eco-intents).
249
+
250
+ As on EVM, finding a genuine settlement does not validate adjacent calls or an
251
+ arbitrary callee that accepts the same instruction discriminator. Match the
252
+ reported target and account plan to the deployment and intent your application
253
+ expects.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eco-incorp/sauce",
3
- "version": "0.99.0",
3
+ "version": "0.99.2",
4
4
  "description": "Sauce protocol tooling: SDK, action primitives, and a local dev environment.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -8,6 +8,7 @@
8
8
  "url": "git+https://github.com/eco-incorp/sauce.git"
9
9
  },
10
10
  "homepage": "https://sauce.eco.com",
11
+ "license": "SEE LICENSE IN LICENSE.md",
11
12
  "bugs": "https://github.com/eco-incorp/sauce/issues",
12
13
  "publishConfig": {
13
14
  "access": "public",
@@ -79,6 +80,7 @@
79
80
  "sauce-dev-tools": "./dev-tools/scripts/init.js"
80
81
  },
81
82
  "files": [
83
+ "LICENSE.md",
82
84
  "sdk/dist",
83
85
  "actions/dist",
84
86
  "sdk/src/skills",
@@ -88,7 +90,9 @@
88
90
  "dev-tools/sauce",
89
91
  "dev-tools/artifacts",
90
92
  "dev-tools/hardhat.config.cjs",
91
- "dev-tools/README.md"
93
+ "dev-tools/README.md",
94
+ "docs/**/*.md",
95
+ "docs/examples/*.ts"
92
96
  ],
93
97
  "dependencies": {
94
98
  "@solana-program/address-lookup-table": "^0.12.1",
@@ -98,7 +102,7 @@
98
102
  "@solana/kit": "^6.10.0",
99
103
  "acorn": "^8.15.0",
100
104
  "dotenv": "^17.3.1",
101
- "sauce-compiler": "npm:@eco-incorp/sauce-compiler@^2.2.0",
105
+ "sauce-compiler": "npm:@eco-incorp/sauce-compiler@2.3.0",
102
106
  "typescript": "^5.7.0",
103
107
  "viem": "^2.45.3"
104
108
  },
@@ -112,9 +116,10 @@
112
116
  "typescript-eslint": "8.70.0"
113
117
  },
114
118
  "engines": {
115
- "node": ">=22"
119
+ "node": ">=24"
116
120
  },
117
121
  "scripts": {
122
+ "docs:check": "node docs/scripts/check-docs.mjs",
118
123
  "build": "pnpm -r --filter './sdk' --filter './actions' build",
119
124
  "typecheck": "pnpm -r typecheck",
120
125
  "test": "pnpm -r test",
@@ -0,0 +1,82 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "commit": "f2f6dfbe38809304d83ca755eb7975c19d35ceab",
4
+ "releases": {
5
+ "v12-evm": {
6
+ "version": "1.0.1",
7
+ "commit": "9281c2eeb0e14557e6565a3a689ae31380740fa7"
8
+ },
9
+ "kitchen-evm": {
10
+ "version": "1.0.0",
11
+ "commit": "f2f6dfbe38809304d83ca755eb7975c19d35ceab"
12
+ },
13
+ "v12-svm": {
14
+ "version": "1.0.1",
15
+ "commit": "9281c2eeb0e14557e6565a3a689ae31380740fa7"
16
+ },
17
+ "kitchen-svm": {
18
+ "version": "1.0.0",
19
+ "commit": "f2f6dfbe38809304d83ca755eb7975c19d35ceab"
20
+ }
21
+ },
22
+ "evm": {
23
+ "chainIndependent": true,
24
+ "factory": "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed",
25
+ "deployer": "0x6Ab56944462222A2405ffb87d01A29e37890abC3",
26
+ "contracts": {
27
+ "engine": {
28
+ "address": "0x9745fdfaB1be84a0003f0472A842A0b91E5A323c",
29
+ "saltName": "Engine",
30
+ "rawSalt": "0x6ab56944462222a2405ffb87d01a29e37890abc300456e67696e650000010001",
31
+ "guardedSalt": "0xbfaa08f51a17021008df6c83a6de420a69d30bb65908e3b1d31b5bcf7b0c20f4",
32
+ "derivation": "CREATE(CREATE2(factory, guardedSalt, keccak256(CreateX proxy initcode)), 1)"
33
+ },
34
+ "router": {
35
+ "address": "0xB820759EDD59318C2BD8B303C51Ad0E5176B608D",
36
+ "saltName": "Router",
37
+ "rawSalt": "0x6ab56944462222a2405ffb87d01a29e37890abc300526f757465720000000002",
38
+ "guardedSalt": "0x1777eb6e606524722e6b410e789c2fab1fb9d27f2cfa743ba22346d622ce2844",
39
+ "derivation": "CREATE(CREATE2(factory, guardedSalt, keccak256(CreateX proxy initcode)), 1)"
40
+ },
41
+ "kitchen": {
42
+ "address": "0x19845b22989150E6B09dE55a661295Dd9188506b",
43
+ "saltName": "Kitchen",
44
+ "rawSalt": "0x6ab56944462222a2405ffb87d01a29e37890abc3004b69746368656e00000002",
45
+ "guardedSalt": "0xb8d1641d5eba3797376adb85f5e4fd7049660a39bb1ecf9825588e60f4b4c324",
46
+ "derivation": "CREATE(CREATE2(factory, guardedSalt, keccak256(CreateX proxy initcode)), 1)",
47
+ "proxyKind": "uups",
48
+ "generation": 2,
49
+ "note": "the UUPS proxy — generation 2 starts a new Kitchen/Pot address family; existing Pots stay at their original addresses"
50
+ },
51
+ "kitchenImplementation": {
52
+ "address": "0x07E7dfc8389269EC5cd796E55e408aDB98D365c2",
53
+ "saltName": "KitchenI",
54
+ "rawSalt": "0x6ab56944462222a2405ffb87d01a29e37890abc3004b69746368656e49010000",
55
+ "guardedSalt": "0x315d3a6196bd5b0a650bac815b651cf33f35532edc4db4777568b82e3145398d",
56
+ "derivation": "CREATE(CREATE2(factory, guardedSalt, keccak256(CreateX proxy initcode)), 1)"
57
+ }
58
+ },
59
+ "pot": {
60
+ "deployer": "0x19845b22989150E6B09dE55a661295Dd9188506b",
61
+ "initCodeHash": "0x47913cfa9c7a1dcfe6b69ea8f3ab25a579befbcb732fa65498e6be8be6613739",
62
+ "saltFormula": "keccak256(abi.encode(owner, salt))",
63
+ "derivation": "CREATE2(kitchen, keccak256(abi.encode(owner, salt)), initCodeHash)"
64
+ }
65
+ },
66
+ "svm": {
67
+ "clusterIndependent": true,
68
+ "programs": {
69
+ "engine": {
70
+ "programId": "8Sgwi8N7JykC3K19ReY8aZzYXmWxKcDTedtQ6r1y6iwH",
71
+ "label": "engine@1.0.1",
72
+ "derivation": "ed25519 keypair from sha256(SOLANA_PROGRAM_KEY_SEED, label)",
73
+ "upgradeAuthority": "none — deployed --final, so this program can never be upgraded or closed"
74
+ },
75
+ "kitchen": {
76
+ "programId": "SauceYLdWyabKFwtevSAgsSDoMjCoTKtx1HTb63eJot",
77
+ "derivation": "fixed keypair, held as SOLANA_KITCHEN_PROGRAM_KEYPAIR; this release's IDL declares the same address",
78
+ "upgradeAuthority": "our deploy authority — the program is upgraded in place, so every Pot survives a release"
79
+ }
80
+ }
81
+ }
82
+ }