@black-market/sdk 0.11.0 → 0.13.0

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 (78) hide show
  1. package/README.md +96 -79
  2. package/dist/lifecycle/abi.d.ts +1 -0
  3. package/dist/lifecycle/abi.d.ts.map +1 -1
  4. package/dist/lifecycle/abi.js +1 -0
  5. package/dist/lifecycle/abi.js.map +1 -1
  6. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts +71 -0
  7. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.d.ts.map +1 -0
  8. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js +73 -0
  9. package/dist/lifecycle/deployments/ufg-dynamic-pool-20261021.js.map +1 -0
  10. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts +71 -0
  11. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.d.ts.map +1 -0
  12. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js +73 -0
  13. package/dist/lifecycle/deployments/ufg-fixed-pool-20261021.js.map +1 -0
  14. package/dist/lifecycle/index.d.ts +1 -0
  15. package/dist/lifecycle/index.d.ts.map +1 -1
  16. package/dist/lifecycle/index.js +1 -0
  17. package/dist/lifecycle/index.js.map +1 -1
  18. package/dist/lifecycle/markets.d.ts +3 -1
  19. package/dist/lifecycle/markets.d.ts.map +1 -1
  20. package/dist/lifecycle/markets.js +20 -3
  21. package/dist/lifecycle/markets.js.map +1 -1
  22. package/dist/lifecycle/planner.d.ts.map +1 -1
  23. package/dist/lifecycle/planner.js +101 -46
  24. package/dist/lifecycle/planner.js.map +1 -1
  25. package/dist/lifecycle/presets.d.ts +4 -2
  26. package/dist/lifecycle/presets.d.ts.map +1 -1
  27. package/dist/lifecycle/presets.js +11 -4
  28. package/dist/lifecycle/presets.js.map +1 -1
  29. package/dist/lifecycle/progress.d.ts +3 -1
  30. package/dist/lifecycle/progress.d.ts.map +1 -1
  31. package/dist/lifecycle/progress.js +145 -59
  32. package/dist/lifecycle/progress.js.map +1 -1
  33. package/dist/lifecycle/rpc.d.ts +8 -2
  34. package/dist/lifecycle/rpc.d.ts.map +1 -1
  35. package/dist/lifecycle/rpc.js +165 -9
  36. package/dist/lifecycle/rpc.js.map +1 -1
  37. package/dist/lifecycle/simulation.d.ts +1 -1
  38. package/dist/lifecycle/simulation.d.ts.map +1 -1
  39. package/dist/lifecycle/simulation.js +15 -11
  40. package/dist/lifecycle/simulation.js.map +1 -1
  41. package/dist/lifecycle/types.d.ts +23 -1
  42. package/dist/lifecycle/types.d.ts.map +1 -1
  43. package/dist/lifecycle/types.js.map +1 -1
  44. package/dist/lifecycle/ufg-abi.d.ts +2386 -0
  45. package/dist/lifecycle/ufg-abi.d.ts.map +1 -0
  46. package/dist/lifecycle/ufg-abi.js +171 -0
  47. package/dist/lifecycle/ufg-abi.js.map +1 -0
  48. package/dist/lifecycle/ufg-config.d.ts +38 -0
  49. package/dist/lifecycle/ufg-config.d.ts.map +1 -0
  50. package/dist/lifecycle/ufg-config.js +75 -0
  51. package/dist/lifecycle/ufg-config.js.map +1 -0
  52. package/dist/lifecycle/ufg.d.ts +21 -0
  53. package/dist/lifecycle/ufg.d.ts.map +1 -0
  54. package/dist/lifecycle/ufg.js +98 -0
  55. package/dist/lifecycle/ufg.js.map +1 -0
  56. package/docs/launch-lifecycle.md +611 -1363
  57. package/docs/reference.md +332 -0
  58. package/examples/.env.example +3 -2
  59. package/examples/README.md +172 -539
  60. package/examples/launch-example-support.ts +11 -3
  61. package/examples/launch-example.ts +1 -1
  62. package/examples/launch-lifecycle-smoke.ts +1 -1
  63. package/examples/ufg-launch-config.ts +31 -0
  64. package/package.json +1 -1
  65. package/src/lifecycle/abi.ts +1 -0
  66. package/src/lifecycle/deployments/ufg-dynamic-pool-20261021.ts +74 -0
  67. package/src/lifecycle/deployments/ufg-fixed-pool-20261021.ts +74 -0
  68. package/src/lifecycle/index.ts +1 -0
  69. package/src/lifecycle/markets.ts +16 -3
  70. package/src/lifecycle/planner.ts +95 -45
  71. package/src/lifecycle/presets.ts +11 -4
  72. package/src/lifecycle/progress.ts +131 -51
  73. package/src/lifecycle/rpc.ts +158 -10
  74. package/src/lifecycle/simulation.ts +14 -10
  75. package/src/lifecycle/types.ts +15 -2
  76. package/src/lifecycle/ufg-abi.ts +173 -0
  77. package/src/lifecycle/ufg-config.ts +77 -0
  78. package/src/lifecycle/ufg.ts +86 -0
@@ -1,1438 +1,686 @@
1
- # Launch lifecycle API
2
-
3
- `@black-market/sdk/lifecycle` is the browser-safe launch API; its exports are also available from `@black-market/sdk`. Supply the exact chain, core, creator and registry domain. Planning, salt preparation, reads and unsigned builders never sign, publish metadata or write to the source chain. A successful controlled-local simulation is not production deployment approval.
4
-
5
- The canonical authorities are the registry/certification/adapter/config contracts under
6
- `contracts/src/launch/lifecycle/v2`, typed hook deployers, and `contracts/src/launch/fees/v3`
7
- in the protocol repository. Plan identity is `LaunchPlanV1`. Pool-bound V4 uses **config 6**,
8
- canonical Abyss uses **config 1**, and generic current shared-V4 support uses **config 4**.
9
-
10
- ## 0.11.0 release: gas sizing, packing and prefix proof
11
-
12
- New atomic/activation envelopes containing HMM V2 markets add one forwarding target:
13
- `R = 4_250_000 + 500_000 * (hmmMarkets - 1)` gas (zero for non-HMM plans).
14
- For measured gross gas `G` (`maxUsedGas`, falling back to `gasUsed`), compute is
15
- `min(max(G + R, ceil(G * (10000 + headroomBps) / 10000)), computeCap)`.
16
- Begin/preparation/approval/cancel commands do not receive this reserve. Nitro poster
17
- gas is budgeted separately inside the same complete gas envelope. Optional padding
18
- and the reserve are targets, not refusal thresholds; exact validated replay proves
19
- the clamped envelope. There is no bisection or extra ordinary-path request.
20
-
21
- Staged planning greedily packs contiguous markets against the unpadded compute cap:
22
- HMM V2 costs 14.5M per market; other profiles cost a conservative 16M. At 32M,
23
- 1/2/3/5 HMM markets produce `[1]`/`[2]`/`[2,1]`/`[2,2,1]`.
24
- Only a packed measurement failure consuming at least 95% of its given gas splits
25
- that batch in half, regardless of its error selector. Low-gas semantic failures
26
- remain failures. `preparationBatchSize` is removed; inspect each preparation's
27
- `marketStart`/`marketCount`. The pure unsigned compiler still accepts explicit
28
- `preparationBatches`.
29
-
30
- Robinhood chain 4663 defaults `limits.maxSimulationGas` to **50_000_000n** aggregate
31
- gas **used**, not the sum of individual legal transaction envelopes. Override it
32
- for a provider with a different budget. The SDK measures and validates the longest
33
- estimated prefix that fits: begin 9.5M, preparations as above, activation 6M per
34
- market plus `R`, and small approvals/cancellation. A measurement failure after
35
- cumulative use reaches 95% of that cap defers the failed call and suffix.
36
- If even the immediate estimate cannot fit that budget, refusal first identifies
37
- any estimated per-transaction compute overflow (gas displayed in millions to one
38
- decimal), rather than suggesting that a larger RPC budget solves it. Estimates
39
- alone do not reject an envelope that can still be measured and exactly proved.
40
-
41
- `simulation.admitted`, `executionProof: "proved"` and `protocolFit: "proved"` cover
42
- only the successful proven prefix. **They do not promise eventual activation.**
43
- `simulation.deferredTransactionIds` explicitly lists unproved remaining steps
44
- (empty for full coverage); these commands carry no `gas`, `gasPrice`, `estimate`
45
- or `admission`. Call `buildNextTransaction` before each signature: canonical
46
- progress advances the proof window and gives the immediate next transaction exact
47
- gas. Reviewed envelopes receive only a direct exact replay of that immediate step,
48
- without new measurement, poster/price recommendations or suffix proof.
49
-
50
- `buySlippageBps` requires actual activation outputs. If activation is deferred,
51
- calibration refuses clearly; use a higher-budget native provider or preserve
52
- already committed minima by omitting recalibration. Outputs are never fabricated.
53
-
54
- ## 0.9.1 release: Abyss 0.01% fee tier
55
-
56
- `ABYSS_FEE_TIERS` now includes `{ feePips: 100, tickSpacing: 1, label: "0.01%" }`.
57
- Pass `fee: 100` to `deriveLaunchPoolRecipe` to derive spacing-one geometry without
58
- an explicit spacing override. Use `tickSpacing: 1` when passing that recipe to
59
- `deriveLaunchPositionRanges`; the permanent boundary tail reaches tick `887272`
60
- for launch token0 or `-887272` for launch token1. Abyss config1 lifecycle planning
61
- derives this spacing from the canonical catalog automatically.
62
-
63
- The Robinhood chain 4663 factory has enabled fee 100 with spacing 1. Other
64
- deployments must enable the tier before execution; local recipe construction is
65
- not evidence of live profile admission. Existing tiers and defaults are unchanged.
66
-
67
- ## 0.10.0 release: HMM V2 only
68
-
69
- The admitted October17 **HMM Fixed V2** and **HMM Dynamic V2** replace the SDK's
70
- earlier HMM offerings. Generic keys `KnownLifecycleProfile.V4HmmFixedPool`
71
- (`v4-hmm-fixed-pool`) and `V4HmmDynamicPool` (`v4-hmm-dynamic-pool`) now select V2.
72
- Versioned hook keys are `KnownLifecycleHook.HmmFixedPoolV2` / `HmmDynamicPoolV2`.
73
- These are not aliases for the non-HMM fixed/dynamic hooks; those APIs are unchanged.
74
-
75
- | Preset | Admitted V2 profile ID |
76
- | --- | --- |
77
- | HMM Fixed V2 (`hooks/hmm-fixed-v2`) | `0x45e957bcc7068350a65f5b4de5453b674d54d0f5eb2a88fc839da13197e80e98` |
78
- | HMM Dynamic V2 (`hooks/hmm-dynamic-v2`) | `0x8e500f203ace505072e209c5f077e11de6d071ac7f298cd75c0e05c6a55c36e6` |
1
+ # Launch a token with the TypeScript SDK
79
2
 
80
- Frozen adapters, envelopes, complete dependency graphs, creation code and admission
81
- fixtures preserve the V2 release and pinned registry readback at block 91,874,655.
82
- Each graph has its own collector/deployer, locker and hook deployer. Presets are
83
- construction data, not a current admission certificate: live
84
- `readLifecycleProfiles` and execution proof remain authoritative.
3
+ Use SDK **0.13.0** on Robinhood Chain mainnet (**4663**). For a first launch, run
4
+ [`launch-erc20-abyss.ts`](../examples/launch-erc20-abyss.ts): one market, one position,
5
+ one buy. [Runner setup](../examples/README.md) covers its environment and commands.
6
+ This guide explains the economics and the public APIs for your own integration.
85
7
 
86
- Both require `lpFeePips: 0` and `developerFeeBps: 0`. Fixed charges `hookFeePips`
87
- as its static fee; Dynamic uses config6 minimum/maximum/sensitivity policy.
88
- Config6 requires a typed `hmmLaunchConfig`:
8
+ ## Choose an offering
89
9
 
90
- ```ts
91
- const hmmLaunchConfig = defaultHmmLaunchConfig({
92
- tokenBudget: marketTokenBudget, quoteAsset: "USDG", quoteDecimals: 6,
93
- // Illustrative caller choices, not SDK risk defaults:
94
- maxBidQuote: 100n * 10n ** 6n, // maximum 100 USDG of new/refreshed bid principal
95
- referenceDeviation: 0, // do not ask below or bid above the rounded reference
96
- });
97
- hmmLaunchConfig.strategyShareBps = 2500; // optional 25%; existing default is 50%
98
- hmmLaunchConfig.strategy.premiumDecaySeconds = 259200; // optional 72h; default off
99
- const config = encodePoolBoundV4LifecycleMarketConfig({
100
- ...reviewedV6Fields, lpFeePips: 0, developerFeeBps: 0, hmmLaunchConfig,
101
- });
102
- ```
10
+ Choose the token behavior, fee destination, and pool implementation separately.
11
+ `LifecycleTokenKind` selects ERC20 or ERC404; `LifecycleRewardMode` selects none,
12
+ staking, or dividends. A pool profile selects the admitted venue/hook implementation.
103
13
 
104
- `HmmStrategyConfig` / `HmmLaunchConfig` are V2-only and mirror Solidity
105
- `HMMStrategyConfigV2` / `HMMLaunchConfigV2`. `encodeHmmLaunchTail` produces exactly
106
- `abi.encode(HMMLaunchConfigV2)`: **16 static words / 512 bytes**. The V6 codec
107
- appends the tail only for current HMM profile IDs. Missing tails, old 448-byte
108
- tails, extra words and noncanonical prefixes are rejected before RPC planning.
109
- Mining and recovery preserve the typed tail. The full launch-plan hash binds
110
- every tail byte, including both new guards.
111
-
112
- The hook constructor is still **one 20-word / 640-byte
113
- `PoolBoundHookParametersV2` tuple**. Do not append the HMM tail to creation code.
114
- The collector factory hashes only the canonical config6 prefix with zero hook
115
- salt for the hook's market-economics commitment; the auxiliary strategy settings
116
- are handed to the manager through the collector. Changing those settings changes
117
- the full plan commitment, but not the hook constructor's prefix-only commitment.
118
-
119
- `validateHmmLaunchConfig` enforces the factory's exact launch guards and Solidity
120
- field widths. Share is 0..10,000 bps. All 15 strategy fields are listed in wire order:
121
-
122
- | Field | Unit and accepted launch values |
123
- | --- | --- |
124
- | `bidWidth` | Tick spacings; positive int24 |
125
- | `askWidth` | Tick spacings; positive int24 |
126
- | `gap` | Tick spacings; nonnegative int24 |
127
- | `staleAfterSeconds` | Positive uint32 seconds |
128
- | `staleDisplacement` | Tick spacings; positive int24 |
129
- | `minQuoteDeploy` | Raw quote units; any uint256, including zero |
130
- | `minQuoteHarvest` | Raw quote units; positive uint256 |
131
- | `minTokenHarvest` | Raw launch-token units; positive, covered by both token caps |
132
- | `resalePremiumBps` | 0..5,000 bps |
133
- | `maxAsks` | 1..8 |
134
- | `maxAskTokenExposure` | Raw launch-token units; at least ask count and minimum token harvest, at most uint128 max |
135
- | `maxAcquiredInventory` | Raw launch-token units; at least minimum token harvest, at most uint128 max |
136
- | `premiumDecaySeconds` | Any uint32 seconds; zero disables decay |
137
- | `maxBidQuote` | Raw quote-principal ceiling for new/refreshed bids; positive and at most uint128 max |
138
- | `referenceDeviation` | Tick spacings; nonnegative int24 |
139
-
140
- For reference pool tick `R`, deviation `D` and spacing `S`, ask lower is at least
141
- `R - D*S` and bid upper is at most `R + D*S`, with side-appropriate grid rounding.
142
- The reference comes from the hook's truncated oracle, not an independent spot
143
- price supplied by the caller.
144
-
145
- The default helper **requires explicit `maxBidQuote` and `referenceDeviation`**;
146
- neither has a guessed risk default. All other defaults are preserved: 50% share,
147
- widths 5/5, gap 1, stale 86,400 seconds/displacement 5, premium 500 bps, 4 asks,
148
- decay off. Token thresholds are raw market-budget ratios: harvest budget/100,000,
149
- ask exposure budget/10, inventory budget. Too-small budgets producing zero harvest
150
- and budgets above uint128 are rejected. WETH quote deploy/harvest thresholds remain
151
- 0.0005/0.005 ETH; USDG is 1/10 six-decimal units. Catalog symbols/addresses work;
152
- explicit decimals must match. Other quotes require explicit `minQuoteDeploy` and
153
- `minQuoteHarvest`; no unsupported asset's USD price or units are inferred.
14
+ | Offering | `KnownLifecycleProfile` keys | Fee behavior / restrictions |
15
+ | --- | --- | --- |
16
+ | Canonical Abyss | `Abyss0`, `Abyss1`, `Abyss2`, `Abyss3` | STANDARD, STANDARD_ORACLE, QUOTE, QUOTE_ORACLE respectively; config1. |
17
+ | Fixed V4 | `V4FixedFeePool` | One bound hook per pool; fixed `hookFeePips`, optional LP fee. |
18
+ | Dynamic V4 | `V4DynamicFeePool` | Oracle-velocity fee between minimum and maximum; LP and developer fees 0. |
19
+ | HMM V2 | `V4HmmFixedPool`, `V4HmmDynamicPool` | Auxiliary fee-funded bids/asks; LP and developer fees 0; explicit risk guards. |
20
+ | UFG | Abyss QUOTE/QUOTE_ORACLE or `V4UfgFixedPool`, `V4UfgDynamicPool` | Treasury route; ERC20 without rewards; quote-only fees, executor bounty 0. |
154
21
 
