@black-market/sdk 0.15.1 → 0.16.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 (60) hide show
  1. package/README.md +6 -5
  2. package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts +71 -0
  3. package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts.map +1 -0
  4. package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js +73 -0
  5. package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js.map +1 -0
  6. package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts +71 -0
  7. package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts.map +1 -0
  8. package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js +73 -0
  9. package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js.map +1 -0
  10. package/dist/lifecycle/gas-profile.d.ts +1 -1
  11. package/dist/lifecycle/gas-profile.d.ts.map +1 -1
  12. package/dist/lifecycle/gas-profile.js +24 -9
  13. package/dist/lifecycle/gas-profile.js.map +1 -1
  14. package/dist/lifecycle/index.d.ts +2 -0
  15. package/dist/lifecycle/index.d.ts.map +1 -1
  16. package/dist/lifecycle/index.js +2 -0
  17. package/dist/lifecycle/index.js.map +1 -1
  18. package/dist/lifecycle/markets.d.ts +2 -0
  19. package/dist/lifecycle/markets.d.ts.map +1 -1
  20. package/dist/lifecycle/markets.js +30 -2
  21. package/dist/lifecycle/markets.js.map +1 -1
  22. package/dist/lifecycle/opening-buys.js +3 -3
  23. package/dist/lifecycle/opening-buys.js.map +1 -1
  24. package/dist/lifecycle/planner.d.ts.map +1 -1
  25. package/dist/lifecycle/planner.js +21 -2
  26. package/dist/lifecycle/planner.js.map +1 -1
  27. package/dist/lifecycle/presets.d.ts +4 -2
  28. package/dist/lifecycle/presets.d.ts.map +1 -1
  29. package/dist/lifecycle/presets.js +8 -1
  30. package/dist/lifecycle/presets.js.map +1 -1
  31. package/dist/lifecycle/raeto-abi.d.ts +175 -0
  32. package/dist/lifecycle/raeto-abi.d.ts.map +1 -0
  33. package/dist/lifecycle/raeto-abi.js +224 -0
  34. package/dist/lifecycle/raeto-abi.js.map +1 -0
  35. package/dist/lifecycle/raeto.d.ts +21 -0
  36. package/dist/lifecycle/raeto.d.ts.map +1 -0
  37. package/dist/lifecycle/raeto.js +59 -0
  38. package/dist/lifecycle/raeto.js.map +1 -0
  39. package/dist/lifecycle/transactions.d.ts.map +1 -1
  40. package/dist/lifecycle/transactions.js +8 -1
  41. package/dist/lifecycle/transactions.js.map +1 -1
  42. package/dist/lifecycle/types.d.ts +2 -2
  43. package/dist/lifecycle/types.d.ts.map +1 -1
  44. package/docs/launch-lifecycle.md +106 -40
  45. package/docs/lifecycle-gas-profiles.md +173 -24
  46. package/docs/reference.md +73 -15
  47. package/examples/README.md +6 -3
  48. package/package.json +1 -1
  49. package/src/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.ts +74 -0
  50. package/src/lifecycle/deployments/raeto-fixed-pool-v1-20261029.ts +74 -0
  51. package/src/lifecycle/gas-profile.ts +21 -9
  52. package/src/lifecycle/index.ts +2 -0
  53. package/src/lifecycle/markets.ts +23 -1
  54. package/src/lifecycle/opening-buys.ts +3 -3
  55. package/src/lifecycle/planner.ts +19 -2
  56. package/src/lifecycle/presets.ts +8 -1
  57. package/src/lifecycle/raeto-abi.ts +223 -0
  58. package/src/lifecycle/raeto.ts +61 -0
  59. package/src/lifecycle/transactions.ts +8 -1
  60. package/src/lifecycle/types.ts +2 -2
package/docs/reference.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use the [launch guide](launch-lifecycle.md) for the end-to-end flow and the
4
4
  [runner reference](../examples/README.md) for environment and recovery artifacts.
5
- This page covers SDK **0.14.1** addresses, limits, wire formats, fees, and diagnostics.
5
+ This page covers SDK **0.16.1** addresses, limits, wire formats, fees, and diagnostics.
6
6
 
7
7
  ## Deployed infrastructure
8
8
 
@@ -20,6 +20,7 @@ start historical log queries there, in chunks of at most **10M blocks**.
20
20
  | `UFG_TREASURY_FACTORY_ADDRESS` | `0x26Aa5D52134c8E6c4C01E9fb53A7568c0C64901F` |
21
21
  | `UFG_UPSTREAM_FACTORY_ADDRESS` | `0xA170b5A58C111334A7237F2Ea2c428ec5022f68E` |
22
22
  | Known deployment `launchLens` | `0xcb4bb3caca71fe52eace8170cf83e901418646f8` |
23
+ | `RAETO_PAYOUT_REGISTRY_ADDRESS` | `0xBEC2C0e91612090F82df6743F31CDF18B4386b50` |
23
24
 
24
25
  `getKnownLifecycleDeployment`, `getKnownLifecycleProfile`, and
25
26
  `listKnownLifecycleProfiles` are pure selectors keyed by chain/core. Unknown
@@ -134,8 +135,8 @@ UFG adds a canonical dynamic tuple via `encodeUfgLaunchConfig`:
134
135
  `decodeUfgLaunchConfig` rejects alternate encodings and extra bytes;
135
136
  `hashUfgLaunchConfig` hashes the tuple. Config6 appends typed `ufgLaunchConfig`
136
137
  for UFG profiles only; Abyss carries no UFG tail. Full plan hashes bind every
137
- auxiliary tail. HMM/UFG constructor economics hash the zero-salt prefix; the
138
- auto-compounding profiles below hash the zero-salt prefix **and** their tail.
138
+ auxiliary tail. HMM/UFG/Raeto constructor economics hash the zero-salt prefix;
139
+ auto-compounding profiles hash the zero-salt prefix **and** their tail.
139
140
 
140
141
  ## Auto-compounding profiles
141
142
 
@@ -160,7 +161,7 @@ The disabled `0x1e41…1d68` / `0x53dd…e0d7` profiles are not supported.
160
161
  `AUTO_COMPOUND_CONFIG_VERSION = keccak256("black-market.auto-compound.config.v1")`.
161
162
  The decoder requires the exact version, length and canonical narrow-integer
162
163
  padding. Config6's typed `autoCompoundConfig` selects this tail only for these
163
- two profiles; HMM and UFG tails cannot be combined with it.
164
+ two profiles; HMM, UFG and Raeto tails cannot be combined with it.
164
165
  `validateAutoCompoundConfig`, the market codec and `validateV4LifecycleMarket`
165
166
  reject invalid shares; the market boundaries also require zero LP/developer fees.
166
167
  Both InputToken and QuoteOnly fee modes are supported.
