@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.
- package/README.md +6 -5
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/gas-profile.d.ts +1 -1
- package/dist/lifecycle/gas-profile.d.ts.map +1 -1
- package/dist/lifecycle/gas-profile.js +24 -9
- package/dist/lifecycle/gas-profile.js.map +1 -1
- package/dist/lifecycle/index.d.ts +2 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +2 -0
- package/dist/lifecycle/index.js.map +1 -1
- package/dist/lifecycle/markets.d.ts +2 -0
- package/dist/lifecycle/markets.d.ts.map +1 -1
- package/dist/lifecycle/markets.js +30 -2
- package/dist/lifecycle/markets.js.map +1 -1
- package/dist/lifecycle/opening-buys.js +3 -3
- package/dist/lifecycle/opening-buys.js.map +1 -1
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +21 -2
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/presets.d.ts +4 -2
- package/dist/lifecycle/presets.d.ts.map +1 -1
- package/dist/lifecycle/presets.js +8 -1
- package/dist/lifecycle/presets.js.map +1 -1
- package/dist/lifecycle/raeto-abi.d.ts +175 -0
- package/dist/lifecycle/raeto-abi.d.ts.map +1 -0
- package/dist/lifecycle/raeto-abi.js +224 -0
- package/dist/lifecycle/raeto-abi.js.map +1 -0
- package/dist/lifecycle/raeto.d.ts +21 -0
- package/dist/lifecycle/raeto.d.ts.map +1 -0
- package/dist/lifecycle/raeto.js +59 -0
- package/dist/lifecycle/raeto.js.map +1 -0
- package/dist/lifecycle/transactions.d.ts.map +1 -1
- package/dist/lifecycle/transactions.js +8 -1
- package/dist/lifecycle/transactions.js.map +1 -1
- package/dist/lifecycle/types.d.ts +2 -2
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/docs/launch-lifecycle.md +106 -40
- package/docs/lifecycle-gas-profiles.md +173 -24
- package/docs/reference.md +73 -15
- package/examples/README.md +6 -3
- package/package.json +1 -1
- package/src/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/deployments/raeto-fixed-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/gas-profile.ts +21 -9
- package/src/lifecycle/index.ts +2 -0
- package/src/lifecycle/markets.ts +23 -1
- package/src/lifecycle/opening-buys.ts +3 -3
- package/src/lifecycle/planner.ts +19 -2
- package/src/lifecycle/presets.ts +8 -1
- package/src/lifecycle/raeto-abi.ts +223 -0
- package/src/lifecycle/raeto.ts +61 -0
- package/src/lifecycle/transactions.ts +8 -1
- 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.
|
|
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;
|
|
138
|
-
auto-compounding profiles
|
|
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
|
|
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
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
package/examples/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Run the examples
|
|
2
2
|
|
|
3
|
-
These commands use the checkout's built `@black-market/sdk` **0.
|
|
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.
|
|
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
|
|
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
|
@@ -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-
|
|
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
|
-
|
|
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
|
|
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) => {
|
package/src/lifecycle/index.ts
CHANGED
|
@@ -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";
|
package/src/lifecycle/markets.ts
CHANGED
|
@@ -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
|
|
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
|
|
51
|
-
//
|
|
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>();
|
package/src/lifecycle/planner.ts
CHANGED
|
@@ -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,
|
|
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 ||
|
|
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");
|
package/src/lifecycle/presets.ts
CHANGED
|
@@ -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,
|
|
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
|
}
|