155
- ### V2 fee funding and owner controls
156
-
157
- V2 reserves the strategy share **on each swap in both pool currencies, after the
158
- protocol treasury share**, rather than waiting for harvest. The remaining fees
159
- follow the normal fee-hub distribution. HMM itself does not burn fees and never
160
- touches the permanently locked launch positions.
161
-
162
- The browser-safe lifecycle and root exports include complete
163
- `hmmLiquidityManagerV2Abi`, `hmmFeeCollectorV2Abi`, `hmmFeeCollectorFactoryV2Abi`,
164
- `hmmFixedHookV2Abi` and `hmmDynamicHookV2Abi`. Use ordinary viem contract calls;
165
- the SDK adds no speculative transaction wrappers:
166
-
167
- - Read `strategyOwner()` and `liquidityManager()` on the collector. Authority
168
- follows the **current** fee owner from the canonical hub/fee-owner registry.
169
- - Call collector `setStrategyShareBps(uint16)` for 0..10,000 bps. It changes future
170
- swap reservations, not fees already reserved.
171
- - Read manager `strategyConfig()` for the complete 15-field tuple, then call
172
- `setStrategyConfig(HMMStrategyConfigV2)` to update every setting immediately.
173
- This queues a book refresh for the next maintenance pass. Lowering intake caps
174
- does not forcibly liquidate existing inventory; existing lots keep their stored
175
- floor and age. New premium settings apply to newly acquired lots.
176
- - Read `placementsPaused()` and call `setPlacementsPaused(bool)` on the manager.
177
- Pausing queues auxiliary-liquidity withdrawal on maintenance and stops new
178
- placements, not trading or fee collection. It does not withdraw locked launch LP.
179
-
180
- These writes require the current fee-owner wallet and explicit transaction
181
- authorization. Read-only planning never invokes them.
182
-
183
- ### Breaking migration from the earlier HMM SDK
184
-
185
- Rebuild unstarted HMM plans with the new preset IDs/adapters/graphs, supply both
186
- new guards, re-encode the 512-byte tail, and re-mine/re-prove the resulting plan.
187
- Do not pad old 448-byte payloads, reuse an old graph/salt, or relabel old bytes.
188
- The former `HmmFixedPoolV1` / `HmmDynamicPoolV1` enum members and old HMM metadata
189
- have no compatibility aliases. Existing onchain HMM V1 profiles/markets were not
190
- deregistered or upgraded by this SDK release; submitted legacy plans must not be
191
- mutated into V2 plans. Use tooling matching their original contract release.
192
-
193
- Independent Solidity ABI fixtures are regenerated with
194
- `node scripts/generate-hmm-fixtures.mjs` (Foundry `cast abi-encode` / `calldata`).
195
- To regenerate canonical V2 metadata/ABIs from preserved evidence without RPC or
196
- onchain writes, use `node --experimental-transform-types
197
- scripts/generate-hmm-presets.mjs release.json live.json`; both JSON files must be
198
- the exact V2 release and matching successful admission/pinned-readback records.
199
-
200
- ## 0.8.1 release
201
-
202
- Adds the Robinhood October11 Dynamic Fee Hook preset:
203
- `KnownLifecycleHook.DynamicFeePoolV1` and `KnownLifecycleProfile.V4DynamicFeePool`
204
- (`"v4-dynamic-fee-pool"`), profile
205
- `0x27f219872fe934a5464bc9b900028256122f215b40cbdb69ef5f88cd5f627ccb`. The fixed
206
- preset and example default are unchanged.
207
-
208
- ## 0.8.0 release
209
-
210
- This release adds unstarted-launch topology validation, boundary tails enabled by
211
- default, and the generalized `positionGaps` option replacing `staircaseBoundaries`.
212
- The TypeScript examples default to an unsigned dry run; `--broadcast` explicitly
213
- authorizes execution without an interactive hash prompt. `--resume` retains the
214
- original plan, receipt evidence, and metadata session instead of relaunching.
215
- The opt-in `LifecycleSessionCache` below reuses only the allowlisted static reads
216
- at the same canonical chain/block; execution proof and financial state stay live.
217
-
218
- ## 0.7.1 transaction-first construction
219
-
220
- Known chain/core/profile identities use frozen release construction metadata.
221
- `getKnownLifecycleDeployment`, `getKnownLifecycleProfile` and
222
- `listKnownLifecycleProfiles` are pure, browser-safe selectors. Profile selection
223
- accepts either `KnownLifecycleProfile` keys or exact profile IDs.
224
- `KnownLifecycleHook.FixedFeePoolV1` and `KnownLifecycleHook.DynamicFeePoolV1`
225
- identify the fixed hook and **Dynamic Fee Hook** respectively; both use the V2 constructor.
226
- Select the latter with `KnownLifecycleProfile.V4DynamicFeePool` (`"v4-dynamic-fee-pool"`).
227
- Unknown identities return no preset; explicit `readLifecycleProfiles` and unlisted
228
- profile construction retain live discovery/certification. Presets describe release
229
- availability, never current admission, and contain no `admitted` claim.
230
- The Robinhood presets retain the mined October8 fixed config6 graph and add the
231
- October11 zero-author-royalty Dynamic Fee Hook, each with its own exact artifact,
232
- review, terms, runtime pins, creation-code chunks and 20-word V2 constructor.
233
- Historical config5 codecs and 18-word V1 ABIs remain explicit for
234
- existing deployments, but October5 evidence is not relabeled or selected as the
235
- current preset. Explicit live discovery certifies unlisted deployments from actual
236
- pinned reads.
237
-
238
- `prepareAndPlanLifecycleLaunch` compiles the exact requested mode before native
239
- execution calibration. Known construction uses local commitments and hook
240
- creation code, mines salts once and compares every final constructor binding.
241
- Token prediction remains a genuine pinned factory read; advancing the block
242
- during asynchronous mining can require a second prediction. Current progress,
243
- receipts, nonce/confirmation gates, exact native proof and final canonical guards
244
- remain authoritative. Public discovery/constructor boundaries observe the current
245
- chain; policy callbacks are resolved freshly rather than cached as constant values.
246
-
247
- Optional `buySlippageBps` (integer 0–9999) protects **every ordered buy** from its
248
- actual diagnostic receipt output using `floor(output * (10000 - bps) / 10000)`.
249
- The diagnostic candidate is never admitted or returned for execution. Only the
250
- complete final protected commitment can pass measurement and validated replay.
251
- Protection is available only for an unstarted launch; omission preserves minima.
252
-
253
- `buildLaunchTransactions({ plan, mode, preparationBatches? })` is a pure unsigned
254
- compiler. Staged preparation counts must cover all markets exactly. Every command
255
- carries the full plan; `PlannedLaunch.totalCalldataBytes` sums exact remaining
256
- command bytes, including approvals. Splitting preparation cannot reduce this
257
- per-command calldata or partition mint/lock/all-buys/public-opening activation.
258
-
259
- Atomic and staged are explicit choices. Only proven compute/gas-envelope capacity
260
- can partition empty preparations. Semantic, opaque `DeploymentFailed`, source,
261
- provider-clamp and byte-cap refusals do not authorize retries or partitioning.
262
- Native explicit OOG recognizes simulator VM code `-32015` and compatible `-32000`,
263
- not near-cap gas consumption. Both activation receipt and event counts must match
264
- the committed positions. Failure DTOs expose safe classifications/numeric facts,
265
- not raw provider messages. Abort closes continuations, including unsupported adapters.
266
-
267
- `deriveLaunchPositionRanges` requires a source-defined Black Market
268
- `distributionPreset`: `"early-scarcity"`, `"staircase"` or `"smooth-ramp"`.
269
- Inventory weights, 64 active spacing steps and intentional gaps follow
270
- `black-market/apps/web/src/lib/launch.ts`. Early Scarcity widens sparse bands;
271
- Staircase inserts three-step gaps only between new inventory shelves; Smooth Ramp
272
- keeps gently narrowing bands contiguous. The SDK defaults to five positions and
273
- supports counts from 2 through 16. Arbitrary equal-tick fractions of the distance
274
- to a protocol boundary are not these presets.
275
- For Staircase and Early Scarcity, `positionGaps: "adjacent"` removes the empty
276
- intervals while retaining the source inventory weights and finite-band widths.
277
- The default `"source-gaps"` preserves their original topology. Smooth Ramp is
278
- always contiguous: omit `positionGaps` or use `"adjacent"`; explicitly supplying
279
- `"source-gaps"` is an error. Adjacent positions share an exact spacing-aligned tick;
280
- overlap is also valid for continuous price coverage.
281
- An empty gap can move the pool price without exchanging tokens in that interval.
282
-
283
-
284
- **Breaking default:** `extendFinalRangeToBoundary` now defaults to `true`.
285
- It replaces only the final band's far endpoint with the usable spacing-aligned
286
- protocol boundary, preserving every earlier band and the final band's near endpoint.
287
- Explicit `false` retains a finite final band, which does not satisfy default planner
288
- admission unless another funded position supplies the permanent tail.
289
- The complete finite preset must fit before this extension is applied.
290
- `boundaryTick` and `boundarySqrtPriceX96` always describe that finite protocol
291
- boundary; endpoint sqrt ratios are not exclusive swap-price guards.
292
-
293
- Pass the raw token budget for **one pool**. Each position exposes `inventoryBps`
294
- and its pre-mint `allocatedTokenAmount` cap: all but the last allocation floor
295
- their basis-point share, and the last receives the exact remaining budget.
296
- All caps and funded liquidities must be positive. `maxTokenAmount` equals the intended
297
- `allocatedTokenAmount`, including any mint-rounding residual; `tokenAmountMaximum`
298
- equals the pool budget. Both venues use the maximum exact budget-safe integer liquidity:
299
- one additional liquidity unit would exceed that position's allocated cap.
300
- `unspentTokenAmount` is the budget minus the canonical rounded-up expected mint
301
- debit, not an extra allocation or creator reserve. Do not add it to `tokenAmountMaximum`.
302
- Current admission requires position maxima to sum exactly to each market budget and
303
- market budgets to sum exactly to minted supply. The SDK planner and pure compiler
304
- enforce these equalities for every supported venue. The orchestrator burns every
305
- actual leftover before any buy. Positive int128 liquidity and V4 signed settlement
306
- limits remain enforced; arbitrary caller plans still need complete live admission.
307
-
308
- The existing ordering convention is `launchedTokenIsQuote: true` for launched
309
- token0. Gross liquidity must fit `maxLiquidityPerTick` at **each endpoint**;
310
- adjacent bands share their endpoint's gross capacity, while the sum of disjoint
311
- positions is not capped as if all began at launch. `openingActiveLiquidity`
312
- reflects the actual `[tickLower, tickUpper)` opening state. Token0 starts in the
313
- first band; token1 has zero opening-active liquidity until a downward quote buy
314
- crosses the opening upper endpoint. `buySideLiquidity` is only the first
315
- reachable band's liquidity, never the sum of all disjoint bands. Each position
316
- also exposes exact endpoint sqrt ratios for display valuation.
317
-
318
- ### Launch position-topology safety
319
-
320
- Every launch-created market must retain a **nonzero permanent tail** and continuous
321
- buy-side coverage from its opening price to that tail. A tail in another pool,
322
- including an optional Abyss allocation, cannot substitute for this market's tail.
323
- The tail ends at the furthest usable spacing-aligned protocol tick: the maximum
324
- tick when `launchedTokenIsQuote` is `true` (launch token0), otherwise the minimum.
325
- V4 uses the config's `tickSpacing`; Abyss config1 uses its canonical fee-tier spacing
326
- from `ABYSS_FEE_TIERS`, without changing the encoded config.
327
-
328
- `assertLaunchTopologyCoverage` is a pure validator exported by both
329
- `@black-market/sdk` and `@black-market/sdk/lifecycle`. It accepts
330
- `{ positions, openingTick, tickSpacing, launchedTokenIsQuote, allowInteriorGaps? }`.
331
- Positions carry `tickLower`, `tickUpper` and `maxTokenAmount` (or the Abyss config's
332
- `tokenAmountMaximum`). Derive the opening tick with exported
333
- `getTickAtSqrtRatio(marketSqrtPriceX96)`, not by rounding it to the spacing grid.
334
- The validator never changes the positions:
335
-
336
- - `TOPOLOGY_OPENING_GAP`: no band contains the opening tick on the buy side.
337
- Token0 containment is `[lower, upper)`; token1 is `(lower, upper]`, including
338
- the opening upper endpoint crossed by the first downward buy.
339
- - `TOPOLOGY_INTERIOR_GAP`: the sorted interval union leaves an uncovered interval
340
- between opening and the permanent tail. Exact adjacency and overlapping
341
- Orbit-style horizons both pass.
342
- - `MISSING_PERMANENT_TAIL`: no boundary-reaching band has a positive token cap.
343
- A finite final band or zero-allocation tail is not permanent liquidity.
344
- - `TOPOLOGY_OFF_GRID_TICK`: a band endpoint is not aligned to this market's spacing.
345
-
346
- The pure validator's `allowInteriorGaps: true` waives **only** interior gaps.
347
- `planLaunch` and `prepareAndPlanLifecycleLaunch` enforce the same checks for every
348
- market of an **unstarted launch**, using the pinned predicted token's ordering
349
- against that market's quote. Progress is read first: waiting/in-flight account or
350
- receipt state returns waiting without applying this creation policy. Started
351
- `Preparing`/`Ready` and terminal `Active`/`Cancelled` plans skip the topology gate.
352
- Their onchain commitments are immutable, so recovery must not retroactively
353
- refuse them for historical topology. Budget/supply, identity, confirmation,
354
- receipt and stateful execution checks still apply.
355
-
356
- | Local planning option | Effect |
357
- | --- | --- |
358
- | `allowTopologyGaps: true` | Allows interior gaps only; the funded permanent tail stays mandatory. |
359
- | `allowMissingPermanentTail: true` | Waives only the boundary-reaching, positive-allocation tail requirement. |
360
-
361
- Both options default to `false`. Even together they **never** waive opening
362
- containment or tick alignment. Staircase and Early Scarcity source gaps therefore
363
- require an explicit gap opt-out; choose `positionGaps: "adjacent"` for continuous
364
- admitted launches instead. These are validation choices, not an execution-proof
365
- bypass. They are retained on `PlannedLaunch` for fresh `simulateLaunchPlan` and
366
- `buildNextTransaction` admission while the launch remains unstarted. Started and
367
- terminal recovery does not require either opt-out. Persist explicit choices
368
- separately when restoring an unstarted saved plan. Budget/supply equalities, ABI
369
- encoding, hashes, calldata and stateful proof requirements are unchanged.
370
-
371
- No cross-review execution cache, caller certificate or execution-proof skip exists.
372
- Recovery and `buildNextTransaction` acquire fresh authority and retain separate
373
- immediate-submission-provider preflight. Construction/proof is not submission.
374
-
375
- ## Reviewed next envelopes
376
-
377
- `BuildNextTransactionOptions.reviewedTransaction` optionally supplies an untrusted
378
- previously reviewed immediate transaction. Omit it to construct a new envelope
379
- with the existing greater-of-recommendation-and-twice-pinned-base fee strategy.
380
- Supply it after review to validate that exact envelope, not to import cached
381
- admission or waive current-state proof.
382
-
383
- The SDK reconstructs the current unfinished commands from fresh canonical
384
- progress, funding/allowances and deployment/profile authority. It matches
385
- `id/kind/chainId/from/to/data/value` before using the reviewed gas or price.
386
- Preparation batching remains SDK-derived, not caller-selected. Malformed,
387
- wrong-step or changed envelopes refuse without returning executable calldata.
388
-
389
- The SDK directly validates only the immediate transaction at its exact held
390
- gas/price. It does not repeat measurement, quote a new gas price/poster budget or
391
- simulate future steps. Current protocol/transaction limits, native metering,
392
- postconditions and immediate actual-balance affordability still apply. Existing
393
- padding may be consumed; neither a new padding target nor a higher advisory quote
394
- alone invalidates a held envelope. Natural child base fees and payer balances are
395
- never overridden, and failed replay never raises held gas or switches backend.
396
-
397
- Approvals/resets, atomic launches, every staged next step and cancellation use
398
- this same contract. Cancellation retains its adapter-independent recovery policy.
399
- Fresh receipt/nonce/confirmation and final canonical checks remain mandatory.
400
- When supplied, `submissionClient` must estimate the exact held gas/price at
401
- `latest`; it still proves only immediate transport acceptance, not wallet identity.
402
- Returned estimates/admission are fresh and do not trust fields supplied with the
403
- reviewed transaction. Generic EVM external data-fee callbacks now receive the
404
- exact simulated `gas` and `gasPrice`.
405
-
406
-
407
-
408
- ## Opt-in static session fast path
409
-
410
- `createLifecycleSessionCache()` creates a caller-owned `LifecycleSessionCache`.
411
- Pass it as `LifecycleRpcClient.sessionCache` to retain the SDK's **explicit static
412
- read class** across `prepareAndPlanLifecycleLaunch`, `planLaunch`,
413
- `simulateLaunchPlan` and `buildNextTransaction`. Omit the option to preserve the
414
- default: only existing invocation-local fixed-state reuse, with no session events
415
- or cross-invocation observations. The SDK neither creates a global cache nor
416
- changes transport batching, selected mode or execution admission.
22
+ Use `getKnownLifecycleProfile` for construction metadata. Check current admission
23
+ with `readLifecycleProfiles`; registered totals include retired profiles.
24
+ This read-only snippet lists the live registry, including each refusal reason:
417
25
 
418
26
  ```ts
419
- import { createLifecycleSessionCache, planLaunch } from "@black-market/sdk/lifecycle";
420
-
421
- const sessionCache = createLifecycleSessionCache();
422
- const client = {
423
- ...publicClient,
424
- sessionCache,
425
- supportsReadBatching: true, // Only when this transport actually batches.
426
- onDiagnostic: (event) => { console.debug("[launch-sdk]", event); },
427
- };
428
-
429
- const first = await planLaunch({ client, plan, account, mode: "staged" });
430
- const second = await planLaunch({ client, plan, account, mode: "staged" });
431
- // At the same canonical head, the second call reuses matching static reads only.
432
- // Execution simulation, funding and canonical checks still run independently.
433
-
434
- sessionCache.block; // readonly { number: bigint, hash } or undefined
435
- sessionCache.invalidate(); // Wallet/chain switch, or each confirmed transaction.
27
+ import {
28
+ createProtocolPublicClient, getAddresses, readLifecycleProfiles,
29
+ } from "@black-market/sdk";
30
+
31
+ const client = createProtocolPublicClient({ chainId: 4663 });
32
+ if (await client.getChainId() !== 4663) throw new Error("Wrong RPC chain");
33
+ const profiles = await readLifecycleProfiles({
34
+ client, orchestrator: getAddresses(4663).launchOrchestrator,
35
+ });
36
+ console.table(profiles.map((p) => ({
37
+ id: p.id, venue: p.venueKind, version: p.topology.configVersion,
38
+ admitted: p.admitted, reason: p.reason ?? "",
39
+ })));
436
40
  ```
437
41
 
438
- The retained class is deliberately narrow:
42
+ Do not hard-code a live profile count. Select the exact admitted profile ID and
43
+ its schema, terms, treasury, and dependency graph. For V4, permit at most **one
44
+ market per quote asset** across all hooks/fees; combine positions in that market.
45
+ An Abyss market can share the same quote. Oracle-enabled does not mean lending-approved.
439
46
 