@@ -170,6 +171,60 @@ for these profiles. Never mine against a prefix-only commitment or append a shar
170
171
  after mining. Use [the launch guide](launch-lifecycle.md#configure-auto-compounding)
171
172
  for selection and gas behavior.
172
173
 
174
+ ## Raeto profiles
175
+
176
+ All of the following are exported from `@black-market/sdk/lifecycle` (and the
177
+ root). These presets are supported on the known Robinhood 4663 deployment.
178
+
179
+ | Profile key / identity constant | Profile ID |
180
+ | --- | --- |
181
+ | `V4RaetoFixedPool` / `RAETO_FIXED_PROFILE_ID` | `0x9161833b162e7ca8160b11c64aedb307561e19a9136fd32f99cd797aab6da3ca` |
182
+ | `V4RaetoDynamicPool` / `RAETO_DYNAMIC_PROFILE_ID` | `0x08387d00ee4f75f860810cc8fb434087328592c2f39ea3321109e589039f80e1` |
183
+
184
+ `RAETO_FIXED_ADAPTER_ID` is
185
+ `0x911d7ecefe56489d329235e3484829717dc00400d4181902f0f2de45f9338615`;
186
+ `RAETO_DYNAMIC_ADAPTER_ID` is
187
+ `0x8ab9c8c9b8fd4c8bbf12b780d9474463fa0fa52e3b450f0d5f68fd067dc1674d`.
188
+ `isRaetoProfile(profileId)` compares IDs case-insensitively.
189
+ `RAETO_PAYOUT_REGISTRY_ADDRESS` identifies the controller-managed payout registry.
190
+ `RAETO_QUOTE_ASSETS` is the frozen checksummed `[WETH, USDG]` tuple:
191
+ `0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73`,
192
+ `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`.
193
+
194
+ `RAETO_SHARE_BPS_OPTIONS` is readonly `[500, 1000, 2500, 5000, 7500]`.
195
+ `RaetoLaunchConfigV1 = { shareBps: number }`, `validateRaetoLaunchConfig`,
196
+ `encodeRaetoLaunchTail` and `decodeRaetoLaunchTail` enforce exactly that menu and
197
+ exactly `abi.encode(uint16 shareBps)` (one 32-byte word). Noncanonical uint16
198
+ padding, extra/missing bytes, zero and non-menu shares throw
199
+ `INVALID_RAETO_CONFIG`. V6 `raetoLaunchConfig` is mutually exclusive with all
200
+ other tails; Raeto requires QuoteOnly, zero LP/developer fees and allowed quotes.
201
+ `validateRaetoLaunchPlan(plan)` checks **every** market and throws
202
+ `INVALID_RAETO_PLAN`, including for wrong profiles/adapters, schemas or quotes.
203
+ It adds no UFG token/reward/proxy restrictions.
204
+
205
+ `raetoFeeCollectorV1Abi` is generated from verified standard-output and includes
206
+ `shareBps()`, `owed(address)`, `launchToken()`, `quoteAsset()`,
207
+ `setShareBps(uint16)`, `claimRaeto(address)` and the exact three Raeto events.
208
+ See [fee ownership and collection semantics](launch-lifecycle.md#configure-raeto).
209
+
210
+ `test/fixtures/raeto-registry-readback.json` preserves admission bytes/receipts,
211
+ runtime hashes, factory metadata, verified ABI provenance and real factory
212
+ `eth_call` share-menu results at **101,180,179**
213
+ (`0xe778e5d89ca2cab5843eedeb8c27b10f5463313d4b95b8971986ac72e297933c`).
214
+ The deployed source commit is `a39c958` (go-live record `02e5cf3`), **not** the
215
+ later local `80ea8c8` share-range change. The generator proves hook creation bytes
216
+ equal the SDK's existing fixed and zero-royalty dynamic bytecode.
217
+
218
+ ```sh
219
+ # Offline, deterministic regeneration from saved evidence (Node 24+):
220
+ node --experimental-transform-types scripts/generate-raeto-presets.mjs
221
+ # Explicit read-only refresh, checking the preserved go-live records:
222
+ node --experimental-transform-types scripts/generate-raeto-presets.mjs \
223
+ --readback /path/to/black-market
224
+ pnpm build
225
+ node --test test/integration/raeto.live.test.mjs
226
+ ```
227
+
173
228
  ## Choose a fee tier
174
229
 
175
230
  One million pips is 100%; 10,000 pips is 1%. Basis points use a 10,000 denominator.
@@ -206,17 +261,20 @@ NodeInterface oracle. See [capacity and poster evidence](lifecycle-gas-profiles.
206
261
 
207
262
  `computeLifecycleLaunchGasBounds({ plan, predictedToken, ufg? })` returns conservative
208
263
  atomic/activation compute upper bounds, excluding poster, or undefined for unknown
209
- coverage. These select modes, not gas limits. Atomic is a preference that may select
210
- staged; persist returned `planned.mode`. A large upper bound is uncertain, not
211
- proof of overflow. Unknown activation gets full-sequence execution before begin.
212
- Conversion-carrying commands/consuming activation always retain exact execution.
213
-
214
- Only an immediate launch command receives a final gas/price/estimate/admission.
215
- Suffix execution metrics stay provisional; build-next constructs only the canonical
216
- next command at the same native ceiling with fresh fees and required admission.
217
- There are no sizing passes or funds-only retries. Balance must cover value plus
218
- the entire ceiling fee even when actual execution uses less gas. Incomplete proof
219
- cannot authorize begin; explicit aggregate policies still refuse excessive work.
264
+ coverage. These select modes, not gas limits. Atomic is a preference: one known-profile
265
+ market may fit, including an empirical2M compute reserve per Swap before at-least-25%
266
+ padding, full encoded-calldata costs and poster allocation. That reserve is not a
267
+ universal bound on arbitrary router execution. Multiple markets and explicit staged
268
+ remain staged; persist returned `planned.mode`. Unknown coverage refuses, and an
269
+ oversized unsplittable activation budget refuses before begin. A large conservative
270
+ bound is not proof of actual overflow. No launch calldata is simulated.
271
+
272
+ Only an immediate launch command receives fresh gas/price/estimate/assessment.
273
+ Build-next constructs only the canonical next command at the same native ceiling
274
+ with fresh inputs, capacity and fees. There are no sizing passes or funds-only
275
+ retries. Balance must cover value plus the entire ceiling fee even when actual
276
+ execution uses less gas. Routers enforce conversion floors/deadlines on-chain;
277
+ `assessment.ready` does not establish execution.
220
278
 
221
279
  On Nitro, `estimate.posterGas` / `posterFee` are buffered allocations **inside**
222
280
  `gasLimit`; `dataFeeIncludedInGas` is true, `dataFee` is zero, and `totalFee` equals
@@ -1,6 +1,6 @@
1
1
  # Run the examples
2
2
 
3
- These commands use the checkout's built `@black-market/sdk` **0.15.1** and viem.
3
+ These commands use the checkout's built `@black-market/sdk` **0.16.1** and viem.
4
4
  Use **Node 24+** for direct TypeScript execution. Start with the one-market
5
5
  `launch-erc20-abyss.ts`; larger cases require staged preparation and a bounded activation.
6
6
  For valuation, token ordering, ranges, and buy protection, read the
@@ -20,7 +20,7 @@ chmod 600 .env
20
20
  Launch wrappers load `.env` from the working directory with `process.loadEnvFile`.
21
21
  Existing environment values take precedence. Values are literal; shell interpolation
22
22
  is not applied. Use the matching SDK version when copying wrappers into a consumer project:
23
- `pnpm add @black-market/sdk@0.14.1 viem`.
23
+ `pnpm add @black-market/sdk@0.16.1 viem`.
24
24
  Copy `launch-example.ts`, `launch-example-support.ts`, and `launch-example-kyber.ts` with the wrapper.
25
25
 
26
26
  ### Configure the environment
@@ -126,7 +126,10 @@ be combined or duplicated. Resume is an execution authorization; omit `--broadca
126
126
 
127
127
  Every launch transaction uses the native ceiling,32M total on4663. Capacity profiles
128
128
  only choose mode/chunks and reject oversized activation; exact local ordered math
129
- protects opening buys. Multiple markets or conversion funding always stage.
129
+ protects opening buys. Multiple markets always stage; a single known-profile market
130
+ can stay atomic when its padded compute, including an empirical2M reserve per Swap,
131
+ plus poster allocation fits. Explicit staged stays staged; the conversion reserve
132
+ does not prove arbitrary router execution.
130
133
  There is no launch simulation, including Kyber. Routers enforce conversion minima
131
134
  and deadlines on-chain; `assessment.ready` is not a receipt or guaranteed execution.
132
135
  See [coverage and migration](../docs/lifecycle-gas-profiles.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@black-market/sdk",
3
- "version": "0.15.1",
3
+ "version": "0.16.1",
4
4
  "description": "TypeScript SDK for Abyss token launches, swaps, and lending.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,74 @@
1
+ import type { LaunchEnvelopeV2, AdapterRegistrationV1, ProfileRegistrationV1, ProfileTopologyV1 } from "../schema.js";
2
+
3
+ // Generated by scripts/generate-raeto-presets.mjs from admission and registry readback.
4
+ // Robinhood block 101180179, 0xe778e5d89ca2cab5843eedeb8c27b10f5463313d4b95b8971986ac72e297933c; admission 0x3148a6696c36bb1de00f8142b2aa6480681ded86203ffa6486a44c4e985c3b31.
5
+ export const raetoDynamicEnvelope = Object.freeze({
6
+ artifactDigest: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
7
+ reviewManifestDigest: "0x9edfb13596015293cd41cf887758bb3799b121d680fac092191afcc0d29a6194",
8
+ configBoundsDigest: "0x11ec57e16f972e0ac5f687d4078d785a51de11d421bcf97e2ba129dfd83fe7b4",
9
+ termsDigest: "0x458cf6674ee60f1e56086a12d0d981db2c1ed815109f552318b1d8fd27a80ba2",
10
+ topology: 2,
11
+ configVersion: 6,
12
+ economicVersion: 3,
13
+ capabilities: 123n,
14
+ flags: 0n,
15
+ callbackFlags: 6908,
16
+ callbackMask: 16383,
17
+ protocolTreasury: "0x961981916AB6575C3af3eeCecbf6A3b7Fad7C9e1",
18
+ protocolFeeDenominator: 6,
19
+ beneficiary: "0x7cb44b8693b3C350A2BcD4b681aF85365aa27783",
20
+ maximumDeveloperFeeBps: 0,
21
+ bounds: Object.freeze({
22
+ minimumTickSpacing: 1,
23
+ maximumTickSpacing: 32767,
24
+ maximumPositions: 32,
25
+ maximumOracleCardinality: 4096,
26
+ feeModeFlags: 2,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0xBF9005094bDa89d5a119A324d6e609A2d8217C1C",
33
+ collectorFactory: "0x3E201A0d72221A9F8c0AEd06EdAE850E27226166",
34
+ collectorDeployer: "0x796E8899824999f6Da8740f712A709dBC65cbEd7",
35
+ hookDeployer: "0x788b88E46be3051633792896F3000EB2Ca57F97E",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0x0990b18576da69dcf545010ddd7abc2252018a1bb0406b07a14e55a2315c6b27",
41
+ collectorFactoryCodeHash: "0xf5a1dea71122eeb3db1b925d7311a3bc89609a218ba8501038936c18fde8c892",
42
+ collectorDeployerCodeHash: "0xb2d108fe4ab95e42ca012cc8a48734a0fcf8cb65325e4874568a6d145dc9e617",
43
+ hookDeployerCodeHash: "0xb71fc43dc8000386815e3d1c5c54be6840b83281ca294db9929867d0862d118f",
44
+ hookCreationCodeHash: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
45
+ codeChunk0: "0x8F8756D9A50fD968a0207a09B997D4ec32525062",
46
+ codeChunk0Hash: "0x818c56bf10ae21129fe54f1b8991d6f807ce4ccef35b34c56251c1fd2d7d623f",
47
+ codeChunk1: "0xdfA2F95713d09a13d1861f09CBD4a94274b18c87",
48
+ codeChunk1Hash: "0xbc73944bfa7e74df5968907a05fe2579a17ab155d3a0db407588d1baff51b4de",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const raetoDynamicAdapter = Object.freeze({
53
+ implementation: "0xfc1502090D8326AB9b70aa93a01c93bEBb6f4910",
54
+ codeHash: "0x1ee51eb5074c356255713d5f66c9fac07e028a6d20161c623a1f409920598a16",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const raetoDynamicRegistration = Object.freeze({
60
+ adapterId: "0x8ab9c8c9b8fd4c8bbf12b780d9474463fa0fa52e3b450f0d5f68fd067dc1674d",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0x2709d930b96f60427579a60cb9801b5ce5aadbda95e261a963fc783e4d2036de",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const raetoDynamicTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0x788b88E46be3051633792896F3000EB2Ca57F97E",
73
+ hookCreationCodeHash: "0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a",
74
+ }) satisfies ProfileTopologyV1;
@@ -0,0 +1,74 @@
1
+ import type { LaunchEnvelopeV2, AdapterRegistrationV1, ProfileRegistrationV1, ProfileTopologyV1 } from "../schema.js";
2
+
3
+ // Generated by scripts/generate-raeto-presets.mjs from admission and registry readback.
4
+ // Robinhood block 101180179, 0xe778e5d89ca2cab5843eedeb8c27b10f5463313d4b95b8971986ac72e297933c; admission 0x99089e4418bcf59fc4a2efb5dd36c95f92331a079401dcfaae36d1c94a08326a.
5
+ export const raetoFixedEnvelope = Object.freeze({
6
+ artifactDigest: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
7
+ reviewManifestDigest: "0x684131bdefed80771e37364f9d5af4969591a31345fbe57c503a4839b4050be2",
8
+ configBoundsDigest: "0x11ec57e16f972e0ac5f687d4078d785a51de11d421bcf97e2ba129dfd83fe7b4",
9
+ termsDigest: "0x22ac34826ee23febf81eb209a7c0ab4c0a44be4744410a3e0b5b1720b93aaacc",
10
+ topology: 2,
11
+ configVersion: 6,
12
+ economicVersion: 3,
13
+ capabilities: 123n,
14
+ flags: 0n,
15
+ callbackFlags: 6908,
16
+ callbackMask: 16383,
17
+ protocolTreasury: "0x961981916AB6575C3af3eeCecbf6A3b7Fad7C9e1",
18
+ protocolFeeDenominator: 6,
19
+ beneficiary: "0x7cb44b8693b3C350A2BcD4b681aF85365aa27783",
20
+ maximumDeveloperFeeBps: 0,
21
+ bounds: Object.freeze({
22
+ minimumTickSpacing: 1,
23
+ maximumTickSpacing: 32767,
24
+ maximumPositions: 32,
25
+ maximumOracleCardinality: 4096,
26
+ feeModeFlags: 2,
27
+ }),
28
+ graph: Object.freeze({
29
+ manager: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
30
+ hookRoot: "0x0000000000000000000000000000000000000000",
31
+ oracleFactory: "0xe7feF2BC860B25bbdEB6F6AB96d88bAAa77ddad7",
32
+ locker: "0x12985Fa618974b45a5de8fA40c1DE90d15E9c5c8",
33
+ collectorFactory: "0xb2f84D9f31cBCfA75E998852B1dCcF176BeaAeDC",
34
+ collectorDeployer: "0xb07558776a71C0b58779F1CAF89775d8E466c173",
35
+ hookDeployer: "0xfdB07076Cab21715244Bc9699A381b4F461157ea",
36
+ coreCodeHash: "0x9fb8f46c3b980b9db25dfdb487a69a308a86be145860269b4036a4e74480787b",
37
+ managerCodeHash: "0xbd3881180b547f5fe817545743cfb4343e96b1bc6640dcd70c106b0066e95626",
38
+ hookRuntimeCodeHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
39
+ oracleFactoryCodeHash: "0x974fb5c72d91ccb99f1eb4679a5d4432c82bbaa0906b1c2917ec4da3499b7b98",
40
+ lockerCodeHash: "0x304fff24ef51d2a583541fcdeddcc2cb256fe6911bbb737d68871195d14e6cc6",
41
+ collectorFactoryCodeHash: "0xe1ee1bfb72f9e652c121945a9ecf312d92258f937b3defd60be34d692fd1487b",
42
+ collectorDeployerCodeHash: "0xb2d108fe4ab95e42ca012cc8a48734a0fcf8cb65325e4874568a6d145dc9e617",
43
+ hookDeployerCodeHash: "0xd291bbfbbf60fb0b5eaf2569a3300408b7ac81f102a092872fd54e76b8bc766a",
44
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
45
+ codeChunk0: "0x46B4C3a2D205C220A20B4432e857a3254B4D051c",
46
+ codeChunk0Hash: "0xe5f56287276954b21f4211cabf2d9c251aae68836c5fa86ce68091ffccdee26b",
47
+ codeChunk1: "0x629Ab46e20f87db9ae761E75EEa733E0B396638D",
48
+ codeChunk1Hash: "0x76efd61e1a109a85140ce3473c43694a83f490eaac54d18673c17872a5262a47",
49
+ sharedHookSalt: "0x0000000000000000000000000000000000000000000000000000000000000000",
50
+ }),
51
+ }) satisfies LaunchEnvelopeV2;
52
+ export const raetoFixedAdapter = Object.freeze({
53
+ implementation: "0x995Da3cB2b643A9D986f28179F62511BE8757e58",
54
+ codeHash: "0x9b6d2c83d25a6cad137ccab7bbe17c948aa1ce27a03b53ed5a4ac7f18d06d5ec",
55
+ capabilities: 123n,
56
+ configVersion: 6,
57
+ enabled: true,
58
+ }) satisfies AdapterRegistrationV1;
59
+ export const raetoFixedRegistration = Object.freeze({
60
+ adapterId: "0x911d7ecefe56489d329235e3484829717dc00400d4181902f0f2de45f9338615",
61
+ configSchema: "0x51c5ca14c40012f78425cd1afb1ea77980da3fed0490a00911a8a4ed34792045",
62
+ dependencyDigest: "0x52beccb89ebac17f1028986ef4ee2e4646b23edc7779400b82976af7e35bc41c",
63
+ venue: "0x8366a39CC670B4001A1121B8F6A443A643e40951",
64
+ factory: "0x0000000000000000000000000000000000000000",
65
+ hook: "0x0000000000000000000000000000000000000000",
66
+ capabilities: 123n,
67
+ enabled: true,
68
+ }) satisfies ProfileRegistrationV1;
69
+ export const raetoFixedTopology = Object.freeze({
70
+ hookTopology: 2,
71
+ configVersion: 6,
72
+ hookDeployer: "0xfdB07076Cab21715244Bc9699A381b4F461157ea",
73
+ hookCreationCodeHash: "0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab",
74
+ }) satisfies ProfileTopologyV1;
@@ -9,18 +9,19 @@ import { buildLifecycleCommand, LIFECYCLE_CAPACITY_PADDING_BPS, preparationCalld
9
9
  import { UFG_LAUNCH_PROXY_ADDRESS, isUfgProfile, ufgPlanPrincipal, type UfgLaunchConfig } from "./ufg-config.js";
10
10
  import { LifecyclePlanningError, type LifecycleBlock, type LifecycleLaunchGasBounds, type LifecycleLimitSource, type LifecycleOpeningBuyQuote, type LifecyclePlanningAssessment, type LifecycleRpcClient, type LifecycleTransaction, type PlannedLaunch } from "./types.js";
11
11
  import { isHmmProfile } from "./hmm.js";
12
+ import { isRaetoProfile } from "./raeto.js";
12
13
 
13
- export const LIFECYCLE_GAS_PROFILE_VERSION = "robinhood-4663-capacity-v3";
14
+ export const LIFECYCLE_GAS_PROFILE_VERSION = "robinhood-4663-capacity-v5";
14
15
  export type NextTransactionEnvelope = Readonly<{ gas: bigint; gasPrice: bigint }>;
15
16
  const ceil = (value: bigint, divisor: bigint) => (value + divisor - 1n) / divisor;
16
17
  const approval = (transaction: LifecycleTransaction) => transaction.kind === "approve" || transaction.kind === "approve-reset";
17
- type MarketGas = { abyss: boolean; hmm: boolean; ufgHook: boolean; positions: number };
18
+ type MarketGas = { abyss: boolean; hmm: boolean; ufgHook: boolean; raeto: boolean; autoCompound: boolean; positions: number };
18
19
 
19
20
  function marketGas(plan: LaunchPlanV1): MarketGas[] {
20
21
  return plan.markets.map((market) => {
21
22
  const abyss = market.configVersion === 1;
22
23
  const config = abyss ? decodeAbyssLifecycleMarketConfig(market.config) : decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
23
- return { abyss, hmm: isHmmProfile(market.profileId), ufgHook: isUfgProfile(market.profileId), positions: config.positions.length };
24
+ return { abyss, hmm: isHmmProfile(market.profileId), ufgHook: isUfgProfile(market.profileId), raeto: isRaetoProfile(market.profileId), autoCompound: isAutoCompoundProfile(market.profileId), positions: config.positions.length };
24
25
  });
25
26
  }
26
27
 
@@ -51,6 +52,8 @@ const activationCosts = {
51
52
  call: 1_500_000n,
52
53
  abyss: { market: 500_000n, position: 1_250_000n },
53
54
  v4: { market: 250_000n, position: 500_000n },
55
+ raeto: { market: 500_000n, position: 500_000n },
56
+ autoCompound: { market: 750_000n, position: 500_000n },
54
57
  hmm: 1_000_000n,
55
58
  ufg: 250_000n,
56
59
  // Fork Abyss32: 64 buys78.44M minimum versus one buy47.49M;
@@ -62,17 +65,29 @@ const activationCosts = {
62
65
  /** Measured-max template budgets, never gas-limit sizing or execution evidence. */
63
66
  function capacityBasis(plan: LaunchPlanV1, transaction: LifecycleTransaction, markets: readonly MarketGas[], quotes: readonly LifecycleOpeningBuyQuote[], ufgRoute: boolean): bigint {
64
67
  const atomic = transaction.kind === "atomic";
65
- let gas = atomic ? 22_000_000n + tokenCreationGas(plan.token) + (ufgRoute ? 6_500_000n : 0n)
68
+ // template-gas-matrix.json: Raeto/auto-compound atomic1 <=19.60M,
69
+ // atomic8 <=23.99M; atomic32 exceeds32M. The18M calibration base plus
70
+ // position/buy work and25% padding bounds compute and forwarding envelopes.
71
+ let gas = atomic ? (markets[0]!.raeto || markets[0]!.autoCompound ? 18_000_000n : 22_000_000n) + tokenCreationGas(plan.token) + (ufgRoute ? 6_500_000n : 0n)
66
72
  : activationCosts.call + (ufgRoute ? activationCosts.ufg : 0n);
73
+ // Escrow executes each Swap during begin, including within atomic. This
74
+ // empirical2M reserve is padded below, not a proof for arbitrary router code.
75
+ if (atomic) for (const funding of plan.funding) if (funding.kind === LifecycleFundingKind.Swap) gas += 2_000_000n;
67
76
  for (const market of markets) {
68
77
  if (atomic) gas += (market.hmm ? 7_000_000n : market.ufgHook ? 1_000_000n : market.abyss ? 500_000n : 0n) +
69
78
  (market.abyss ? 1_500_000n : 600_000n) * BigInt(market.positions - 1);
70
79
  else {
71
- const cost = market.abyss ? activationCosts.abyss : activationCosts.v4;
80
+ const cost = market.abyss ? activationCosts.abyss : market.raeto ? activationCosts.raeto : market.autoCompound ? activationCosts.autoCompound : activationCosts.v4;
72
81
  gas += cost.market + cost.position * BigInt(market.positions) + (market.hmm ? activationCosts.hmm : market.ufgHook ? activationCosts.ufg : 0n);
73
82
  }
74
83
  }
75
84
  gas += activationCosts.buy * BigInt(quotes.length);
85
+ // These collectors revalidate the prepared position set for each buy. At32
86
+ // positions the measured marginal exceeds1M/buy; flat0.5M is insufficient.
87
+ for (const quote of quotes) {
88
+ const market = markets[quote.marketIndex]!;
89
+ if (market.raeto || market.autoCompound) gas += 25_000n * BigInt(market.positions);
90
+ }
76
91
  if (plan.token.kind === LifecycleTokenKind.ERC404) for (const quote of quotes) gas += activationCosts.nft * ceil(quote.tokenOut, plan.token.nftUnit);
77
92
  return gas + 24n * BigInt((transaction.data.length - 2) / 2) + 100_000n * BigInt(plan.feeAssets.length);
78
93
  }
@@ -87,14 +102,11 @@ export type ProfiledLaunchCapacity = {
87
102
  export function deriveLifecycleLaunchCapacity(options: CapacityOptions, openingBuys?: readonly LifecycleOpeningBuyQuote[]): ProfiledLaunchCapacity | undefined {
88
103
  const { plan, ufg } = options;
89
104
  if (!hasProfiledOpeningMath(plan) || (plan.creator.toLowerCase() === UFG_LAUNCH_PROXY_ADDRESS.toLowerCase()) !== (ufg !== undefined)) return undefined;
90
- // Auto-compounding templates have no measured gas yet; never invent their budgets.
91
- if (plan.markets.some((market) => isAutoCompoundProfile(market.profileId))) return undefined;
92
105
  const headroomBps = options.headroomBps ?? 1500;
93
106
  if (!Number.isSafeInteger(headroomBps) || headroomBps < 0 || headroomBps > 10000) throw new LifecyclePlanningError("INVALID_LIMITS", "Headroom must be between zero and 10000 basis points");
94
107
  const initialBuys = openingBuys ?? computeLifecycleOpeningBuys(options);
95
108
  const route = ufg === undefined ? undefined : { account: ufgPlanPrincipal(plan), config: ufg.config };
96
- const atomic = plan.markets.length === 1 && !plan.funding.some((funding) => funding.kind === LifecycleFundingKind.Swap)
97
- ? buildLifecycleCommand(plan, { kind: "atomic" }, route) : undefined;
109
+ const atomic = plan.markets.length === 1 ? buildLifecycleCommand(plan, { kind: "atomic" }, route) : undefined;
98
110
  const activation = buildLifecycleCommand(plan, { kind: "activate" }, route);
99
111
  const markets = marketGas(plan), reserve = hmmV2ForwardingReserve(plan);
100
112
  const bound = (transaction: LifecycleTransaction) => {
@@ -6,6 +6,8 @@ export * from "./markets.js";
6
6
  export * from "./hmm.js";
7
7
  export * from "./ufg.js";
8
8
  export * from "./auto-compound.js";
9
+ export * from "./raeto.js";
10
+ export * from "./raeto-abi.js";
9
11
  export { ABYSS_LIFECYCLE_CONFIG_SCHEMA, readLifecycleTokenAtBlock, readLifecycleHeadProgress, predictLifecycleToken,
10
12
  validateV4LifecycleOracle, readLifecycleProfiles, readPoolBoundHookDeployment,
11
13
  buildPoolBoundHookDeploymentTransaction, validateLifecycleMarketIdentity, readLaunchProgress } from "./progress.js";
@@ -4,6 +4,7 @@ import { LifecyclePlanningError, type LifecycleProfile, type PoolBoundHookSaltPr
4
4
  import { decodeHmmLaunchTail, encodeHmmLaunchTail, isHmmProfile, type HmmLaunchConfig } from "./hmm.js";
5
5
  import { decodeUfgLaunchConfig, encodeUfgLaunchConfig, isUfgProfile, type UfgLaunchConfig } from "./ufg-config.js";
6
6
  import { decodeAutoCompoundTail, encodeAutoCompoundTail, isAutoCompoundProfile, validateAutoCompoundConfig, type AutoCompoundConfigV1 } from "./auto-compound.js";
7
+ import { decodeRaetoLaunchTail, encodeRaetoLaunchTail, isRaetoProfile, RAETO_QUOTE_ASSETS, validateRaetoLaunchConfig, type RaetoLaunchConfigV1 } from "./raeto.js";
7
8
 
8
9
  export type V4LifecyclePositionConfig = {
9
10
  tickLower: number; tickUpper: number; liquidity: bigint; salt: Hex; maxTokenAmount: bigint;
@@ -48,6 +49,7 @@ export type V4PoolBoundLifecycleMarketConfigV6 = Omit<V4LifecycleMarketConfig, "
48
49
  hmmLaunchConfig?: HmmLaunchConfig;
49
50
  ufgLaunchConfig?: UfgLaunchConfig;
50
51
  autoCompoundConfig?: AutoCompoundConfigV1;
52
+ raetoLaunchConfig?: RaetoLaunchConfigV1;
51
53
  };
52
54
  export type V4PoolBoundLifecycleMarketConfig = V4PoolBoundLifecycleMarketConfigV5 | V4PoolBoundLifecycleMarketConfigV6;
53
55
  export const V4_LIFECYCLE_CONFIG_SCHEMA = keccak256(stringToHex("(uint16,uint24,int24,uint160,uint24,uint8,uint8,address,bool,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])"));
@@ -96,15 +98,27 @@ function assertV1HookFeeShape(config: object): void {
96
98
 
97
99
  function validateAutoCompoundMarket(config: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): asserts config is V4PoolBoundLifecycleMarketConfigV6 & { autoCompoundConfig: AutoCompoundConfigV1 } {
98
100
  if (config.version !== 6 || config.autoCompoundConfig === undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles require config6 and an explicit autoCompoundConfig");
99
- if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles cannot carry HMM or UFG tails");
101
+ if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles cannot carry HMM, UFG or Raeto tails");
100
102
  if (config.lpFeePips !== 0) throw new LifecyclePlanningError("INVALID_HOOK_FEES", "Auto-compounding profiles require zero LP fee");
101
103
  if (config.developerFeeBps !== 0) throw new LifecyclePlanningError("DEVELOPER_FEE_CEILING", "Auto-compounding profiles require zero developer fee");
102
104
  validateAutoCompoundConfig(config.autoCompoundConfig);
103
105
  }
104
106
 
107
+ function validateRaetoMarket(config: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): asserts config is V4PoolBoundLifecycleMarketConfigV6 & { raetoLaunchConfig: RaetoLaunchConfigV1 } {
108
+ if (config.version !== 6 || config.raetoLaunchConfig === undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles require config6 and an explicit raetoLaunchConfig");
109
+ if (config.hmmLaunchConfig !== undefined || config.ufgLaunchConfig !== undefined || config.autoCompoundConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles cannot carry HMM, UFG or auto-compounding tails");
110
+ if (config.feeMode !== 1 || config.lpFeePips !== 0 || config.developerFeeBps !== 0) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto requires QuoteOnly feeMode 1, zero LP fee and zero developer fee");
111
+ validateRaetoLaunchConfig(config.raetoLaunchConfig);
112
+ }
113
+
105
114
  /** Auxiliary launch profiles require their typed tail and append it automatically. */
106
115
  export function encodePoolBoundV4LifecycleMarketConfig(config: V4PoolBoundLifecycleMarketConfig): Hex {
107
116
  const prefix = encodePoolBoundV4Prefix(config);
117
+ if (isRaetoProfile(config.profileId)) {
118
+ validateRaetoMarket(config);
119
+ return concatHex([prefix, encodeRaetoLaunchTail(config.raetoLaunchConfig)]);
120
+ }
121
+ if (config.version === 6 && config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "A Raeto tail requires a Raeto profile");
108
122
  if (isAutoCompoundProfile(config.profileId)) {
109
123
  validateAutoCompoundMarket(config);
110
124
  return concatHex([prefix, encodeAutoCompoundTail(config.autoCompoundConfig)]);
@@ -145,6 +159,10 @@ export function decodePoolBoundV4LifecycleMarketConfig(encoded: Hex, expectedVer
145
159
  const config = version === 5
146
160
  ? decodeAbiParameters([{ type: "tuple", components: poolBoundV4LifecycleMarketComponentsV5 }], encoded)[0] as V4PoolBoundLifecycleMarketConfigV5
147
161
  : decodeAbiParameters([{ type: "tuple", components: poolBoundV4LifecycleMarketComponentsV6 }], encoded)[0] as V4PoolBoundLifecycleMarketConfigV6;
162
+ if (isRaetoProfile(config.profileId)) {
163
+ if (config.version !== 6) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto profiles require config6");
164
+ config.raetoLaunchConfig = decodeRaetoLaunchTail(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
165
+ }
148
166
  if (isAutoCompoundProfile(config.profileId)) {
149
167
  if (config.version !== 6) throw new LifecyclePlanningError("INVALID_AUTO_COMPOUND_CONFIG", "Auto-compounding profiles require config6");
150
168
  config.autoCompoundConfig = decodeAutoCompoundTail(`0x${encoded.slice(encodePoolBoundV4Prefix(config).length)}`);
@@ -180,6 +198,10 @@ export function validateV4LifecycleMarket(options: {
180
198
  if (config.version === 6) validatePoolBoundHookFees(config);
181
199
  else if (config.version === 5) assertV1HookFeeShape(config);
182
200
  if (isAutoCompoundProfile(config.profileId)) validateAutoCompoundMarket(config);
201
+ if (isRaetoProfile(config.profileId)) {
202
+ validateRaetoMarket(config);
203
+ if (!RAETO_QUOTE_ASSETS.some((quote) => quote.toLowerCase() === market.quoteAsset.toLowerCase())) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto quote asset must be WETH or USDG");
204
+ } else if (config.version === 6 && config.raetoLaunchConfig !== undefined) throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "A Raeto tail requires a Raeto profile");
183
205
  const { envelope, developerTerms: terms, protocolMaximumDeveloperFeeBps: protocolCeiling } = profile;
184
206
  if (envelope === undefined || terms === undefined || protocolCeiling === undefined || !terms.enabled ||
185
207
  profile.topology.hookTopology !== (config.version === 4 ? 1 : 2) || market.configVersion !== config.version ||
@@ -47,12 +47,12 @@ function openingState(plan: LaunchPlanV1, marketIndex: number): OpeningState {
47
47
  price = config.openingSqrtPriceX96; spacing = tier.tickSpacing; lpFee = BigInt(config.fee); positions = config.positions;
48
48
  } else {
49
49
  // All current release-owned V4 offerings use config6. Dynamic first buys
50
- // share the opening block's minimum fee; HMM strategy work starts onOpened,
51
- // after the ordered initial buys, never during this unopened curve.
50
+ // share the opening block's minimum fee. HMM work starts onOpened and
51
+ // auto-compounding defers until openingCompletedAt, after all opening buys.
52
52
  const config = decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
53
53
  if (config.profileId.toLowerCase() !== market.profileId.toLowerCase()) throw new LifecyclePlanningError("INVALID_MARKET", "V4 opening config differs from the selected profile");
54
54
  price = config.sqrtPriceX96; spacing = config.tickSpacing; lpFee = BigInt(config.lpFeePips); positions = config.positions;
55
- const dynamic = preset.key === KnownLifecycleProfile.V4DynamicFeePool || preset.key === KnownLifecycleProfile.V4HmmDynamicPool || preset.key === KnownLifecycleProfile.V4UfgDynamicPool || preset.key === KnownLifecycleProfile.V4AutoCompoundDynamicPool;
55
+ const dynamic = preset.key === KnownLifecycleProfile.V4DynamicFeePool || preset.key === KnownLifecycleProfile.V4HmmDynamicPool || preset.key === KnownLifecycleProfile.V4UfgDynamicPool || preset.key === KnownLifecycleProfile.V4AutoCompoundDynamicPool || preset.key === KnownLifecycleProfile.V4RaetoDynamicPool;
56
56
  hookFee = BigInt(dynamic ? config.minimumHookFeePips! : config.hookFeePips);
57
57
  }
58
58
  const tick = getTickAtSqrtRatio(price), liquidityNet = new Map<number, bigint>();
@@ -2,7 +2,7 @@ import { encodeFunctionData, keccak256, toHex, zeroAddress, type Address, type H
2
2
  import { ABYSS_FEE_TIERS } from "../abyss.js";
3
3
  import { assertLaunchTopologyCoverage, getTickAtSqrtRatio } from "../launch.js";
4
4
  import { launchLifecycleAbi, lifecycleAdapterAbi, lifecycleErc20Abi } from "./abi.js";
5
- import { hashLaunchIdentity, hashLaunchPlan, LifecycleFundingKind, LifecyclePhase, LifecycleRewardMode, LifecycleTokenKind, LIFECYCLE_MAX_REWARD_ERC20_SUPPLY, LIFECYCLE_MAX_ERC404_SUPPLY, parseLaunchPlan, serializeLaunchPlan, type LaunchPlanV1 } from "./schema.js";
5
+ import { hashLaunchIdentity, hashLaunchPlan, LifecycleFundingKind, LifecyclePhase, LifecycleRewardMode, LifecycleTokenKind, LIFECYCLE_MAX_ERC404_SUPPLY, LIFECYCLE_MAX_REWARD_ERC20_SUPPLY, parseLaunchPlan, serializeLaunchPlan, type LaunchPlanV1, type MarketConfigV1 } from "./schema.js";
6
6
  import { readLaunchProgress, readLifecycleExecutionProgress, readLifecycleHeadProgress, readLifecycleProfiles, readLifecycleTokenAtBlock, readPoolBoundHookDeployment } from "./progress.js";
7
7
  import { decodeAbyssLifecycleMarketConfig, decodePoolBoundV4LifecycleMarketConfig, decodeV4LifecycleMarketConfig, encodePoolBoundV4LifecycleMarketConfig, isPoolBoundV4ConfigVersion, type AbyssLifecycleMarketConfig, type V4LifecycleMarketConfig, type V4PoolBoundLifecycleMarketConfig } from "./markets.js";
8
8
  import { lifecyclePinnedRpc, lifecycleStaticRpc, lifecycleStage, nitroPosterGasBound, readLifecycleChainId, readLifecycleContract, readNitroPrices, registerLifecycleFinalCheck, resolveLifecycleLimits, rpcHex, rpcQuantity, withLifecycleReadClient } from "./rpc.js";
@@ -18,6 +18,7 @@ import { mineLifecycleHooks } from "./mining.js";
18
18
  import { computeLifecycleOpeningBuys, hasProfiledOpeningMath } from "./opening-buys.js";
19
19
  import { assessLifecycleTransactions, deriveLifecycleLaunchCapacity, type NextTransactionEnvelope, type ProfiledLaunchCapacity } from "./gas-profile.js";
20
20
  import type { LifecycleOpeningBuyQuote } from "./types.js";
21
+ import { isRaetoProfile, RAETO_QUOTE_ASSETS } from "./raeto.js";
21
22
 
22
23
  type ValidatedPlanShape = {
23
24
  commitment: Hex;
@@ -38,7 +39,7 @@ function observedFields<T extends object>(value: T): () => boolean {
38
39
 
39
40
  async function selectLaunchMode(requested: "atomic" | "staged", plan: LaunchPlanV1, capacity: ProfiledLaunchCapacity | undefined,
40
41
  limits: ResolvedLifecycleLimits, client: LifecycleRpcClient, block: LifecycleBlock): Promise<"atomic" | "staged"> {
41
- if (requested !== "atomic" || plan.markets.length !== 1 || plan.funding.some((funding) => funding.kind === LifecycleFundingKind.Swap) ||
42
+ if (requested !== "atomic" || plan.markets.length !== 1 ||
42
43
  capacity?.atomic === undefined || capacity.bounds.atomicComputeGasUpperBound === undefined) return "staged";
43
44
  const poster = limits.protocol === "nitro" ? nitroPosterGasBound(capacity.atomic, await readNitroPrices(client, block)).posterGas : 0n;
44
45
  return capacity.bounds.atomicComputeGasUpperBound + poster <= limits.executionGasCeiling ? "atomic" : "staged";
@@ -53,6 +54,20 @@ async function preparationBatches(plan: LaunchPlanV1, prepared: number, ufg: Pla
53
54
  return packPreparationBatches(plan, prepared, limits.executionGasCeiling - poster, limits.headroomBps);
54
55
  }
55
56
 
57
+ /** Preserve Raeto's outer quote/profile binding even on known-preset recovery. */
58
+ function validateRaetoMarketContext(market: MarketConfigV1, config?: V4LifecycleMarketConfig | V4PoolBoundLifecycleMarketConfig): void {
59
+ if (!isRaetoProfile(market.profileId)) return;
60
+ if (market.configVersion !== 6 || !RAETO_QUOTE_ASSETS.some((quote) => quote.toLowerCase() === market.quoteAsset.toLowerCase())) {
61
+ throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto requires config6 and a WETH or USDG quote");
62
+ }
63
+ // Normal planning supplies its already decoded config. Continuation must also
64
+ // reject malformed fee/share tails before reading or building its next command.
65
+ const decoded = config ?? decodePoolBoundV4LifecycleMarketConfig(market.config, 6);
66
+ if (decoded.version !== 6 || decoded.profileId.toLowerCase() !== market.profileId.toLowerCase()) {
67
+ throw new LifecyclePlanningError("INVALID_RAETO_CONFIG", "Raeto config must bind its market's Raeto profile");
68
+ }
69
+ }
70
+
56
71
  function validatePlanShape(plan: LaunchPlanV1): ValidatedPlanShape {
57
72
  // Encoding checks all exact integer widths, addresses, byte strings and tuple fields.
58
73
  const commitment = hashLaunchPlan(plan);
@@ -85,6 +100,7 @@ function validatePlanShape(plan: LaunchPlanV1): ValidatedPlanShape {
85
100
  if (market.configVersion !== 1 && market.configVersion !== 4 && !isPoolBoundV4ConfigVersion(market.configVersion)) throw new LifecyclePlanningError("UNSUPPORTED_CONFIG_VERSION", "Encode reviewed SharedV4 version 4 or pool-bound version 5/6 only on its exact matching deployment");
86
101
  if (market.configVersion === 4) config = decodeV4LifecycleMarketConfig(market.config);
87
102
  else if (isPoolBoundV4ConfigVersion(market.configVersion)) config = decodePoolBoundV4LifecycleMarketConfig(market.config, market.configVersion);
103
+ validateRaetoMarketContext(market, config);
88
104
  if (config !== undefined) {
89
105
  if (config.profileId.toLowerCase() !== market.profileId.toLowerCase()) throw new LifecyclePlanningError("PROFILE_TERMS_MISMATCH", "Inner config profile differs from the committed market profile");
90
106
  const quote = market.quoteAsset.toLowerCase();
@@ -455,6 +471,7 @@ function finalizeNextTransaction(options: BuildNextTransactionOptions, next: Lif
455
471
  /** Recovery observes actual canonical receipts, then constructs and budgets only
456
472
  * the next command. No launch transaction is executed during planning. */
457
473
  export async function buildNextTransaction(options: BuildNextTransactionOptions): Promise<LifecycleTransaction | undefined> {
474
+ if (options.action !== "cancel") for (const market of options.planned.plan.markets) validateRaetoMarketContext(market);
458
475
  const original = options.planned, matches = observedFields(original);
459
476
  const assertInput = () => {
460
477
  if (options.planned !== original || !matches()) throw new LifecyclePlanningError("PLAN_MUTATED", "Stored launch context changed while constructing its next transaction");
@@ -14,6 +14,9 @@ import { UFG_FIXED_PROFILE_ID, UFG_DYNAMIC_PROFILE_ID } from "./ufg-config.js";
14
14
  import { autoCompoundStaticEnvelope, autoCompoundStaticAdapter, autoCompoundStaticRegistration, autoCompoundStaticCreationCode } from "./deployments/auto-compound-static-pool-v1-20261028.js";
15
15
  import { autoCompoundDynamicEnvelope, autoCompoundDynamicAdapter, autoCompoundDynamicRegistration, autoCompoundDynamicCreationCode } from "./deployments/auto-compound-dynamic-pool-v1-20261028.js";
16
16
  import { AUTO_COMPOUND_STATIC_V1_PROFILE_ID, AUTO_COMPOUND_DYNAMIC_V1_PROFILE_ID } from "./auto-compound.js";
17
+ import { raetoFixedEnvelope, raetoFixedAdapter, raetoFixedRegistration } from "./deployments/raeto-fixed-pool-v1-20261029.js";
18
+ import { raetoDynamicEnvelope, raetoDynamicAdapter, raetoDynamicRegistration } from "./deployments/raeto-dynamic-pool-v1-20261029.js";
19
+ import { RAETO_FIXED_PROFILE_ID, RAETO_DYNAMIC_PROFILE_ID } from "./raeto.js";
17
20
 
18
21
  export enum KnownLifecycleProfile {
19
22
  Abyss0 = "abyss-0",
@@ -28,6 +31,8 @@ export enum KnownLifecycleProfile {
28
31
  V4UfgDynamicPool = "v4-ufg-dynamic-pool",
29
32
  V4AutoCompoundStaticPool = "v4-auto-compound-static-pool",
30
33
  V4AutoCompoundDynamicPool = "v4-auto-compound-dynamic-pool",
34
+ V4RaetoFixedPool = "v4-raeto-fixed-pool",
35
+ V4RaetoDynamicPool = "v4-raeto-dynamic-pool",
31
36
  }
32
37
 
33
38
  export enum KnownLifecycleHook {
@@ -360,6 +365,8 @@ const knownDeployment: LifecycleDeploymentPreset = Object.freeze({
360
365
  poolBoundPreset(KnownLifecycleProfile.V4UfgDynamicPool, UFG_DYNAMIC_PROFILE_ID, ufgDynamicEnvelope, ufgDynamicAdapter, ufgDynamicRegistration, dynamicFeePoolHookV1CreationCode),
361
366
  poolBoundPreset(KnownLifecycleProfile.V4AutoCompoundStaticPool, AUTO_COMPOUND_STATIC_V1_PROFILE_ID, autoCompoundStaticEnvelope, autoCompoundStaticAdapter, autoCompoundStaticRegistration, autoCompoundStaticCreationCode),
362
367
  poolBoundPreset(KnownLifecycleProfile.V4AutoCompoundDynamicPool, AUTO_COMPOUND_DYNAMIC_V1_PROFILE_ID, autoCompoundDynamicEnvelope, autoCompoundDynamicAdapter, autoCompoundDynamicRegistration, autoCompoundDynamicCreationCode),
368
+ poolBoundPreset(KnownLifecycleProfile.V4RaetoFixedPool, RAETO_FIXED_PROFILE_ID, raetoFixedEnvelope, raetoFixedAdapter, raetoFixedRegistration, fixedFeePoolHookV1CreationCode),
369
+ poolBoundPreset(KnownLifecycleProfile.V4RaetoDynamicPool, RAETO_DYNAMIC_PROFILE_ID, raetoDynamicEnvelope, raetoDynamicAdapter, raetoDynamicRegistration, dynamicFeePoolHookV1CreationCode),
363
370
  ]),
364
371
  provenance: Object.freeze({ sourceCommit: "e174ce695c7010f50ca9211b07b9f178c990beac", deploymentBlock: 82880546n }),
365
372
  });
@@ -389,7 +396,7 @@ export function getKnownLifecycleProfile(options: KnownLifecycleDeploymentIdenti
389
396
  return undefined;
390
397
  }
391
398
 
392
- /** Stable, frozen order: Abyss, fixed/dynamic V4, HMM, UFG, then auto-compounding. */
399
+ /** Stable, frozen order: Abyss, fixed/dynamic V4, HMM, UFG, auto-compounding, then Raeto. */
393
400
  export function listKnownLifecycleProfiles(options: KnownLifecycleDeploymentIdentity): readonly LifecycleProfilePreset[] {
394
401
  return getKnownLifecycleDeployment(options)?.profiles ?? noProfiles;
395
402
  }