@black-market/sdk 0.12.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.
- package/README.md +96 -96
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +59 -24
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/progress.d.ts +3 -1
- package/dist/lifecycle/progress.d.ts.map +1 -1
- package/dist/lifecycle/progress.js +120 -55
- package/dist/lifecycle/progress.js.map +1 -1
- package/dist/lifecycle/rpc.d.ts +8 -2
- package/dist/lifecycle/rpc.d.ts.map +1 -1
- package/dist/lifecycle/rpc.js +165 -9
- package/dist/lifecycle/rpc.js.map +1 -1
- package/dist/lifecycle/simulation.d.ts +1 -1
- package/dist/lifecycle/simulation.d.ts.map +1 -1
- package/dist/lifecycle/simulation.js +11 -10
- package/dist/lifecycle/simulation.js.map +1 -1
- package/dist/lifecycle/types.d.ts +12 -0
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/docs/launch-lifecycle.md +605 -1495
- package/docs/reference.md +332 -0
- package/examples/.env.example +3 -2
- package/examples/README.md +171 -552
- package/examples/launch-example-support.ts +11 -3
- package/examples/launch-example.ts +1 -1
- package/examples/launch-lifecycle-smoke.ts +1 -1
- package/package.json +1 -1
- package/src/lifecycle/planner.ts +58 -23
- package/src/lifecycle/progress.ts +110 -47
- package/src/lifecycle/rpc.ts +158 -10
- package/src/lifecycle/simulation.ts +11 -9
- package/src/lifecycle/types.ts +9 -1
package/docs/launch-lifecycle.md
CHANGED
|
@@ -1,1576 +1,686 @@
|
|
|
1
|
-
# Launch
|
|
1
|
+
# Launch a token with the TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
|
4
7
|
|
|
5
|
-
|
|
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**.
|
|
8
|
+
## Choose an offering
|
|
9
9
|
|
|
10
|
-
|
|
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.
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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. |
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| `UFG_TREASURY_FACTORY_ADDRESS` | `0x26Aa5D52134c8E6c4C01E9fb53A7568c0C64901F` |
|
|
20
|
-
| `UFG_UPSTREAM_FACTORY_ADDRESS` | `0xA170b5A58C111334A7237F2Ea2c428ec5022f68E` |
|
|
21
|
-
| `UFG_ORCHESTRATOR_ADDRESS` | `0x91560876033d568d25CDe98C78c33ff8FC43962c` |
|
|
22
|
-
|
|
23
|
-
`KnownLifecycleProfile.V4UfgFixedPool` (`v4-ufg-fixed-pool`) selects profile
|
|
24
|
-
`0x5c6045af480814e469f3dba7c120d264047c9320b869c63a064536041a2dbae6`;
|
|
25
|
-
`V4UfgDynamicPool` (`v4-ufg-dynamic-pool`) selects
|
|
26
|
-
`0x03de8d5e38f2957d80ecb9f2e59d555601ff091dfb17bce84178956a2e8d9b41`.
|
|
27
|
-
`isUfgProfile` recognizes only these IDs. Frozen envelopes, adapter/registration/
|
|
28
|
-
topology and bound-hook metadata come from committed registry readback at block
|
|
29
|
-
**94,551,140** (`test/fixtures/ufg-registry-readback.json`). Regenerate with
|
|
30
|
-
`node --experimental-transform-types scripts/generate-ufg-presets.mjs /path/to/black-market`;
|
|
31
|
-
add `--readback` only to recapture that exact block with read-only RPC.
|
|
32
|
-
The fixed and zero-royalty dynamic creation bytes exactly match the existing
|
|
33
|
-
`FixedFeePoolV1` / `DynamicFeePoolV1` artifacts, so no duplicate hook enum is needed.
|
|
34
|
-
UFG deployers, lockers, collectors and adapters are nevertheless different graphs.
|
|
35
|
-
Frozen presets are construction evidence, not live admission.
|
|
36
|
-
|
|
37
|
-
### Configuration and supported markets
|
|
38
|
-
|
|
39
|
-
`UfgLaunchConfig` is `{ treasuryShareBps, exitFeeBps, reserveAssets }`. The proxy
|
|
40
|
-
requires treasury share **10000**, integer exit fee **0..2000 bps**, and **1..7**
|
|
41
|
-
nonzero, unique, strictly ascending reserve addresses, excluding the predicted
|
|
42
|
-
launch token. Reserves and market quotes must form exactly the same set.
|
|
43
|
-
|
|
44
|
-
- ERC20 only, no staking/dividends, zero executor fee and at least one market.
|
|
45
|
-
Neither inventory nor initial-buy recipients may be the proxy.
|
|
46
|
-
- Native Abyss uses the canonical adapter with config1 profile **2 (QUOTE)** or
|
|
47
|
-
**3 (QUOTE_ORACLE)** and the matching canonical profile ID. Its canonical
|
|
48
|
-
config has **no tail**.
|
|
49
|
-
- V4 uses config6 and one of the two UFG profiles, `feeMode: 1` (QuoteOnly) and
|
|
50
|
-
`lpFeePips: 0`. Preset zero-royalty terms still apply. Supply/position budgets,
|
|
51
|
-
price/ranges, oracle registration and ordinary lifecycle bounds are unchanged.
|
|
52
|
-
- Fee policies contain exactly the token plus reserves in ascending order:
|
|
53
|
-
token `{ ownerBps: 0, rewardsBps: 0, burnBps: 10000 }`, reserves
|
|
54
|
-
`{ ownerBps: 10000, rewardsBps: 0, burnBps: 0 }`.
|
|
55
|
-
`buildUfgFeeAssetPolicies(predictedToken, reserveAssets)` builds that exact set;
|
|
56
|
-
reserve ordering is validated, never silently repaired.
|
|
57
|
-
|
|
58
|
-
`encodeUfgLaunchConfig` encodes **one dynamic tuple**:
|
|
59
|
-
`abi.encode((uint16,uint16,address[]))`, including the leading `0x20` offset.
|
|
60
|
-
`decodeUfgLaunchConfig` checks canonical re-encoding; trailing bytes, alternate
|
|
61
|
-
offsets and dirty padding are rejected. `hashUfgLaunchConfig` is its keccak256.
|
|
62
|
-
Config6's typed `ufgLaunchConfig` automatically appends that encoding after the
|
|
63
|
-
canonical V6 prefix and decodes/splits it on read. Every UFG V4 tail must equal
|
|
64
|
-
the proxy config. The constructor economics hash remains **prefix-only with zero
|
|
65
|
-
hook salt**; the full plan hash binds the tail. No UFG tail is added to ordinary
|
|
66
|
-
V4, HMM or Abyss configs. Independent `cast abi-encode` fixtures are regenerated
|
|
67
|
-
with `node scripts/generate-ufg-fixtures.mjs`.
|
|
68
|
-
|
|
69
|
-
### Principal funding, planning and recovery
|
|
70
|
-
|
|
71
|
-
The economic plan's **creator is the proxy**. Its nonce is
|
|
72
|
-
`ufgLaunchNonce(principal, nonce96) = (uint160(principal) << 96) | nonce96`.
|
|
73
|
-
The `account` and every sender are the **same principal**, never the proxy.
|
|
74
|
-
The core still derives launch ID/token from the committed core/proxy/nonce.
|
|
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:
|
|
75
25
|
|
|
76
26
|
```ts
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
const token = await client.readContract({ address: plan.orchestrator,
|
|
86
|
-
abi: launchLifecycleAbi, functionName: "predictToken", args: [plan] });
|
|
87
|
-
plan.feeAssets = buildUfgFeeAssetPolicies(token, config.reserveAssets);
|
|
88
|
-
validateUfgLaunchPlan(plan, config, token); // pure/offline proxy rules
|
|
89
|
-
const planned = await prepareAndPlanLifecycleLaunch({
|
|
90
|
-
client, account: principal, plan, mode: "staged", ufg: { config },
|
|
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,
|
|
91
35
|
});
|
|
92
|
-
|
|
93
|
-
|
|
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
|
+
})));
|
|
94
40
|
```
|
|
95
41
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Salt mining and optional buy-minimum calibration use the existing machinery.
|
|
101
|
-
Native Nitro metering/execution proofs remain mandatory on production chain4663.
|
|
102
|
-
|
|
103
|
-
The proxy pulls summed non-native inputs from the principal: ERC20 asset/amount
|
|
104
|
-
or swap inputAsset/inputAmount. **Approve the proxy, not the funding escrow**.
|
|
105
|
-
`buildUfgApprovals(plan)` builds exact summed approvals; planning observes current
|
|
106
|
-
allowances and includes zero-reset commands when needed. Native-wrap and native
|
|
107
|
-
swap inputs are `msg.value` on atomic/begin only. Refunds return to the principal.
|
|
108
|
-
|
|
109
|
-
Pure `buildUfgLaunchTransactions({ plan, config, mode, preparationBatches })`
|
|
110
|
-
produces proxy `launchAtomic(plan, config)`, or `beginLaunch(plan, Staged, config)`,
|
|
111
|
-
ordered `prepareMarkets` batches, then `activateLaunch`. The explicit batches
|
|
112
|
-
must cover all markets. `buildUfgCancelTransaction({ plan, preparedMarkets })`
|
|
113
|
-
targets the same proxy. These builders alone do not establish execution admission.
|
|
114
|
-
`validateUfgLaunchPlan` checks offline proxy rules; live registry continuity,
|
|
115
|
-
reserve/token code and supply bounds, transfers and treasury creation require RPC
|
|
116
|
-
simulation. The existing non-UFG core transaction builder is intentionally unchanged.
|
|
117
|
-
|
|
118
|
-
`readUfgTreasury(client, token)` reads the treasury factory's `treasuryOf(token)`
|
|
119
|
-
and returns the upstream address, or `undefined` for zero. Complete
|
|
120
|
-
`ufgLaunchProxyV1Abi`, `ufgTreasuryFactoryV1Abi`, `ufgBlackMarketFactoryAbi` and
|
|
121
|
-
`ufgBlackMarketTreasuryAbi` expose proxy config hashes and upstream treasury
|
|
122
|
-
collect/redeem/assets/backing/position/debt operations without inventing wrappers.
|
|
123
|
-
The pure example is `node examples/ufg-launch-config.ts` after building.
|
|
124
|
-
|
|
125
|
-
### UFG owned-fork check
|
|
126
|
-
|
|
127
|
-
This explicitly authorized local-only integration uses the unlocked Anvil default
|
|
128
|
-
account, no keys, and only public SDK launch APIs. In separate terminals:
|
|
129
|
-
|
|
130
|
-
```sh
|
|
131
|
-
anvil --fork-url https://rpc.mainnet.chain.robinhood.com/ \
|
|
132
|
-
--chain-id 4663 --port 8561 \
|
|
133
|
-
--gas-limit 100000000 --silent
|
|
134
|
-
pnpm build
|
|
135
|
-
UFG_FORK_RPC_URL=http://127.0.0.1:8561 node test/integration/ufg-launch.fork.mjs
|
|
136
|
-
```
|
|
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.
|
|
137
46
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
command from the principal first, then checks Active, a nonzero `readUfgTreasury`
|
|
142
|
-
and `proxy.launchConfigHash == hashUfgLaunchConfig`. Snapshot restoration makes
|
|
143
|
-
the check repeatable. Stop Anvil afterward. Generic Anvil proves EVM contract
|
|
144
|
-
behavior here, **not ArbOS compute/poster admission**: construction/read/mining/
|
|
145
|
-
unsigned APIs plus actual fork `eth_call`/receipts are used, not a fake native
|
|
146
|
-
Nitro planner certificate. Ordinary `pnpm test` never runs this funded check.
|
|
147
|
-
|
|
148
|
-
## 0.11.0 release: gas sizing, packing and prefix proof
|
|
149
|
-
|
|
150
|
-
New atomic/activation envelopes containing HMM V2 markets add one forwarding target:
|
|
151
|
-
`R = 4_250_000 + 500_000 * (hmmMarkets - 1)` gas (zero for non-HMM plans).
|
|
152
|
-
For measured gross gas `G` (`maxUsedGas`, falling back to `gasUsed`), compute is
|
|
153
|
-
`min(max(G + R, ceil(G * (10000 + headroomBps) / 10000)), computeCap)`.
|
|
154
|
-
Begin/preparation/approval/cancel commands do not receive this reserve. Nitro poster
|
|
155
|
-
gas is budgeted separately inside the same complete gas envelope. Optional padding
|
|
156
|
-
and the reserve are targets, not refusal thresholds; exact validated replay proves
|
|
157
|
-
the clamped envelope. There is no bisection or extra ordinary-path request.
|
|
158
|
-
|
|
159
|
-
Staged planning greedily packs contiguous markets against the unpadded compute cap:
|
|
160
|
-
HMM V2 costs 14.5M per market; other profiles cost a conservative 16M. At 32M,
|
|
161
|
-
1/2/3/5 HMM markets produce `[1]`/`[2]`/`[2,1]`/`[2,2,1]`.
|
|
162
|
-
Only a packed measurement failure consuming at least 95% of its given gas splits
|
|
163
|
-
that batch in half, regardless of its error selector. Low-gas semantic failures
|
|
164
|
-
remain failures. `preparationBatchSize` is removed; inspect each preparation's
|
|
165
|
-
`marketStart`/`marketCount`. The pure unsigned compiler still accepts explicit
|
|
166
|
-
`preparationBatches`.
|
|
167
|
-
|
|
168
|
-
Robinhood chain 4663 defaults `limits.maxSimulationGas` to **50_000_000n** aggregate
|
|
169
|
-
gas **used**, not the sum of individual legal transaction envelopes. Override it
|
|
170
|
-
for a provider with a different budget. The SDK measures and validates the longest
|
|
171
|
-
estimated prefix that fits: begin 9.5M, preparations as above, activation 6M per
|
|
172
|
-
market plus `R`, and small approvals/cancellation. A measurement failure after
|
|
173
|
-
cumulative use reaches 95% of that cap defers the failed call and suffix.
|
|
174
|
-
If even the immediate estimate cannot fit that budget, refusal first identifies
|
|
175
|
-
any estimated per-transaction compute overflow (gas displayed in millions to one
|
|
176
|
-
decimal), rather than suggesting that a larger RPC budget solves it. Estimates
|
|
177
|
-
alone do not reject an envelope that can still be measured and exactly proved.
|
|
178
|
-
|
|
179
|
-
`simulation.admitted`, `executionProof: "proved"` and `protocolFit: "proved"` cover
|
|
180
|
-
only the successful proven prefix. **They do not promise eventual activation.**
|
|
181
|
-
`simulation.deferredTransactionIds` explicitly lists unproved remaining steps
|
|
182
|
-
(empty for full coverage); these commands carry no `gas`, `gasPrice`, `estimate`
|
|
183
|
-
or `admission`. Call `buildNextTransaction` before each signature: canonical
|
|
184
|
-
progress advances the proof window and gives the immediate next transaction exact
|
|
185
|
-
gas. Reviewed envelopes receive only a direct exact replay of that immediate step,
|
|
186
|
-
without new measurement, poster/price recommendations or suffix proof.
|
|
187
|
-
|
|
188
|
-
`buySlippageBps` requires actual activation outputs. If activation is deferred,
|
|
189
|
-
calibration refuses clearly; use a higher-budget native provider or preserve
|
|
190
|
-
already committed minima by omitting recalibration. Outputs are never fabricated.
|
|
191
|
-
|
|
192
|
-
## 0.9.1 release: Abyss 0.01% fee tier
|
|
193
|
-
|
|
194
|
-
`ABYSS_FEE_TIERS` now includes `{ feePips: 100, tickSpacing: 1, label: "0.01%" }`.
|
|
195
|
-
Pass `fee: 100` to `deriveLaunchPoolRecipe` to derive spacing-one geometry without
|
|
196
|
-
an explicit spacing override. Use `tickSpacing: 1` when passing that recipe to
|
|
197
|
-
`deriveLaunchPositionRanges`; the permanent boundary tail reaches tick `887272`
|
|
198
|
-
for launch token0 or `-887272` for launch token1. Abyss config1 lifecycle planning
|
|
199
|
-
derives this spacing from the canonical catalog automatically.
|
|
200
|
-
|
|
201
|
-
The Robinhood chain 4663 factory has enabled fee 100 with spacing 1. Other
|
|
202
|
-
deployments must enable the tier before execution; local recipe construction is
|
|
203
|
-
not evidence of live profile admission. Existing tiers and defaults are unchanged.
|
|
204
|
-
|
|
205
|
-
## 0.10.0 release: HMM V2 only
|
|
206
|
-
|
|
207
|
-
The admitted October17 **HMM Fixed V2** and **HMM Dynamic V2** replace the SDK's
|
|
208
|
-
earlier HMM offerings. Generic keys `KnownLifecycleProfile.V4HmmFixedPool`
|
|
209
|
-
(`v4-hmm-fixed-pool`) and `V4HmmDynamicPool` (`v4-hmm-dynamic-pool`) now select V2.
|
|
210
|
-
Versioned hook keys are `KnownLifecycleHook.HmmFixedPoolV2` / `HmmDynamicPoolV2`.
|
|
211
|
-
These are not aliases for the non-HMM fixed/dynamic hooks; those APIs are unchanged.
|
|
212
|
-
|
|
213
|
-
| Preset | Admitted V2 profile ID |
|
|
214
|
-
| --- | --- |
|
|
215
|
-
| HMM Fixed V2 (`hooks/hmm-fixed-v2`) | `0x45e957bcc7068350a65f5b4de5453b674d54d0f5eb2a88fc839da13197e80e98` |
|
|
216
|
-
| HMM Dynamic V2 (`hooks/hmm-dynamic-v2`) | `0x8e500f203ace505072e209c5f077e11de6d071ac7f298cd75c0e05c6a55c36e6` |
|
|
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.
|
|
217
50
|
|
|
218
|
-
|
|
219
|
-
fixtures preserve the V2 release and pinned registry readback at block 91,874,655.
|
|
220
|
-
Each graph has its own collector/deployer, locker and hook deployer. Presets are
|
|
221
|
-
construction data, not a current admission certificate: live
|
|
222
|
-
`readLifecycleProfiles` and execution proof remain authoritative.
|
|
51
|
+
## Price the launch
|
|
223
52
|
|
|
224
|
-
|
|
225
|
-
as its static fee; Dynamic uses config6 minimum/maximum/sensitivity policy.
|
|
226
|
-
Config6 requires a typed `hmmLaunchConfig`:
|
|
53
|
+
Choose supply and a whole-supply opening valuation (FDV):
|
|
227
54
|
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
// Illustrative caller choices, not SDK risk defaults:
|
|
232
|
-
maxBidQuote: 100n * 10n ** 6n, // maximum 100 USDG of new/refreshed bid principal
|
|
233
|
-
referenceDeviation: 0, // do not ask below or bid above the rounded reference
|
|
234
|
-
});
|
|
235
|
-
hmmLaunchConfig.strategyShareBps = 2500; // optional 25%; existing default is 50%
|
|
236
|
-
hmmLaunchConfig.strategy.premiumDecaySeconds = 259200; // optional 72h; default off
|
|
237
|
-
const config = encodePoolBoundV4LifecycleMarketConfig({
|
|
238
|
-
...reviewedV6Fields, lpFeePips: 0, developerFeeBps: 0, hmmLaunchConfig,
|
|
239
|
-
});
|
|
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
|
|
240
58
|
```
|
|
241
59
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
Mining and recovery preserve the typed tail. The full launch-plan hash binds
|
|
248
|
-
every tail byte, including both new guards.
|
|
249
|
-
|
|
250
|
-
The hook constructor is still **one 20-word / 640-byte
|
|
251
|
-
`PoolBoundHookParametersV2` tuple**. Do not append the HMM tail to creation code.
|
|
252
|
-
The collector factory hashes only the canonical config6 prefix with zero hook
|
|
253
|
-
salt for the hook's market-economics commitment; the auxiliary strategy settings
|
|
254
|
-
are handed to the manager through the collector. Changing those settings changes
|
|
255
|
-
the full plan commitment, but not the hook constructor's prefix-only commitment.
|
|
256
|
-
|
|
257
|
-
`validateHmmLaunchConfig` enforces the factory's exact launch guards and Solidity
|
|
258
|
-
field widths. Share is 0..10,000 bps. All 15 strategy fields are listed in wire order:
|
|
259
|
-
|
|
260
|
-
| Field | Unit and accepted launch values |
|
|
261
|
-
| --- | --- |
|
|
262
|
-
| `bidWidth` | Tick spacings; positive int24 |
|
|
263
|
-
| `askWidth` | Tick spacings; positive int24 |
|
|
264
|
-
| `gap` | Tick spacings; nonnegative int24 |
|
|
265
|
-
| `staleAfterSeconds` | Positive uint32 seconds |
|
|
266
|
-
| `staleDisplacement` | Tick spacings; positive int24 |
|
|
267
|
-
| `minQuoteDeploy` | Raw quote units; any uint256, including zero |
|
|
268
|
-
| `minQuoteHarvest` | Raw quote units; positive uint256 |
|
|
269
|
-
| `minTokenHarvest` | Raw launch-token units; positive, covered by both token caps |
|
|
270
|
-
| `resalePremiumBps` | 0..5,000 bps |
|
|
271
|
-
| `maxAsks` | 1..8 |
|
|
272
|
-
| `maxAskTokenExposure` | Raw launch-token units; at least ask count and minimum token harvest, at most uint128 max |
|
|
273
|
-
| `maxAcquiredInventory` | Raw launch-token units; at least minimum token harvest, at most uint128 max |
|
|
274
|
-
| `premiumDecaySeconds` | Any uint32 seconds; zero disables decay |
|
|
275
|
-
| `maxBidQuote` | Raw quote-principal ceiling for new/refreshed bids; positive and at most uint128 max |
|
|
276
|
-
| `referenceDeviation` | Tick spacings; nonnegative int24 |
|
|
277
|
-
|
|
278
|
-
For reference pool tick `R`, deviation `D` and spacing `S`, ask lower is at least
|
|
279
|
-
`R - D*S` and bid upper is at most `R + D*S`, with side-appropriate grid rounding.
|
|
280
|
-
The reference comes from the hook's truncated oracle, not an independent spot
|
|
281
|
-
price supplied by the caller.
|
|
282
|
-
|
|
283
|
-
The default helper **requires explicit `maxBidQuote` and `referenceDeviation`**;
|
|
284
|
-
neither has a guessed risk default. All other defaults are preserved: 50% share,
|
|
285
|
-
widths 5/5, gap 1, stale 86,400 seconds/displacement 5, premium 500 bps, 4 asks,
|
|
286
|
-
decay off. Token thresholds are raw market-budget ratios: harvest budget/100,000,
|
|
287
|
-
ask exposure budget/10, inventory budget. Too-small budgets producing zero harvest
|
|
288
|
-
and budgets above uint128 are rejected. WETH quote deploy/harvest thresholds remain
|
|
289
|
-
0.0005/0.005 ETH; USDG is 1/10 six-decimal units. Catalog symbols/addresses work;
|
|
290
|
-
explicit decimals must match. Other quotes require explicit `minQuoteDeploy` and
|
|
291
|
-
`minQuoteHarvest`; no unsupported asset's USD price or units are inferred.
|
|
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.
|
|
292
65
|
|
|
293
|
-
###
|
|
66
|
+
### Account for decimals and address order
|
|
294
67
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
The browser-safe lifecycle and root exports include complete
|
|
301
|
-
`hmmLiquidityManagerV2Abi`, `hmmFeeCollectorV2Abi`, `hmmFeeCollectorFactoryV2Abi`,
|
|
302
|
-
`hmmFixedHookV2Abi` and `hmmDynamicHookV2Abi`. Use ordinary viem contract calls;
|
|
303
|
-
the SDK adds no speculative transaction wrappers:
|
|
304
|
-
|
|
305
|
-
- Read `strategyOwner()` and `liquidityManager()` on the collector. Authority
|
|
306
|
-
follows the **current** fee owner from the canonical hub/fee-owner registry.
|
|
307
|
-
- Call collector `setStrategyShareBps(uint16)` for 0..10,000 bps. It changes future
|
|
308
|
-
swap reservations, not fees already reserved.
|
|
309
|
-
- Read manager `strategyConfig()` for the complete 15-field tuple, then call
|
|
310
|
-
`setStrategyConfig(HMMStrategyConfigV2)` to update every setting immediately.
|
|
311
|
-
This queues a book refresh for the next maintenance pass. Lowering intake caps
|
|
312
|
-
does not forcibly liquidate existing inventory; existing lots keep their stored
|
|
313
|
-
floor and age. New premium settings apply to newly acquired lots.
|
|
314
|
-
- Read `placementsPaused()` and call `setPlacementsPaused(bool)` on the manager.
|
|
315
|
-
Pausing queues auxiliary-liquidity withdrawal on maintenance and stops new
|
|
316
|
-
placements, not trading or fee collection. It does not withdraw locked launch LP.
|
|
317
|
-
|
|
318
|
-
These writes require the current fee-owner wallet and explicit transaction
|
|
319
|
-
authorization. Read-only planning never invokes them.
|
|
320
|
-
|
|
321
|
-
### Breaking migration from the earlier HMM SDK
|
|
322
|
-
|
|
323
|
-
Rebuild unstarted HMM plans with the new preset IDs/adapters/graphs, supply both
|
|
324
|
-
new guards, re-encode the 512-byte tail, and re-mine/re-prove the resulting plan.
|
|
325
|
-
Do not pad old 448-byte payloads, reuse an old graph/salt, or relabel old bytes.
|
|
326
|
-
The former `HmmFixedPoolV1` / `HmmDynamicPoolV1` enum members and old HMM metadata
|
|
327
|
-
have no compatibility aliases. Existing onchain HMM V1 profiles/markets were not
|
|
328
|
-
deregistered or upgraded by this SDK release; submitted legacy plans must not be
|
|
329
|
-
mutated into V2 plans. Use tooling matching their original contract release.
|
|
330
|
-
|
|
331
|
-
Independent Solidity ABI fixtures are regenerated with
|
|
332
|
-
`node scripts/generate-hmm-fixtures.mjs` (Foundry `cast abi-encode` / `calldata`).
|
|
333
|
-
To regenerate canonical V2 metadata/ABIs from preserved evidence without RPC or
|
|
334
|
-
onchain writes, use `node --experimental-transform-types
|
|
335
|
-
scripts/generate-hmm-presets.mjs release.json live.json`; both JSON files must be
|
|
336
|
-
the exact V2 release and matching successful admission/pinned-readback records.
|
|
337
|
-
|
|
338
|
-
## 0.8.1 release
|
|
339
|
-
|
|
340
|
-
Adds the Robinhood October11 Dynamic Fee Hook preset:
|
|
341
|
-
`KnownLifecycleHook.DynamicFeePoolV1` and `KnownLifecycleProfile.V4DynamicFeePool`
|
|
342
|
-
(`"v4-dynamic-fee-pool"`), profile
|
|
343
|
-
`0x27f219872fe934a5464bc9b900028256122f215b40cbdb69ef5f88cd5f627ccb`. The fixed
|
|
344
|
-
preset and example default are unchanged.
|
|
345
|
-
|
|
346
|
-
## 0.8.0 release
|
|
347
|
-
|
|
348
|
-
This release adds unstarted-launch topology validation, boundary tails enabled by
|
|
349
|
-
default, and the generalized `positionGaps` option replacing `staircaseBoundaries`.
|
|
350
|
-
The TypeScript examples default to an unsigned dry run; `--broadcast` explicitly
|
|
351
|
-
authorizes execution without an interactive hash prompt. `--resume` retains the
|
|
352
|
-
original plan, receipt evidence, and metadata session instead of relaunching.
|
|
353
|
-
The opt-in `LifecycleSessionCache` below reuses only the allowlisted static reads
|
|
354
|
-
at the same canonical chain/block; execution proof and financial state stay live.
|
|
355
|
-
|
|
356
|
-
## 0.7.1 transaction-first construction
|
|
357
|
-
|
|
358
|
-
Known chain/core/profile identities use frozen release construction metadata.
|
|
359
|
-
`getKnownLifecycleDeployment`, `getKnownLifecycleProfile` and
|
|
360
|
-
`listKnownLifecycleProfiles` are pure, browser-safe selectors. Profile selection
|
|
361
|
-
accepts either `KnownLifecycleProfile` keys or exact profile IDs.
|
|
362
|
-
`KnownLifecycleHook.FixedFeePoolV1` and `KnownLifecycleHook.DynamicFeePoolV1`
|
|
363
|
-
identify the fixed hook and **Dynamic Fee Hook** respectively; both use the V2 constructor.
|
|
364
|
-
Select the latter with `KnownLifecycleProfile.V4DynamicFeePool` (`"v4-dynamic-fee-pool"`).
|
|
365
|
-
Unknown identities return no preset; explicit `readLifecycleProfiles` and unlisted
|
|
366
|
-
profile construction retain live discovery/certification. Presets describe release
|
|
367
|
-
availability, never current admission, and contain no `admitted` claim.
|
|
368
|
-
The Robinhood presets retain the mined October8 fixed config6 graph and add the
|
|
369
|
-
October11 zero-author-royalty Dynamic Fee Hook, each with its own exact artifact,
|
|
370
|
-
review, terms, runtime pins, creation-code chunks and 20-word V2 constructor.
|
|
371
|
-
Historical config5 codecs and 18-word V1 ABIs remain explicit for
|
|
372
|
-
existing deployments, but October5 evidence is not relabeled or selected as the
|
|
373
|
-
current preset. Explicit live discovery certifies unlisted deployments from actual
|
|
374
|
-
pinned reads.
|
|
375
|
-
|
|
376
|
-
`prepareAndPlanLifecycleLaunch` compiles the exact requested mode before native
|
|
377
|
-
execution calibration. Known construction uses local commitments and hook
|
|
378
|
-
creation code, mines salts once and compares every final constructor binding.
|
|
379
|
-
Token prediction remains a genuine pinned factory read; advancing the block
|
|
380
|
-
during asynchronous mining can require a second prediction. Current progress,
|
|
381
|
-
receipts, nonce/confirmation gates, exact native proof and final canonical guards
|
|
382
|
-
remain authoritative. Public discovery/constructor boundaries observe the current
|
|
383
|
-
chain; policy callbacks are resolved freshly rather than cached as constant values.
|
|
384
|
-
|
|
385
|
-
Optional `buySlippageBps` (integer 0–9999) protects **every ordered buy** from its
|
|
386
|
-
actual diagnostic receipt output using `floor(output * (10000 - bps) / 10000)`.
|
|
387
|
-
The diagnostic candidate is never admitted or returned for execution. Only the
|
|
388
|
-
complete final protected commitment can pass measurement and validated replay.
|
|
389
|
-
Protection is available only for an unstarted launch; omission preserves minima.
|
|
390
|
-
|
|
391
|
-
`buildLaunchTransactions({ plan, mode, preparationBatches? })` is a pure unsigned
|
|
392
|
-
compiler. Staged preparation counts must cover all markets exactly. Every command
|
|
393
|
-
carries the full plan; `PlannedLaunch.totalCalldataBytes` sums exact remaining
|
|
394
|
-
command bytes, including approvals. Splitting preparation cannot reduce this
|
|
395
|
-
per-command calldata or partition mint/lock/all-buys/public-opening activation.
|
|
396
|
-
|
|
397
|
-
Atomic and staged are explicit choices. Only proven compute/gas-envelope capacity
|
|
398
|
-
can partition empty preparations. Semantic, opaque `DeploymentFailed`, source,
|
|
399
|
-
provider-clamp and byte-cap refusals do not authorize retries or partitioning.
|
|
400
|
-
Native explicit OOG recognizes simulator VM code `-32015` and compatible `-32000`,
|
|
401
|
-
not near-cap gas consumption. Both activation receipt and event counts must match
|
|
402
|
-
the committed positions. Failure DTOs expose safe classifications/numeric facts,
|
|
403
|
-
not raw provider messages. Abort closes continuations, including unsupported adapters.
|
|
404
|
-
|
|
405
|
-
`deriveLaunchPositionRanges` requires a source-defined Black Market
|
|
406
|
-
`distributionPreset`: `"early-scarcity"`, `"staircase"` or `"smooth-ramp"`.
|
|
407
|
-
Inventory weights, 64 active spacing steps and intentional gaps follow
|
|
408
|
-
`black-market/apps/web/src/lib/launch.ts`. Early Scarcity widens sparse bands;
|
|
409
|
-
Staircase inserts three-step gaps only between new inventory shelves; Smooth Ramp
|
|
410
|
-
keeps gently narrowing bands contiguous. The SDK defaults to five positions and
|
|
411
|
-
supports counts from 2 through 16. Arbitrary equal-tick fractions of the distance
|
|
412
|
-
to a protocol boundary are not these presets.
|
|
413
|
-
For Staircase and Early Scarcity, `positionGaps: "adjacent"` removes the empty
|
|
414
|
-
intervals while retaining the source inventory weights and finite-band widths.
|
|
415
|
-
The default `"source-gaps"` preserves their original topology. Smooth Ramp is
|
|
416
|
-
always contiguous: omit `positionGaps` or use `"adjacent"`; explicitly supplying
|
|
417
|
-
`"source-gaps"` is an error. Adjacent positions share an exact spacing-aligned tick;
|
|
418
|
-
overlap is also valid for continuous price coverage.
|
|
419
|
-
An empty gap can move the pool price without exchanging tokens in that interval.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
**Breaking default:** `extendFinalRangeToBoundary` now defaults to `true`.
|
|
423
|
-
It replaces only the final band's far endpoint with the usable spacing-aligned
|
|
424
|
-
protocol boundary, preserving every earlier band and the final band's near endpoint.
|
|
425
|
-
Explicit `false` retains a finite final band, which does not satisfy default planner
|
|
426
|
-
admission unless another funded position supplies the permanent tail.
|
|
427
|
-
The complete finite preset must fit before this extension is applied.
|
|
428
|
-
`boundaryTick` and `boundarySqrtPriceX96` always describe that finite protocol
|
|
429
|
-
boundary; endpoint sqrt ratios are not exclusive swap-price guards.
|
|
430
|
-
|
|
431
|
-
Pass the raw token budget for **one pool**. Each position exposes `inventoryBps`
|
|
432
|
-
and its pre-mint `allocatedTokenAmount` cap: all but the last allocation floor
|
|
433
|
-
their basis-point share, and the last receives the exact remaining budget.
|
|
434
|
-
All caps and funded liquidities must be positive. `maxTokenAmount` equals the intended
|
|
435
|
-
`allocatedTokenAmount`, including any mint-rounding residual; `tokenAmountMaximum`
|
|
436
|
-
equals the pool budget. Both venues use the maximum exact budget-safe integer liquidity:
|
|
437
|
-
one additional liquidity unit would exceed that position's allocated cap.
|
|
438
|
-
`unspentTokenAmount` is the budget minus the canonical rounded-up expected mint
|
|
439
|
-
debit, not an extra allocation or creator reserve. Do not add it to `tokenAmountMaximum`.
|
|
440
|
-
Current admission requires position maxima to sum exactly to each market budget and
|
|
441
|
-
market budgets to sum exactly to minted supply. The SDK planner and pure compiler
|
|
442
|
-
enforce these equalities for every supported venue. The orchestrator burns every
|
|
443
|
-
actual leftover before any buy. Positive int128 liquidity and V4 signed settlement
|
|
444
|
-
limits remain enforced; arbitrary caller plans still need complete live admission.
|
|
445
|
-
|
|
446
|
-
The existing ordering convention is `launchedTokenIsQuote: true` for launched
|
|
447
|
-
token0. Gross liquidity must fit `maxLiquidityPerTick` at **each endpoint**;
|
|
448
|
-
adjacent bands share their endpoint's gross capacity, while the sum of disjoint
|
|
449
|
-
positions is not capped as if all began at launch. `openingActiveLiquidity`
|
|
450
|
-
reflects the actual `[tickLower, tickUpper)` opening state. Token0 starts in the
|
|
451
|
-
first band; token1 has zero opening-active liquidity until a downward quote buy
|
|
452
|
-
crosses the opening upper endpoint. `buySideLiquidity` is only the first
|
|
453
|
-
reachable band's liquidity, never the sum of all disjoint bands. Each position
|
|
454
|
-
also exposes exact endpoint sqrt ratios for display valuation.
|
|
455
|
-
|
|
456
|
-
### Launch position-topology safety
|
|
457
|
-
|
|
458
|
-
Every launch-created market must retain a **nonzero permanent tail** and continuous
|
|
459
|
-
buy-side coverage from its opening price to that tail. A tail in another pool,
|
|
460
|
-
including an optional Abyss allocation, cannot substitute for this market's tail.
|
|
461
|
-
The tail ends at the furthest usable spacing-aligned protocol tick: the maximum
|
|
462
|
-
tick when `launchedTokenIsQuote` is `true` (launch token0), otherwise the minimum.
|
|
463
|
-
V4 uses the config's `tickSpacing`; Abyss config1 uses its canonical fee-tier spacing
|
|
464
|
-
from `ABYSS_FEE_TIERS`, without changing the encoded config.
|
|
465
|
-
|
|
466
|
-
`assertLaunchTopologyCoverage` is a pure validator exported by both
|
|
467
|
-
`@black-market/sdk` and `@black-market/sdk/lifecycle`. It accepts
|
|
468
|
-
`{ positions, openingTick, tickSpacing, launchedTokenIsQuote, allowInteriorGaps? }`.
|
|
469
|
-
Positions carry `tickLower`, `tickUpper` and `maxTokenAmount` (or the Abyss config's
|
|
470
|
-
`tokenAmountMaximum`). Derive the opening tick with exported
|
|
471
|
-
`getTickAtSqrtRatio(marketSqrtPriceX96)`, not by rounding it to the spacing grid.
|
|
472
|
-
The validator never changes the positions:
|
|
473
|
-
|
|
474
|
-
- `TOPOLOGY_OPENING_GAP`: no band contains the opening tick on the buy side.
|
|
475
|
-
Token0 containment is `[lower, upper)`; token1 is `(lower, upper]`, including
|
|
476
|
-
the opening upper endpoint crossed by the first downward buy.
|
|
477
|
-
- `TOPOLOGY_INTERIOR_GAP`: the sorted interval union leaves an uncovered interval
|
|
478
|
-
between opening and the permanent tail. Exact adjacency and overlapping
|
|
479
|
-
Orbit-style horizons both pass.
|
|
480
|
-
- `MISSING_PERMANENT_TAIL`: no boundary-reaching band has a positive token cap.
|
|
481
|
-
A finite final band or zero-allocation tail is not permanent liquidity.
|
|
482
|
-
- `TOPOLOGY_OFF_GRID_TICK`: a band endpoint is not aligned to this market's spacing.
|
|
483
|
-
|
|
484
|
-
The pure validator's `allowInteriorGaps: true` waives **only** interior gaps.
|
|
485
|
-
`planLaunch` and `prepareAndPlanLifecycleLaunch` enforce the same checks for every
|
|
486
|
-
market of an **unstarted launch**, using the pinned predicted token's ordering
|
|
487
|
-
against that market's quote. Progress is read first: waiting/in-flight account or
|
|
488
|
-
receipt state returns waiting without applying this creation policy. Started
|
|
489
|
-
`Preparing`/`Ready` and terminal `Active`/`Cancelled` plans skip the topology gate.
|
|
490
|
-
Their onchain commitments are immutable, so recovery must not retroactively
|
|
491
|
-
refuse them for historical topology. Budget/supply, identity, confirmation,
|
|
492
|
-
receipt and stateful execution checks still apply.
|
|
493
|
-
|
|
494
|
-
| Local planning option | Effect |
|
|
495
|
-
| --- | --- |
|
|
496
|
-
| `allowTopologyGaps: true` | Allows interior gaps only; the funded permanent tail stays mandatory. |
|
|
497
|
-
| `allowMissingPermanentTail: true` | Waives only the boundary-reaching, positive-allocation tail requirement. |
|
|
498
|
-
|
|
499
|
-
Both options default to `false`. Even together they **never** waive opening
|
|
500
|
-
containment or tick alignment. Staircase and Early Scarcity source gaps therefore
|
|
501
|
-
require an explicit gap opt-out; choose `positionGaps: "adjacent"` for continuous
|
|
502
|
-
admitted launches instead. These are validation choices, not an execution-proof
|
|
503
|
-
bypass. They are retained on `PlannedLaunch` for fresh `simulateLaunchPlan` and
|
|
504
|
-
`buildNextTransaction` admission while the launch remains unstarted. Started and
|
|
505
|
-
terminal recovery does not require either opt-out. Persist explicit choices
|
|
506
|
-
separately when restoring an unstarted saved plan. Budget/supply equalities, ABI
|
|
507
|
-
encoding, hashes, calldata and stateful proof requirements are unchanged.
|
|
508
|
-
|
|
509
|
-
No cross-review execution cache, caller certificate or execution-proof skip exists.
|
|
510
|
-
Recovery and `buildNextTransaction` acquire fresh authority and retain separate
|
|
511
|
-
immediate-submission-provider preflight. Construction/proof is not submission.
|
|
512
|
-
|
|
513
|
-
## Reviewed next envelopes
|
|
514
|
-
|
|
515
|
-
`BuildNextTransactionOptions.reviewedTransaction` optionally supplies an untrusted
|
|
516
|
-
previously reviewed immediate transaction. Omit it to construct a new envelope
|
|
517
|
-
with the existing greater-of-recommendation-and-twice-pinned-base fee strategy.
|
|
518
|
-
Supply it after review to validate that exact envelope, not to import cached
|
|
519
|
-
admission or waive current-state proof.
|
|
520
|
-
|
|
521
|
-
The SDK reconstructs the current unfinished commands from fresh canonical
|
|
522
|
-
progress, funding/allowances and deployment/profile authority. It matches
|
|
523
|
-
`id/kind/chainId/from/to/data/value` before using the reviewed gas or price.
|
|
524
|
-
Preparation batching remains SDK-derived, not caller-selected. Malformed,
|
|
525
|
-
wrong-step or changed envelopes refuse without returning executable calldata.
|
|
526
|
-
|
|
527
|
-
The SDK directly validates only the immediate transaction at its exact held
|
|
528
|
-
gas/price. It does not repeat measurement, quote a new gas price/poster budget or
|
|
529
|
-
simulate future steps. Current protocol/transaction limits, native metering,
|
|
530
|
-
postconditions and immediate actual-balance affordability still apply. Existing
|
|
531
|
-
padding may be consumed; neither a new padding target nor a higher advisory quote
|
|
532
|
-
alone invalidates a held envelope. Natural child base fees and payer balances are
|
|
533
|
-
never overridden, and failed replay never raises held gas or switches backend.
|
|
534
|
-
|
|
535
|
-
Approvals/resets, atomic launches, every staged next step and cancellation use
|
|
536
|
-
this same contract. Cancellation retains its adapter-independent recovery policy.
|
|
537
|
-
Fresh receipt/nonce/confirmation and final canonical checks remain mandatory.
|
|
538
|
-
When supplied, `submissionClient` must estimate the exact held gas/price at
|
|
539
|
-
`latest`; it still proves only immediate transport acceptance, not wallet identity.
|
|
540
|
-
Returned estimates/admission are fresh and do not trust fields supplied with the
|
|
541
|
-
reviewed transaction. Generic EVM external data-fee callbacks now receive the
|
|
542
|
-
exact simulated `gas` and `gasPrice`.
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
## Opt-in static session fast path
|
|
547
|
-
|
|
548
|
-
`createLifecycleSessionCache()` creates a caller-owned `LifecycleSessionCache`.
|
|
549
|
-
Pass it as `LifecycleRpcClient.sessionCache` to retain the SDK's **explicit static
|
|
550
|
-
read class** across `prepareAndPlanLifecycleLaunch`, `planLaunch`,
|
|
551
|
-
`simulateLaunchPlan` and `buildNextTransaction`. Omit the option to preserve the
|
|
552
|
-
default: only existing invocation-local fixed-state reuse, with no session events
|
|
553
|
-
or cross-invocation observations. The SDK neither creates a global cache nor
|
|
554
|
-
changes transport batching, selected mode or execution admission.
|
|
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)`.
|
|
555
72
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const client = {
|
|
561
|
-
...publicClient,
|
|
562
|
-
sessionCache,
|
|
563
|
-
supportsReadBatching: true, // Only when this transport actually batches.
|
|
564
|
-
onDiagnostic: (event) => { console.debug("[launch-sdk]", event); },
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
const first = await planLaunch({ client, plan, account, mode: "staged" });
|
|
568
|
-
const second = await planLaunch({ client, plan, account, mode: "staged" });
|
|
569
|
-
// At the same canonical head, the second call reuses matching static reads only.
|
|
570
|
-
// Execution simulation, funding and canonical checks still run independently.
|
|
571
|
-
|
|
572
|
-
sessionCache.block; // readonly { number: bigint, hash } or undefined
|
|
573
|
-
sessionCache.invalidate(); // Wallet/chain switch, or each confirmed transaction.
|
|
574
|
-
```
|
|
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` |
|
|
575
77
|
|
|
576
|
-
|
|
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.
|
|
577
81
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
| Oracle configuration and factory presence | Pinned `oracleConfigs(configId)`, certified oracle-factory code and token-factory code-presence checks |
|
|
585
|
-
| Hook deployer creation/constructor/runtime evidence | Creation-code hash, both chunk addresses/bytes, exact constructor metadata, initcode/CREATE2 comparisons and deployer-recorded runtime digests |
|
|
586
|
-
|
|
587
|
-
Known construction presets continue to avoid discovery/getter mirrors they already
|
|
588
|
-
omit; enabling a cache does not introduce extra certification reads. Unlisted
|
|
589
|
-
profiles still use their normal frozen-envelope certification. Session hits retain
|
|
590
|
-
private wire hex, not mutable public profile/deployment DTOs. Each consumer still
|
|
591
|
-
decodes and checks its exact registration, graph, constructor and market bindings.
|
|
592
|
-
|
|
593
|
-
**Never retained across invocations:** native/ERC20 balances, allowances,
|
|
594
|
-
progress/market and core domain/prediction/binding reads, receipts/transactions,
|
|
595
|
-
chain identity, head/latest/pending observations, account code/nonces,
|
|
596
|
-
`eth_estimateGas`, `eth_simulateV1`, gas-price recommendations, funding-target
|
|
597
|
-
admission, non-view calls, submission preflight and all write-adjacent calls.
|
|
598
|
-
In particular the **native Nitro metering simulation probe is not cached**:
|
|
599
|
-
its `eth_simulateV1` request remains separate from the static ArbSys/ArbGasInfo
|
|
600
|
-
getters, and permissive measurement plus exact validated replay stay live.
|
|
601
|
-
Existing invocation-local reuse for eligible fixed reads is unchanged.
|
|
602
|
-
|
|
603
|
-
Each entry group owns one pinned block **number and hash**. Before session
|
|
604
|
-
observations can be consumed, the invocation must read a fresh canonical head and
|
|
605
|
-
chain identity. A changed head hash (including a same-height reorg), number or
|
|
606
|
-
chain identity clears the old group before use. Exact
|
|
607
|
-
wire parameters also participate in identity; changed caller, target, calldata,
|
|
608
|
-
value, gas or constructor economics cannot hit another request's entry.
|
|
609
|
-
Externally supplied pins without a fresh invocation-owned head bypass the session.
|
|
610
|
-
Only successfully settled wire reads are shared; rejected requests, in-flight
|
|
611
|
-
promises and obsolete completions after closure/invalidation are not retained.
|
|
612
|
-
Final canonical/reorg and chain checks remain live and clear the session on
|
|
613
|
-
identity failure.
|
|
614
|
-
|
|
615
|
-
The caller-owned session is the cross-invocation identity boundary, not the
|
|
616
|
-
reader object or `request` function. Recreated per-operation readers may share
|
|
617
|
-
it while keeping their own transport cancellation signal. They still acquire
|
|
618
|
-
fresh head/chain observations and run their own live requests; in-flight work
|
|
619
|
-
and cancellation state are never shared. Do not route concurrent operation
|
|
620
|
-
signals through one mutable global reader.
|
|
621
|
-
|
|
622
|
-
The caller **must call `invalidate()` on wallet/chain switches and after every
|
|
623
|
-
confirmed transaction**. It discards the pin and all memoized values immediately,
|
|
624
|
-
including preventing older pending reads from repopulating the discarded group.
|
|
625
|
-
It does not cancel an operation, freeze the chain or grant permission to submit
|
|
626
|
-
a saved transaction. A new block causes fresh static reads; the cache is a
|
|
627
|
-
same-snapshot acceleration, not a TTL or an assumption that facts never change.
|
|
628
|
-
|
|
629
|
-
With `onDiagnostic`, each opted-in invocation emits a `session-cache` start and
|
|
630
|
-
success/failure summary. `hits` counts static reads resolved from the session,
|
|
631
|
-
`misses` counts new static reads, and `reuses` counts existing invocation-local
|
|
632
|
-
static reuse. Summaries contain counts only: no cache keys, pins, RPC URLs,
|
|
633
|
-
parameters, addresses, calldata, results or errors. Nested continuations share one
|
|
634
|
-
summary, and listener failures remain isolated from financial behavior.
|
|
635
|
-
|
|
636
|
-
Correctness follows from deterministic static observations at the **same exact
|
|
637
|
-
canonical snapshot**, complete request identity and preserved live proof. The
|
|
638
|
-
session never stores an admission certificate or replaces balances, receipt/nonce
|
|
639
|
-
continuity, native capability simulation, execution replay or submission checks.
|
|
640
|
-
Offline RPC-count regressions compare two sequential complete `planLaunch`
|
|
641
|
-
operations with and without the option; they prove fewer repeated static reads,
|
|
642
|
-
not a live end-to-end latency guarantee.
|
|
643
|
-
|
|
644
|
-
Deterministic offline measurements (RPC messages, not HTTP batches):
|
|
645
|
-
|
|
646
|
-
| Fixture, two sequential `planLaunch` calls at the same pin | Cache off: first / second | Cache on: first / second |
|
|
647
|
-
| --- | --- | --- |
|
|
648
|
-
| Admitted Nitro/Abyss staged plan, serial or batching transport | 33 / 33 | 33 / 22 |
|
|
649
|
-
| Two-bound-market, two-creation-chunk V4 certification/constructor fixture | 64 / 64 | 64 / 19 |
|
|
650
|
-
|
|
651
|
-
The first fixture performs the native Nitro probe, measurement and validated
|
|
652
|
-
replay on **both** calls (three `eth_simulateV1` requests per call). The bound
|
|
653
|
-
fixture deliberately refuses a smart account after completing read-only metadata;
|
|
654
|
-
its savings prove static-read reuse, not economic execution. Both compare the
|
|
655
|
-
complete returned plans for equality. Reproduce after `pnpm build` with
|
|
656
|
-
`node --test test/lifecycle-read-pipeline.test.mjs test/lifecycle-execution.test.mjs`;
|
|
657
|
-
the tests print the per-call counts and assert unchanged counts with the cache off.
|
|
658
|
-
|
|
659
|
-
## 0.6.3 certification and dependency-round reductions
|
|
660
|
-
|
|
661
|
-
The public API, deployment authority and protocol admission rules are unchanged. With an
|
|
662
|
-
actually batching source, selected-profile certification no longer waits for registry
|
|
663
|
-
authority before reading the selected registrations, or for adapter registration before
|
|
664
|
-
reading topology and applicable V4 envelope/terms. Eligibility overlaps graph certification.
|
|
665
|
-
Private profile certification uses the registry's pinned `requireEligible` result and
|
|
666
|
-
requires its returned implementation to match the registration. This covers discovery
|
|
667
|
-
and standalone bound-hook metadata. Three duplicate implementation RPCs (`eth_getCode`,
|
|
668
|
-
`core`, `dependencyDigest`) were removed: the registry already checks enabled records,
|
|
669
|
-
exact profile/version/capability agreement, live runtime hash, core and live digest.
|
|
670
|
-
The existing local V4 graph-digest comparison uses `registration.dependencyDigest`,
|
|
671
|
-
whose equality to the live implementation digest is established by that same call.
|
|
672
|
-
|
|
673
|
-
Abyss certification no longer re-reads `factory`, `CONFIG_SCHEMA`, `CONFIG_VERSION` or
|
|
674
|
-
factory code. The registry certifies those fixed bindings before storing a profile;
|
|
675
|
-
current eligibility pins the approved runtime and rechecks its live graph digest.
|
|
676
|
-
SDK-side schema/version/topology and canonical chain/factory/variant checks still use
|
|
677
|
-
the returned registration, including factory/venue agreement and no hook. A changed
|
|
678
|
-
runtime or factory graph must fail authoritative eligibility, not an optional duplicate
|
|
679
|
-
getter. Market resolution and both exact planning/simulation passes remain required.
|
|
680
|
-
|
|
681
|
-
Source reasons in the reviewed protocol repository:
|
|
682
|
-
|
|
683
|
-
- `contracts/src/launch/lifecycle/v2/LaunchImplementationRegistryV2.sol:285-296`
|
|
684
|
-
implements current eligibility; `:88-97` certifies Abyss before storing it and
|
|
685
|
-
`:153-174` prevents profile rebinding.
|
|
686
|
-
- `contracts/src/launch/lifecycle/v2/LaunchCertificationV2.sol:79-102` certifies
|
|
687
|
-
Abyss schema/version/capabilities, factory/code/canonical identity and graph digest.
|
|
688
|
-
- `contracts/src/launch/lifecycle/v1/AbyssMarketAdapterV1.sol:75-76,150-167`
|
|
689
|
-
makes the core/factory immutable and binds the live graph code/initcode hashes.
|
|
690
|
-
|
|
691
|
-
V4 metadata, reviewed dependency code/getters, creation chunks and shared-root
|
|
692
|
-
provenance remain independent pinned reads. Chunk addresses come from the frozen
|
|
693
|
-
envelope only for scheduling; live deployer getters must still match them, including
|
|
694
|
-
STOP prefixes, size/hash bounds, constructor creation hash, graph digest, runtime
|
|
695
|
-
provenance and callback permissions.
|
|
696
|
-
|
|
697
|
-
Planning reads swap-input admission and existing escrow balances alongside profile
|
|
698
|
-
certification. A market's resolution uses its certified implementation while exact
|
|
699
|
-
capability eligibility, selected-oracle validation and any bound-hook evidence settle.
|
|
700
|
-
Their results must all agree before the resolved identity can authorize simulation.
|
|
701
|
-
|
|
702
|
-
For batching-capable Nitro sources, the isolated ArbOS probe, NodeInterface poster
|
|
703
|
-
quote and permissive exact-calldata measurement overlap. Probe isolation and its balance
|
|
704
|
-
override do not enter the real execution sequence. Exact-gas validated replay waits for
|
|
705
|
-
matching native metering, the poster budget and successful measurement. The redundant
|
|
706
|
-
probe-only chain/hash recheck was removed: successful admission and simulation refusal
|
|
707
|
-
still perform the enclosing live chain/canonical-block assertion. Natural child-block
|
|
708
|
-
fees, uint64 gas bounds, real payer affordability, EIP-150 envelope discovery and
|
|
709
|
-
postconditions are unchanged. Non-batching sources retain sequential measurement.
|
|
710
|
-
|
|
711
|
-
No process-wide or cross-review cache, new read authority, public scope API, admission
|
|
712
|
-
skip or write was introduced. Both opening-buy planning passes still choose fresh heads,
|
|
713
|
-
retain live chain/pending/receipt observations and execute their own native proofs and
|
|
714
|
-
validated replay. Only identical, complete pinned wire reads inside one invocation reuse
|
|
715
|
-
observations.
|
|
716
|
-
|
|
717
|
-
Offline regressions cover concurrent retained dependency responses, changed runtime,
|
|
718
|
-
authority, graph digest and capability refusal through contract-modeled eligibility,
|
|
719
|
-
canonical registry identity mismatch, build-next refusal after graph drift, V4
|
|
720
|
-
expected-address evidence with mismatched live getters, overlapped measurement without
|
|
721
|
-
premature replay, failed native evidence, serial/batched plan and fee equality, and
|
|
722
|
-
retained final canonical checks. Obsolete duplicate-getter tests were removed.
|
|
723
|
-
The released 0.6.3 SDK passed 133 offline tests with one opt-in real-AMM skip.
|
|
724
|
-
Actual consumer-route timings are recorded by the integrating app, not a
|
|
725
|
-
universal network-latency guarantee.
|
|
726
|
-
|
|
727
|
-
## 0.6.2 opt-in internal timing
|
|
728
|
-
|
|
729
|
-
Initialize a lifecycle read client with optional `onDiagnostic(event)` to observe internal
|
|
730
|
-
planning, profile certification, simulation context, Nitro probe, poster estimate, measurement,
|
|
731
|
-
exact replay and envelope-discovery stages. Each stage reports start and completion/failure.
|
|
732
|
-
RPC events distinguish queue admission, actual request start, settlement and invocation-local
|
|
733
|
-
read reuse; `queueMs` is separate from request `durationMs`. `requestId` is a local numeric
|
|
734
|
-
sequence, not a network or wallet identifier. Associate each client with your own local operation
|
|
735
|
-
label when several reviews run concurrently.
|
|
82
|
+
### Derive and display the aligned opening
|
|
83
|
+
|
|
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.
|
|
736
88
|
|
|
737
89
|
```ts
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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
|
+
}
|
|
743
113
|
```
|
|
744
114
|
|
|
745
|
-
|
|
746
|
-
diagnostic clocks or event allocations. Events omit RPC URLs, parameters/results, accounts,
|
|
747
|
-
addresses, signatures, calldata and raw errors; RPC method names are allowlisted. Synchronous
|
|
748
|
-
listener throws and asynchronous listener rejections are isolated from financial behavior.
|
|
749
|
-
Successful timing settlement means the function returned, not that the returned plan/profile
|
|
750
|
-
was admitted: inspect its normal typed admission result.
|
|
751
|
-
|
|
752
|
-
Independent domain/progress reads now overlap after token prediction. Simulation context
|
|
753
|
-
reads, Nitro/poster work and final chain/canonical observations also overlap where their inputs
|
|
754
|
-
are independent, still within the existing transport-opted-in read bound. Serial transports,
|
|
755
|
-
exact state/identity guards and both measurement and validated execution are retained.
|
|
756
|
-
No total-launch latency claim is made from these scheduling changes.
|
|
757
|
-
|
|
758
|
-
Verification: typecheck and the built offline suite passed **126 tests: 125 passing and one
|
|
759
|
-
opt-in real-AMM skip**. Diagnostics regressions cover timing events, payload omission and
|
|
760
|
-
throwing/rejecting observers without changing valid profile admission.
|
|
761
|
-
|
|
762
|
-
## 0.6.1 read-pipeline changes
|
|
763
|
-
|
|
764
|
-
Existing standalone calls, deployment targets, economic commitments and admission
|
|
765
|
-
requirements remain compatible. Invalid plan shapes are still refused before RPC work.
|
|
766
|
-
The optional `LifecycleRpcClient.supportsReadBatching` transport hint enables independent
|
|
767
|
-
getter dependency rounds with at most eight SDK-issued requests outstanding per invocation.
|
|
768
|
-
Set it to `true` only when the supplied transport batches concurrent requests; the SDK
|
|
769
|
-
does not select or configure a transport. Other clients retain serial requests, avoiding
|
|
770
|
-
the measured concurrent-unbatched RPC regression. With batching enabled, initial head
|
|
771
|
-
and chain reads overlap. Failed reads release their slots without rejecting unrelated
|
|
772
|
-
queued callers or automatically retrying.
|
|
773
|
-
|
|
774
|
-
A vanilla one-pool, one-quote, one-range plan selects only its committed profile IDs.
|
|
775
|
-
Abyss-only profile selection no longer requests the V4-only
|
|
776
|
-
`protocolMaximumDeveloperFeeBps` getter. A required V4 fee-limit read still fails the
|
|
777
|
-
operation if unavailable. V4 oracle/deployer/terms work, extra token/position capabilities
|
|
778
|
-
and swap-funding checks remain conditional on the actual committed plan. There is no
|
|
779
|
-
weakened single-pool mode: adapter eligibility, live code hashes, authority/dependency
|
|
780
|
-
bindings, schema/topology and applicable frozen terms remain mandatory.
|
|
781
|
-
|
|
782
|
-
Without the optional static session fast path above, identical fixed-state reads share observations only within one planning invocation.
|
|
783
|
-
Identity includes the original source client, pinned block number/hash and complete
|
|
784
|
-
request parameters, including caller, target, calldata, value and gas context. Rejected
|
|
785
|
-
reads are not retained. State changes, another caller/source/block or a subsequent public
|
|
786
|
-
planning invocation cannot reuse those observations; mutated plans and obsolete
|
|
787
|
-
completions are refused. There is no global cache or new public read-scope option.
|
|
788
|
-
|
|
789
|
-
Chain checks, latest/head/pending observations, receipt reads and canonical block rechecks
|
|
790
|
-
remain live. Wallet/provider preflight, non-view execution calls and stateful/fork RPC
|
|
791
|
-
are not cached. Nitro metering probes, discovery and exact validated replay remain
|
|
792
|
-
separate proofs. A protected opening-buy minimum changes the committed calldata and
|
|
793
|
-
still requires a second full plan and stateful simulation against a fresh latest snapshot.
|
|
794
|
-
|
|
795
|
-
Raw `request({method,params})` clients remain valid. JSON-RPC HTTP batching is optional
|
|
796
|
-
and transport-owned; concurrent reads allow a configured batch scheduler to combine
|
|
797
|
-
independent messages without changing `msg.sender` or the pinned state. No API planner
|
|
798
|
-
service, transport fallback, signature or broadcast is introduced. The existing Node 20
|
|
799
|
-
minimum and ES2022 target are unchanged; shipped scheduling does not require
|
|
800
|
-
`Promise.withResolvers`.
|
|
801
|
-
|
|
802
|
-
Verification on 2026-10-06: `pnpm typecheck` and `pnpm test` passed, including the build,
|
|
803
|
-
with **123 tests: 122 passing, one opt-in real-AMM test skipped and zero failures**.
|
|
804
|
-
Offline regressions exercise the vanilla
|
|
805
|
-
Abyss path without V4 fee metadata, mandatory V4 read failures, bounded overlap and
|
|
806
|
-
duplicate reads, exact combined funding, changed code/authority/terms, partial failures,
|
|
807
|
-
chain drift/reorgs, source/caller/call-context separation, failed-slot release and
|
|
808
|
-
obsolete results. These offline checks are not real-wallet or on-chain execution evidence.
|
|
809
|
-
|
|
810
|
-
A live read-only comparison against installed 0.6.0 measured **one selected canonical
|
|
811
|
-
Abyss profile certification only**, not whole planning, simulation or launch execution.
|
|
812
|
-
Both versions used Node 24.11.1, viem 2.56.3 and identical pinned chain 4663 state at
|
|
813
|
-
block 81455627, hash
|
|
814
|
-
`0x66f20d4c04b1c2357e9cd711c984a83fc8913ab208449ff1a0c8289bf2854036`.
|
|
815
|
-
Five runs per version and transport alternated version order; returned profiles were
|
|
816
|
-
deep-equal, and the chain and canonical block were independently rechecked.
|
|
817
|
-
|
|
818
|
-
| Transport | Version | Median / p95 (ms) | RPC messages | HTTP envelopes | Peak outstanding |
|
|
819
|
-
| --- | --- | --- | --- | --- | --- |
|
|
820
|
-
| Unbatched, default serial | 0.6.0 | 1496.10 / 1677.93 | 15 | 15 | 1 |
|
|
821
|
-
| Unbatched, default serial | 0.6.1 | 1402.10 / 1414.52 | 14 | 14 | 1 |
|
|
822
|
-
| Batched, explicit opt-in | 0.6.0 | 1503.38 / 1541.41 | 15 | 15 | 1 |
|
|
823
|
-
| Batched, explicit opt-in | 0.6.1 | 1005.11 / 1219.87 | 14 | 10 | 3 |
|
|
824
|
-
|
|
825
|
-
These scoped measurements do not establish end-to-end launch latency or a general
|
|
826
|
-
provider guarantee. An earlier unbatched concurrency trial regressed from a 1150.64 ms
|
|
827
|
-
baseline median to 3870.97 ms; explicit transport opt-in and default serial scheduling
|
|
828
|
-
remove that scheduling choice for existing clients. For reproduction, keep the selected
|
|
829
|
-
profile, pinned state, source, retry/batching settings and runtime equal; count RPC
|
|
830
|
-
messages separately from HTTP envelopes and retain failures as failures. Do not log RPC
|
|
831
|
-
URLs, accounts, calldata or provider messages, or substitute full-registry/complex-only
|
|
832
|
-
timing for the selected-profile path.
|
|
833
|
-
|
|
834
|
-
## 0.6.0 admission changes
|
|
835
|
-
|
|
836
|
-
Optional caller policy no longer substitutes for, or gates, actual sequential execution proof.
|
|
837
|
-
Results distinguish `executionProof`, `protocolFit`, and `transportPreflight`. Robinhood
|
|
838
|
-
admission reads pinned Nitro compute limits and poster budgets, then requires native exact
|
|
839
|
-
validated replay. `buildNextTransaction` optionally preflights the immediate next envelope
|
|
840
|
-
through `submissionClient`. Deployment addresses, lifecycle plan/schema domains, profile
|
|
841
|
-
capabilities and explicit atomic/staged behavior are unchanged.
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
## Deployed infrastructure
|
|
845
|
-
|
|
846
|
-
Robinhood mainnet (`4663`) selects the mined `pool-launch-v1` deployment captured at block
|
|
847
|
-
`82880546` in `contracts/deployments/launch/pool-launch-v1/20261008T000141Z-e174ce6/manifest.json`.
|
|
848
|
-
The October8 manifest records 22 successful receipts and canonical runtime evidence,
|
|
849
|
-
with two adapters and five profiles at that deployment. The subsequent October11
|
|
850
|
-
Dynamic Fee Hook admission adds a third adapter and sixth profile to the same
|
|
851
|
-
core/registry: four canonical Abyss variants and fixed/dynamic pool-bound config6/V2.
|
|
852
|
-
Neither offering deploys a shared V4 root. The fixed preset and example selection
|
|
853
|
-
remain `0xf18140c2fb66a4202a0f22d62d6288bf7976db108de5381e5497aaed332a06f8`,
|
|
854
|
-
with creation hash `0x11c4c7b1f265ed708b7d53ab828c89d237ca821333daa808f1913986c6f8f1ab`.
|
|
855
|
-
The Dynamic Fee Hook profile is
|
|
856
|
-
`0x27f219872fe934a5464bc9b900028256122f215b40cbdb69ef5f88cd5f627ccb`,
|
|
857
|
-
with creation hash `0xd448a4117b78714cc4f96824356c6a90ec666449fde5c57e2b7bbe072f5e4a7a`.
|
|
858
|
-
Its exact graph and terms are prepared in
|
|
859
|
-
`contracts/deployments/launch/pool-hook-template-v1/20261011T033141Z-dynamic-fee-zero-royalty/admission.json`;
|
|
860
|
-
that file is **unsigned preparation, not a mined receipt**. Registration is evidenced
|
|
861
|
-
by the successful `forge-broadcast/AdmitPoolHookTemplateV1.s.sol/4663/admit-latest.json`
|
|
862
|
-
receipt for `0x1928b13d1a6bf8826d08493a18c483fc7d244a3ec4100a7f8118f510a5db640c`.
|
|
863
|
-
Creation bytes concatenate the preserved storage-child runtimes after stripping each
|
|
864
|
-
first STOP byte, exactly as `PoolHookDeployerV1._initCode` does; constructor arguments
|
|
865
|
-
are appended separately. An unpatched artifact runtime is not a deployed hook-instance runtime.
|
|
866
|
-
October5 config5/V1 evidence remains historical, never a substitute for this graph.
|
|
867
|
-
|
|
868
|
-
| SDK field | Mainnet address |
|
|
869
|
-
| --- | --- |
|
|
870
|
-
| `launchOrchestrator` | `0x91560876033d568d25CDe98C78c33ff8FC43962c` |
|
|
871
|
-
| `launchImplementationRegistry` | `0xB2B0f9F36617810D67b8fC175153Aa10024C1358` |
|
|
872
|
-
| `launchFeeOwnerRegistry` | `0x64b5ca1f21B8E84305b0e4D847924dca39Eb1fcb` |
|
|
873
|
-
|
|
874
|
-
`getAddresses(4663)` exposes this graph; `robinhoodLaunchApplication` exposes the mined
|
|
875
|
-
launch constants. Launch addresses on `31337` and `46631` remain zero unless configured.
|
|
876
|
-
Address overrides are evaluated once on import: bare names win, then `VITE_`, then
|
|
877
|
-
`NEXT_PUBLIC_`. Configure `LAUNCH_ORCHESTRATOR`, `LAUNCH_IMPLEMENTATION_REGISTRY`, and
|
|
878
|
-
`LAUNCH_FEE_OWNER_REGISTRY` from the same deployment evidence.
|
|
879
|
-
|
|
880
|
-
Canonical Abyss defaults are retained. DEX overrides apply on `31337` and `46631`, not
|
|
881
|
-
mainnet. Lending mainnet defaults use `contracts/deployments/robinhood/replacement-infrastructure.json`;
|
|
882
|
-
the workbench's existing lending endpoints follow that replacement. Lending overrides apply
|
|
883
|
-
on `31337` (all three prefixes) and `46631` (`VITE_`/`NEXT_PUBLIC_`); liquidation-executor
|
|
884
|
-
overrides use all three prefixes on every chain. Workbench chain RPC configuration reads
|
|
885
|
-
`VITE_RPC_URL`, then `NEXT_PUBLIC_RPC_URL`, then `RPC_URL`; client factories prefer their explicit
|
|
886
|
-
`rpcUrl`, then `RPC_URL`, then the chain endpoint. Select the chain explicitly in applications.
|
|
887
|
-
|
|
888
|
-
Registry V2 has one `LaunchCertificationV2` child. V4 uses `profileEnvelope`, `profileId`, and
|
|
889
|
-
signed six-argument `registerProfile`. Admin-only `registerAbyssProfile(uint8,registration)`
|
|
890
|
-
independently certifies config-1 variants without an author envelope or royalty allocation.
|
|
891
|
-
The admission EIP-712 domain is `Black Market Launch Registry`, version `2`.
|
|
892
|
-
|
|
893
|
-
`LaunchBoundsV2` has five members: minimum/maximum tick spacing, maximum positions,
|
|
894
|
-
maximum oracle cardinality, and fee-mode flags. LP and SharedV4 hook fees remain below
|
|
895
|
-
1,000,000 pips. Pool-bound minimum/maximum hook fees satisfy
|
|
896
|
-
`0 <= minimumHookFeePips <= hookFeePips <= 1,000,000`; sensitivity is an explicit uint32.
|
|
897
|
-
Creators also select a registered oracle configuration and per-pool external-liquidity policy.
|
|
898
|
-
Author royalty ceilings are separate. Robinhood P1 `(1,4096)`, P2 `(6,4096)`, and P3 `(17,4096)`
|
|
899
|
-
can use the same admitted profile; the selected oracle is checked at the pinned block.
|
|
900
|
-
With `externalLiquidityDisabled=false`, third-party LP add/remove is allowed after opening.
|
|
901
|
-
Permanent launch custody and pre-opening protection still apply.
|
|
902
|
-
|
|
903
|
-
Config5 exports `fixedFeePoolHookV1Abi`, `poolHookDeployerV1Abi` and
|
|
904
|
-
`poolFeeCollectorFactoryV1Abi` for the actual V1 wire contracts. Config6 exports
|
|
905
|
-
`fixedFeePoolHookConfigV6Abi`, `poolHookDeployerConfigV6Abi` and
|
|
906
|
-
`poolFeeCollectorFactoryConfigV6Abi`, including its 20-word constructor and
|
|
907
|
-
`minimumHookFeePips()` / `feeSensitivityPipsSecondsPerTick()` getters. Existing
|
|
908
|
-
config5 hooks are not queried for nonexistent V2 fee getters. Constructor encoding
|
|
909
|
-
and initcode hashing require explicit `configVersion`; schema constants are
|
|
910
|
-
`V4_POOL_BOUND_LIFECYCLE_CONFIG_SCHEMA_V5` and `_V6`, never an ambiguous alias.
|
|
911
|
-
Generic shared contracts are `FixedFeeSharedHookV1`, `SharedHookDeployerV1`, and
|
|
912
|
-
`SharedMarketAdapterV1`; they require their own admitted deployment graph.
|
|
913
|
-
Other current ABI exports include `sharedMarketAdapterV1Abi`, `sharedHookDeployerV1Abi`,
|
|
914
|
-
`poolMarketAdapterV1Abi`, `poolHookDeployerV1Abi`, and `poolFeeCollectorFactoryV1Abi`.
|
|
915
|
-
Validation uses `validateV4LifecycleMarket`; the collector factory getter is
|
|
916
|
-
`dependencyDigest(address)`. Identity domains are `black-market.launch-profile.v2`,
|
|
917
|
-
`black-market.v4-dependencies.v2`, and `black-market.pool-bound-market-economics.v1`.
|
|
918
|
-
|
|
919
|
-
## Public operations
|
|
920
|
-
|
|
921
|
-
| Operation | Contract |
|
|
922
|
-
| --- | --- |
|
|
923
|
-
| `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. |
|
|
924
|
-
| `predictLifecycleToken({client, plan})` | Exact prediction from the explicit core. |
|
|
925
|
-
| `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. |
|
|
926
|
-
| `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. |
|
|
927
|
-
| `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. |
|
|
928
|
-
| `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. |
|
|
929
|
-
| `simulateLaunchPlan({client, planned, limits?, fork?, receipts?, confirmations?})` | Rereads canonical state and proves remaining work. Preserves receipt evidence, economics and selected mode. |
|
|
930
|
-
| `readLaunchProgress({client, planned, receipts?, confirmations?})` | Confirmation-bound canonical state, latest head, receipt/replacement/reorg status, account-nonce safety and actual prepared market/live state. |
|
|
931
|
-
| `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`. |
|
|
115
|
+
Output for the inputs above (raw integers except FDV):
|
|
932
116
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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 |
|
|
936
121
|
|
|
937
|
-
|
|
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.
|
|
938
126
|
|
|
939
|
-
|
|
127
|
+
### Split inventory across pools and ranges
|
|
940
128
|
|
|
941
|
-
|
|
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.
|
|
942
133
|
|
|
943
|
-
|
|
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:
|
|
944
138
|
|
|
945
139
|
```ts
|
|
946
|
-
import {
|
|
947
|
-
|
|
948
|
-
const
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
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());
|
|
952
160
|
```
|
|
953
161
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
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.
|
|
957
|
-
|
|
958
|
-
`LifecycleProfile` contains `registration`, `adapter`, unchanged `topology`, `venueKind`, `admitted` and optional refusal `reason`. Reviewed V4 adds:
|
|
162
|
+
The returned raw caps and ticks are:
|
|
959
163
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
- `
|
|
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` |
|
|
963
170
|
|
|
964
|
-
The
|
|
171
|
+
The expected mint dust burned is **6,401,491 raw units** (0.000000000006401491 tokens).
|
|
965
172
|
|
|
966
|
-
|
|
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.
|
|
967
178
|
|
|
968
|
-
|
|
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.
|
|
969
185
|
|
|
970
|
-
|
|
186
|
+
### Protect the opening buy
|
|
971
187
|
|
|
972
|
-
|
|
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.
|
|
973
192
|
|
|
974
|
-
`
|
|
193
|
+
`prepareAndPlanLifecycleLaunch({ buySlippageBps: 50 })` derives every ordered buy's
|
|
194
|
+
minimum from stateful diagnostic output, then proves the final protected commitment:
|
|
975
195
|
|
|
976
196
|
```text
|
|
977
|
-
(
|
|
197
|
+
minTokenOut = floor(simulatedTokenOut × (10000 - buySlippageBps) / 10000)
|
|
198
|
+
50 bps: floor(simulatedTokenOut × 9950 / 10000)
|
|
978
199
|
```
|
|
979
200
|
|
|
980
|
-
|
|
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.
|
|
981
205
|
|
|
982
|
-
`
|
|
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.
|
|
983
212
|
|
|
984
|
-
|
|
985
|
-
(uint16,uint24,int24,uint160,uint24,uint24,uint32,uint8,uint8,address,bool,bytes32,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])
|
|
986
|
-
```
|
|
213
|
+
## Build the plan
|
|
987
214
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
The current reviewed `FixedFeePoolHookV1` uses a **fixed maximum-pips schedule**:
|
|
994
|
-
each applicable hook fee is `floor(amount * hookFeePips / 1,000,000)`.
|
|
995
|
-
Its base stores and exposes `minimumHookFeePips` and
|
|
996
|
-
`feeSensitivityPipsSecondsPerTick`, but this concrete hook does not use them in fee
|
|
997
|
-
calculation. Sensitivity's encoded units are fee-pips × seconds/tick; they do not
|
|
998
|
-
imply an active oracle-driven fee formula. Registered oracle configuration still
|
|
999
|
-
governs the pool's oracle behavior, not this hook's fixed fee rate.
|
|
1000
|
-
|
|
1001
|
-
The registered **Dynamic Fee Hook** instead uses the oracle's upward quote-per-base
|
|
1002
|
-
tick velocity: `minimum + floor(positiveTickChange * sensitivity / elapsedSeconds)`,
|
|
1003
|
-
capped at `hookFeePips` (the maximum). Quiet/falling prices, zero elapsed time or zero
|
|
1004
|
-
sensitivity use the minimum. Select its own preset/terms, set **`lpFeePips: 0`** and
|
|
1005
|
-
explicitly encode all three config6 fee settings. Its reviewed author allocation is
|
|
1006
|
-
**0 bps**, so `developerFeeBps` must be zero. Generic config6 codecs do not identify
|
|
1007
|
-
fee behavior or certify constructor compatibility; live constructor/simulation
|
|
1008
|
-
authority remains required. Fixed launch examples continue selecting the fixed preset.
|
|
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.
|
|
1009
220
|
|
|
1010
221
|
```ts
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
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
|
+
}
|
|
1025
289
|
```
|
|
1026
290
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
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 |
|
|
319
|
+
| --- | --- | --- |
|
|
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. |
|
|
1038
322
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
client, account: draft.creator, plan: draft, mode: "staged", signal: stop.signal,
|
|
1043
|
-
onProgress: ({marketIndex, attempts, predictedHook}) => console.log(marketIndex, attempts.toString(), predictedHook),
|
|
1044
|
-
});
|
|
1045
|
-
const saved = serializeLaunchPlan(finalized.plan);
|
|
1046
|
-
if (!finalized.simulation.admitted) throw new Error(finalized.simulation.reason);
|
|
1047
|
-
// Use finalized.progress and finalized.hookDeployments; do not immediately plan again.
|
|
1048
|
-
const boundIndex = finalized.plan.markets.findIndex((market) => market.configVersion === 6);
|
|
1049
|
-
const optionalPredeploy = await buildPoolBoundHookDeploymentTransaction({client, plan: finalized.plan, marketIndex: boundIndex});
|
|
1050
|
-
// Inspect only; separately admit/authenticate/sign any optional predeployment.
|
|
1051
|
-
```
|
|
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.
|
|
1052
326
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
The positive validated getter values establish `maxTxComputeGas`, `maxBlockComputeGas`
|
|
1121
|
-
and their minimum `executionGasCeiling`. Failed reads never fall back to the huge Nitro
|
|
1122
|
-
header or a hard-coded 32M. `limits.protocol` identifies `"nitro"` or `"evm"`.
|
|
1123
|
-
|
|
1124
|
-
Nitro `transactionGasCeiling`, when present, is the minimum of supplied **complete**
|
|
1125
|
-
chain/RPC/account gas-envelope restrictions. It is independent of the compute ceiling:
|
|
1126
|
-
an admitted transaction's `gas` may exceed `executionGasCeiling` because poster gas is
|
|
1127
|
-
not compute. NodeInterface (`0xc8`).`gasEstimateL1Component` is read at the same pinned
|
|
1128
|
-
block with the exact sender, destination, calldata and value, including future dependent
|
|
1129
|
-
steps whose execution cannot yet be independently estimated. It budgets poster gas only.
|
|
1130
|
-
The buffered compute-discovery envelope plus buffered poster budget is carried into
|
|
1131
|
-
exact validated replay; an approximate poster quote is never subtracted from total
|
|
1132
|
-
gas use to certify exact compute fit.
|
|
1133
|
-
Measurement waits for successful capability and candidate-specific poster evidence,
|
|
1134
|
-
then uses the legal complete compute-plus-poster envelope. A packed preparation
|
|
1135
|
-
failure consuming at least 95% may invalidate its cost estimate without claiming
|
|
1136
|
-
its selector diagnoses OOG. Unsupported/transport evidence remains unavailable,
|
|
1137
|
-
except an observed aggregate-budget exhaustion can preserve a successful prefix.
|
|
1138
|
-
|
|
1139
|
-
A separate pinned validated simulation probes all three ArbOS/version/getter values
|
|
1140
|
-
against the canonical observations. Only that isolated capability probe temporarily
|
|
1141
|
-
overrides the probe account's balance, so probe-only fees cannot reject an exactly-funded
|
|
1142
|
-
launch. Probe funding/nonce changes, steps and fees never enter real plan measurement,
|
|
1143
|
-
replay, postconditions or affordability, which use actual payer state. The native Nitro
|
|
1144
|
-
`eth_simulateV1` commit-mode ArbOS charging hook removes the **actual** poster charge and
|
|
1145
|
-
holds excess compute gas before execution. Successful exact replay and postconditions,
|
|
1146
|
-
not the quote or permissive pass, prove fit. Missing native metering or a mismatched
|
|
1147
|
-
probe fails closed. Generic Anvil/Hardhat forks cannot certify Nitro execution.
|
|
1148
|
-
|
|
1149
|
-
Transactions expose `estimate.executionFee`, optional external `dataFee`/`totalFee` and
|
|
1150
|
-
`feeConfidence: "execution-and-data" | "execution-only"`. On Nitro, `posterGas`/`posterFee`
|
|
1151
|
-
are the estimated buffered allocation **inside** `gasLimit`, `dataFeeIncludedInGas` is
|
|
1152
|
-
true, `dataFee` is zero and `totalFee` equals `gasLimit * gasPrice`. Affordability counts
|
|
1153
|
-
this complete envelope once; adding `posterFee` again would double-charge. A caller
|
|
1154
|
-
`estimateDataFee` is therefore rejected on Nitro. On generic EVM it retains its original
|
|
1155
|
-
semantics as a validated external fee added outside execution gas. Missing external fee
|
|
1156
|
-
does not manufacture an all-in estimate. All observations and limits refresh for build-next.
|
|
1157
|
-
For initial construction, the exact legacy gas-price envelope is the greater of
|
|
1158
|
-
the fresh RPC recommendation and twice the pinned base fee. This avoids
|
|
1159
|
-
underpriced submission when `eth_gasPrice` lags the block base fee. Reviewed
|
|
1160
|
-
envelopes retain exact gas/price through direct immediate native validated replay
|
|
1161
|
-
and immediate affordability, without repeating measurement or applying new padding.
|
|
1162
|
-
The held price need not equal a new recommendation or twice the current base fee;
|
|
1163
|
-
natural child fees and the actual submission estimate must accept it. Replay,
|
|
1164
|
-
affordability and submission use that same price, without a base-fee override.
|
|
1165
|
-
An aggregate budget selects the longest fitting estimated prefix; only when even
|
|
1166
|
-
the immediate estimate does not fit is no proof possible. A definitive returned
|
|
1167
|
-
failure from the final exact replay skips a later payer-balance lookup, while
|
|
1168
|
-
retaining fee/estimate validation and final canonical checks. Successful replay
|
|
1169
|
-
still requires current actual-balance affordability.
|
|
1170
|
-
|
|
1171
|
-
Source references: [ArbSys version encoding](https://github.com/OffchainLabs/nitro-precompile-interfaces/blob/main/ArbSys.sol),
|
|
1172
|
-
[ArbGasInfo compute getters](https://github.com/OffchainLabs/nitro-precompile-interfaces/blob/main/ArbGasInfo.sol),
|
|
1173
|
-
[native simulate commit mode](https://github.com/OffchainLabs/go-ethereum/blob/51d716ccf8293072077feb9764d63d73f5e4ff20/internal/ethapi/simulate.go),
|
|
1174
|
-
[ArbOS actual poster/compute charging](https://github.com/OffchainLabs/nitro/blob/ccc5c828d9ea22f161efc784bac4d4a6559b7e59/arbos/tx_processor.go),
|
|
1175
|
-
and [NodeInterface poster estimate](https://github.com/OffchainLabs/nitro-contracts/blob/main/src/node-interface/NodeInterface.sol).
|
|
1176
|
-
These describe backend semantics, not evidence of a live launch executed by this SDK release.
|
|
1177
|
-
|
|
1178
|
-
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.
|
|
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.
|
|
1179
394
|
|
|
1180
395
|
```ts
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
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
|
+
}
|
|
468
|
+
}
|
|
1186
469
|
```
|
|
1187
470
|
|
|
1188
|
-
|
|
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.
|
|
1189
476
|
|
|
1190
|
-
|
|
477
|
+
Completion has **four checks**: receipt confirmed → markets active → metadata
|
|
478
|
+
published → API indexed. A successful transaction alone does not establish the last two.
|
|
1191
479
|
|
|
1192
|
-
|
|
480
|
+
## Publish metadata
|
|
1193
481
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
| `protocolFit` | `"proved"`, `"failed"`, `"unknown"` | Applicable proven protocol and known tightening restrictions. Missing optional policy remains separately disclosed. |
|
|
1200
|
-
| `transportPreflight` | `"not-requested"`, `"passed"`, `"failed"` | Immediate exact next-transaction acceptance estimate on the supplied submission RPC. |
|
|
1201
|
-
|
|
1202
|
-
`admitted` means the proven prefix fits and is affordable, not that deferred
|
|
1203
|
-
transactions have executed or that eventual activation is guaranteed. Always
|
|
1204
|
-
inspect `simulation.deferredTransactionIds`. Admission reuses `blockNumber`,
|
|
1205
|
-
`blockHash`, `account`, `chainId` and `limits`; signing uses only fresh build-next
|
|
1206
|
-
admission. Plans never preflight future steps independently against nonexistent state.
|
|
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.
|
|
1207
487
|
|
|
1208
488
|
```ts
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
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 };
|
|
1218
530
|
}
|
|
1219
531
|
```
|
|
1220
532
|
|
|
1221
|
-
|
|
1222
|
-
`
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
is rechecked before returning. Success sets `next.admission.transportPreflight` to
|
|
1226
|
-
`"passed"`. Refusal, unsupported RPC, malformed estimate, over-envelope estimate or
|
|
1227
|
-
chain drift raises `SUBMISSION_PREFLIGHT_FAILED` without returning a transaction.
|
|
1228
|
-
The error's `simulation` retains execution admission and its canonical context, changing
|
|
1229
|
-
only transport outcome/reason to `"failed"`. Cancellation uses the same preflight.
|
|
1230
|
-
Without a submission client, `"not-requested"` remains honest and no wallet RPC is implied.
|
|
1231
|
-
Applications still own fresh active account/provider guards around asynchronous work;
|
|
1232
|
-
a read-only preflight does not authenticate an active wallet or authorize a signature.
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
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.
|
|
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.
|
|
1236
537
|
|
|
1237
|
-
|
|
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`.
|
|
1238
543
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
```ts
|
|
1246
|
-
const cancel = await buildNextTransaction({client, planned, receipts, limits, fork, action: "cancel"});
|
|
1247
|
-
// Apply identical wallet-domain/exact-envelope/receipt handling before submission.
|
|
1248
|
-
```
|
|
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.
|
|
1249
549
|
|
|
1250
|
-
##
|
|
550
|
+
## Recover or cancel
|
|
1251
551
|
|
|
1252
|
-
|
|
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.
|
|
1253
556
|
|
|
1254
|
-
|
|
|
557
|
+
| Canonical phase / evidence | Action |
|
|
1255
558
|
| --- | --- |
|
|
1256
|
-
|
|
|
1257
|
-
|
|
|
1258
|
-
|
|
|
1259
|
-
|
|
|
1260
|
-
|
|
|
1261
|
-
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
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. |
|
|
1275
582
|
|
|
1276
|
-
|
|
583
|
+
## After launch
|
|
1277
584
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
```
|
|
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.
|
|
1281
587
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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:
|
|
1287
652
|
|
|
1288
|
-
|
|
653
|
+
```ts
|
|
654
|
+
import { defaultHmmLaunchConfig, encodeHmmLaunchTail } from "@black-market/sdk";
|
|
1289
655
|
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
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);
|
|
1293
663
|
```
|
|
1294
664
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
can be provisional and cannot produce an admitted next transaction.
|
|
1300
|
-
|
|
1301
|
-
`examples/launch-lifecycle-smoke.ts manifest.json sdk-plans.json` executes Solidity-exported
|
|
1302
|
-
plans only on explicitly authorized owned loopback fixtures. It exercises atomic/staged
|
|
1303
|
-
modes, typed predeployment, ordered buys, permanent custody, canonical recovery, no-argument
|
|
1304
|
-
V3 harvest, and authenticated author claims. `test/lifecycle-chain.test.mjs` exercises
|
|
1305
|
-
real-graph refusals/reorg/cancellation with the same fixture environment. See
|
|
1306
|
-
[example instructions](../examples/README.md#actual-owned-fixture-proof) for the explicit
|
|
1307
|
-
local-execution opt-in and required files.
|
|
1308
|
-
|
|
1309
|
-
## Individual token creation examples
|
|
1310
|
-
|
|
1311
|
-
Eleven independent `examples/launch-erc20-*.ts` / `launch-erc404-*.ts` files invoke
|
|
1312
|
-
the shared `runLaunchExample(caseObject)` using valuation-driven economics with no
|
|
1313
|
-
required CLI parameters or fixture files. **No mode flag means a dry run**:
|
|
1314
|
-
the first output is `DRY RUN — no transactions signed or broadcast.`, followed by
|
|
1315
|
-
the full economic review and retained planning artifacts. Successful planning exits
|
|
1316
|
-
`0` without constructing a wallet signer, signing, broadcasting, uploading or publishing.
|
|
1317
|
-
The final output line is the same case command with `--broadcast` appended:
|
|
1318
|
-
|
|
1319
|
-
```sh
|
|
1320
|
-
node examples/launch-erc20-v4.ts
|
|
1321
|
-
node examples/launch-erc20-v4.ts --broadcast
|
|
1322
|
-
```
|
|
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.
|
|
1323
669
|
|
|
1324
|
-
|
|
1325
|
-
economic-review admission.** It prints/saves the same review and computed hash,
|
|
1326
|
-
plans afresh against current state, then performs guarded signing, broadcast,
|
|
1327
|
-
chain verification, image upload and publication. It does not execute the dry run's
|
|
1328
|
-
saved plan. Unknown, duplicate or mixed flags fail fast with usage text.
|
|
1329
|
-
Optional `--resume <recovery-dir>` continues the original committed launch unchanged,
|
|
1330
|
-
without needing `--broadcast`. CLI dry-run/broadcast selection is independent of
|
|
1331
|
-
the case's atomic/staged execution mode. The eight original cases remain; the three additions
|
|
1332
|
-
(`launch-erc20-multi-quote.ts`, `launch-erc20-depth-v4.ts`, and
|
|
1333
|
-
`launch-erc20-dividends-multiquote-mixed.ts`) await user live-run validation before
|
|
1334
|
-
any replacement decision. See the [example guide](../examples/README.md#individual-token-creation)
|
|
1335
|
-
for all one-line commands and setup-once working-directory `.env`.
|
|
1336
|
-
Node 24+ loads `.env` once, with existing process environment taking precedence.
|
|
1337
|
-
`LAUNCH_API_URL` and **exactly one** signer source are required before RPC/signing/API
|
|
1338
|
-
work: `PRIVATE_KEY`, or `EXAMPLE_KEYSTORE_PATH` for an owner-only local V3
|
|
1339
|
-
scrypt/AES-128-CTR JSON keystore. `EXAMPLE_KEYSTORE_PASSWORD` defaults to the empty
|
|
1340
|
-
string; both/neither sources reject. The bounded keystore loader authenticates the
|
|
1341
|
-
MAC and declared address before deriving the creator. There is no default key,
|
|
1342
|
-
guessed metadata API or API-omission mode. Dry runs derive only the public creator
|
|
1343
|
-
address (keystore decryption is allowed for this); local signing methods are constructed
|
|
1344
|
-
only for broadcast or nonterminal resume execution. Broadcast mainnet writes are
|
|
1345
|
-
irreversible. The official chain-4663 RPC is the default.
|
|
1346
|
-
|
|
1347
|
-
The implementation imports public `@black-market/sdk`, resolves `getAddresses(4663)`,
|
|
1348
|
-
derives the creator from the selected signer and discovers actual admitted profiles.
|
|
1349
|
-
V4 requires bound topology/config `6` on a V2-constructor graph; Abyss requires exact
|
|
1350
|
-
adapter `profileId(3)` QUOTE_ORACLE/config `1`. WETH verifies wrapped-native
|
|
1351
|
-
binding/18 decimals and registered P1 oracle `(1,4096)`. USDG uses 6 decimals,
|
|
1352
|
-
the reviewed `usdPeg` USD-X18 seed `1e18`, and a compatible registered oracle
|
|
1353
|
-
discovered from pinned factory history/mapping, not an invented WETH oracle ID.
|
|
1354
|
-
The eight original cases retain their token/reward/market/position/mode choices:
|
|
1355
|
-
ERC20 `1_000_000e18` supply; ERC404 `10_000e18` supply / `100e18` NFT unit; selected
|
|
1356
|
-
staking/dividends and token-only burn; one through five positions and ordered buys.
|
|
1357
|
-
All cases now fund those buys through native-ETH Kyber conversion. Identity,
|
|
1358
|
-
finalized salts and exact plans are saved before execution; refusal never changes
|
|
1359
|
-
mode, drops positions/buys or overrides failed admission.
|
|
1360
|
-
Pricing uses a USD 5000 target (optional exact `EXAMPLE_TARGET_MARKET_CAP_USD`),
|
|
1361
|
-
actual total minted supply, predicted token order and each market's integer budget.
|
|
1362
|
-
`deriveLaunchPoolRecipe` owns one-position pricing/liquidity; multi-position markets
|
|
1363
|
-
use `deriveLaunchPositionRanges` with exact counts, `positionGaps: "adjacent"` and a
|
|
1364
|
-
boundary final tail. Staircase remains the original multi-position default; the
|
|
1365
|
-
four-position progressive Depth case uses Early Scarcity with adjacent bands and
|
|
1366
|
-
increasing inventory allocations, not the separate historical eight-position
|
|
1367
|
-
catalogue. Both venues use spacing 60/LP fee 3000. There is no 1:1 price,
|
|
1368
|
-
fixed-liquidity reserve or arbitrary absolute range. All intended supply funds LP
|
|
1369
|
-
except explicitly computed rounded-up mint-debit dust, which burns.
|
|
1370
|
-
|
|
1371
|
-
Every opening buy defaults to **0.00001 native ETH** (`10000000000000` wei).
|
|
1372
|
-
`EXAMPLE_BUY_AMOUNT_WEI` overrides the ETH input per buy, not the eventual quote
|
|
1373
|
-
amount. The runner aggregates inputs by quote and obtains one fresh
|
|
1374
|
-
`POST /api/v1/quote/kyber/build?chainId=4663` build per quote, using native
|
|
1375
|
-
zero-address `tokenIn`, exact input, actual escrow sender/recipient, **50 bps**
|
|
1376
|
-
conversion slippage and the same fixed **300-second launch-purpose deadline**
|
|
1377
|
-
as the plan. `EXAMPLE_KYBER_API_URL` defaults to `LAUNCH_API_URL`; the app's public
|
|
1378
|
-
trade default is `https://api.abyss.trading`, so a different service must be chosen
|
|
1379
|
-
explicitly. The API owns route preview; preview GET bytes are not executable funding.
|
|
1380
|
-
|
|
1381
|
-
Each row is `LifecycleFundingKind.Swap`, with native zero-address `inputAsset`,
|
|
1382
|
-
the reviewed router target and original built calldata. The runner decodes the
|
|
1383
|
-
reviewed `swap` entry point and binds currencies, escrow recipient, exact input,
|
|
1384
|
-
minimum output, executor payload and flags. The API floor
|
|
1385
|
-
`amountOutMinimum = floor(amountOut * 9950 / 10000)` becomes the quote budget;
|
|
1386
|
-
ordered buys sharing a quote divide that budget, assigning the integer remainder
|
|
1387
|
-
to the last buy. The creator needs native ETH for conversion **plus gas**, not
|
|
1388
|
-
WETH/USDG wallet balances or ERC20 approvals. Registry target/spender/code-hash
|
|
1389
|
-
admission is checked and rechecked before signatures. Any refusal stops unsigned
|
|
1390
|
-
with retained evidence, never a native-wrap/direct-ERC20/separate-wallet-swap
|
|
1391
|
-
fallback, route retry or rewritten deadline.
|
|
1392
|
-
|
|
1393
|
-
Optional `EXAMPLE_TOKEN_NAME`, `EXAMPLE_TOKEN_SYMBOL` and
|
|
1394
|
-
`EXAMPLE_TOKEN_DESCRIPTION` override each case's defaults while retaining the
|
|
1395
|
-
existing normalized text and API/lifecycle length limits. Optional
|
|
1396
|
-
`EXAMPLE_IMAGE_PATH` supplies actual PNG/JPEG/WebP artwork, bounded to 1 byte
|
|
1397
|
-
through 5 MiB. Its exact SHA-256/content-type/length is part of the reviewed,
|
|
1398
|
-
signed attribution; the runner follows the API-issued upload and completion flow.
|
|
1399
|
-
Without that option, metadata-only sessions still require `image: null`.
|
|
1400
|
-
|
|
1401
|
-
The indicative WETH USD seed comes only from the configured `LAUNCH_API_URL` token-prices
|
|
1402
|
-
API: one uncached GET `/api/v1/token-prices?chainId=4663&limit=100`, with a 30-second
|
|
1403
|
-
timeout, 1 MiB streamed body limit and no pagination, redirects or retries. The
|
|
1404
|
-
reviewed WETH row must have chain 4663, ready metadata, 18 decimals, `priced: true`,
|
|
1405
|
-
anchor source and direct WETH/Chainlink provenance with aggregator
|
|
1406
|
-
`0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9`. Price parsing requires an exact positive
|
|
1407
|
-
uint256 decimal `priceUsdX18`. Missing, unpriced, mismatched or unavailable data
|
|
1408
|
-
rejects without a manual or alternate-source fallback. API publication supplies
|
|
1409
|
-
an indicative launch valuation, not executable swap, receipt or chain authority.
|
|
1410
|
-
API origin, index/graph blocks, upstream timestamp/age and local retrieval time are
|
|
1411
|
-
preserved and displayed; retrieval does not refresh the upstream observation.
|
|
1412
|
-
There is no 15-minute contract-round gate or API-block canonicality requirement.
|
|
1413
|
-
Public `economic-review.json` and exact private recovery precede the first signature.
|
|
1414
|
-
Review includes quote/source/time, target, actual minted supply, exact price
|
|
1415
|
-
orientation, all allocations/liquidity/fees,
|
|
1416
|
-
expected retained supply and aligned opening valuations. The final admitted
|
|
1417
|
-
activation simulation supplies each ordered buy's quote spent/token output,
|
|
1418
|
-
all-in average USD/token and fee-plus-price-impact premium. This is not a claim
|
|
1419
|
-
of simulated final marginal spot. Alignment and buys mean the eventual valuation
|
|
1420
|
-
need not equal USD 5000; use actual retained supply and observed post-buy price.
|
|
1421
|
-
|
|
1422
|
-
The computed review hash is provenance evidence, never an authorization input:
|
|
1423
|
-
there is no interactive prompt or environment hash gate. `--broadcast` alone is
|
|
1424
|
-
the explicit mode authorization, recorded in `economic-admission.json` as
|
|
1425
|
-
`authorization: "--broadcast"` with the computed hash; this artifact is not another gate.
|
|
1426
|
-
Before each attribution/transaction signature, the immutable review hash, saved
|
|
1427
|
-
plan/supply/order/target and fresh RPC token prediction are rechecked, then the same
|
|
1428
|
-
API source is reread. A changed exact price, API origin, chain, WETH/decimals or
|
|
1429
|
-
direct-anchor identity/kind/source rejects without rewriting intent. Failed or
|
|
1430
|
-
unpriced reads reject. Index/graph and observation/retrieval times may advance for
|
|
1431
|
-
an unchanged exact price and source, without replacing the original review.
|
|
1432
|
-
RPC still owns provider chain, balances, nonce, deadlines and native execution
|
|
1433
|
-
proof. The saved deadline is checked again after asynchronous quote/authority
|
|
1434
|
-
reads and before signatures/staging; expiry stops without extending it.
|
|
1435
|
-
Partial execution never grants permission to replay or silently adopt different economics.
|
|
1436
|
-
The current 0.7.1 V4 examples require the config6/V2 profile, freezing max `10000`,
|
|
1437
|
-
min `1000` pips and sensitivity `7654321` fee-pips × seconds/tick. Its reviewed
|
|
1438
|
-
`FixedFeePoolHookV1` charges the fixed maximum `10000` pips (1%) on applicable amounts;
|
|
1439
|
-
minimum and sensitivity are stored constructor evidence, not a dynamic fee schedule.
|
|
1440
|
-
Optional `NFT_BASE_URI` provides an ERC404 base URI you actually host; its default is
|
|
1441
|
-
empty, with real NFT units/mirror behavior but no claim of hosted NFT metadata.
|
|
1442
|
-
|
|
1443
|
-
The chain-4663 examples require native sequential Nitro `eth_simulateV1`; generic
|
|
1444
|
-
Anvil/Hardhat simulation is not an ArbOS compute/poster proof. Source RPC requests
|
|
1445
|
-
have a 120-second bound and are not retried. There are no invented default gas or
|
|
1446
|
-
calldata caps. Explicit environment restrictions only tighten the complete envelope;
|
|
1447
|
-
headroom defaults to 1,500 bps. SDK native pinned compute/poster reads and exact replay
|
|
1448
|
-
remain mandatory, and build-next uses the same source RPC as the read-only submission
|
|
1449
|
-
preflight before each local signature. Environment options are documented in the example guide.
|
|
1450
|
-
|
|
1451
|
-
Execution rechecks chain/creator/destination and exact finalized calldata before each
|
|
1452
|
-
send. Exact admitted envelopes are signed locally; computed hashes and unsigned
|
|
1453
|
-
envelopes are saved **before** the single raw broadcast, and included receipts are
|
|
1454
|
-
saved before status/provenance assertions. One canonical confirmation is required.
|
|
1455
|
-
Actual verification covers Active state, factory/token runtime/name/symbol/kind/rewards,
|
|
1456
|
-
ERC404 unit/URI/mirror, opened markets, sealed V4 custody/permanent Abyss lock terms,
|
|
1457
|
-
fee policies and ordered activation buys.
|
|
1458
|
-
|
|
1459
|
-
Actual SDK API metadata staging uses locally signed full-domain attribution.
|
|
1460
|
-
Before **every** publication attempt and before final success, a fresh canonical
|
|
1461
|
-
RPC barrier binds the original activation hash/receipt to the saved commitment
|
|
1462
|
-
and Active state; a different later activation observation cannot replace it.
|
|
1463
|
-
Only that original hash is published. Genuine pending-indexer HTTP `202` is
|
|
1464
|
-
polled within 90 seconds respecting `Retry-After`; other failures are not retried.
|
|
1465
|
-
Success requires an optimistic/final session and real indexed
|
|
1466
|
-
`/api/v1/launches/<token>?chainId=4663` DTO with matching creator/token/hash/metadata.
|
|
1467
|
-
Missing/incompatible indexing fails without manufacturing projections, skipping
|
|
1468
|
-
API or launching another token.
|
|
1469
|
-
|
|
1470
|
-
When `EXAMPLE_IMAGE_PATH` is set, metadata staging alone is insufficient:
|
|
1471
|
-
|
|
1472
|
-
1. The completed session must show the exact signed SHA-256/content-type/length
|
|
1473
|
-
and a ready image.
|
|
1474
|
-
2. Publication must retain that descriptor and reference a ready public image.
|
|
1475
|
-
3. The indexed token must carry a non-null matching `imageUrl`, with matching
|
|
1476
|
-
metadata type/length and a token-bound `imageKey`.
|
|
1477
|
-
4. One bounded, no-redirect GET of that URL must return **HTTP 200**, an image
|
|
1478
|
-
content-type family and nonempty bytes. Byte-identical output must match the
|
|
1479
|
-
upload's exact SHA-256/type/length. Different served bytes are recorded as an
|
|
1480
|
-
inferred API/CDN transformation, proving only the image-family/nonempty-body
|
|
1481
|
-
check, not byte identity. The canonical RPC barrier runs again after this GET.
|
|
1482
|
-
|
|
1483
|
-
Any failed binding, HTTP/type/size/body check exits nonzero with retained evidence;
|
|
1484
|
-
there is no image retry or metadata-only fallback. Without an image path, the
|
|
1485
|
-
metadata-only null-image behavior remains.
|
|
1486
|
-
|
|
1487
|
-
Every dry run or broadcast automatically creates fresh `launch-results/<timestamp-case-random>/`;
|
|
1488
|
-
`--resume` appends recovery evidence in the original directory. Dry runs retain
|
|
1489
|
-
all planning/review/recovery artifacts, but no admission, signed bytes, API session
|
|
1490
|
-
or publication artifacts:
|
|
1491
|
-
|
|
1492
|
-
| Artifact | Evidence |
|
|
1493
|
-
| --- | --- |
|
|
1494
|
-
| `events.jsonl` | Timestamped case/stage events, RPC/API errors, admission/simulation and actual chain observations. |
|
|
1495
|
-
| `plan.json` | Redacted finalized plan for public inspection, not exact recovery authority. |
|
|
1496
|
-
| `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. |
|
|
1497
|
-
| `economic-admission.json` | Broadcast-only mode authorization (`authorization: "--broadcast"`) and computed review hash as provenance, not supplied-hash admission. |
|
|
1498
|
-
| `receipts.json` | Empty for a dry run; execution retains exact signed-envelope hashes pre-broadcast, followed by real receipts/references. |
|
|
1499
|
-
| `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. |
|
|
1500
|
-
| `published-token.json` | Actual indexed API representation. |
|
|
1501
|
-
| `published-image.json` | Optional bounded public-image HTTP/type/length/SHA-256 verification, transformation qualification or failure evidence. |
|
|
1502
|
-
| `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. |
|
|
1503
|
-
|
|
1504
|
-
Public artifacts preserve structured field names and redact sensitive values:
|
|
1505
|
-
known keys/signatures/raw bytes/capabilities/auth values and endpoint secrets,
|
|
1506
|
-
while retaining public calldata/hashes/revert bytes. `node examples/<case>.ts
|
|
1507
|
-
--resume <recovery-dir>` reloads the owner-only exact plan, retained economic authorization
|
|
1508
|
-
provenance, original mode/confirmations/restrictions and typed original inclusion references.
|
|
1509
|
-
Fresh `planLaunch` (never preparation/mining) re-admits that commitment.
|
|
1510
|
-
Canonical Preparing/Ready runs only the remaining build-next sequence; canonical
|
|
1511
|
-
Active recovers the retained activation receipt and performs verification and
|
|
1512
|
-
publication only. Missing/unconfirmed, moved/reorged or replaced receipt evidence
|
|
1513
|
-
and unresolved signed hashes stop for read-only reconciliation, never replay.
|
|
1514
|
-
The API session is refreshed while retaining its one-time capability. A pending
|
|
1515
|
-
image requires the original `EXAMPLE_IMAGE_PATH` bytes and signed SHA-256/type/length;
|
|
1516
|
-
only expired PUT responses (403/410/412) permit one upload-URL renewal/retry.
|
|
1517
|
-
Existing chain verification and every publication canonicality barrier remain required.
|
|
1518
|
-
Never reload redacted `plan.json` as the commitment. See
|
|
1519
|
-
[recovery instructions](../examples/README.md#evidence-and-failure-recovery).
|
|
1520
|
-
Configuration, admission, broadcast, publication and interruption failures exit
|
|
1521
|
-
nonzero and preserve evidence. No source rollback, cancellation, broadcast retry or
|
|
1522
|
-
relaunch occurs.
|
|
1523
|
-
Inspect retained transaction hashes before deciding to run a new case after an
|
|
1524
|
-
ambiguous send. `test/launch-example.test.mjs`, `test/launch-example-matrix.test.mjs`,
|
|
1525
|
-
`test/launch-example-mode.test.mjs` and `test/launch-example-resume.test.mjs` cover offline
|
|
1526
|
-
financial bounds, funding/rounding, quote/admission, signing/retention/config, default
|
|
1527
|
-
dry-run/no-signing/banner/command, broadcast routing and resume boundaries,
|
|
1528
|
-
not actual chain/API proof. The older independent whole-graph local
|
|
1529
|
-
Solidity-exported proof remains separate.
|
|
1530
|
-
|
|
1531
|
-
## Real HTTP API integration
|
|
1532
|
-
|
|
1533
|
-
The opt-in suites use `LaunchApiClient` and actual HTTP requests—not a mocked transport.
|
|
1534
|
-
They do not start a service or provision storage. Configure an abyss-api service with:
|
|
1535
|
-
|
|
1536
|
-
- `/api/v1/launch-upload-sessions` and its capability-protected read route;
|
|
1537
|
-
- real application PostgreSQL storage with launch-upload-session migrations applied;
|
|
1538
|
-
- an enabled request chain matching `LAUNCH_API_TEST_CHAIN_ID`;
|
|
1539
|
-
- its current launch verifying contract matching `LAUNCH_API_TEST_ORCHESTRATOR`.
|
|
1540
|
-
|
|
1541
|
-
For the actual abyss-api service, that verifying contract is the configured deployment
|
|
1542
|
-
`contracts.launchFactory` field, which must contain the current orchestrator address.
|
|
1543
|
-
The signed attribution domain is `Abyss Launch Attribution`, version `1`. Session signature
|
|
1544
|
-
deadlines must be future timestamps at most 15 minutes away. Metadata hashes use canonical
|
|
1545
|
-
NFC/trimmed text, normalized URLs, fixed field order, and null absent optional values.
|
|
1546
|
-
|
|
1547
|
-
| Environment | Meaning |
|
|
1548
|
-
| --- | --- |
|
|
1549
|
-
| `LAUNCH_API_TEST_URL` | Required HTTP service root, e.g. `http://127.0.0.1:18763`; no implicit production target. |
|
|
1550
|
-
| `LAUNCH_API_TEST_CHAIN_ID` | Defaults to `4663`; must be configured on the test service. |
|
|
1551
|
-
| `LAUNCH_API_TEST_ORCHESTRATOR` | Defaults to `getAddresses(4663).launchOrchestrator` (October8 mined graph); must match the service's signing domain. |
|
|
1552
|
-
| `LAUNCH_API_TEST_PRIVATE_KEY` | Required only for the explicit signed suite; disposable EOA key, never a production key. |
|
|
1553
|
-
|
|
1554
|
-
```sh
|
|
1555
|
-
# Read-only capability/error boundaries; no key and no storage writes.
|
|
1556
|
-
LAUNCH_API_TEST_URL=http://127.0.0.1:18763 pnpm test:api
|
|
1557
|
-
|
|
1558
|
-
# Signed metadata-session writes, allowed only on an owned disposable loopback service.
|
|
1559
|
-
LAUNCH_API_TEST_URL=http://127.0.0.1:18763 \
|
|
1560
|
-
LAUNCH_API_TEST_PRIVATE_KEY="$DISPOSABLE_TEST_PRIVATE_KEY" pnpm test:api:write
|
|
1561
|
-
```
|
|
670
|
+
### V2 fee funding and owner controls
|
|
1562
671
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
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.
|