440
- | Static observations eligible for session reuse | Scope |
441
- | --- | --- |
442
- | Nitro capability getters and compute ceilings | Pinned `ArbSys.arbOSVersion`, `ArbGasInfo.getMaxTxGasLimit` / `getMaxBlockGasLimit` |
443
- | Nitro poster quotes | Pinned NodeInterface `gasEstimateL1Component`, including the exact payer, destination, calldata and value |
444
- | Frozen-profile registry certification | Profile/adapter registration (including dependency digest), topology, reviewed envelope, developer terms/cap and exact `requireEligible` request |
445
- | Reviewed immutable certification graph | Adapter metadata/dependency getters, graph runtime-code checks, locker/collector authorities and shared-hook constructor/runtime provenance |
446
- | Oracle configuration and factory presence | Pinned `oracleConfigs(configId)`, certified oracle-factory code and token-factory code-presence checks |
447
- | Hook deployer creation/constructor/runtime evidence | Creation-code hash, both chunk addresses/bytes, exact constructor metadata, initcode/CREATE2 comparisons and deployer-recorded runtime digests |
448
-
449
- Known construction presets continue to avoid discovery/getter mirrors they already
450
- omit; enabling a cache does not introduce extra certification reads. Unlisted
451
- profiles still use their normal frozen-envelope certification. Session hits retain
452
- private wire hex, not mutable public profile/deployment DTOs. Each consumer still
453
- decodes and checks its exact registration, graph, constructor and market bindings.
454
-
455
- **Never retained across invocations:** native/ERC20 balances, allowances,
456
- progress/market and core domain/prediction/binding reads, receipts/transactions,
457
- chain identity, head/latest/pending observations, account code/nonces,
458
- `eth_estimateGas`, `eth_simulateV1`, gas-price recommendations, funding-target
459
- admission, non-view calls, submission preflight and all write-adjacent calls.
460
- In particular the **native Nitro metering simulation probe is not cached**:
461
- its `eth_simulateV1` request remains separate from the static ArbSys/ArbGasInfo
462
- getters, and permissive measurement plus exact validated replay stay live.
463
- Existing invocation-local reuse for eligible fixed reads is unchanged.
464
-
465
- Each entry group owns one pinned block **number and hash**. Before session
466
- observations can be consumed, the invocation must read a fresh canonical head and
467
- chain identity. A changed head hash (including a same-height reorg), number or
468
- chain identity clears the old group before use. Exact
469
- wire parameters also participate in identity; changed caller, target, calldata,
470
- value, gas or constructor economics cannot hit another request's entry.
471
- Externally supplied pins without a fresh invocation-owned head bypass the session.
472
- Only successfully settled wire reads are shared; rejected requests, in-flight
473
- promises and obsolete completions after closure/invalidation are not retained.
474
- Final canonical/reorg and chain checks remain live and clear the session on
475
- identity failure.
476
-
477
- The caller-owned session is the cross-invocation identity boundary, not the
478
- reader object or `request` function. Recreated per-operation readers may share
479
- it while keeping their own transport cancellation signal. They still acquire
480
- fresh head/chain observations and run their own live requests; in-flight work
481
- and cancellation state are never shared. Do not route concurrent operation
482
- signals through one mutable global reader.
483
-
484
- The caller **must call `invalidate()` on wallet/chain switches and after every
485
- confirmed transaction**. It discards the pin and all memoized values immediately,
486
- including preventing older pending reads from repopulating the discarded group.
487
- It does not cancel an operation, freeze the chain or grant permission to submit
488
- a saved transaction. A new block causes fresh static reads; the cache is a
489
- same-snapshot acceleration, not a TTL or an assumption that facts never change.
490
-
491
- With `onDiagnostic`, each opted-in invocation emits a `session-cache` start and
492
- success/failure summary. `hits` counts static reads resolved from the session,
493
- `misses` counts new static reads, and `reuses` counts existing invocation-local
494
- static reuse. Summaries contain counts only: no cache keys, pins, RPC URLs,
495
- parameters, addresses, calldata, results or errors. Nested continuations share one
496
- summary, and listener failures remain isolated from financial behavior.
497
-
498
- Correctness follows from deterministic static observations at the **same exact
499
- canonical snapshot**, complete request identity and preserved live proof. The
500
- session never stores an admission certificate or replaces balances, receipt/nonce
501
- continuity, native capability simulation, execution replay or submission checks.
502
- Offline RPC-count regressions compare two sequential complete `planLaunch`
503
- operations with and without the option; they prove fewer repeated static reads,
504
- not a live end-to-end latency guarantee.
505
-
506
- Deterministic offline measurements (RPC messages, not HTTP batches):
507
-
508
- | Fixture, two sequential `planLaunch` calls at the same pin | Cache off: first / second | Cache on: first / second |
509
- | --- | --- | --- |
510
- | Admitted Nitro/Abyss staged plan, serial or batching transport | 33 / 33 | 33 / 22 |
511
- | Two-bound-market, two-creation-chunk V4 certification/constructor fixture | 64 / 64 | 64 / 19 |
512
-
513
- The first fixture performs the native Nitro probe, measurement and validated
514
- replay on **both** calls (three `eth_simulateV1` requests per call). The bound
515
- fixture deliberately refuses a smart account after completing read-only metadata;
516
- its savings prove static-read reuse, not economic execution. Both compare the
517
- complete returned plans for equality. Reproduce after `pnpm build` with
518
- `node --test test/lifecycle-read-pipeline.test.mjs test/lifecycle-execution.test.mjs`;
519
- the tests print the per-call counts and assert unchanged counts with the cache off.
520
-
521
- ## 0.6.3 certification and dependency-round reductions
522
-
523
- The public API, deployment authority and protocol admission rules are unchanged. With an
524
- actually batching source, selected-profile certification no longer waits for registry
525
- authority before reading the selected registrations, or for adapter registration before
526
- reading topology and applicable V4 envelope/terms. Eligibility overlaps graph certification.
527
- Private profile certification uses the registry's pinned `requireEligible` result and
528
- requires its returned implementation to match the registration. This covers discovery
529
- and standalone bound-hook metadata. Three duplicate implementation RPCs (`eth_getCode`,
530
- `core`, `dependencyDigest`) were removed: the registry already checks enabled records,
531
- exact profile/version/capability agreement, live runtime hash, core and live digest.
532
- The existing local V4 graph-digest comparison uses `registration.dependencyDigest`,
533
- whose equality to the live implementation digest is established by that same call.
534
-
535
- Abyss certification no longer re-reads `factory`, `CONFIG_SCHEMA`, `CONFIG_VERSION` or
536
- factory code. The registry certifies those fixed bindings before storing a profile;
537
- current eligibility pins the approved runtime and rechecks its live graph digest.
538
- SDK-side schema/version/topology and canonical chain/factory/variant checks still use
539
- the returned registration, including factory/venue agreement and no hook. A changed
540
- runtime or factory graph must fail authoritative eligibility, not an optional duplicate
541
- getter. Market resolution and both exact planning/simulation passes remain required.
542
-
543
- Source reasons in the reviewed protocol repository:
544
-
545
- - `contracts/src/launch/lifecycle/v2/LaunchImplementationRegistryV2.sol:285-296`
546
- implements current eligibility; `:88-97` certifies Abyss before storing it and
547
- `:153-174` prevents profile rebinding.
548
- - `contracts/src/launch/lifecycle/v2/LaunchCertificationV2.sol:79-102` certifies
549
- Abyss schema/version/capabilities, factory/code/canonical identity and graph digest.
550
- - `contracts/src/launch/lifecycle/v1/AbyssMarketAdapterV1.sol:75-76,150-167`
551
- makes the core/factory immutable and binds the live graph code/initcode hashes.
552
-
553
- V4 metadata, reviewed dependency code/getters, creation chunks and shared-root
554
- provenance remain independent pinned reads. Chunk addresses come from the frozen
555
- envelope only for scheduling; live deployer getters must still match them, including
556
- STOP prefixes, size/hash bounds, constructor creation hash, graph digest, runtime
557
- provenance and callback permissions.
558
-
559
- Planning reads swap-input admission and existing escrow balances alongside profile
560
- certification. A market's resolution uses its certified implementation while exact
561
- capability eligibility, selected-oracle validation and any bound-hook evidence settle.
562
- Their results must all agree before the resolved identity can authorize simulation.
563
-
564
- For batching-capable Nitro sources, the isolated ArbOS probe, NodeInterface poster
565
- quote and permissive exact-calldata measurement overlap. Probe isolation and its balance
566
- override do not enter the real execution sequence. Exact-gas validated replay waits for
567
- matching native metering, the poster budget and successful measurement. The redundant
568
- probe-only chain/hash recheck was removed: successful admission and simulation refusal
569
- still perform the enclosing live chain/canonical-block assertion. Natural child-block
570
- fees, uint64 gas bounds, real payer affordability, EIP-150 envelope discovery and
571
- postconditions are unchanged. Non-batching sources retain sequential measurement.
572
-
573
- No process-wide or cross-review cache, new read authority, public scope API, admission
574
- skip or write was introduced. Both opening-buy planning passes still choose fresh heads,
575
- retain live chain/pending/receipt observations and execute their own native proofs and
576
- validated replay. Only identical, complete pinned wire reads inside one invocation reuse
577
- observations.
578
-
579
- Offline regressions cover concurrent retained dependency responses, changed runtime,
580
- authority, graph digest and capability refusal through contract-modeled eligibility,
581
- canonical registry identity mismatch, build-next refusal after graph drift, V4
582
- expected-address evidence with mismatched live getters, overlapped measurement without
583
- premature replay, failed native evidence, serial/batched plan and fee equality, and
584
- retained final canonical checks. Obsolete duplicate-getter tests were removed.
585
- The released 0.6.3 SDK passed 133 offline tests with one opt-in real-AMM skip.
586
- Actual consumer-route timings are recorded by the integrating app, not a
587
- universal network-latency guarantee.
588
-
589
- ## 0.6.2 opt-in internal timing
590
-
591
- Initialize a lifecycle read client with optional `onDiagnostic(event)` to observe internal
592
- planning, profile certification, simulation context, Nitro probe, poster estimate, measurement,
593
- exact replay and envelope-discovery stages. Each stage reports start and completion/failure.
594
- RPC events distinguish queue admission, actual request start, settlement and invocation-local
595
- read reuse; `queueMs` is separate from request `durationMs`. `requestId` is a local numeric
596
- sequence, not a network or wallet identifier. Associate each client with your own local operation
597
- label when several reviews run concurrently.
47
+ <a id="deployed-infrastructure"></a>
48
+ [Deployment addresses](reference.md#deployed-infrastructure), [fee tiers](reference.md#choose-a-fee-tier),
49
+ and [config6 fields](reference.md#pool-bound-v4-version-6) are in the reference.
598
50
 
599
- ```ts
600
- const client = {
601
- supportsReadBatching: true, // Only with an actually batching transport.
602
- request: (args) => publicClient.request(args),
603
- onDiagnostic: (event) => { console.debug("[launch-sdk]", event); },
604
- };
51
+ ## Price the launch
52
+
53
+ Choose supply and a whole-supply opening valuation (FDV):
54
+
55
+ ```text
56
+ FDV in USD = price per token in USD × total minted token supply
57
+ quote per token = target FDV in USD ÷ token supply ÷ quote USD price
605
58
  ```
606
59
 
607
- The SDK never enables console output or telemetry itself. Without a listener there are no
608
- diagnostic clocks or event allocations. Events omit RPC URLs, parameters/results, accounts,
609
- addresses, signatures, calldata and raw errors; RPC method names are allowlisted. Synchronous
610
- listener throws and asynchronous listener rejections are isolated from financial behavior.
611
- Successful timing settlement means the function returned, not that the returned plan/profile
612
- was admitted: inspect its normal typed admission result.
613
-
614
- Independent domain/progress reads now overlap after token prediction. Simulation context
615
- reads, Nitro/poster work and final chain/canonical observations also overlap where their inputs
616
- are independent, still within the existing transport-opted-in read bound. Serial transports,
617
- exact state/identity guards and both measurement and validated execution are retained.
618
- No total-launch latency claim is made from these scheduling changes.
619
-
620
- Verification: typecheck and the built offline suite passed **126 tests: 125 passing and one
621
- opt-in real-AMM skip**. Diagnostics regressions cover timing events, payload omission and
622
- throwing/rejecting observers without changing valid profile admission.
623
-
624
- ## 0.6.1 read-pipeline changes
625
-
626
- Existing standalone calls, deployment targets, economic commitments and admission
627
- requirements remain compatible. Invalid plan shapes are still refused before RPC work.
628
- The optional `LifecycleRpcClient.supportsReadBatching` transport hint enables independent
629
- getter dependency rounds with at most eight SDK-issued requests outstanding per invocation.
630
- Set it to `true` only when the supplied transport batches concurrent requests; the SDK
631
- does not select or configure a transport. Other clients retain serial requests, avoiding
632
- the measured concurrent-unbatched RPC regression. With batching enabled, initial head
633
- and chain reads overlap. Failed reads release their slots without rejecting unrelated
634
- queued callers or automatically retrying.
635
-
636
- A vanilla one-pool, one-quote, one-range plan selects only its committed profile IDs.
637
- Abyss-only profile selection no longer requests the V4-only
638
- `protocolMaximumDeveloperFeeBps` getter. A required V4 fee-limit read still fails the
639
- operation if unavailable. V4 oracle/deployer/terms work, extra token/position capabilities
640
- and swap-funding checks remain conditional on the actual committed plan. There is no
641
- weakened single-pool mode: adapter eligibility, live code hashes, authority/dependency
642
- bindings, schema/topology and applicable frozen terms remain mandatory.
643
-
644
- Without the optional static session fast path above, identical fixed-state reads share observations only within one planning invocation.
645
- Identity includes the original source client, pinned block number/hash and complete
646
- request parameters, including caller, target, calldata, value and gas context. Rejected
647
- reads are not retained. State changes, another caller/source/block or a subsequent public
648
- planning invocation cannot reuse those observations; mutated plans and obsolete
649
- completions are refused. There is no global cache or new public read-scope option.
650
-
651
- Chain checks, latest/head/pending observations, receipt reads and canonical block rechecks
652
- remain live. Wallet/provider preflight, non-view execution calls and stateful/fork RPC
653
- are not cached. Nitro metering probes, discovery and exact validated replay remain
654
- separate proofs. A protected opening-buy minimum changes the committed calldata and
655
- still requires a second full plan and stateful simulation against a fresh latest snapshot.
656
-
657
- Raw `request({method,params})` clients remain valid. JSON-RPC HTTP batching is optional
658
- and transport-owned; concurrent reads allow a configured batch scheduler to combine
659
- independent messages without changing `msg.sender` or the pinned state. No API planner
660
- service, transport fallback, signature or broadcast is introduced. The existing Node 20
661
- minimum and ES2022 target are unchanged; shipped scheduling does not require
662
- `Promise.withResolvers`.
663
-
664
- Verification on 2026-10-06: `pnpm typecheck` and `pnpm test` passed, including the build,
665
- with **123 tests: 122 passing, one opt-in real-AMM test skipped and zero failures**.
666
- Offline regressions exercise the vanilla
667
- Abyss path without V4 fee metadata, mandatory V4 read failures, bounded overlap and
668
- duplicate reads, exact combined funding, changed code/authority/terms, partial failures,
669
- chain drift/reorgs, source/caller/call-context separation, failed-slot release and
670
- obsolete results. These offline checks are not real-wallet or on-chain execution evidence.
671
-
672
- A live read-only comparison against installed 0.6.0 measured **one selected canonical
673
- Abyss profile certification only**, not whole planning, simulation or launch execution.
674
- Both versions used Node 24.11.1, viem 2.56.3 and identical pinned chain 4663 state at
675
- block 81455627, hash
676
- `0x66f20d4c04b1c2357e9cd711c984a83fc8913ab208449ff1a0c8289bf2854036`.
677
- Five runs per version and transport alternated version order; returned profiles were
678
- deep-equal, and the chain and canonical block were independently rechecked.
679
-
680
- | Transport | Version | Median / p95 (ms) | RPC messages | HTTP envelopes | Peak outstanding |
681
- | --- | --- | --- | --- | --- | --- |
682
- | Unbatched, default serial | 0.6.0 | 1496.10 / 1677.93 | 15 | 15 | 1 |
683
- | Unbatched, default serial | 0.6.1 | 1402.10 / 1414.52 | 14 | 14 | 1 |
684
- | Batched, explicit opt-in | 0.6.0 | 1503.38 / 1541.41 | 15 | 15 | 1 |
685
- | Batched, explicit opt-in | 0.6.1 | 1005.11 / 1219.87 | 14 | 10 | 3 |
686
-
687
- These scoped measurements do not establish end-to-end launch latency or a general
688
- provider guarantee. An earlier unbatched concurrency trial regressed from a 1150.64 ms
689
- baseline median to 3870.97 ms; explicit transport opt-in and default serial scheduling
690
- remove that scheduling choice for existing clients. For reproduction, keep the selected
691
- profile, pinned state, source, retry/batching settings and runtime equal; count RPC
692
- messages separately from HTTP envelopes and retain failures as failures. Do not log RPC
693
- URLs, accounts, calldata or provider messages, or substitute full-registry/complex-only
694
- timing for the selected-profile path.
695
-
696
- ## 0.6.0 admission changes
697
-
698
- Optional caller policy no longer substitutes for, or gates, actual sequential execution proof.
699
- Results distinguish `executionProof`, `protocolFit`, and `transportPreflight`. Robinhood
700
- admission reads pinned Nitro compute limits and poster budgets, then requires native exact
701
- validated replay. `buildNextTransaction` optionally preflights the immediate next envelope
702
- through `submissionClient`. Deployment addresses, lifecycle plan/schema domains, profile
703
- capabilities and explicit atomic/staged behavior are unchanged.
704
-
705
-
706
- ## Deployed infrastructure
707
-
708
- Robinhood mainnet (`4663`) selects the mined `pool-launch-v1` deployment captured at block
709
- `82880546` in `contracts/deployments/launch/pool-launch-v1/20261008T000141Z-e174ce6/manifest.json`.
710
- The October8 manifest records 22 successful receipts and canonical runtime evidence,
711
- with two adapters and five profiles at that deployment. The subsequent October11
712
- Dynamic Fee Hook admission adds a third adapter and sixth profile to the same
713
- core/registry: four canonical Abyss variants and fixed/dynamic pool-bound config6/V2.
714
- Neither offering deploys a shared V4 root. The fixed preset and example selection
715
- remain `0xf18140c2fb66a4202a0f22d62d6288bf7976db108de5381e5497aaed332a06f8`,
716
- with creation hash `0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab`.
717
- The Dynamic Fee Hook profile is
718
- `0x27f219872fe934a5464bc9b900028256122f215b40cbdb69ef5f88cd5f627ccb`,
719
- with creation hash `0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a`.
720
- Its exact graph and terms are prepared in
721
- `contracts/deployments/launch/pool-hook-template-v1/20261011T033141Z-dynamic-fee-zero-royalty/admission.json`;
722
- that file is **unsigned preparation, not a mined receipt**. Registration is evidenced
723
- by the successful `forge-broadcast/AdmitPoolHookTemplateV1.s.sol/4663/admit-latest.json`
724
- receipt for `0x1928b13d1a6bf8826d08493a18c483fc7d244a3ec4100a7f8118f510a5db640c`.
725
- Creation bytes concatenate the preserved storage-child runtimes after stripping each
726
- first STOP byte, exactly as `PoolHookDeployerV1._initCode` does; constructor arguments
727
- are appended separately. An unpatched artifact runtime is not a deployed hook-instance runtime.
728
- October5 config5/V1 evidence remains historical, never a substitute for this graph.
729
-
730
- | SDK field | Mainnet address |
731
- | --- | --- |
732
- | `launchOrchestrator` | `0x91560876033d568d25CDe98C78c33ff8FC43962c` |
733
- | `launchImplementationRegistry` | `0xB2B0f9F36617810D67b8fC175153Aa10024C1358` |
734
- | `launchFeeOwnerRegistry` | `0x64b5ca1f21B8E84305b0e4D847924dca39Eb1fcb` |
735
-
736
- `getAddresses(4663)` exposes this graph; `robinhoodLaunchApplication` exposes the mined
737
- launch constants. Launch addresses on `31337` and `46631` remain zero unless configured.
738
- Address overrides are evaluated once on import: bare names win, then `VITE_`, then
739
- `NEXT_PUBLIC_`. Configure `LAUNCH_ORCHESTRATOR`, `LAUNCH_IMPLEMENTATION_REGISTRY`, and
740
- `LAUNCH_FEE_OWNER_REGISTRY` from the same deployment evidence.
741
-
742
- Canonical Abyss defaults are retained. DEX overrides apply on `31337` and `46631`, not
743
- mainnet. Lending mainnet defaults use `contracts/deployments/robinhood/replacement-infrastructure.json`;
744
- the workbench's existing lending endpoints follow that replacement. Lending overrides apply
745
- on `31337` (all three prefixes) and `46631` (`VITE_`/`NEXT_PUBLIC_`); liquidation-executor
746
- overrides use all three prefixes on every chain. Workbench chain RPC configuration reads
747
- `VITE_RPC_URL`, then `NEXT_PUBLIC_RPC_URL`, then `RPC_URL`; client factories prefer their explicit
748
- `rpcUrl`, then `RPC_URL`, then the chain endpoint. Select the chain explicitly in applications.
749
-
750
- Registry V2 has one `LaunchCertificationV2` child. V4 uses `profileEnvelope`, `profileId`, and
751
- signed six-argument `registerProfile`. Admin-only `registerAbyssProfile(uint8,registration)`
752
- independently certifies config-1 variants without an author envelope or royalty allocation.
753
- The admission EIP-712 domain is `Black Market Launch Registry`, version `2`.
754
-
755
- `LaunchBoundsV2` has five members: minimum/maximum tick spacing, maximum positions,
756
- maximum oracle cardinality, and fee-mode flags. LP and SharedV4 hook fees remain below
757
- 1,000,000 pips. Pool-bound minimum/maximum hook fees satisfy
758
- `0 <= minimumHookFeePips <= hookFeePips <= 1,000,000`; sensitivity is an explicit uint32.
759
- Creators also select a registered oracle configuration and per-pool external-liquidity policy.
760
- Author royalty ceilings are separate. Robinhood P1 `(1,4096)`, P2 `(6,4096)`, and P3 `(17,4096)`
761
- can use the same admitted profile; the selected oracle is checked at the pinned block.
762
- With `externalLiquidityDisabled=false`, third-party LP add/remove is allowed after opening.
763
- Permanent launch custody and pre-opening protection still apply.
764
-
765
- Config5 exports `fixedFeePoolHookV1Abi`, `poolHookDeployerV1Abi` and
766
- `poolFeeCollectorFactoryV1Abi` for the actual V1 wire contracts. Config6 exports
767
- `fixedFeePoolHookConfigV6Abi`, `poolHookDeployerConfigV6Abi` and
768
- `poolFeeCollectorFactoryConfigV6Abi`, including its 20-word constructor and
769
- `minimumHookFeePips()` / `feeSensitivityPipsSecondsPerTick()` getters. Existing
770
- config5 hooks are not queried for nonexistent V2 fee getters. Constructor encoding
771
- and initcode hashing require explicit `configVersion`; schema constants are
772
- `V4_POOL_BOUND_LIFECYCLE_CONFIG_SCHEMA_V5` and `_V6`, never an ambiguous alias.
773
- Generic shared contracts are `FixedFeeSharedHookV1`, `SharedHookDeployerV1`, and
774
- `SharedMarketAdapterV1`; they require their own admitted deployment graph.
775
- Other current ABI exports include `sharedMarketAdapterV1Abi`, `sharedHookDeployerV1Abi`,
776
- `poolMarketAdapterV1Abi`, `poolHookDeployerV1Abi`, and `poolFeeCollectorFactoryV1Abi`.
777
- Validation uses `validateV4LifecycleMarket`; the collector factory getter is
778
- `dependencyDigest(address)`. Identity domains are `black-market.launch-profile.v2`,
779
- `black-market.v4-dependencies.v2`, and `black-market.pool-bound-market-economics.v1`.
780
-
781
- ## Public operations
782
-
783
- | Operation | Contract |
784
- | --- | --- |
785
- | `readLifecycleProfiles({client, orchestrator, profileIds?, offset?, limit?})` | Bounded registry discovery, schema/topology dispatch, reviewed graph/terms certification and current registry admission. Default offset/limit is 0/100; explicit IDs can select a reviewed deployment's identities. |
786
- | `predictLifecycleToken({client, plan})` | Exact prediction from the explicit core. |
787
- | `prepareAndPlanLifecycleLaunch({client, account, plan, mode, buySlippageBps?, allowTopologyGaps?, allowMissingPermanentTail?, limits?, fork?, receipts?, confirmations?, signal?, onProgress?})` | Mines config6/V2 salts offchain, verifies per-market topology and exact final deployment bindings, and proves the selected-mode prefix under one fresh post-mining snapshot. Reports deferred steps; buy calibration requires activation coverage. No source-chain deployment or broadcast. |
788
- | `readPoolBoundHookDeployment({client, plan, marketIndex})` | Verifies typed factory, code chunks, constructor, normalized economics, initcode, salt, CREATE2 prediction and recorded provenance of existing code. Works with draft salts; permission bits are additionally required for executable predeployment. |
789
- | `buildPoolBoundHookDeploymentTransaction({client, plan, marketIndex})` | Optional permissionless typed `deploy(parameters,salt)` calldata. Does not create a token, register/initialize a pool, bind a collector or activate a launch. |
790
- | `planLaunch({client, account, plan, mode, allowTopologyGaps?, allowMissingPermanentTail?, limits?, fork?, receipts?, confirmations?, signal?})` | Independently fresh per-market topology/domain/funding/profile/progress/execution admission of the already-finalized commitment, simulating only the explicitly selected mode. |
791
- | `simulateLaunchPlan({client, planned, limits?, fork?, receipts?, confirmations?})` | Rereads canonical state and proves remaining work. Preserves receipt evidence, economics and selected mode. |
792
- | `readLaunchProgress({client, planned, receipts?, confirmations?})` | Confirmation-bound canonical state, latest head, receipt/replacement/reorg status, account-nonce safety and actual prepared market/live state. |
793
- | `buildNextTransaction({client, planned, reviewedTransaction?, submissionClient?, limits?, fork?, receipts?, confirmations?, action?})` | Rereads canonical progress and constraints, proves the immediate next transaction plus the fitting prefix, and returns one admitted envelope. With `reviewedTransaction`, directly replays only that matching immediate step at its exact held gas/price. Optional `submissionClient` adds read-only exact-envelope preflight. `action: "cancel"` retains adapter-independent recovery. Terminal launches return `undefined`. |
60
+ **1,000,000 tokens at $5,000 FDV = $0.005/token.** At an illustrative WETH price
61
+ of $2,486.49, that is about **0.00000201 WETH/token**. FDV is not cash raised or
62
+ quote deposited: the initial positions hold launch tokens only.
63
+ The SDK examples default to $5,000; the app defaults to $15,000. Neither number is
64
+ a recommendation or an anti-sniper guarantee. Compare the buyer's actual trade size.
794
65
 
795
- Clients may be viem public clients or raw `request({method,params})` RPC clients. Transport, wallet, signing and durable storage are application-owned. `PlannedLaunch` contains bigint values and live limit callbacks: persist `serializeLaunchPlan(plan)`, explicit execution mode, confirmation policy and receipt references, not the entire object.
66
+ ### Account for decimals and address order
796
67
 
797
- ## Commitment and integer representation
68
+ Let `q` be human quote units per launch token, `dQ` quote decimals, and `dL` launch
69
+ token decimals (18 for these recipes). The smaller numeric address is token0.
70
+ The helper's confusing `launchedTokenIsQuote: true` means **launch token is token0**.
71
+ Determine it from `BigInt(predictedToken) < BigInt(quoteAddress)`.
798
72
 
799
- The economic tuple contains chain/core/creator/nonce; ERC20/ERC404 token and token-global reward configuration; sorted funding outputs and fee assets; ordered markets; ordered initial buys; deadline; and initial executor fee. Each market commits exact adapter/profile/quote/budget/version/config bytes. Each buy commits market index, quote input, minimum token output, recipient and Q64.96 price limit; repeated indices keep their order.
73
+ | Launch-token order | Raw token1/token0 ratio | $0.005, 6-decimal quote, 18-decimal token |
74
+ | --- | --- | --- |
75
+ | token0 | `q × 10^(dQ-dL)` | `5 × 10^-15` |
76
+ | token1 | `1 / (q × 10^(dQ-dL))` | `2 × 10^14` |
800
77
 
801
- `hashLaunchPlan` is `keccak256(abi.encode(keccak256(bytes("BLACK_MARKET_LAUNCH_PLAN_V1")),plan))`. `hashLaunchIdentity` is `keccak256(abi.encode(chainId,orchestrator,creator,nonce))`. Token prediction depends on that identity and token configuration, not the economic plan hash, so the predicted token can appear in sorted fee assets without circularity. Economics cannot change after begin. Mode/batching are execution metadata outside the tuple.
78
+ Before tick alignment, `sqrtPriceX96 = floor(sqrt(raw ratio) × 2^96)`.
79
+ `1n << 96n` means raw-unit parity, not a dollar price. Keep integer amounts as
80
+ `bigint`; parse display amounts with viem `parseUnits`, not floating-point arithmetic.
802
81
 
803
- Use bigint for uint256/uint160/uint128 values and decimal strings in portable JSON. `parseLaunchPlan` rejects lossy JSON numbers and out-of-width values. Amounts are base units, liquidity is uint128, and `1n << 96n` is raw-unit price ratio 1, not a display-unit price. The pure helpers `deriveLaunchPoolRecipe`, `estimateLaunchInitialBuy` and `deriveLaunchBuySqrtPriceLimitX96` do not prove fees, market admission or execution; derive actual minimum outputs from stateful simulation and review the resulting final commitment again.
82
+ ### Derive and display the aligned opening
804
83
 
805
- Bounds: 1–16 markets, 1–8 fee assets, at most 8 funding outputs, 64 ordered buys and 32 total positions. None guarantees gas feasibility. Reward-free ERC20 allows the positive uint256 supply domain; reward-enabled ERC20 is capped at `10^77`; ERC404 supply fits uint96. Current exported supply bounds preserve these exact numerical domains.
84
+ Pricing helpers are imported from the **package root**, not `/lifecycle`.
85
+ Run this pure example with no wallet or RPC. It prices the full 1M supply while
86
+ allocating 500,000 tokens to this pool; the other half could fund a second pool.
87
+ The $1 six-decimal quote here is an arithmetic input, not a live price lookup.
806
88
 
807
89
  ```ts
808
- import { parseLaunchPlan, serializeLaunchPlan, encodeLaunchPlan, hashLaunchPlan, hashLaunchIdentity } from "@black-market/sdk/lifecycle";
809
- const plan = parseLaunchPlan(savedPlanJson);
810
- const bytes = encodeLaunchPlan(plan);
811
- const commitment = hashLaunchPlan(plan);
812
- const identity = hashLaunchIdentity(plan);
813
- const portable = serializeLaunchPlan(plan);
90
+ import { deriveLaunchPoolRecipe } from "@black-market/sdk";
91
+ import { formatUnits } from "viem";
92
+
93
+ const WAD = 10n ** 18n;
94
+ const supply = 1_000_000n * WAD;
95
+ for (const launchedTokenIsQuote of [true, false]) {
96
+ const r = deriveLaunchPoolRecipe({
97
+ pairedTokenDecimals: 6, pairedTokenUsdPriceX18: WAD,
98
+ targetMarketCapUsdX18: 5_000n * WAD,
99
+ launchedTokenIsQuote, fee: 3000, tickSpacing: 60,
100
+ supply, tokenBudget: supply / 2n,
101
+ });
102
+ const squared = r.launchSqrtPriceX96 ** 2n;
103
+ const fdvX18 = launchedTokenIsQuote
104
+ ? squared * supply * WAD / ((1n << 192n) * 10n ** 6n)
105
+ : (1n << 192n) * supply * WAD / (squared * 10n ** 6n);
106
+ console.log({
107
+ launchedTokenIsQuote, tick: r.launchTick,
108
+ sqrtPriceX96: r.launchSqrtPriceX96.toString(),
109
+ range: [r.tickLower, r.tickUpper], liquidity: r.liquidity.toString(),
110
+ alignedFdvUsd: formatUnits(fdvX18, 18),
111
+ });
112
+ }
814
113
  ```
815
114
 
816
- ## Registry-driven profile selection and frozen consent
115
+ Output for the inputs above (raw integers except FDV):
817
116
 
818
- The exact canonical registry getters are `profileCount`, `profileIds(offset,limit)`, `adapterCount`, `adapterIds(offset,limit)`, `profile`, `adapter`, `profileTopology` and `requireEligible`. There is no SDK template-ID allowlist and no invented `profiles()`/`isProfileEligible()` ABI. Schema plus certified topology dispatches supported implementations; an unsupported schema is reported separately from invalid/unsupported positions.
117
+ | Launch order | Tick | `sqrtPriceX96` | Range | Liquidity | Aligned FDV (USD) |
118
+ | --- | --- | --- | --- | --- | --- |
119
+ | token0 (`true`) | -329280 | `5610644101265567582035` | [-329280, 887220] | `35408142276778286` | 5014.946157970295405007 |
120
+ | token1 (`false`) | 329280 | `1118784514236214582089729076342544510` | [-887220, 329280] | `35408142276778286` | 5014.946157970295405007 |
819
121
 
820
- `LifecycleProfile` contains `registration`, `adapter`, unchanged `topology`, `venueKind`, `admitted` and optional refusal `reason`. Reviewed V4 adds:
122
+ Tick spacing rounds the intended opening. Show the aligned FDV before signing;
123
+ use the actual quote/USD snapshot and actual predicted token orientation.
124
+ Always pass `supply`: the helper's omitted-supply default is **one billion** tokens,
125
+ not the runner's one million. `tokenBudget` changes depth, not whole-supply price.
821
126
 
822
- - `envelope?: LaunchEnvelopeV2`: artifact/review/bounds/terms digests; topology, config/economic versions, capabilities, flags/callbacks, treasury policy, stable beneficiary/maximum rate, numerical bounds and the exact dependency graph.
823
- - `developerTerms?: {adapter, beneficiary, maximumDeveloperFeeBps, termsDigest, enabled}`.
824
- - `protocolMaximumDeveloperFeeBps?: number`.
127
+ ### Split inventory across pools and ranges
825
128
 
826
- The profile identity uses domain `black-market.launch-profile.v2` and commits the four review/economic digests, topology/config/economic versions, stable beneficiary, maximum author rate and capabilities. It deliberately excludes instance addresses. `hashLifecycleProfile`, `encode/decodeLaunchEnvelope`, `encode/decode/hashLaunchBounds` and `hashLaunchDependencies` expose exact canonical encodings/domains. Graph dependency hashing includes chain/core/registry/registrar, live runtime commitments and exact code-chunk provenance; only the shared deployment salt is outside that economic dependency digest.
129
+ Choose **one valuation**, then split token supply among pools. Each pool translates
130
+ that valuation using its quote's decimals and USD price. Two pools each priced at
131
+ $5,000 FDV still describe one $5,000 token valuation; their FDVs are not additive.
132
+ Less inventory at the same opening price means less depth.
827
133
 
828
- Profile certification checks reviewed capabilities/bounds, adapter/core/graph runtime hashes, manager/oracle/locker/collector dependencies, typed hook deployer and STOP-prefixed creation-code chunks. Shared roots additionally require exact constructor/salt prediction and the deployer's recorded runtime. Bound roots require exact immutable constructor/key/economic commitment and recorded runtime when deployed. Address bits `0x1afc` under mask `0x3fff` are necessary but never sufficient. Runtime/initcode portability bounds remain 24,576/49,152 bytes; no compiler/code-size relaxation is assumed.
134
+ Start with the recipe's single range. For multiple bands, `deriveLaunchPositionRanges`
135
+ supports `early-scarcity`, `staircase`, and `smooth-ramp` via `distributionPreset`.
136
+ The app's Single range / Even spread / Layered / Higher ground choices are separate
137
+ app presets. This pure SDK example creates four adjacent Early Scarcity bands:
829
138
 
830
- Registry `authorizationDigest`, `beneficiaryNonces` and `registerProfile` ABIs expose canonical reviewed admission/author consent. Admission does not make a template name an SDK allowlist or bypass current `requireEligible`. Profile retirement prevents new/pending source binding; it does not rewrite frozen active source terms or disable stable-author fee claims.
139
+ ```ts
140
+ import { deriveLaunchPoolRecipe, deriveLaunchPositionRanges } from "@black-market/sdk";
141
+
142
+ const budget = 500_000n * 10n ** 18n;
143
+ const recipe = deriveLaunchPoolRecipe({
144
+ pairedTokenDecimals: 6, pairedTokenUsdPriceX18: 10n ** 18n,
145
+ targetMarketCapUsdX18: 5_000n * 10n ** 18n,
146
+ launchedTokenIsQuote: true, fee: 3000,
147
+ supply: 1_000_000n * 10n ** 18n, tokenBudget: budget,
148
+ });
149
+ const ranges = deriveLaunchPositionRanges({
150
+ launchSqrtPriceX96: recipe.launchSqrtPriceX96,
151
+ launchedTokenIsQuote: true, tokenBudget: budget, tickSpacing: 60,
152
+ venue: "uniswap-v4", distributionPreset: "early-scarcity",
153
+ positionCount: 4, positionGaps: "adjacent",
154
+ });
155
+ console.table(ranges.positions.map((p) => ({
156
+ lower: p.tickLower, upper: p.tickUpper, bps: p.inventoryBps,
157
+ cap: p.maxTokenAmount.toString(),
158
+ })));
159
+ console.log("expected mint dust burned:", ranges.unspentTokenAmount.toString());
160
+ ```
831
161
 
832
- ## Current venue codecs
162
+ The returned raw caps and ticks are:
833
163
 
834
- ### Shared V4, version 4
164
+ | Range | Inventory bps | Token cap (18-decimal raw units) |
165
+ | --- | --- | --- |
166
+ | [-329280, -328920] | 366 | `18300000000000000000000` |
167
+ | [-328920, -328140] | 975 | `48750000000000000000000` |
168
+ | [-328140, -327000] | 2805 | `140250000000000000000000` |
169
+ | [-327000, 887220] | 5854 | `292700000000000000000000` |
835
170
 
836
- `encodeV4LifecycleMarketConfig` / `decodeV4LifecycleMarketConfig` accept only inner version 4. Market `configVersion` is 4. Exact schema:
171
+ The expected mint dust burned is **6,401,491 raw units** (0.000000000006401491 tokens).
837
172
 
838
- ```text
839
- (uint16,uint24,int24,uint160,uint24,uint8,uint8,address,bool,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])
840
- ```
173
+ The inventory weights are **3.66% / 9.75% / 28.05% / 58.54%** of this pool's budget.
174
+ Use `positionGaps: "adjacent"` for default continuous planner admission; Early
175
+ Scarcity and Staircase otherwise preserve source gaps. Smooth Ramp is always adjacent.
176
+ The final band reaches the spacing-aligned protocol boundary by default.
177
+ Coverage must run continuously from opening to a funded permanent tail in **each** pool.
841
178
 
842
- ### Pool-bound V4, version 6
179
+ Market budgets sum exactly to minted supply; position caps sum exactly to their
180
+ market budget. Actual integer mint debits may be lower. Every unused launch token
181
+ is **burned before opening buys**, not held as a creator reserve. Inspect material
182
+ burn separately from small rounding dust. Tail allocation is part of the budget.
183
+ At a token1 opening, active liquidity may be zero until the first downward swap
184
+ crosses the opening upper tick; inspect reachable buy-side liquidity too.
843
185
 
844
- `encodePoolBoundV4LifecycleMarketConfig` / `decodePoolBoundV4LifecycleMarketConfig` support explicit inner versions 5 and 6. The current October8 graph requires version 6 and matching market `configVersion`; historical version 5 requires its own graph and V1 constructor. Version 6 schema:
186
+ ### Protect the opening buy
845
187
 
846
- ```text
847
- (uint16,uint24,int24,uint160,uint24,uint24,uint32,uint8,uint8,address,bool,bytes32,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])
848
- ```
188
+ Show estimated **tokens and share of supply**, quote spent, fees, and final marginal
189
+ price. A 0.00001 ETH smoke buy bought about 4.9 tokens out of 1M in recorded fixed-V4
190
+ examples; it does not predict the impact of a $100 or $1,000 buy.
191
+ A larger buy traverses ranges and can acquire a large share of supply.
849
192
 
850
- Both preserve LP/hook fees, tick spacing, opening price, fee mode/denominator/treasury, external-liquidity policy, and canonical oracle identity. Pool-bound version6 inserts `uint24 minimumHookFeePips` and `uint32 feeSensitivityPipsSecondsPerTick` **immediately after `uint24 hookFeePips`**; `hookFeePips` remains the maximum. All other fields retain their order, including `hookSalt` immediately before `profileId`. Then come `profileId`, `termsDigest`, `developerBeneficiary`, explicit `developerFeeBps`, and positions. Every developer rate, including zero, is creator-selected. Copy terms from the selected profile's envelope. Inner/outer profile IDs must match; author identity is not the live payout. The creator rate cannot exceed either reviewed maximum or protocol ceiling.
851
-
852
- All three hook fee settings are independently chosen per pool and frozen at launch.
853
- One million pips is 100%, and 10,000 pips is 1%. `validatePoolBoundHookFees` validates
854
- integer `0 <= minimum <= maximum <= 1,000,000` and sensitivity `0..4,294,967,295`.
855
- The current reviewed `FixedFeePoolHookV1` uses a **fixed maximum-pips schedule**:
856
- each applicable hook fee is `floor(amount * hookFeePips / 1,000,000)`.
857
- Its base stores and exposes `minimumHookFeePips` and
858
- `feeSensitivityPipsSecondsPerTick`, but this concrete hook does not use them in fee
859
- calculation. Sensitivity's encoded units are fee-pips × seconds/tick; they do not
860
- imply an active oracle-driven fee formula. Registered oracle configuration still
861
- governs the pool's oracle behavior, not this hook's fixed fee rate.
862
-
863
- The registered **Dynamic Fee Hook** instead uses the oracle's upward quote-per-base
864
- tick velocity: `minimum + floor(positiveTickChange * sensitivity / elapsedSeconds)`,
865
- capped at `hookFeePips` (the maximum). Quiet/falling prices, zero elapsed time or zero
866
- sensitivity use the minimum. Select its own preset/terms, set **`lpFeePips: 0`** and
867
- explicitly encode all three config6 fee settings. Its reviewed author allocation is
868
- **0 bps**, so `developerFeeBps` must be zero. Generic config6 codecs do not identify
869
- fee behavior or certify constructor compatibility; live constructor/simulation
870
- authority remains required. Fixed launch examples continue selecting the fixed preset.
193
+ `prepareAndPlanLifecycleLaunch({ buySlippageBps: 50 })` derives every ordered buy's
194
+ minimum from stateful diagnostic output, then proves the final protected commitment:
871
195
 
872
- ```ts
873
- const profile = profiles.find((row) => row.id === selectedProfileId);
874
- if (!profile?.admitted || !profile.envelope || !profile.developerTerms) throw new Error("Selected profile is not reviewed/admitted");
875
- const config = encodePoolBoundV4LifecycleMarketConfig({
876
- version: 6, hookSalt: zeroHash, lpFeePips, tickSpacing, sqrtPriceX96,
877
- hookFeePips: creatorMaximumFeePips, minimumHookFeePips: creatorMinimumFeePips,
878
- feeSensitivityPipsSecondsPerTick: creatorSensitivityPipsSecondsPerTick, feeMode,
879
- protocolFeeDenominator: profile.envelope.protocolFeeDenominator,
880
- treasury: profile.envelope.protocolTreasury,
881
- externalLiquidityDisabled: creatorSelectedExternalLiquidityDisabled,
882
- oracleConfigId: creatorSelectedOracleConfigId,
883
- profileId: profile.id, termsDigest: profile.developerTerms.termsDigest,
884
- developerBeneficiary: profile.developerTerms.beneficiary,
885
- developerFeeBps: creatorSelectedRate, positions,
886
- });
196
+ ```text
197
+ minTokenOut = floor(simulatedTokenOut × (10000 - buySlippageBps) / 10000)
198
+ 50 bps: floor(simulatedTokenOut × 9950 / 10000)
887
199
  ```
888
200
 
889
- `validateV4LifecycleMarket` checks profile/terms/topology/version, explicit author-rate ceilings and exact envelope bounds. Registry/adapter validation remains the execution authority. Positions must require **zero quote deposit** at the committed opening price in actual token orientation. Quotes fund ordered buys, not two-sided initial LP. At most one V4 market per quote is allowed across all templates/topologies/fees/salts; put that quote's positions into one market. Abyss may use the same quote.
890
-
891
- `validateV4LifecycleOracle({client,envelope,oracleConfigId,block})` checks the selected registered
892
- oracle against the certified factory and `maximumOracleCardinality`. Profile discovery does
893
- not choose an oracle or query a profile-pinned oracle ID.
201
+ This requires activation inside the simulated prefix. The option accepts 0–9,999
202
+ bps and applies only before begin; omitting it preserves your committed minima.
203
+ A 1-wei minimum is effectively unprotected. Never submit the diagnostic draft.
204
+ A Kyber conversion minimum protects ETH→quote output, not quote→launch-token output.
894
205
 
895
- Abyss retains `encodeAbyssLifecycleMarketConfig` / `decodeAbyssLifecycleMarketConfig`: canonical pool profile, fee, oracle ID, opening price and ordered tick/liquidity/token-max positions. Quote/fee assets and direct ERC20/native-wrap funding are permissionless subject to actual code, transfers/balances/budgets and canonical bindings. Quote catalog metadata is not admission. Only swap-conversion inputs/targets use registry funding admission.
206
+ `deriveLaunchBuySqrtPriceLimitX96` is a separate, directional **marginal-price guard**.
207
+ Its `slippageBps` accepts 1–9,999 (default 50). It may stop a buy early; check partial
208
+ fills and refunds. It does not calculate minimum token output.
209
+ `estimateLaunchInitialBuy` is a pure single-position estimate, not a model of
210
+ multi-band traversal, prior buys, or hook execution. Use exact simulation for signing.
211
+ Final valuation uses the retained supply after burn and the observed post-buy price.
896
212
 
897
- ## Freeze and finalize bound economics
213
+ ## Build the plan
898
214
 
899
- Freeze chain/core/creator/nonce, token identity, sorted fee policies, all funding/budgets/positions/terms and ordered buys before mining. Create config6 with all three creator fee settings, the chosen bound profile's exact terms and a draft salt; never implicitly reinterpret a shared or historical config5 config.
215
+ For a complete wrapper, use [`launch-erc20-abyss.ts`](../examples/launch-erc20-abyss.ts).
216
+ For your own application, this function builds and prepares one market: 1M ERC20 supply,
217
+ Abyss QUOTE_ORACLE, 0.30% fee, one position, and a 0.00001 ETH native-wrap buy.
218
+ Pass a current WETH/USD-X18 price as `wethUsdPriceX18`. It reads and simulates, without signing.
219
+ The caller chooses `name` and `symbol`; keep API metadata identical to these fields.
900
220
 
901
221
  ```ts
902
- const stop = new AbortController();
903
- const finalized = await prepareAndPlanLifecycleLaunch({
904
- client, account: draft.creator, plan: draft, mode: "staged", signal: stop.signal,
905
- onProgress: ({marketIndex, attempts, predictedHook}) => console.log(marketIndex, attempts.toString(), predictedHook),
906
- });
907
- const saved = serializeLaunchPlan(finalized.plan);
908
- if (!finalized.simulation.admitted) throw new Error(finalized.simulation.reason);
909
- // Use finalized.progress and finalized.hookDeployments; do not immediately plan again.
910
- const boundIndex = finalized.plan.markets.findIndex((market) => market.configVersion === 6);
911
- const optionalPredeploy = await buildPoolBoundHookDeploymentTransaction({client, plan: finalized.plan, marketIndex: boundIndex});
912
- // Inspect only; separately admit/authenticate/sign any optional predeployment.
913
- ```
914
-
915
- The collector supplies canonical normalized economic commitment and constructor metadata. `hashPoolBoundV4MarketCommitment` uses domain `black-market.pool-bound-market-economics.v1`: chain, core, registrar, predicted token, adapter/profile/quote/budget/version and encoded config hash with **only hookSalt zeroed**. Minimum, maximum and sensitivity, plus developer identity/digest/rate, remain committed. `PoolBoundHookParametersV2` and `poolBoundHookParametersV2Components` are the current constructor API; there is no V1 alias. The constructor freezes manager, registrar, oracle factory, core, locker, token/quote, fees/spacing/price/policy, economic commitment and position count. Salt is used verbatim by CREATE2, not as a constructor argument. Local/remote constructor equality and deployed immutable getters bind both new values.
916
-
917
- Mining is cancellable/nonblocking; `abort()` raises `AbortError` and does not cancel an onchain launch. The miner reuses the exact CREATE2 preimage's immutable prefix/suffix and checks all 14 permission bits before materializing rejected-address progress at bounded macrotask boundaries. Persist the returned finalized plan, not the draft. A salt-only change preserves normalized economics but changes final plan hash. Other changes invalidate initcode/mining; concurrent mutation is refused. Normal next-step review rechecks token factory and the captured `hookDeployments` baseline. Predeployment is permissionless, but code presence or self-reported getters alone cannot be adopted as provenance. It does not register/initialize/seal/open a market and does not eliminate real code-deposit/setup gas.
918
-
919
- ## Explicit execution mode and indivisible activation
920
-
921
- Every planning call requires `mode: "atomic" | "staged"`. Only that requested mode receives economic simulation; staged does not compute or expose an unused atomic attempt.
922
-
923
- - Atomic: after funding prerequisites, token creation, empty infrastructure, all mint/lock/buys/public activation are one transaction.
924
- - Staged: prerequisites, `beginLaunch(Staged)`, greedily packed contiguous empty `prepareMarkets` batches, then one `activateLaunch`. A packed measurement failure using at least 95% of its given gas splits only that batch; low-gas semantic errors, byte caps and unlocated provider failures do not justify a split. Proof may cover only a prefix, with the unproved suffix explicitly deferred.
925
- - Activation cannot split. If mint/lock/all buys/opening cannot fit, staged is also refused. No position/buy/minimum is omitted to manufacture success.
926
-
927
- No automatic atomic-to-staged fallback exists. Obtain separate consent to review the same commitment as staged. Both venues use token transfer restrictions plus activation-time canonical opening-state checks, not a pool gate. Manipulated opening price or preactivation liquidity fails verification; the token stays inactive and the launch remains Ready/cancellable. Failed activation rolls back every mint, seal, buy and opening together.
928
-
929
- ## Execution constraints and stateful simulation
930
-
931
- Optional `chainGasLimit`, `rpcGasLimit`, `accountGasLimit` and `maxCalldataBytes`
932
- tighten admission. `maxSimulationGas` sets the aggregate used-gas proof-window
933
- budget (default 50M on 4663, unknown on other chains). Missing policy stays explicit
934
- in `limits.unknownExecutionConstraints`/`unknownConstraints`; no policy service is required.
935
- A `LifecycleLimitSource` callback receives the canonical chain/account/core/block context.
936
- Any supplied provenance must match it; stale/mismatched/malformed facts or a failed supplied
937
- resolver reject rather than disappearing into optional uncertainty. Gas caps are positive
938
- exact uint64 `bigint`; calldata is a positive safe integer byte count.
939
- Reviewed gas envelopes are positive uint64 too; zero-metering observations cannot admit
940
- a zero-gas transaction. Headroom calculations retain wide exact bigint intermediates.
941
-
942
- Headroom defaults to 1,500 bps, bounded 0–10,000; it clamps to current legal ceilings
943
- instead of rejecting a fitting measured requirement. HMM V2 adds the forwarding
944
- target documented above once on atomic/activation. Generic EVM admission uses the pinned
945
- bounded header and supplied total-envelope restrictions plus actual validated RPC proof.
946
- It reports an absent independent per-transaction cutoff honestly, without importing a
947
- universal Ethereum cutoff. `executionGasCeiling` and `transactionGasCeiling` are equal on
948
- generic EVM. The permissive measurement pass never admits a launch: replay must execute
949
- the exact returned gas/fee envelope, every postcondition and all ordered buy bounds.
950
- Fork discovery uses gross sequential estimates, not refund-reduced receipt gas as an
951
- executable minimum. Explicit ceiling recovery preserves gasleft/EIP-150 validation and
952
- carries that successfully replayed ceiling, never a smaller unproved envelope.
953
-
954
- Replay source, HTTP and malformed-response failures remain provisional with
955
- `executionProof: "unavailable"` and do not retry economic execution. `AbortError`
956
- propagates unchanged, including cancellation during supplied policy and Nitro getter
957
- reads. Only explicit genuine native out-of-gas evidence may discover at most one
958
- larger validated envelope within the same legal compute/total limits. Without returned
959
- failing-call evidence, `failedTransactionId` stays absent; an opaque RPC error does
960
- not invent a failing transaction or authorize preparation partitioning.
961
- Returned failures retain the actual exact-replay prefix and its first failing
962
- transaction, never a transaction ID borrowed from permissive measurement. For the
963
- first failed preparation only, reviewed invariant errors may decode native
964
- `error.data` when raw `returnData` is empty; nonempty raw bytes take precedence.
965
- Unknown errors, `Panic`, generic `Error` and deployment wrappers do not establish
966
- a deterministic preparation invariant or an out-of-gas cause.
967
-
968
- Sequential backends:
969
-
970
- 1. `eth_simulateV1`: ordered transactions with state carried between synthetic blocks, followed by exact validated replay.
971
- 2. Generic EVM only: explicitly separate disposable loopback fork, with snapshot-isolated real transactions, pinned chain/header identity, canonical poststate/allowances and mandatory cleanup. Source RPC stays read-only.
972
- 3. Neither: unavailable/provisional/unadmitted; disconnected dependent `eth_call` estimates cannot create an executable next transaction.
973
-
974
- Every proof completion rechecks the planned source chain ID and pinned block hash. A
975
- changed source transport cannot retain admission merely by returning the same fork hash.
976
-
977
- ### Nitro compute and poster accounting
978
-
979
- For Robinhood `4663`, each pinned context reads ArbSys (`0x64`).`arbOSVersion` and ArbGasInfo
980
- (`0x6c`).`getMaxTxGasLimit`/`getMaxBlockGasLimit`. ArbSys returns **55 + logical ArbOS version**;
981
- the raw value must be at least 105, and `limits.arbOSVersion` reports logical version 50+.
982
- The positive validated getter values establish `maxTxComputeGas`, `maxBlockComputeGas`
983
- and their minimum `executionGasCeiling`. Failed reads never fall back to the huge Nitro
984
- header or a hard-coded 32M. `limits.protocol` identifies `"nitro"` or `"evm"`.
985
-
986
- Nitro `transactionGasCeiling`, when present, is the minimum of supplied **complete**
987
- chain/RPC/account gas-envelope restrictions. It is independent of the compute ceiling:
988
- an admitted transaction's `gas` may exceed `executionGasCeiling` because poster gas is
989
- not compute. NodeInterface (`0xc8`).`gasEstimateL1Component` is read at the same pinned
990
- block with the exact sender, destination, calldata and value, including future dependent
991
- steps whose execution cannot yet be independently estimated. It budgets poster gas only.
992
- The buffered compute-discovery envelope plus buffered poster budget is carried into
993
- exact validated replay; an approximate poster quote is never subtracted from total
994
- gas use to certify exact compute fit.
995
- Measurement waits for successful capability and candidate-specific poster evidence,
996
- then uses the legal complete compute-plus-poster envelope. A packed preparation
997
- failure consuming at least 95% may invalidate its cost estimate without claiming
998
- its selector diagnoses OOG. Unsupported/transport evidence remains unavailable,
999
- except an observed aggregate-budget exhaustion can preserve a successful prefix.
1000
-
1001
- A separate pinned validated simulation probes all three ArbOS/version/getter values
1002
- against the canonical observations. Only that isolated capability probe temporarily
1003
- overrides the probe account's balance, so probe-only fees cannot reject an exactly-funded
1004
- launch. Probe funding/nonce changes, steps and fees never enter real plan measurement,
1005
- replay, postconditions or affordability, which use actual payer state. The native Nitro
1006
- `eth_simulateV1` commit-mode ArbOS charging hook removes the **actual** poster charge and
1007
- holds excess compute gas before execution. Successful exact replay and postconditions,
1008
- not the quote or permissive pass, prove fit. Missing native metering or a mismatched
1009
- probe fails closed. Generic Anvil/Hardhat forks cannot certify Nitro execution.
1010
-
1011
- Transactions expose `estimate.executionFee`, optional external `dataFee`/`totalFee` and
1012
- `feeConfidence: "execution-and-data" | "execution-only"`. On Nitro, `posterGas`/`posterFee`
1013
- are the estimated buffered allocation **inside** `gasLimit`, `dataFeeIncludedInGas` is
1014
- true, `dataFee` is zero and `totalFee` equals `gasLimit * gasPrice`. Affordability counts
1015
- this complete envelope once; adding `posterFee` again would double-charge. A caller
1016
- `estimateDataFee` is therefore rejected on Nitro. On generic EVM it retains its original
1017
- semantics as a validated external fee added outside execution gas. Missing external fee
1018
- does not manufacture an all-in estimate. All observations and limits refresh for build-next.
1019
- For initial construction, the exact legacy gas-price envelope is the greater of
1020
- the fresh RPC recommendation and twice the pinned base fee. This avoids
1021
- underpriced submission when `eth_gasPrice` lags the block base fee. Reviewed
1022
- envelopes retain exact gas/price through direct immediate native validated replay
1023
- and immediate affordability, without repeating measurement or applying new padding.
1024
- The held price need not equal a new recommendation or twice the current base fee;
1025
- natural child fees and the actual submission estimate must accept it. Replay,
1026
- affordability and submission use that same price, without a base-fee override.
1027
- An aggregate budget selects the longest fitting estimated prefix; only when even
1028
- the immediate estimate does not fit is no proof possible. A definitive returned
1029
- failure from the final exact replay skips a later payer-balance lookup, while
1030
- retaining fee/estimate validation and final canonical checks. Successful replay
1031
- still requires current actual-balance affordability.
1032
-
1033
- Source references: [ArbSys version encoding](https://github.com/OffchainLabs/nitro-precompile-interfaces/blob/main/ArbSys.sol),
1034
- [ArbGasInfo compute getters](https://github.com/OffchainLabs/nitro-precompile-interfaces/blob/main/ArbGasInfo.sol),
1035
- [native simulate commit mode](https://github.com/OffchainLabs/go-ethereum/blob/51d716ccf8293072077feb9764d63d73f5e4ff20/internal/ethapi/simulate.go),
1036
- [ArbOS actual poster/compute charging](https://github.com/OffchainLabs/nitro/blob/ccc5c828d9ea22f161efc784bac4d4a6559b7e59/arbos/tx_processor.go),
1037
- and [NodeInterface poster estimate](https://github.com/OffchainLabs/nitro-contracts/blob/main/src/node-interface/NodeInterface.sol).
1038
- These describe backend semantics, not evidence of a live launch executed by this SDK release.
1039
-
1040
- Atomic/activation simulation `steps[].returnData` encodes the actual `LaunchReceiptV1` tuple. Controlled-fork output is reconstructed from matching real activation/buy receipt logs and canonical state, never geometric estimates or echoed request minima. `tokenOut` and `quoteSpent` are parallel arrays indexed by ordered buys.
1041
-
1042
- ```ts
1043
- const fork = createControlledLifecycleFork({
1044
- sourceRpcUrl: "http://127.0.0.1:18555", forkRpcUrl: "http://127.0.0.1:18556",
1045
- allowTransactions: true, impersonation: "anvil",
1046
- });
1047
- const planned = await planLaunch({client, account: plan.creator, plan, mode: "staged", limits, fork});
222
+ import { randomBytes } from "node:crypto";
223
+ import { toHex, zeroAddress, type Address, type PublicClient } from "viem";
224
+ import {
225
+ deriveLaunchPoolRecipe, deriveLaunchBuySqrtPriceLimitX96,
226
+ encodeAbyssLifecycleMarketConfig, getAddresses, getKnownLifecycleProfile,
227
+ KnownLifecycleProfile, LAUNCH_ORACLE_CONFIG_ID, LifecycleFundingKind,
228
+ LifecycleRewardMode, LifecycleTokenKind, predictLifecycleToken,
229
+ prepareAndPlanLifecycleLaunch, readLifecycleProfiles, type LaunchPlanV1, type PlannedLaunch,
230
+ } from "@black-market/sdk";
231
+
232
+ export async function prepareOneMarketLaunch(
233
+ client: PublicClient, principal: Address, wethUsdPriceX18: bigint,
234
+ name: string, symbol: string,
235
+ ): Promise<PlannedLaunch> {
236
+ if (await client.getChainId() !== 4663) throw new Error("Wrong RPC chain");
237
+ const { launchOrchestrator: orchestrator, weth } = getAddresses(4663);
238
+ const preset = getKnownLifecycleProfile({
239
+ chainId: 4663, orchestrator, key: KnownLifecycleProfile.Abyss3,
240
+ });
241
+ if (!preset) throw new Error("Unknown deployment");
242
+ const [profile] = await readLifecycleProfiles({
243
+ client, orchestrator, profileIds: [preset.profile.id],
244
+ });
245
+ if (!profile?.admitted) throw new Error(profile?.reason ?? "Profile unavailable");
246
+ const supply = 1_000_000n * 10n ** 18n;
247
+ const buy = 10_000_000_000_000n;
248
+ const draft: LaunchPlanV1 = {
249
+ chainId: 4663n, orchestrator, creator: principal,
250
+ nonce: BigInt(toHex(randomBytes(32))),
251
+ token: {
252
+ kind: LifecycleTokenKind.ERC20, rewardMode: LifecycleRewardMode.None,
253
+ name, symbol, supply, nftUnit: 0n, metadataURI: "",
254
+ salt: toHex(randomBytes(32)), inventoryRecipient: principal, burnOnCancel: false,
255
+ },
256
+ funding: [], feeAssets: [], markets: [], buys: [],
257
+ deadline: BigInt(Math.floor(Date.now() / 1000)) + 3600n, executorFeeBps: 275,
258
+ };
259
+ const token = await predictLifecycleToken({ client, plan: draft });
260
+ const token0 = BigInt(token) < BigInt(weth);
261
+ const r = deriveLaunchPoolRecipe({
262
+ pairedTokenDecimals: 18, pairedTokenUsdPriceX18: wethUsdPriceX18,
263
+ targetMarketCapUsdX18: 5_000n * 10n ** 18n,
264
+ launchedTokenIsQuote: token0, fee: 3000, supply, tokenBudget: supply,
265
+ });
266
+ const plan: LaunchPlanV1 = {
267
+ ...draft,
268
+ funding: [{ asset: weth, amount: buy, kind: LifecycleFundingKind.NativeWrap,
269
+ inputAsset: weth, inputAmount: buy, target: zeroAddress, data: "0x" }],
270
+ feeAssets: [token, weth].sort((a, b) => BigInt(a) < BigInt(b) ? -1 : 1)
271
+ .map((asset) => ({ asset, ownerBps: 10000, rewardsBps: 0, burnBps: 0 })),
272
+ markets: [{ adapterId: profile.registration.adapterId, profileId: profile.id,
273
+ quoteAsset: weth, tokenBudget: supply, configVersion: 1,
274
+ config: encodeAbyssLifecycleMarketConfig({
275
+ profile: 3, fee: 3000, oracleConfigId: LAUNCH_ORACLE_CONFIG_ID,
276
+ openingSqrtPriceX96: r.launchSqrtPriceX96,
277
+ positions: [{ tickLower: r.tickLower, tickUpper: r.tickUpper,
278
+ liquidity: r.liquidity, tokenAmountMaximum: supply }],
279
+ }) }],
280
+ buys: [{ marketIndex: 0, quoteAmountIn: buy, minTokenOut: 1n,
281
+ recipient: principal, sqrtPriceLimitX96: deriveLaunchBuySqrtPriceLimitX96({
282
+ launchSqrtPriceX96: r.launchSqrtPriceX96, launchedTokenIsQuote: token0,
283
+ }) }],
284
+ };
285
+ return prepareAndPlanLifecycleLaunch({
286
+ client, account: principal, plan, mode: "atomic", buySlippageBps: 50,
287
+ });
288
+ }
1048
289
  ```
1049
290
 
1050
- The fork endpoint must be distinct/loopback, including localhost/IP aliases and effective port. Anvil reset/impersonation is default; disposable Hardhat may explicitly use its reset method/impersonation. Never pass the source client as a fork or use a live unlocked wallet as a disposable backend. Operators own exclusive fork access during generic EVM proof. Controlled-local execution does not prove wallet submission acceptance and cannot certify Nitro metering or imply bound topology is a gas optimization.
1051
-
1052
- ## Wallet submission and canonical recovery
1053
-
1054
- The SDK never signs. Before **every** approval/reset/core/predeploy/cancel signature, compare the wallet's configured chain (if any) and fresh connected `getChainId()` with the returned `next.chainId`. Failure/invalid identity is a refusal. Supply a matching explicit viem Chain descriptor; do not pass `chain: null` or disable wallet chain checks. Send exact `from/to/data/value/gas/gasPrice`, not a cached estimate or wallet batch.
1055
-
1056
- Simulation and `next.admission` carry flat, independent proof outcomes:
1057
-
1058
- | Field | Values | Scope |
291
+ The draft's `minTokenOut: 1n` is diagnostic. The function calls
292
+ `prepareAndPlanLifecycleLaunch` with `buySlippageBps: 50` and returns the final
293
+ protected plan. Token prediction uses core/creator/nonce/token configuration, so
294
+ the predicted token can enter sorted fee assets without a circular market-config hash.
295
+ `executorFeeBps: 275` matches the example runner: 2.75% of newly collected fees
296
+ goes to whoever calls `claimAndSplit()`. It is not charged to traders. Use 0 for none.
297
+
298
+ <a id="pool-bound-v4-version-6"></a>
299
+ For V4, use `encodePoolBoundV4LifecycleMarketConfig` with explicit `version: 6`,
300
+ all three hook-fee fields, selected oracle, external-liquidity policy, sorted fee
301
+ assets, positions, and the chosen profile's treasury/terms. A draft `hookSalt` is
302
+ finalized by `prepareAndPlanLifecycleLaunch`; freeze economics before mining.
303
+ [Config6 reference](reference.md#pool-bound-v4-version-6) describes fixed vs dynamic fees.
304
+
305
+ **Direct-core funding:** creator, payer, and refund recipient are the same address.
306
+ ERC20 inputs approve the core's `fundingEscrow`, not the core or router. Native
307
+ WETH buys use `NativeWrap`; other quotes can use admitted Kyber conversion, or be
308
+ funded directly as ERC20. Gas ETH is extra. [UFG](#launch-a-ufg-treasury) instead
309
+ uses a proxy creator, principal payer/refund recipient, and proxy approvals.
310
+
311
+ The wrappers set the plan deadline to **now + 3,600 seconds**. A Kyber conversion
312
+ uses **now + 300 seconds**, at most 1,200 seconds and never beyond plan expiry.
313
+ Staging can outlive the conversion even while the plan is valid. Do not edit a
314
+ saved deadline or replace committed conversion bytes after begin.
315
+
316
+ ## Prepare and simulate
317
+
318
+ | Mode | Transactions after any approvals | Choose when |
1059
319
  | --- | --- | --- |
1060
- | `executionProof` | `"proved"`, `"failed"`, `"unavailable"` | Stateful exact-envelope execution/postconditions for the proven prefix (or the immediate reviewed step), never measurement alone or an unproved suffix. |
1061
- | `protocolFit` | `"proved"`, `"failed"`, `"unknown"` | Applicable proven protocol and known tightening restrictions. Missing optional policy remains separately disclosed. |
1062
- | `transportPreflight` | `"not-requested"`, `"passed"`, `"failed"` | Immediate exact next-transaction acceptance estimate on the supplied submission RPC. |
320
+ | `atomic` | One transaction creates, prepares, mints, locks, buys, and opens. | The exact full launch fits the execution envelope. |
321
+ | `staged` | Begin → prepare batches → one activation that mints, locks, buys, and opens all markets. | Preparation needs separate transactions. |
1063
322
 
1064
- `admitted` means the proven prefix fits and is affordable, not that deferred
1065
- transactions have executed or that eventual activation is guaranteed. Always
1066
- inspect `simulation.deferredTransactionIds`. Admission reuses `blockNumber`,
1067
- `blockHash`, `account`, `chainId` and `limits`; signing uses only fresh build-next
1068
- admission. Plans never preflight future steps independently against nonexistent state.
323
+ Staging is not rollback. A begun plan remains begun after its deadline until cancelled.
324
+ Activation cannot be split into separate position mints or buys.
325
+ The SDK never switches your requested mode or removes markets to make it fit.
326
+
327
+ | Operation | Options type / purpose |
328
+ | --- | --- |
329
+ | `prepareAndPlanLifecycleLaunch` | `PrepareAndPlanLifecycleLaunchOptions`: `client`, `account`, `plan`, `mode`; optional `ufg: { config }`, `buySlippageBps`, `fixedFinalEnvelope`, `limits`, `fork`, `receipts`, `confirmations`, `signal`, `onProgress`, topology opt-outs. |
330
+ | `planLaunch` | `PlanLaunchOptions`: same execution context, including optional `ufg: { config }` and `signal`; re-admits an already-finalized plan without changing salts/minima. |
331
+ | `simulateLaunchPlan` | `client`, `planned`; optional `limits`, `fork`, `receipts`, `confirmations`, `signal`. |
332
+ | `readLaunchProgress` | `client`, `planned`; optional `receipts`, `confirmations`, `signal`. |
333
+ | `buildNextTransaction` | Progress options, plus optional `action`, `limits`, `fork`, `submissionClient`, `reviewedTransaction`. |
334
+
335
+ `buildLaunchTransactions` compiles unsigned commands; it does not prove execution.
336
+ Persist `serializeLaunchPlan(planned.plan)`, mode, confirmation policy, receipt
337
+ references, and UFG config if applicable. `parseLaunchPlan` restores bigint values.
338
+ Do not serialize the entire `PlannedLaunch`, which can contain live limit callbacks.
339
+
340
+ Robinhood proof requires native Nitro `eth_simulateV1`. A generic Anvil/Hardhat fork
341
+ can exercise EVM behavior but cannot certify Nitro compute/poster accounting.
342
+ The default aggregate proof window is **50M used gas**, not a per-transaction ceiling.
343
+ Inspect `simulation.deferredTransactionIds` even when `simulation.admitted` is true:
344
+ admission can cover only a prefix. Deferred steps have no gas, price, or admission.
345
+ Buy-output calibration refuses a deferred activation. Start with one market; raise
346
+ `limits.maxSimulationGas` only with a provider that supports the larger window.
347
+
348
+ Review the returned final plan/hash, aligned price, burn, retained supply, fees,
349
+ ordered buy outputs/minima, funding, refunds, and complete gas envelope. A fresh
350
+ `buildNextTransaction` proves the immediate next step as canonical progress advances.
351
+ `submissionClient` adds read-only exact-envelope preflight on the sending RPC.
352
+
353
+ `planned.transactions[0]` already contains the immediate exact `from/to/data/value`,
354
+ `nonce`, `gas` and `gasPrice` when that step has admitted execution proof. There is
355
+ no need for another unreviewed build just to discover its envelope. The envelope
356
+ is reviewable and reusable; its block-bound admission is historical, not permission
357
+ to sign later. Pass it as `reviewedTransaction` for fresh immediate admission after
358
+ review or recovery. This is execution revalidation, not a second user review gate.
359
+ Reuse `planned.progress` for the same result's display instead of reading progress
360
+ independently beside the plan.
361
+
362
+ For an atomic caller with a chosen final gas envelope, prepare with
363
+ `fixedFinalEnvelope: { gas: 31_000_000n }`. This is an explicit chosen gas amount,
364
+ not a universal gas recommendation. `limits.accountGasLimit` remains only a ceiling.
365
+ The option accepts exactly one immediate atomic command with no approval prefix;
366
+ staged mode and approval-first shapes refuse it. Diagnostic and final protection
367
+ share one frozen fee recommendation. Supplying `gasPrice` holds that fee exactly;
368
+ it is never bumped to obtain admission. The final protected calldata still receives
369
+ one natural-child-fee validated replay at the exact chosen envelope. Failure never
370
+ enlarges it or switches mode.
371
+
372
+ On chain4663, independent Nitro getters, known factory prediction and known-core
373
+ head progress can share one Multicall3 read after pinned runtime attestation.
374
+ Poster estimates retain their original sender/value and are never aggregated.
375
+ One invocation owns the final fresh chain check and every distinct canonical
376
+ proof pin, including after optional sending-RPC estimation. Balances and economic
377
+ proofs are not shared across invocations.
378
+
379
+ ## Sign and confirm
380
+
381
+ Call `buildNextTransaction` before **every signature**, including approvals and
382
+ cancellation. For a reviewed command, pass `reviewedTransaction` so the SDK replays
383
+ the same gas/fee/nonce rather than rediscovering it. Send the exact returned
384
+ `from/to/data/value/nonce/gas/gasPrice` with a matching explicit viem chain.
385
+ `confirmations` defaults to 1; choose and retain your policy before begin.
386
+ SDK affordability is observed at block B, not at the provider's pending state.
387
+ Immediately before signing, the host must freshly compare pending nonce and
388
+ balance with this exact envelope and verify the active provider account/chain
389
+ after asynchronous work. Changed identity, nonce, intent or insufficient pending
390
+ funds blocks the signature; never overwrite the reviewed nonce or replay a write.
391
+ The following local-account loop signs only when explicitly called by your application.
392
+ Use a new owner-only journal path inside a private directory; on reload, restore the
393
+ original plan and receipt references before calling it. Journal records contain secrets.
1069
394
 
1070
395
  ```ts
1071
- const planned = await planLaunch({ client, account: plan.creator, plan, mode: "atomic" });
1072
- const submissionClient = {
1073
- request: ({ method, params }) => activeProvider.request({ method, params }),
1074
- };
1075
- const reviewedTransaction = await buildNextTransaction({ client, planned, receipts, submissionClient });
1076
- // Present this exact envelope for user review. After explicit confirmation:
1077
- if (reviewedTransaction !== undefined) {
1078
- const next = await buildNextTransaction({ client, planned, receipts, submissionClient, reviewedTransaction });
1079
- // Recheck active account/connector/chain and strict exact-envelope equality before signing next.
396
+ import { appendFile } from "node:fs/promises";
397
+ import {
398
+ keccak256, type Chain, type Hash, type LocalAccount, type PublicClient,
399
+ type Transport, type WalletClient,
400
+ } from "viem";
401
+ import {
402
+ buildNextTransaction, LifecyclePhase, readLaunchProgress, serializeLaunchPlan,
403
+ type LifecycleReceiptReference, type PlannedLaunch,
404
+ } from "@black-market/sdk";
405
+
406
+ export async function executeLaunch(
407
+ client: PublicClient, wallet: WalletClient<Transport, Chain, LocalAccount>,
408
+ planned: PlannedLaunch, receipts: LifecycleReceiptReference[], journalPath: string,
409
+ activationHash?: Hash,
410
+ ) {
411
+ const record = (value: unknown) => appendFile(journalPath,
412
+ JSON.stringify(value, (_, v) => typeof v === "bigint" ? v.toString() : v) + "\n",
413
+ { mode: 0o600 });
414
+ await record({ plan: serializeLaunchPlan(planned.plan), mode: planned.mode,
415
+ confirmations: planned.confirmations, ufg: planned.ufg, receipts });
416
+ for (;;) {
417
+ const next = await buildNextTransaction({
418
+ client, planned, receipts, submissionClient: client,
419
+ });
420
+ if (!next) {
421
+ const progress = await readLaunchProgress({ client, planned, receipts });
422
+ if (!progress.confirmationSafe || progress.canonical.phase !== LifecyclePhase.Active
423
+ || !progress.receipts.every((r) => r.status === "confirmed")
424
+ || !progress.markets.every((m) => m.live?.publicTrading) || !activationHash) {
425
+ throw new Error("Launch not confirmed Active; reconcile the journal");
426
+ }
427
+ return { progress, activationHash };
428
+ }
429
+ if (!next.admission?.admitted || next.gas === undefined || next.gasPrice === undefined) {
430
+ throw new Error("Immediate transaction is not admitted");
431
+ }
432
+ const [nonce, pendingBalance] = await Promise.all([
433
+ client.getTransactionCount({ address: next.from, blockTag: "pending" }),
434
+ client.getBalance({ address: next.from, blockTag: "pending" }),
435
+ ]);
436
+ const dataFee = next.estimate?.dataFee;
437
+ if (next.nonce === undefined || BigInt(nonce) !== next.nonce || dataFee === undefined
438
+ || pendingBalance < next.value + next.gas * next.gasPrice + dataFee) {
439
+ throw new Error("Pending nonce or complete affordability changed; revalidate");
440
+ }
441
+ const [address] = await wallet.getAddresses();
442
+ if (wallet.chain.id !== next.chainId || await wallet.getChainId() !== next.chainId
443
+ || await client.getChainId() !== next.chainId
444
+ || address?.toLowerCase() !== next.from.toLowerCase()
445
+ || wallet.account.address.toLowerCase() !== planned.account.toLowerCase()) {
446
+ throw new Error("Wallet account or chain changed");
447
+ }
448
+ const raw = await wallet.signTransaction({
449
+ chain: wallet.chain, account: wallet.account, nonce,
450
+ to: next.to, data: next.data, value: next.value, gas: next.gas, gasPrice: next.gasPrice,
451
+ });
452
+ const hash = keccak256(raw);
453
+ await record({ transactionId: next.id, kind: next.kind, hash, raw });
454
+ const sent = await client.sendRawTransaction({ serializedTransaction: raw });
455
+ if (sent !== hash) throw new Error("Submission hash mismatch; reconcile before continuing");
456
+ const receipt = await client.waitForTransactionReceipt({
457
+ hash, confirmations: planned.confirmations,
458
+ });
459
+ await record({ hash, receipt });
460
+ if (receipt.status !== "success" || receipt.transactionHash !== hash) {
461
+ throw new Error("Reverted or replaced transaction; reconcile before continuing");
462
+ }
463
+ receipts.push({ transactionHash: hash, confirmations: planned.confirmations,
464
+ observedBlockNumber: receipt.blockNumber, observedBlockHash: receipt.blockHash });
465
+ if (next.kind === "atomic" || next.kind === "activate") activationHash = hash;
466
+ await record({ receipts, activationHash });
467
+ }
1080
468
  }
1081
469
  ```
1082
470
 
1083
- When supplied, `submissionClient` receives only read-only `eth_chainId` and
1084
- `eth_estimateGas` for the immediate next `from/to/data/value/gas/gasPrice` at `latest`.
1085
- Its positive estimate must fit the reviewed gas exactly; gas is never silently enlarged.
1086
- Chain identity is checked before and after estimation, and the source pinned hash/chain
1087
- is rechecked before returning. Success sets `next.admission.transportPreflight` to
1088
- `"passed"`. Refusal, unsupported RPC, malformed estimate, over-envelope estimate or
1089
- chain drift raises `SUBMISSION_PREFLIGHT_FAILED` without returning a transaction.
1090
- The error's `simulation` retains execution admission and its canonical context, changing
1091
- only transport outcome/reason to `"failed"`. Cancellation uses the same preflight.
1092
- Without a submission client, `"not-requested"` remains honest and no wallet RPC is implied.
1093
- Applications still own fresh active account/provider guards around asynchronous work;
1094
- a read-only preflight does not authenticate an active wallet or authorize a signature.
1095
-
1096
-
1097
- Persist transaction hashes immediately. After receipt, retain `observedBlockNumber`, `observedBlockHash`, confirmation policy and, for replacements, original `transactionHash` plus effective `replacementHash`. A same-nonce self-transfer is replacement-cancelled, not launch completion. Removed observed blocks are reorged; status zero is reverted; a missing receipt at the unchanged observed block remains pending. Unknown hashes do not invent reorgs.
471
+ A send timeout is ambiguous: the hash may already be mined. Stop, query the saved
472
+ hash, and reconcile pending nonce/receipt state; do not automatically resend.
473
+ For an interactive review delay, pass the previously displayed command as
474
+ `reviewedTransaction` to a fresh `buildNextTransaction` before signing.
475
+ That directly replays the same immediate envelope at its held nonce, gas and gas price.
1098
476
 
1099
- `confirmations` is positive and defaults to 1. Progress anchors confirmed canonical and latest head hashes, compares confirmed/head/pending account nonces, and prevents ref-free reloads from advancing unconfirmed work. Pending receipts/state return no executable envelope (`RECEIPT_PENDING`/`UNCONFIRMED_STATE`). Reload the exact plan/mode/policy/receipt references; never trust a cached step counter. Market read failures are surfaced without removing adapter-independent cancellation.
477
+ Completion has **four checks**: receipt confirmed → markets active → metadata
478
+ published → API indexed. A successful transaction alone does not establish the last two.
1100
479
 
1101
- ## Funding and cancellation
480
+ ## Publish metadata
1102
481
 
1103
- Creator/payer/refund recipient are the same address. ERC20 prerequisites approve immutable `fundingEscrow`, not core/adapters; amounts aggregate by input asset and insufficient nonzero allowances reset before exact approval. NativeWrap requires canonical wrapped-native binding and exact summed native value; there is no invented launch fee. Swap funding commits approved target/spender/code hash and exact input/output/calldata. Unrelated donations/other launches are not swept as refunds.
1104
-
1105
- Preparing/Ready cancellation uses the stored commitment after expiry/retirement without calling adapters or requiring new profile/funding admission. It refunds unspent external funding only. Wrapped-native refunds are wrapped ERC20, not original native gas funds. Cancelled token inventory remains inactive or burns according to the plan. Cancellation still needs current execution admission and nonce/receipt safety; Active/Cancelled are terminal and there is no postactivation creator pause.
482
+ Stage metadata **before chain signatures**, after you freeze the final plan. The
483
+ call order is `createUploadSession` → optional `putImage` → `completeUpload` →
484
+ confirm activation → `publishUploadSession`. Metadata-only sessions skip the image calls.
485
+ The following metadata-only function signs attribution and writes the API; call it
486
+ only with authorization. It works with a direct creator or the UFG principal.
1106
487
 
1107
488
  ```ts
1108
- const cancel = await buildNextTransaction({client, planned, receipts, limits, fork, action: "cancel"});
1109
- // Apply identical wallet-domain/exact-envelope/receipt handling before submission.
489
+ import { randomBytes, randomUUID } from "node:crypto";
490
+ import { appendFile } from "node:fs/promises";
491
+ import { toHex, zeroHash, type Chain, type LocalAccount, type Transport, type WalletClient } from "viem";
492
+ import {
493
+ canonicalLaunchMetadataHash, LaunchApiClient, launchAttributionTypes,
494
+ type LaunchSessionCreateMetadata, type PlannedLaunch,
495
+ } from "@black-market/sdk";
496
+
497
+ export async function stageMetadata(
498
+ wallet: WalletClient<Transport, Chain, LocalAccount>, planned: PlannedLaunch,
499
+ metadata: LaunchSessionCreateMetadata, journalPath: string,
500
+ ) {
501
+ if (wallet.account.address.toLowerCase() !== planned.account.toLowerCase()
502
+ || await wallet.getChainId() !== Number(planned.chainId)
503
+ || wallet.chain.id !== Number(planned.chainId)) throw new Error("Wrong signer domain");
504
+ if (metadata.name !== planned.plan.token.name || metadata.symbol !== planned.plan.token.symbol) {
505
+ throw new Error("Metadata differs from plan");
506
+ }
507
+ const record = (v: unknown) => appendFile(journalPath, JSON.stringify(v) + "\n", { mode: 0o600 });
508
+ const idempotencyKey = randomUUID();
509
+ const nonce = toHex(randomBytes(32));
510
+ const deadline = BigInt(Math.floor(Date.now() / 1000)) + 600n;
511
+ const signature = await wallet.signTypedData({
512
+ account: wallet.account,
513
+ domain: { name: "Abyss Launch Attribution", version: "1",
514
+ chainId: Number(planned.chainId), verifyingContract: planned.plan.orchestrator },
515
+ types: launchAttributionTypes, primaryType: "LaunchAttribution",
516
+ message: { chainId: planned.chainId, wallet: planned.account,
517
+ metadataHash: canonicalLaunchMetadataHash(metadata), imageSha256: zeroHash,
518
+ imageContentType: "", imageContentLength: 0n, idempotencyKey, nonce, deadline },
519
+ });
520
+ const body = { chainId: Number(planned.chainId), wallet: planned.account, metadata,
521
+ authorization: { nonce, deadline: deadline.toString(), signature } };
522
+ await record({ idempotencyKey, body });
523
+ const api = new LaunchApiClient({ baseUrl: "https://api.abyss.trading", retries: 1 });
524
+ const session = await api.createUploadSession(body, idempotencyKey);
525
+ await record({ session }); // Save the one-time capability before continuing.
526
+ if (!session.capability || session.status !== "ready_to_launch") {
527
+ throw new Error("Metadata session not ready");
528
+ }
529
+ return { api, sessionId: session.sessionId, capability: session.capability };
530
+ }
1110
531
  ```
1111
532
 
1112
- ## Stable author APIs and V3 fees
1113
-
1114
- `developerBeneficiary`/envelope `beneficiary` is stable `authorId`. Registry `authorPayout(authorId)` is mutable live routing/controller; zero means unknown. Registry admin or current payout/controller may change a known nonzero route with `setAuthorPayout`. Retirement never changes stable identity or blocks existing active developer credits.
1115
-
1116
- | Helper | Inputs / semantics |
1117
- | --- | --- |
1118
- | `readLifecycleAuthor` | `{client,registry,authorId}` → canonical core/factory, known/live payout, hub count, pinned chain/block. |
1119
- | `readAuthorHubs` | Same + `offset?:bigint,limit?:bigint` (defaults 0/100), bounded **1..100**, offset ≤ total, actual hubs/nextOffset/total/cursorComplete. |
1120
- | `readDeveloperFees` | Same + `hub,assets?` → authenticated V3 hub, actual assets, claimable/reserved balances, frozen source terms/assets. Explicit unsupported assets are flagged, not relabeled supported. |
1121
- | `buildSetAuthorPayoutTransaction` | Same + `payout,account,chainId:bigint`; requires current controller/admin and known identity. |
1122
- | `buildClaimDeveloperFeesTransaction` | Same + `hub,asset,account,chainId:bigint`; permissionless fixed-live-payout direct claim. |
1123
- | `buildClaimDeveloperFeesPageTransaction` | Same + `offset:bigint,limit:bigint,assets?,account,chainId:bigint`; factory page **1..10**. |
1124
- | `decodeDeveloperClaimReceipt` | `{receipt,transaction}` using exact unsigned claim context; validates emitter/account/target/context/cursor/status/rows. |
533
+ Retain the capability separately: `getUploadSession`, `renewUploadUrl`, and
534
+ `completeUpload` responses do not reissue it. With an image, authorize its SHA-256,
535
+ content type, and byte length using `sha256Hex`; upload only the signed bytes to the
536
+ API-issued PUT URL/headers. Wait for verified image readiness before launching.
1125
537
 
1126
- Unsigned objects carry exact `chainId/from/to/data/value`, with no execution default. Canonical membership is anchored to **registry.core → core.feeFactory → factory.isHub** before any hub self-report; selected registry/core/factory bindings are also checked. Page assets are sorted unique nonzero addresses, at most eight; `[]` means each hub's actual assets. Page cursor completion is independent of payment success: statuses **0 paid, 1 zero, 2 unsupported, 3 failed** remain distinct; preserve retryable failed rows even when the cursor reaches total. A successful direct receipt without `DeveloperFeesClaimed` is `unobserved`, not an invented zero payment.
538
+ Publish the **original atomic/activation transaction hash**, not an approval or begin
539
+ hash. Before publication, reread `readLaunchProgress` with all retained receipts;
540
+ require confirmation-safe Active, all markets public, and the activation confirmed at
541
+ its saved block number/hash. Call `publishUploadSession(chainId, sessionId, capability,
542
+ { chainId, transactionHash })` on the same `LaunchApiClient`.
1127
543
 
1128
- Choose an explicit page gas budget under the current account/RPC/chain limits, including every bounded hub/asset call plus factory overhead and EIP-150 headroom. `eth_estimateGas` success alone does not prove every row was attempted: the factory can complete the cursor while reporting failed rows under insufficient caller gas. Always decode and retry failed rows; never equate transaction success or cursor completion with payment success.
544
+ Catch `LaunchPublishPending`: its `session` retains indexing state and `retryAfterMs`
545
+ tells you when to poll `getUploadSession` or retry the same publication. HTTP 202 is
546
+ pending indexing, not a deployment revert. A published/indexed response must match
547
+ the predicted token, activation hash, metadata, and image. An API/image failure after
548
+ Active calls for publication recovery, not another deployment.
1129
549
 
1130
- Current ordinary fee preview/building uses public `lifecycleFeeHubAbi` with **no-argument `claimAndSplit()`**. Preview via viem `simulateContract`/`eth_call`, and build unsigned calldata with `encodeFunctionData`; neither guarantees execution. V3 freezes each source's adapter/profile/terms/stable author/maximum/selected rate. For each actual collected asset: executor bounty is deducted, owner/rewards/burn policy is split with canonical dust allocation, then developer fees are floor-rounded from each source's proportional contribution to the owner share. Developer fees do not reduce rewards/burn, do not reward donations and do not spend prior reserved credits. Owner and developer allocations are reserved before external payouts. `Distributed` includes `developerAmount`; hub reserved inventory is `reservedOwnerFees + reservedDeveloperFees`, not owner reserves alone.
550
+ ## Recover or cancel
1131
551
 
1132
- Current registered fee owners may update executor bounty up to 1,000 bps. Each no-arg harvest snapshots one rate for all sources, including already accrued source fees. Owner/reward/burn policy and frozen developer terms do not change; old owner credits remain with the credited owner. Owner `claimOwnerFees(asset,recipient)` withdraws reserved credits without harvesting/bounty. Developer `claimDeveloperFees(authorId,asset)` has no recipient argument and resolves live registry payout at execution.
552
+ Restore the exact saved plan with `parseLaunchPlan`, original mode, confirmations,
553
+ receipt references, and UFG config. Use `planLaunch` to re-admit it; obtain fresh
554
+ commands with `buildNextTransaction`. Never regenerate nonce, salts, or minima.
555
+ For runner launches use `--resume <original-run-dir>`; do not substitute a fresh run.
1133
556
 
1134
- Lifecycle dividend tokens retain independent current-owner dividend bounty up to 1,000 bps, gross previews and net beneficiary payments with separate caller bounty; self-claims get full gross. Staking claims have no dividend payout bounty. Oracle genesis/cardinality/opening state is not lending-feed maturity, depth or recency approval; unrelated lending checks remain unchanged.
1135
-
1136
- ## Independent vectors and local proof
557
+ | Canonical phase / evidence | Action |
558
+ | --- | --- |
559
+ | None, no submitted hashes | Replan before signing; an expired unstarted plan needs a new explicit review. Runner resume stops for reconciliation. |
560
+ | Preparing / Ready, deadline valid | Resume the original plan's remaining preparations/activation. |
561
+ | Preparing / Ready, expired or retired | Request `buildNextTransaction({ client, planned, receipts, action: "cancel" })`; apply the same signing/receipt checks. |
562
+ | Active | Verify markets and original activation, then finish publication/claims. |
563
+ | Cancelled | Terminal; confirm refunds and inactive token state. |
564
+ | Pending / unconfirmed / replaced / reorged receipt | Reconcile the saved hash, inclusion, and nonce first; do not advance from a cached step counter. |
565
+
566
+ Preparing/Ready cancellation uses the committed plan without adapter calls or new
567
+ profile admission. It refunds **unspent external funding**; wrapped-native refunds
568
+ are WETH, not ETH gas. Token inventory stays inactive or burns per `burnOnCancel`.
569
+ Active liquidity cannot be cancelled or withdrawn, and there is no postlaunch creator pause.
570
+ `buildNextTransaction` returning `undefined` can mean Active **or Cancelled**; read phase.
571
+
572
+ | Symptom | Cause | Next action |
573
+ | --- | --- | --- |
574
+ | HTTP 403/429 on `eth_chainId`, `eth_getBalance`, `eth_simulateV1` | RPC throttling | Wait or use another RPC; reconcile and resume the same run. A 429 is not a revert. |
575
+ | Begun launch, deadline passed | Interrupted staged execution | Cancel as above; a fresh invocation cannot continue the original funds. |
576
+ | `eth_getLogs` range error | Genesis scan exceeds the 10M-block limit | Scan from core deployment block 82,880,313 in chunks of at most 10M. |
577
+ | `KYBER_UNAVAILABLE` / invalid WETH route | Trying to swap ETH→WETH | Use native wrapping; Kyber converts other quotes. |
578
+ | `INVALID_KYBER_INTENT` | Conversion deadline reused the plan deadline / exceeds 1,200 seconds | Use the separate 300-second conversion clock before committing. |
579
+ | `PLAN_NOT_ADMITTED` gas error | Saved envelope no longer fits | Rebuild the immediate envelope with `buildNextTransaction`. |
580
+ | `ECONOMIC_REVIEW_REQUIRED` hash mismatch | Review belongs to a different plan invocation | Review and admit the same saved plan. |
581
+ | `PUBLISH_TIMEOUT` / `API_INDEX_TIMEOUT` / image URL error after activation | Publication/indexing | Check Active; resume publication for the existing token. |
1137
582
 
1138
- `test/fixtures/launch-lifecycle-v1.json` is a portable **offline wire vector**, not a deployed launch. Its independent generator owns the literal canonical ABI tuple:
583
+ ## After launch
1139
584
 
1140
- ```sh
1141
- node examples/generate-lifecycle-commitment-fixture.ts test/fixtures/launch-lifecycle-v1.json
1142
- ```
585
+ Read the confirmed progress's `feeHub`, rewards module, and prepared market identities.
586
+ Locked launch positions are permanent; collecting fees never withdraws their principal.
1143
587
 
1144
- Build and run the offline unit suite with `pnpm test`, and deployed read-only discovery with
1145
- `pnpm examples`. Unit regressions cover commitment/identity/numerical domains,
1146
- reviewed terms/rate/bounds, salt normalization/mining, receipt recovery, and author
1147
- authentication/routing/page outcomes. Wire vectors remain
1148
- offline schema references; they are not a mainnet launch or an admitted deployment graph.
588
+ | Role | What to do |
589
+ | --- | --- |
590
+ | Anyone | Call fee hub `claimAndSplit()` to collect and split fees; receive the executor bounty if configured. |
591
+ | Fee owner | Read `claimableOwnerFees(owner, asset)`; call `claimOwnerFees(asset, recipient)` for credited fees. |
592
+ | Token holder | Claim staking rewards or dividends from the rewards module; the app has holder claim UI. |
593
+ | Hook author | Use `readDeveloperFees` and `buildClaimDeveloperFeesTransaction`; [author reference](reference.md#stable-author-apis-and-v3-fees). |
594
+ | UFG holder | Read the treasury with `readUfgTreasury(client, token)`; redeem through its contract. |
595
+
596
+ For ordinary owner fees, first simulate fee hub `claimAndSplit()` with
597
+ `lifecycleFeeHubAbi`, submit that approved transaction, and wait for confirmation.
598
+ Then read `claimableOwnerFees(owner, asset)`. Simulate and submit
599
+ `claimOwnerFees(asset, recipient)` from the credited owner account. The second call
600
+ withdraws credits without harvesting again. Check each receipt and `Distributed` /
601
+ `OwnerFeesClaimed` events; an outer success can still contain failed individual payouts.
602
+
603
+ <a id="stable-author-apis-and-v3-fees"></a>
604
+ V3 author royalties come from attributable owner fees **after** the executor bounty;
605
+ they do not reduce holder rewards or burn allocations. Author identity is stable,
606
+ while its registry payout can change. Owner credits remain with the credited owner.
607
+ The current fee owner may change executor bounty up to **1,000 bps**; policy fractions
608
+ and frozen author terms stay fixed. See the [full fee reference](reference.md#stable-author-apis-and-v3-fees).
609
+
610
+ <a id="0120-release-opt-in-ufg-treasuries"></a>
611
+ ## Launch a UFG treasury
612
+
613
+ UFG is an opt-in launch route, not another DEX venue. Creating one requires the SDK;
614
+ the app can display treasury launches but its creation route is not available here.
615
+ Start with the pure [`ufg-launch-config.ts`](../examples/ufg-launch-config.ts) example.
616
+ Neither the eleven wrappers nor the generic `examples/launch.ts` CLI supports UFG deployment.
617
+
618
+ 1. Choose reward-free **ERC20**, executor bounty **0**, treasury share **10,000 bps**,
619
+ exit fee **0–2,000 bps**, and **1–7 sorted unique reserve addresses**.
620
+ The reserve set must equal the market quote set and exclude the launch token.
621
+ 2. Before prediction, set creator to `UFG_LAUNCH_PROXY_ADDRESS` and nonce to
622
+ `ufgLaunchNonce(principal, nonce96)`. Keep inventory/buy recipients external to the proxy.
623
+ Recompute token orientation, ranges, and fees for that predicted token.
624
+ 3. Use canonical Abyss config1 **2 QUOTE / 3 QUOTE_ORACLE**, or UFG fixed/dynamic V4
625
+ config6 with `feeMode: 1` (QuoteOnly), LP fee 0, developer fee 0, and the identical
626
+ typed `ufgLaunchConfig` tail. HMM and ordinary V4 profiles cannot substitute.
627
+ 4. Build policies with `buildUfgFeeAssetPolicies(predictedToken, reserveAssets)`:
628
+ launch-token fees burn; reserve fees fund the treasury after protocol share.
629
+ 5. Call `prepareAndPlanLifecycleLaunch` or `planLaunch` with `account: principal`
630
+ and **`ufg: { config }`**. Every sender/payer/refund recipient stays the principal.
631
+ Approve the **proxy**, not the funding escrow, for non-native inputs.
632
+ 6. Preserve `PlannedLaunch.ufg` and restore the same config on recovery.
633
+ `readLaunchProgress` and `buildNextTransaction`, including cancellation, keep proxy routing.
634
+
635
+ `validateUfgLaunchPlan` checks offline restrictions. `buildUfgApprovals`,
636
+ `buildUfgLaunchTransactions`, and `buildUfgCancelTransaction` build unsigned commands;
637
+ use planner admission before signing. [UFG addresses/codecs](reference.md#deployed-infrastructure)
638
+ and `ufgBlackMarketTreasuryAbi` cover treasury reads, `collect()`, and redemption.
639
+
640
+ `readUfgTreasury(client, token)` returns the treasury address or `undefined`.
641
+ Holders burn tokens for a pro-rata share of **current collected reserves**, less
642
+ exit fee; this is not a guaranteed USD floor. Accrued pool fees are not collected
643
+ backing. Inspect collection failure events as well as receipt success; a fork check
644
+ needed at least 750k gas for `collect()`, not a universal mainnet gas limit.
645
+
646
+ <a id="0100-release-hmm-v2-only"></a>
647
+ ## Configure HMM V2
648
+
649
+ Select `V4HmmFixedPool` or `V4HmmDynamicPool`, with LP/developer fees **0**.
650
+ HMM adds auxiliary strategy liquidity; it cannot withdraw locked launch positions.
651
+ `defaultHmmLaunchConfig` requires explicit bid-principal and reference-price guards:
1149
652
 
1150
- `examples/launch.ts` reviews a saved plan without signatures or source-chain writes:
653
+ ```ts
654
+ import { defaultHmmLaunchConfig, encodeHmmLaunchTail } from "@black-market/sdk";
1151
655
 
1152
- ```sh
1153
- pnpm build
1154
- node examples/launch.ts --plan plan.json --rpc https://rpc.mainnet.chain.robinhood.com/ --mode staged --mine
656
+ const config = defaultHmmLaunchConfig({
657
+ tokenBudget: 500_000n * 10n ** 18n, quoteAsset: "USDG", quoteDecimals: 6,
658
+ maxBidQuote: 100n * 10n ** 6n, referenceDeviation: 0,
659
+ });
660
+ config.strategyShareBps = 2500;
661
+ config.strategy.premiumDecaySeconds = 259200;
662
+ console.log("tail bytes:", (encodeHmmLaunchTail(config).length - 2) / 2);
1155
663
  ```
1156
664
 
1157
- The saved plan must use that RPC's chain and current deployment. `--mine` finalizes bound
1158
- salts offchain; `--limits current-limits.json`, `--receipts receipts.json`, and `--confirmations N`
1159
- supply explicit execution/recovery evidence. The command never invents provider/account limits.
1160
- Without a sequential simulation backend and matching execution-limit provenance, its review
1161
- can be provisional and cannot produce an admitted next transaction.
1162
-
1163
- `examples/launch-lifecycle-smoke.ts manifest.json sdk-plans.json` executes Solidity-exported
1164
- plans only on explicitly authorized owned loopback fixtures. It exercises atomic/staged
1165
- modes, typed predeployment, ordered buys, permanent custody, canonical recovery, no-argument
1166
- V3 harvest, and authenticated author claims. `test/lifecycle-chain.test.mjs` exercises
1167
- real-graph refusals/reorg/cancellation with the same fixture environment. See
1168
- [example instructions](../examples/README.md#actual-owned-fixture-proof) for the explicit
1169
- local-execution opt-in and required files.
1170
-
1171
- ## Individual token creation examples
1172
-
1173
- Eleven independent `examples/launch-erc20-*.ts` / `launch-erc404-*.ts` files invoke
1174
- the shared `runLaunchExample(caseObject)` using valuation-driven economics with no
1175
- required CLI parameters or fixture files. **No mode flag means a dry run**:
1176
- the first output is `DRY RUN — no transactions signed or broadcast.`, followed by
1177
- the full economic review and retained planning artifacts. Successful planning exits
1178
- `0` without constructing a wallet signer, signing, broadcasting, uploading or publishing.
1179
- The final output line is the same case command with `--broadcast` appended:
1180
-
1181
- ```sh
1182
- node examples/launch-erc20-v4.ts
1183
- node examples/launch-erc20-v4.ts --broadcast
1184
- ```
665
+ These 100-USDG/zero-deviation/25% choices illustrate units, not recommended risk
666
+ settings. Put the typed config in config6 `hmmLaunchConfig`; the codec appends its
667
+ **512-byte** tail automatically. The [reference](reference.md#hmm-fields-and-migration)
668
+ lists all 15 strategy fields and the short HMM V1 migration note.
1185
669
 
1186
- **`--broadcast` authorizes full execution and intentionally skips manual
1187
- economic-review admission.** It prints/saves the same review and computed hash,
1188
- plans afresh against current state, then performs guarded signing, broadcast,
1189
- chain verification, image upload and publication. It does not execute the dry run's
1190
- saved plan. Unknown, duplicate or mixed flags fail fast with usage text.
1191
- Optional `--resume <recovery-dir>` continues the original committed launch unchanged,
1192
- without needing `--broadcast`. CLI dry-run/broadcast selection is independent of
1193
- the case's atomic/staged execution mode. The eight original cases remain; the three additions
1194
- (`launch-erc20-multi-quote.ts`, `launch-erc20-depth-v4.ts`, and
1195
- `launch-erc20-dividends-multiquote-mixed.ts`) await user live-run validation before
1196
- any replacement decision. See the [example guide](../examples/README.md#individual-token-creation)
1197
- for all one-line commands and setup-once working-directory `.env`.
1198
- Node 24+ loads `.env` once, with existing process environment taking precedence.
1199
- `LAUNCH_API_URL` and **exactly one** signer source are required before RPC/signing/API
1200
- work: `PRIVATE_KEY`, or `EXAMPLE_KEYSTORE_PATH` for an owner-only local V3
1201
- scrypt/AES-128-CTR JSON keystore. `EXAMPLE_KEYSTORE_PASSWORD` defaults to the empty
1202
- string; both/neither sources reject. The bounded keystore loader authenticates the
1203
- MAC and declared address before deriving the creator. There is no default key,
1204
- guessed metadata API or API-omission mode. Dry runs derive only the public creator
1205
- address (keystore decryption is allowed for this); local signing methods are constructed
1206
- only for broadcast or nonterminal resume execution. Broadcast mainnet writes are
1207
- irreversible. The official chain-4663 RPC is the default.
1208
-
1209
- The implementation imports public `@black-market/sdk`, resolves `getAddresses(4663)`,
1210
- derives the creator from the selected signer and discovers actual admitted profiles.
1211
- V4 requires bound topology/config `6` on a V2-constructor graph; Abyss requires exact
1212
- adapter `profileId(3)` QUOTE_ORACLE/config `1`. WETH verifies wrapped-native
1213
- binding/18 decimals and registered P1 oracle `(1,4096)`. USDG uses 6 decimals,
1214
- the reviewed `usdPeg` USD-X18 seed `1e18`, and a compatible registered oracle
1215
- discovered from pinned factory history/mapping, not an invented WETH oracle ID.
1216
- The eight original cases retain their token/reward/market/position/mode choices:
1217
- ERC20 `1_000_000e18` supply; ERC404 `10_000e18` supply / `100e18` NFT unit; selected
1218
- staking/dividends and token-only burn; one through five positions and ordered buys.
1219
- All cases now fund those buys through native-ETH Kyber conversion. Identity,
1220
- finalized salts and exact plans are saved before execution; refusal never changes
1221
- mode, drops positions/buys or overrides failed admission.
1222
- Pricing uses a USD 5000 target (optional exact `EXAMPLE_TARGET_MARKET_CAP_USD`),
1223
- actual total minted supply, predicted token order and each market's integer budget.
1224
- `deriveLaunchPoolRecipe` owns one-position pricing/liquidity; multi-position markets
1225
- use `deriveLaunchPositionRanges` with exact counts, `positionGaps: "adjacent"` and a
1226
- boundary final tail. Staircase remains the original multi-position default; the
1227
- four-position progressive Depth case uses Early Scarcity with adjacent bands and
1228
- increasing inventory allocations, not the separate historical eight-position
1229
- catalogue. Both venues use spacing 60/LP fee 3000. There is no 1:1 price,
1230
- fixed-liquidity reserve or arbitrary absolute range. All intended supply funds LP
1231
- except explicitly computed rounded-up mint-debit dust, which burns.
1232
-
1233
- Every opening buy defaults to **0.00001 native ETH** (`10000000000000` wei).
1234
- `EXAMPLE_BUY_AMOUNT_WEI` overrides the ETH input per buy, not the eventual quote
1235
- amount. The runner aggregates inputs by quote and obtains one fresh
1236
- `POST /api/v1/quote/kyber/build?chainId=4663` build per quote, using native
1237
- zero-address `tokenIn`, exact input, actual escrow sender/recipient, **50 bps**
1238
- conversion slippage and the same fixed **300-second launch-purpose deadline**
1239
- as the plan. `EXAMPLE_KYBER_API_URL` defaults to `LAUNCH_API_URL`; the app's public
1240
- trade default is `https://api.abyss.trading`, so a different service must be chosen
1241
- explicitly. The API owns route preview; preview GET bytes are not executable funding.
1242
-
1243
- Each row is `LifecycleFundingKind.Swap`, with native zero-address `inputAsset`,
1244
- the reviewed router target and original built calldata. The runner decodes the
1245
- reviewed `swap` entry point and binds currencies, escrow recipient, exact input,
1246
- minimum output, executor payload and flags. The API floor
1247
- `amountOutMinimum = floor(amountOut * 9950 / 10000)` becomes the quote budget;
1248
- ordered buys sharing a quote divide that budget, assigning the integer remainder
1249
- to the last buy. The creator needs native ETH for conversion **plus gas**, not
1250
- WETH/USDG wallet balances or ERC20 approvals. Registry target/spender/code-hash
1251
- admission is checked and rechecked before signatures. Any refusal stops unsigned
1252
- with retained evidence, never a native-wrap/direct-ERC20/separate-wallet-swap
1253
- fallback, route retry or rewritten deadline.
1254
-
1255
- Optional `EXAMPLE_TOKEN_NAME`, `EXAMPLE_TOKEN_SYMBOL` and
1256
- `EXAMPLE_TOKEN_DESCRIPTION` override each case's defaults while retaining the
1257
- existing normalized text and API/lifecycle length limits. Optional
1258
- `EXAMPLE_IMAGE_PATH` supplies actual PNG/JPEG/WebP artwork, bounded to 1 byte
1259
- through 5 MiB. Its exact SHA-256/content-type/length is part of the reviewed,
1260
- signed attribution; the runner follows the API-issued upload and completion flow.
1261
- Without that option, metadata-only sessions still require `image: null`.
1262
-
1263
- The indicative WETH USD seed comes only from the configured `LAUNCH_API_URL` token-prices
1264
- API: one uncached GET `/api/v1/token-prices?chainId=4663&limit=100`, with a 30-second
1265
- timeout, 1 MiB streamed body limit and no pagination, redirects or retries. The
1266
- reviewed WETH row must have chain 4663, ready metadata, 18 decimals, `priced: true`,
1267
- anchor source and direct WETH/Chainlink provenance with aggregator
1268
- `0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9`. Price parsing requires an exact positive
1269
- uint256 decimal `priceUsdX18`. Missing, unpriced, mismatched or unavailable data
1270
- rejects without a manual or alternate-source fallback. API publication supplies
1271
- an indicative launch valuation, not executable swap, receipt or chain authority.
1272
- API origin, index/graph blocks, upstream timestamp/age and local retrieval time are
1273
- preserved and displayed; retrieval does not refresh the upstream observation.
1274
- There is no 15-minute contract-round gate or API-block canonicality requirement.
1275
- Public `economic-review.json` and exact private recovery precede the first signature.
1276
- Review includes quote/source/time, target, actual minted supply, exact price
1277
- orientation, all allocations/liquidity/fees,
1278
- expected retained supply and aligned opening valuations. The final admitted
1279
- activation simulation supplies each ordered buy's quote spent/token output,
1280
- all-in average USD/token and fee-plus-price-impact premium. This is not a claim
1281
- of simulated final marginal spot. Alignment and buys mean the eventual valuation
1282
- need not equal USD 5000; use actual retained supply and observed post-buy price.
1283
-
1284
- The computed review hash is provenance evidence, never an authorization input:
1285
- there is no interactive prompt or environment hash gate. `--broadcast` alone is
1286
- the explicit mode authorization, recorded in `economic-admission.json` as
1287
- `authorization: "--broadcast"` with the computed hash; this artifact is not another gate.
1288
- Before each attribution/transaction signature, the immutable review hash, saved
1289
- plan/supply/order/target and fresh RPC token prediction are rechecked, then the same
1290
- API source is reread. A changed exact price, API origin, chain, WETH/decimals or
1291
- direct-anchor identity/kind/source rejects without rewriting intent. Failed or
1292
- unpriced reads reject. Index/graph and observation/retrieval times may advance for
1293
- an unchanged exact price and source, without replacing the original review.
1294
- RPC still owns provider chain, balances, nonce, deadlines and native execution
1295
- proof. The saved deadline is checked again after asynchronous quote/authority
1296
- reads and before signatures/staging; expiry stops without extending it.
1297
- Partial execution never grants permission to replay or silently adopt different economics.
1298
- The current 0.7.1 V4 examples require the config6/V2 profile, freezing max `10000`,
1299
- min `1000` pips and sensitivity `7654321` fee-pips × seconds/tick. Its reviewed
1300
- `FixedFeePoolHookV1` charges the fixed maximum `10000` pips (1%) on applicable amounts;
1301
- minimum and sensitivity are stored constructor evidence, not a dynamic fee schedule.
1302
- Optional `NFT_BASE_URI` provides an ERC404 base URI you actually host; its default is
1303
- empty, with real NFT units/mirror behavior but no claim of hosted NFT metadata.
1304
-
1305
- The chain-4663 examples require native sequential Nitro `eth_simulateV1`; generic
1306
- Anvil/Hardhat simulation is not an ArbOS compute/poster proof. Source RPC requests
1307
- have a 120-second bound and are not retried. There are no invented default gas or
1308
- calldata caps. Explicit environment restrictions only tighten the complete envelope;
1309
- headroom defaults to 1,500 bps. SDK native pinned compute/poster reads and exact replay
1310
- remain mandatory, and build-next uses the same source RPC as the read-only submission
1311
- preflight before each local signature. Environment options are documented in the example guide.
1312
-
1313
- Execution rechecks chain/creator/destination and exact finalized calldata before each
1314
- send. Exact admitted envelopes are signed locally; computed hashes and unsigned
1315
- envelopes are saved **before** the single raw broadcast, and included receipts are
1316
- saved before status/provenance assertions. One canonical confirmation is required.
1317
- Actual verification covers Active state, factory/token runtime/name/symbol/kind/rewards,
1318
- ERC404 unit/URI/mirror, opened markets, sealed V4 custody/permanent Abyss lock terms,
1319
- fee policies and ordered activation buys.
1320
-
1321
- Actual SDK API metadata staging uses locally signed full-domain attribution.
1322
- Before **every** publication attempt and before final success, a fresh canonical
1323
- RPC barrier binds the original activation hash/receipt to the saved commitment
1324
- and Active state; a different later activation observation cannot replace it.
1325
- Only that original hash is published. Genuine pending-indexer HTTP `202` is
1326
- polled within 90 seconds respecting `Retry-After`; other failures are not retried.
1327
- Success requires an optimistic/final session and real indexed
1328
- `/api/v1/launches/<token>?chainId=4663` DTO with matching creator/token/hash/metadata.
1329
- Missing/incompatible indexing fails without manufacturing projections, skipping
1330
- API or launching another token.
1331
-
1332
- When `EXAMPLE_IMAGE_PATH` is set, metadata staging alone is insufficient:
1333
-
1334
- 1. The completed session must show the exact signed SHA-256/content-type/length
1335
- and a ready image.
1336
- 2. Publication must retain that descriptor and reference a ready public image.
1337
- 3. The indexed token must carry a non-null matching `imageUrl`, with matching
1338
- metadata type/length and a token-bound `imageKey`.
1339
- 4. One bounded, no-redirect GET of that URL must return **HTTP 200**, an image
1340
- content-type family and nonempty bytes. Byte-identical output must match the
1341
- upload's exact SHA-256/type/length. Different served bytes are recorded as an
1342
- inferred API/CDN transformation, proving only the image-family/nonempty-body
1343
- check, not byte identity. The canonical RPC barrier runs again after this GET.
1344
-
1345
- Any failed binding, HTTP/type/size/body check exits nonzero with retained evidence;
1346
- there is no image retry or metadata-only fallback. Without an image path, the
1347
- metadata-only null-image behavior remains.
1348
-
1349
- Every dry run or broadcast automatically creates fresh `launch-results/<timestamp-case-random>/`;
1350
- `--resume` appends recovery evidence in the original directory. Dry runs retain
1351
- all planning/review/recovery artifacts, but no admission, signed bytes, API session
1352
- or publication artifacts:
1353
-
1354
- | Artifact | Evidence |
1355
- | --- | --- |
1356
- | `events.jsonl` | Timestamped case/stage events, RPC/API errors, admission/simulation and actual chain observations. |
1357
- | `plan.json` | Redacted finalized plan for public inspection, not exact recovery authority. |
1358
- | `economic-review.json` | Public exact quotes, native Kyber inputs/calldata/minima/deadline, metadata/image descriptors, target, aligned minted/retained valuation, position budgets/debits/dust, fees, protected buys and simulated all-in execution prices; redacted, not recovery authority. |
1359
- | `economic-admission.json` | Broadcast-only mode authorization (`authorization: "--broadcast"`) and computed review hash as provenance, not supplied-hash admission. |
1360
- | `receipts.json` | Empty for a dry run; execution retains exact signed-envelope hashes pre-broadcast, followed by real receipts/references. |
1361
- | `result.json` | `black-market.launch-example-result.v1`, runMode, scope, status, failure stage and causal evidence. A successful dry run has `scope: "planning"` and `execution: "dry-run"`; it does not claim chain/API completion. |
1362
- | `published-token.json` | Actual indexed API representation. |
1363
- | `published-image.json` | Optional bounded public-image HTTP/type/length/SHA-256 verification, transformation qualification or failure evidence. |
1364
- | `private-recovery.json` | Mode `0600`; complete exact finalized `plan`, original `mode`/`confirmations` and immutable economic review/hash saved during planning. Broadcast adds immutable mode authorization/hash provenance, signed raw bytes, API signature and one-time capability retained across updates. Never share/commit. |
1365
-
1366
- Public artifacts preserve structured field names and redact sensitive values:
1367
- known keys/signatures/raw bytes/capabilities/auth values and endpoint secrets,
1368
- while retaining public calldata/hashes/revert bytes. `node examples/<case>.ts
1369
- --resume <recovery-dir>` reloads the owner-only exact plan, retained economic authorization
1370
- provenance, original mode/confirmations/restrictions and typed original inclusion references.
1371
- Fresh `planLaunch` (never preparation/mining) re-admits that commitment.
1372
- Canonical Preparing/Ready runs only the remaining build-next sequence; canonical
1373
- Active recovers the retained activation receipt and performs verification and
1374
- publication only. Missing/unconfirmed, moved/reorged or replaced receipt evidence
1375
- and unresolved signed hashes stop for read-only reconciliation, never replay.
1376
- The API session is refreshed while retaining its one-time capability. A pending
1377
- image requires the original `EXAMPLE_IMAGE_PATH` bytes and signed SHA-256/type/length;
1378
- only expired PUT responses (403/410/412) permit one upload-URL renewal/retry.
1379
- Existing chain verification and every publication canonicality barrier remain required.
1380
- Never reload redacted `plan.json` as the commitment. See
1381
- [recovery instructions](../examples/README.md#evidence-and-failure-recovery).
1382
- Configuration, admission, broadcast, publication and interruption failures exit
1383
- nonzero and preserve evidence. No source rollback, cancellation, broadcast retry or
1384
- relaunch occurs.
1385
- Inspect retained transaction hashes before deciding to run a new case after an
1386
- ambiguous send. `test/launch-example.test.mjs`, `test/launch-example-matrix.test.mjs`,
1387
- `test/launch-example-mode.test.mjs` and `test/launch-example-resume.test.mjs` cover offline
1388
- financial bounds, funding/rounding, quote/admission, signing/retention/config, default
1389
- dry-run/no-signing/banner/command, broadcast routing and resume boundaries,
1390
- not actual chain/API proof. The older independent whole-graph local
1391
- Solidity-exported proof remains separate.
1392
-
1393
- ## Real HTTP API integration
1394
-
1395
- The opt-in suites use `LaunchApiClient` and actual HTTP requests—not a mocked transport.
1396
- They do not start a service or provision storage. Configure an abyss-api service with:
1397
-
1398
- - `/api/v1/launch-upload-sessions` and its capability-protected read route;
1399
- - real application PostgreSQL storage with launch-upload-session migrations applied;
1400
- - an enabled request chain matching `LAUNCH_API_TEST_CHAIN_ID`;
1401
- - its current launch verifying contract matching `LAUNCH_API_TEST_ORCHESTRATOR`.
1402
-
1403
- For the actual abyss-api service, that verifying contract is the configured deployment
1404
- `contracts.launchFactory` field, which must contain the current orchestrator address.
1405
- The signed attribution domain is `Abyss Launch Attribution`, version `1`. Session signature
1406
- deadlines must be future timestamps at most 15 minutes away. Metadata hashes use canonical
1407
- NFC/trimmed text, normalized URLs, fixed field order, and null absent optional values.
1408
-
1409
- | Environment | Meaning |
1410
- | --- | --- |
1411
- | `LAUNCH_API_TEST_URL` | Required HTTP service root, e.g. `http://127.0.0.1:18763`; no implicit production target. |
1412
- | `LAUNCH_API_TEST_CHAIN_ID` | Defaults to `4663`; must be configured on the test service. |
1413
- | `LAUNCH_API_TEST_ORCHESTRATOR` | Defaults to `getAddresses(4663).launchOrchestrator` (October8 mined graph); must match the service's signing domain. |
1414
- | `LAUNCH_API_TEST_PRIVATE_KEY` | Required only for the explicit signed suite; disposable EOA key, never a production key. |
1415
-
1416
- ```sh
1417
- # Read-only capability/error boundaries; no key and no storage writes.
1418
- LAUNCH_API_TEST_URL=http://127.0.0.1:18763 pnpm test:api
1419
-
1420
- # Signed metadata-session writes, allowed only on an owned disposable loopback service.
1421
- LAUNCH_API_TEST_URL=http://127.0.0.1:18763 \
1422
- LAUNCH_API_TEST_PRIVATE_KEY="$DISPOSABLE_TEST_PRIVATE_KEY" pnpm test:api:write
1423
- ```
670
+ ### V2 fee funding and owner controls
1424
671
 
1425
- The write suite creates metadata-only sessions, reads persisted normalized metadata,
1426
- replays the byte-identical signed body without reissuing the one-time capability, refuses a
1427
- changed authorized payload under the same idempotency key, and checks capability isolation.
1428
- It also rejects wrong signers, wrong orchestrator/chain domains, altered metadata, a changed
1429
- idempotency key, expired authorization, and invalid signatures. The private key signs EIP-712
1430
- metadata only; it need not have a balance. Unique session/key/nonces permit repeat runs.
1431
- The disposable service operator owns database cleanup; the API has no session-deletion route.
1432
-
1433
- Neither suite needs an image store, indexed launch, confirmed transaction hash, or chain
1434
- write. Metadata sessions do not prove token deployment, image publication, or transaction
1435
- indexing. Image/upload/publication operations require those additional real prerequisites
1436
- and are not exercised here. Explicitly selected suites fail on missing URL/key, absent
1437
- storage/routes, an unreachable service, or incompatible signing configuration instead of
1438
- silently skipping. Ordinary `pnpm test` stays offline and does not select HTTP integration.
672
+ HMM V2 reserves its strategy share **on each swap in both currencies, after protocol
673
+ treasury share**. The remainder follows normal fee-hub distribution. HMM does not
674
+ burn strategy fees. Funded bids and maintenance events do not prove fills or profit.
675
+
676
+ Use `hmmFeeCollectorV2Abi` to read `strategyOwner()` / `liquidityManager()` and call
677
+ `setStrategyShareBps(0..10000)` as the current fee owner. Use
678
+ `hmmLiquidityManagerV2Abi` for `strategyConfig()`, `setStrategyConfig(...)`,
679
+ `placementsPaused()`, and `setPlacementsPaused(bool)`. Pausing stops new placements
680
+ and queues auxiliary withdrawal on maintenance, not trading or fee collection.
681
+ Lower intake caps do not liquidate existing lots; premium changes affect new lots.
682
+
683
+ For reference tick `R`, deviation `D`, and spacing `S`, ask lower is at least
684
+ `R - D*S`; bid upper is at most `R + D*S`, with grid rounding. A wider deviation
685
+ permits placements farther from the truncated oracle reference but weakens its
686
+ price bound. Choose guards against the actual pool; there is no universal safe setting.