@black-market/sdk 0.15.0 → 0.16.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 +10 -8
- package/dist/lifecycle/auto-compound.d.ts +21 -0
- package/dist/lifecycle/auto-compound.d.ts.map +1 -0
- package/dist/lifecycle/auto-compound.js +34 -0
- package/dist/lifecycle/auto-compound.js.map +1 -0
- package/dist/lifecycle/calibration.d.ts +2 -4
- package/dist/lifecycle/calibration.d.ts.map +1 -1
- package/dist/lifecycle/calibration.js +1 -26
- package/dist/lifecycle/calibration.js.map +1 -1
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.d.ts +73 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.d.ts.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.js +75 -0
- package/dist/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.js.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.d.ts +73 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.d.ts.map +1 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.js +75 -0
- package/dist/lifecycle/deployments/auto-compound-static-pool-v1-20261028.js.map +1 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts +71 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.d.ts.map +1 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js +73 -0
- package/dist/lifecycle/deployments/raeto-fixed-pool-v1-20261029.js.map +1 -0
- package/dist/lifecycle/gas-profile.d.ts +17 -13
- package/dist/lifecycle/gas-profile.d.ts.map +1 -1
- package/dist/lifecycle/gas-profile.js +133 -113
- package/dist/lifecycle/gas-profile.js.map +1 -1
- package/dist/lifecycle/index.d.ts +6 -4
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +6 -4
- package/dist/lifecycle/index.js.map +1 -1
- package/dist/lifecycle/markets.d.ts +4 -0
- package/dist/lifecycle/markets.d.ts.map +1 -1
- package/dist/lifecycle/markets.js +58 -3
- package/dist/lifecycle/markets.js.map +1 -1
- package/dist/lifecycle/opening-buys.js +3 -3
- package/dist/lifecycle/opening-buys.js.map +1 -1
- package/dist/lifecycle/planner.d.ts +6 -9
- package/dist/lifecycle/planner.d.ts.map +1 -1
- package/dist/lifecycle/planner.js +122 -208
- package/dist/lifecycle/planner.js.map +1 -1
- package/dist/lifecycle/presets.d.ts +9 -3
- package/dist/lifecycle/presets.d.ts.map +1 -1
- package/dist/lifecycle/presets.js +17 -1
- package/dist/lifecycle/presets.js.map +1 -1
- package/dist/lifecycle/raeto-abi.d.ts +175 -0
- package/dist/lifecycle/raeto-abi.d.ts.map +1 -0
- package/dist/lifecycle/raeto-abi.js +224 -0
- package/dist/lifecycle/raeto-abi.js.map +1 -0
- package/dist/lifecycle/raeto.d.ts +21 -0
- package/dist/lifecycle/raeto.d.ts.map +1 -0
- package/dist/lifecycle/raeto.js +59 -0
- package/dist/lifecycle/raeto.js.map +1 -0
- package/dist/lifecycle/rpc.d.ts +3 -13
- package/dist/lifecycle/rpc.d.ts.map +1 -1
- package/dist/lifecycle/rpc.js +11 -37
- package/dist/lifecycle/rpc.js.map +1 -1
- package/dist/lifecycle/snapshot.d.ts.map +1 -1
- package/dist/lifecycle/snapshot.js +1 -2
- package/dist/lifecycle/snapshot.js.map +1 -1
- package/dist/lifecycle/transactions.d.ts +10 -3
- package/dist/lifecycle/transactions.d.ts.map +1 -1
- package/dist/lifecycle/transactions.js +47 -10
- package/dist/lifecycle/transactions.js.map +1 -1
- package/dist/lifecycle/types.d.ts +32 -107
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js +3 -3
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/lifecycle/ufg.d.ts +1 -1
- package/dist/lifecycle/ufg.d.ts.map +1 -1
- package/dist/lifecycle/ufg.js +1 -1
- package/dist/lifecycle/ufg.js.map +1 -1
- package/docs/launch-lifecycle.md +113 -1
- package/docs/lifecycle-gas-profiles.md +141 -24
- package/docs/reference.md +112 -3
- package/examples/.env.example +0 -3
- package/examples/README.md +11 -11
- package/examples/launch-example-support.ts +4 -9
- package/examples/launch-example.ts +12 -28
- package/examples/launch-lifecycle-smoke.ts +10 -22
- package/examples/launch.ts +8 -11
- package/package.json +1 -1
- package/src/lifecycle/auto-compound.ts +38 -0
- package/src/lifecycle/calibration.ts +3 -23
- package/src/lifecycle/deployments/auto-compound-dynamic-pool-v1-20261028.ts +77 -0
- package/src/lifecycle/deployments/auto-compound-static-pool-v1-20261028.ts +77 -0
- package/src/lifecycle/deployments/raeto-dynamic-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/deployments/raeto-fixed-pool-v1-20261029.ts +74 -0
- package/src/lifecycle/gas-profile.ts +125 -104
- package/src/lifecycle/index.ts +6 -4
- package/src/lifecycle/markets.ts +47 -3
- package/src/lifecycle/opening-buys.ts +3 -3
- package/src/lifecycle/planner.ts +116 -191
- package/src/lifecycle/presets.ts +17 -1
- package/src/lifecycle/raeto-abi.ts +223 -0
- package/src/lifecycle/raeto.ts +61 -0
- package/src/lifecycle/rpc.ts +10 -32
- package/src/lifecycle/snapshot.ts +1 -2
- package/src/lifecycle/transactions.ts +46 -9
- package/src/lifecycle/types.ts +38 -87
- package/src/lifecycle/ufg.ts +1 -1
- package/dist/lifecycle/fork.d.ts +0 -15
- package/dist/lifecycle/fork.d.ts.map +0 -1
- package/dist/lifecycle/fork.js +0 -36
- package/dist/lifecycle/fork.js.map +0 -1
- package/dist/lifecycle/simulation.d.ts +0 -17
- package/dist/lifecycle/simulation.d.ts.map +0 -1
- package/dist/lifecycle/simulation.js +0 -605
- package/dist/lifecycle/simulation.js.map +0 -1
- package/src/lifecycle/fork.ts +0 -36
- package/src/lifecycle/simulation.ts +0 -543
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lifecycle gas, capacity, execution evidence and RPC budgets
|
|
2
2
|
|
|
3
|
-
Version 0.
|
|
3
|
+
Version **0.16.0**, model **`robinhood-4663-capacity-v4`**, separates the native transaction ceiling, conservative capacity bounds, exact opening-curve quotes and actual transaction receipts. A ready assessment is not execution proof.
|
|
4
4
|
|
|
5
5
|
## One native ceiling, not component-sized gas
|
|
6
6
|
|
|
@@ -12,43 +12,160 @@ A reviewed launch gas differing from the ceiling is stale and refuses with `STAL
|
|
|
12
12
|
|
|
13
13
|
## Capacity selects the mode, not the gas limit
|
|
14
14
|
|
|
15
|
-
`computeLifecycleLaunchGasBounds({ plan, predictedToken, ufg?, headroomBps? })` returns conservative `atomicComputeGasUpperBound` and `activationComputeGasUpperBound`, excluding poster gas, or undefined for unknown coverage. The
|
|
15
|
+
`computeLifecycleLaunchGasBounds({ plan, predictedToken, ufg?, headroomBps? })` returns conservative `atomicComputeGasUpperBound` and `activationComputeGasUpperBound`, excluding poster gas, or undefined for unknown coverage. The v4 model covers Raeto fixed/dynamic and current auto-compounding static/dynamic in addition to the existing Abyss, V4, HMM and UFG templates. It accounts for token/reward creation, actual UFG proxy/treasury route, measured market/position work, ordered buys, NFT minting and HMM forwarding overhead. UFG route overhead is independent of market profile names.
|
|
16
16
|
|
|
17
|
-
An atomic request is a preference.
|
|
17
|
+
An atomic request is a preference. Multiple markets or conversion funding always select staged; one non-conversion market can remain atomic only when its conservative bound plus poster allocation fits. Explicit staged remains staged. Review and persist returned `planned.mode`, not the requested mode. No positions, markets or buys are dropped, and the gas envelope is never resized.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Preparation greedily packs contiguous markets using measured per-template/per-position costs, full calldata processing and padding. Activation cannot split. An activation bound plus poster allocation above 32M refuses before begin with `ACTIVATION_GAS_LIMIT`; an unknown profile refuses with `UNKNOWN_GAS_PROFILE`. A conservative refusal is not proof the actual transaction would overflow, but there is no simulation or execution fallback.
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## What planning does, and does not prove
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
| --- | --- | --- |
|
|
25
|
-
| Approval/reset | Wallet prepares gas/fees | Wallet prepares gas/fees |
|
|
26
|
-
| Begin | Conditional template admission | Exact native execution of the conversion |
|
|
27
|
-
| Prepare markets/hooks | Conditional template admission | Conditional admission when isolated after begin |
|
|
28
|
-
| Activate and opening buys | Conditional admission and exact local curve math | Exact native execution consuming conversion funding |
|
|
29
|
-
| Atomic launch | Conditional admission and exact local curve math | Exact native execution of the complete transaction |
|
|
30
|
-
| Cancel | Conditional admission | Conditional admission when isolated |
|
|
31
|
-
|
|
32
|
-
A conversion review proves the complete staged sequence through activation in one validated `eth_simulateV1` call, with every launch call at32M. Unknown template/currency coverage, another chain/ArbOS epoch or uncertain activation also uses real execution. A refused full review cannot authorize a new begin from a successful prefix; already-started recovery and cancellation remain available. Explicit `simulateLaunchPlan` always requests execution. A generic EVM fork is not Nitro protocol proof.
|
|
33
|
-
|
|
34
|
-
Unknown curve behavior retains a separate provisional, unvalidated buy-output diagnostic at the same ceiling before protecting minima. It is not gas sizing, final admission or a retry. The final protected commitment still requires its exact execution. There is no SDK-invented50M aggregate window; explicit `maxSimulationGas` policies remain enforced against complete observed work without prefix admission.
|
|
23
|
+
Planning and build-next read one pinned input/progress snapshot, compute exact local opening-buy outputs, check deterministic capacity and check affordability. They **never execute launch calldata**, including for conversion funding. The real router enforces its committed conversion floor/deadline when the user submits the transaction.
|
|
35
24
|
|
|
36
|
-
|
|
25
|
+
| Command | Planning/build-next behavior |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| Approval/reset | Discover allowance; wallet owns gas preparation. |
|
|
28
|
+
| Begin | Check inputs, complete activation capacity and full-ceiling affordability. |
|
|
29
|
+
| Prepare markets/hooks | Pack deterministic contiguous batches and check their budgets. |
|
|
30
|
+
| Activate and opening buys | Check unsplittable activation capacity and exact local ordered-buy floors. |
|
|
31
|
+
| Atomic launch | Require one non-conversion market with known capacity headroom. |
|
|
32
|
+
| Cancel | Build from canonical progress; no new profile capacity requirement. |
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
Check `planned.assessment.ready`, `code`, `reason`, optional `capacityConstraint`,
|
|
35
|
+
`assessment.estimate` and `assessment.gasProfile`. The gas profile contains
|
|
36
|
+
`version`, capacity `bounds` and exact local `initialBuys`, never invented
|
|
37
|
+
`gasUsed`. Launch commands use the native ceiling; approvals omit gas/fees.
|
|
38
|
+
Only actual included receipts and canonical Active/public-market state establish
|
|
39
|
+
execution. The owned fork harness below exercises the real contracts separately;
|
|
40
|
+
it is never selected as a planning backend.
|
|
42
41
|
|
|
43
42
|
## Retained empirical evidence
|
|
44
43
|
|
|
45
|
-
`robinhood-4663-
|
|
44
|
+
`robinhood-4663-capacity-v4` extends the retained release-template budgets with [Raeto and auto-compounding measurements](#raeto-and-auto-compounding-v4-evidence). These are empirical capacity bounds, not gas-limit sizing, a promise about arbitrary upgrades/future ArbOS rules, or native execution proof. Currency admission is separate: only Raeto imposes its deployed WETH/USDG quote allowlist.
|
|
46
45
|
|
|
47
46
|
Research retained176 lifecycle receipts, including75 successful current-template atomic/activation observations with opening buys. Isolated forks extend depth, buys and combinations; failed CREATE2 cases were not counted as successful coverage. One Abyss and one fixed-V4 historical native/fork calibration matched compute exactly (19,272,603 and18,130,251 gas), while minimum successful envelopes were higher (20,527,230 and19,356,279). These two calibrations do not establish general Anvil/Nitro equivalence. Compute and poster components remain separate. Profiles are empirical capacity bounds, never transaction gas sizing or proof about arbitrary upgrades/future ArbOS rules.
|
|
48
47
|
|
|
48
|
+
## Raeto and auto-compounding v4 evidence
|
|
49
|
+
|
|
50
|
+
`test/integration/template-gas.fork.mjs` owns an explicitly supplied loopback
|
|
51
|
+
Anvil on **8571** and accepts only its unlocked default development account.
|
|
52
|
+
It never loads a key or sends to mainnet. Each case snapshots/reverts the fork
|
|
53
|
+
and executes real SDK-produced calldata against the admitted deployment graph.
|
|
54
|
+
The matrix retains full portable plans and receipts' transaction hashes,
|
|
55
|
+
block numbers, `gasUsed`, characterization envelopes, calldata sizes,
|
|
56
|
+
Anvil minimum-gas estimates and separate 32M `eth_call` fit results in
|
|
57
|
+
`test/fixtures/template-gas-matrix.json`. Separate read-only SDK planning/build-next
|
|
58
|
+
assessments, referencing those retained real executions without replaying them,
|
|
59
|
+
are in `test/fixtures/template-gas-smoke.json`.
|
|
60
|
+
The creator/token identity may repeat across **isolated, reverted** cases, and
|
|
61
|
+
identical CREATE2 preimages reuse the SDK's deterministic mined salt. This avoids
|
|
62
|
+
unnecessary new empty-slot archive queries without retaining any launch state
|
|
63
|
+
between experiments. Complete plans identify the exact identity used in every
|
|
64
|
+
observation. The harness verifies the source pin and Anvil version and always
|
|
65
|
+
skips any scenario already recorded. The final missing-case selection covers
|
|
66
|
+
boundary depths/buys/market counts rather than repeating a redundant Cartesian
|
|
67
|
+
interior. Earlier valid observations remain in the evidence unchanged.
|
|
68
|
+
|
|
69
|
+
The source block/hash and Anvil version are recorded per run. Public RPC pruning,
|
|
70
|
+
rate limits and archive backend failures are not execution failures; the final
|
|
71
|
+
missing cases use a configured Alchemy archive. Its credential-bearing URL is
|
|
72
|
+
never logged or committed; evidence identifies the provider only as `alchemy`.
|
|
73
|
+
The synthetic economics ($5,000 FDV, WETH $3,000 / USDG $1) are explicit test
|
|
74
|
+
fixtures, not a live pricing recommendation.
|
|
75
|
+
Single-position recipes and adjacent 8-position distributions use SDK helpers;
|
|
76
|
+
an explicit adjacent 32-band fixture reaches the templates' structural maximum
|
|
77
|
+
without changing the public distribution catalogue's 2–16-position API.
|
|
78
|
+
Two-market cases divide at most 32 **total** positions between WETH and USDG.
|
|
79
|
+
Raeto cannot have a third V4 market because those are its only allowed quotes.
|
|
80
|
+
|
|
81
|
+
Anvil does not implement ArbOS precompiles. The harness reads
|
|
82
|
+
`ArbGasInfo.getPricesInWei` from the real native chain through the configured
|
|
83
|
+
archive at the fork's source pin. For read-only LaunchLens planning snapshots,
|
|
84
|
+
an `eth_call`-only ArbSys override maps `arbBlockNumber()` / `arbBlockHash(uint256)`
|
|
85
|
+
to Anvil's actual `NUMBER` / `BLOCKHASH` environment; it does not invent balances,
|
|
86
|
+
progress, addresses or protocol results. No deployed launch code/storage is
|
|
87
|
+
overridden and no measured launch is replayed by that smoke. All launch execution
|
|
88
|
+
uses the ordinary fork contracts.
|
|
89
|
+
USDG fixture funding is an ordinary deployed-token transfer from the fork's
|
|
90
|
+
real PoolManager balance, using fork-only impersonation; protocol code/storage
|
|
91
|
+
is not replaced. Characterization uses 100M gas to measure without assuming fit,
|
|
92
|
+
and separately calls the exact launch at 32M. The read-only profiled smoke checks
|
|
93
|
+
the SDK's actual 32M next-command envelope without re-executing a retained case.
|
|
94
|
+
**Anvil compute and successful local 32M calls are not native ArbOS/poster proof.**
|
|
95
|
+
|
|
96
|
+
The committed run contains **84 real launches / 186 successful launch
|
|
97
|
+
transactions** at Robinhood block **101,180,179**
|
|
98
|
+
(`0xe778e5d89ca2cab5843eedeb8c27b10f5463313d4b95b8971986ac72e297933c`):
|
|
99
|
+
59 retained observations plus 25 approved missing boundary cases. No retained
|
|
100
|
+
case was replayed. Depths are 1/8/32 total positions, one/two markets and
|
|
101
|
+
0/1/4 ordered buys, with both Raeto quotes and both auto-compound fee modes.
|
|
102
|
+
|
|
103
|
+
Observed peak EVM `gasUsed`, in millions (preparation columns distinguish batch size):
|
|
104
|
+
|
|
105
|
+
| Template | Cases | Atomic max | Prepare 1 market max | Prepare 2 markets max | Activation max |
|
|
106
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
107
|
+
| Raeto fixed | 42 | 41.664 | 11.222 | 17.831 | 22.228 |
|
|
108
|
+
| Raeto dynamic | 22 | 41.694 | 11.186 | 17.804 | 22.332 |
|
|
109
|
+
| Auto-compound static | 10 | 41.285 | 10.694 | 16.874 | 22.403 |
|
|
110
|
+
| Auto-compound dynamic | 10 | 41.369 | 10.753 | 16.992 | 22.445 |
|
|
111
|
+
|
|
112
|
+
The 32-position atomic extremes exceed 32M and select staged; their
|
|
113
|
+
activations fit. All measured one/eight-position atomic cases fit, including
|
|
114
|
+
several buys. `test/template-gas.test.mjs` requires every transaction's observed
|
|
115
|
+
gas **and** Anvil forwarding estimate to fit its model bound, at least 5%
|
|
116
|
+
observed-gas margin, and a bound below 32M whenever the observation fit that
|
|
117
|
+
ceiling. Begin uses the native 32M budget rather than a fabricated estimate.
|
|
118
|
+
|
|
119
|
+
V4 template coefficients below are compute basis, before at least **25%**
|
|
120
|
+
padding (or larger requested headroom), calldata processing and applicable
|
|
121
|
+
token/reward/NFT/fee-asset work. Existing offerings' coefficients are unchanged.
|
|
122
|
+
|
|
123
|
+
| Component | Raeto fixed/dynamic | Auto-compound static/dynamic |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| One-market atomic base | 18,000,000 | 18,000,000 |
|
|
126
|
+
| Atomic extra position | 600,000 | 600,000 |
|
|
127
|
+
| Activation call base | 1,500,000 | 1,500,000 |
|
|
128
|
+
| Activation per market | 500,000 | 750,000 |
|
|
129
|
+
| Activation per position | 500,000 | 500,000 |
|
|
130
|
+
| Preparation per market | 9,300,000 | 8,900,000 |
|
|
131
|
+
| Preparation extra position | 70,000 | 70,000 |
|
|
132
|
+
| Each opening buy | 500,000 + 25,000 × that market's positions | Same |
|
|
133
|
+
|
|
134
|
+
The per-buy position term matters: at 32 positions the measured marginal
|
|
135
|
+
exceeds 1M gas per buy, so inheriting the ordinary flat 0.5M would understate
|
|
136
|
+
larger buy sequences. Full calldata contributes 24 gas/byte and fee assets
|
|
137
|
+
100,000 each before padding. `computeLifecycleLaunchGasBounds` remains the
|
|
138
|
+
consumer API; coefficients are not transaction gas limits.
|
|
139
|
+
|
|
140
|
+
Auto-compounding's `_attemptCompound` exits for `Opening` before its 80k
|
|
141
|
+
low-gas guard whenever `_openingCompletedAt == 0`. The orchestrator executes all
|
|
142
|
+
ordered `_buy` calls before `_openMarkets`; opening completion is the terminal
|
|
143
|
+
market boundary. The harness checks exact quote spend/token outputs against
|
|
144
|
+
`InitialBuyExecuted`, every opening deferral, no `CompoundExecuted`, and
|
|
145
|
+
opening-completed event ordering. Therefore launch activation needs no
|
|
146
|
+
post-opening compounding forwarding reserve; HMM's separate reserve stays intact.
|
|
147
|
+
These launch constants are **not** gas limits for post-opening swaps.
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
# In each terminal, source the existing credential environment without printing it:
|
|
151
|
+
source ~/.config/robinhood-archive-rpc.env
|
|
152
|
+
export ROBINHOOD_ARCHIVE_RPC_URL
|
|
153
|
+
# Terminal 1; stop Anvil when finished:
|
|
154
|
+
anvil --fork-url "$ROBINHOOD_ARCHIVE_RPC_URL" \
|
|
155
|
+
--fork-block-number 101180179 --chain-id 4663 --port 8571 --host 127.0.0.1 \
|
|
156
|
+
--hardfork cancun --gas-limit 120000000 --quiet
|
|
157
|
+
# Terminal 2, in the worktree (source/export the environment here too):
|
|
158
|
+
pnpm build
|
|
159
|
+
TEMPLATE_FORK_RPC_URL=http://127.0.0.1:8571 \
|
|
160
|
+
node test/integration/template-gas.fork.mjs
|
|
161
|
+
# Read-only assessment of retained executed plans; no launch replay:
|
|
162
|
+
TEMPLATE_FORK_RPC_URL=http://127.0.0.1:8571 \
|
|
163
|
+
node test/integration/template-gas.fork.mjs --smoke
|
|
164
|
+
```
|
|
165
|
+
|
|
49
166
|
## Exact ordered opening-buy math
|
|
50
167
|
|
|
51
|
-
`computeLifecycleOpeningBuys({ plan, predictedToken })` follows all liquidity bands, prior buys, initialized zero-net ticks, bitmap boundaries, both currency directions, LP/opening-hook fees, partial fills and integer output floors. HMM opening work occurs after initial buys. V4's zero price-limit sentinel resolves locally to the contract-defined directional limit without changing calldata; Abyss still rejects zero.
|
|
168
|
+
`computeLifecycleOpeningBuys({ plan, predictedToken })` follows all liquidity bands, prior buys, initialized zero-net ticks, bitmap boundaries, both currency directions, LP/opening-hook fees, partial fills and integer output floors. HMM opening work occurs after initial buys. Auto-compounding defers until opening completes, after all initial buys; Raeto reuses the ordinary fixed/dynamic fee curve. V4's zero price-limit sentinel resolves locally to the contract-defined directional limit without changing calldata; Abyss still rejects zero.
|
|
52
169
|
|
|
53
170
|
Covered `buySlippageBps` protection uses `floor(tokenOut * (10000 - bps) / 10000)`. A zero floor rejects, never becomes1. Independent parity matched token output, quote spent and final square-root price across97 native/fork cases, including both directions, overlapping bands and gaps. Portable historical vectors and focused rounding/sentinel cases live under `test/fixtures/lifecycle-opening-buys.json` and `test/lifecycle-opening-buys.test.mjs`. These conditional curve quotes do not prove conversion, funding or wallet submission.
|
|
54
171
|
|
package/docs/reference.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the [launch guide](launch-lifecycle.md) for the end-to-end flow and the
|
|
4
4
|
[runner reference](../examples/README.md) for environment and recovery artifacts.
|
|
5
|
-
This page covers SDK **0.
|
|
5
|
+
This page covers SDK **0.16.0** addresses, limits, wire formats, fees, and diagnostics.
|
|
6
6
|
|
|
7
7
|
## Deployed infrastructure
|
|
8
8
|
|
|
@@ -20,6 +20,7 @@ start historical log queries there, in chunks of at most **10M blocks**.
|
|
|
20
20
|
| `UFG_TREASURY_FACTORY_ADDRESS` | `0x26Aa5D52134c8E6c4C01E9fb53A7568c0C64901F` |
|
|
21
21
|
| `UFG_UPSTREAM_FACTORY_ADDRESS` | `0xA170b5A58C111334A7237F2Ea2c428ec5022f68E` |
|
|
22
22
|
| Known deployment `launchLens` | `0xcb4bb3caca71fe52eace8170cf83e901418646f8` |
|
|
23
|
+
| `RAETO_PAYOUT_REGISTRY_ADDRESS` | `0xBEC2C0e91612090F82df6743F31CDF18B4386b50` |
|
|
23
24
|
|
|
24
25
|
`getKnownLifecycleDeployment`, `getKnownLifecycleProfile`, and
|
|
25
26
|
`listKnownLifecycleProfiles` are pure selectors keyed by chain/core. Unknown
|
|
@@ -133,8 +134,96 @@ UFG adds a canonical dynamic tuple via `encodeUfgLaunchConfig`:
|
|
|
133
134
|
`abi.encode((uint16,uint16,address[]))`, including the leading `0x20` offset.
|
|
134
135
|
`decodeUfgLaunchConfig` rejects alternate encodings and extra bytes;
|
|
135
136
|
`hashUfgLaunchConfig` hashes the tuple. Config6 appends typed `ufgLaunchConfig`
|
|
136
|
-
for UFG profiles only; Abyss carries no UFG tail. Full plan hashes bind
|
|
137
|
-
|
|
137
|
+
for UFG profiles only; Abyss carries no UFG tail. Full plan hashes bind every
|
|
138
|
+
auxiliary tail. HMM/UFG/Raeto constructor economics hash the zero-salt prefix;
|
|
139
|
+
auto-compounding profiles hash the zero-salt prefix **and** their tail.
|
|
140
|
+
|
|
141
|
+
## Auto-compounding profiles
|
|
142
|
+
|
|
143
|
+
| `KnownLifecycleProfile` | Profile ID |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| `V4AutoCompoundStaticPool` | `0xdd53c2c686f822b2d17536ccf4f9db954b4976d1be80404bc74571253179fae0` |
|
|
146
|
+
| `V4AutoCompoundDynamicPool` | `0x46b81bfe9316fbaa90e930c6f1d5ad5e6ecfced2c886fd5520ca2bae11b92744` |
|
|
147
|
+
|
|
148
|
+
`AUTO_COMPOUND_STATIC_V1_PROFILE_ID` / `AUTO_COMPOUND_DYNAMIC_V1_PROFILE_ID`
|
|
149
|
+
export these identities. The presets freeze the admitted envelope, adapter,
|
|
150
|
+
registration, topology and exact hook creation code. The generator checks preserved
|
|
151
|
+
admission bytes and successful receipts against registry `profile`,
|
|
152
|
+
`profileTopology`, `profileEnvelope`, adapter metadata, module identity and runtime
|
|
153
|
+
hashes at Robinhood block **100,486,085**
|
|
154
|
+
(`0xa41849e3e83fb977ed2fbfc7ff71c639bdf1fc34489dc46878128c021fdb6c44`).
|
|
155
|
+
These are construction snapshots, not a claim of current admission.
|
|
156
|
+
The disabled `0x1e41…1d68` / `0x53dd…e0d7` profiles are not supported.
|
|
157
|
+
|
|
158
|
+
`AutoCompoundConfigV1` contains `compoundShareBps` (integer 0–10,000).
|
|
159
|
+
`encodeAutoCompoundTail` / `decodeAutoCompoundTail` encode exactly
|
|
160
|
+
`abi.encode(bytes32 version, uint16 compoundShareBps)` (64 bytes), where
|
|
161
|
+
`AUTO_COMPOUND_CONFIG_VERSION = keccak256("black-market.auto-compound.config.v1")`.
|
|
162
|
+
The decoder requires the exact version, length and canonical narrow-integer
|
|
163
|
+
padding. Config6's typed `autoCompoundConfig` selects this tail only for these
|
|
164
|
+
two profiles; HMM, UFG and Raeto tails cannot be combined with it.
|
|
165
|
+
`validateAutoCompoundConfig`, the market codec and `validateV4LifecycleMarket`
|
|
166
|
+
reject invalid shares; the market boundaries also require zero LP/developer fees.
|
|
167
|
+
Both InputToken and QuoteOnly fee modes are supported.
|
|
168
|
+
|
|
169
|
+
`hashPoolBoundV4MarketCommitment` includes the entire canonical zero-salt config
|
|
170
|
+
for these profiles. Never mine against a prefix-only commitment or append a share
|
|
171
|
+
after mining. Use [the launch guide](launch-lifecycle.md#configure-auto-compounding)
|
|
172
|
+
for selection and gas behavior.
|
|
173
|
+
|
|
174
|
+
## Raeto profiles
|
|
175
|
+
|
|
176
|
+
All of the following are exported from `@black-market/sdk/lifecycle` (and the
|
|
177
|
+
root). These presets are supported on the known Robinhood 4663 deployment.
|
|
178
|
+
|
|
179
|
+
| Profile key / identity constant | Profile ID |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| `V4RaetoFixedPool` / `RAETO_FIXED_PROFILE_ID` | `0x9161833b162e7ca8160b11c64aedb307561e19a9136fd32f99cd797aab6da3ca` |
|
|
182
|
+
| `V4RaetoDynamicPool` / `RAETO_DYNAMIC_PROFILE_ID` | `0x08387d00ee4f75f860810cc8fb434087328592c2f39ea3321109e589039f80e1` |
|
|
183
|
+
|
|
184
|
+
`RAETO_FIXED_ADAPTER_ID` is
|
|
185
|
+
`0x911d7ecefe56489d329235e3484829717dc00400d4181902f0f2de45f9338615`;
|
|
186
|
+
`RAETO_DYNAMIC_ADAPTER_ID` is
|
|
187
|
+
`0x8ab9c8c9b8fd4c8bbf12b780d9474463fa0fa52e3b450f0d5f68fd067dc1674d`.
|
|
188
|
+
`isRaetoProfile(profileId)` compares IDs case-insensitively.
|
|
189
|
+
`RAETO_PAYOUT_REGISTRY_ADDRESS` identifies the controller-managed payout registry.
|
|
190
|
+
`RAETO_QUOTE_ASSETS` is the frozen checksummed `[WETH, USDG]` tuple:
|
|
191
|
+
`0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73`,
|
|
192
|
+
`0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`.
|
|
193
|
+
|
|
194
|
+
`RAETO_SHARE_BPS_OPTIONS` is readonly `[500, 1000, 2500, 5000, 7500]`.
|
|
195
|
+
`RaetoLaunchConfigV1 = { shareBps: number }`, `validateRaetoLaunchConfig`,
|
|
196
|
+
`encodeRaetoLaunchTail` and `decodeRaetoLaunchTail` enforce exactly that menu and
|
|
197
|
+
exactly `abi.encode(uint16 shareBps)` (one 32-byte word). Noncanonical uint16
|
|
198
|
+
padding, extra/missing bytes, zero and non-menu shares throw
|
|
199
|
+
`INVALID_RAETO_CONFIG`. V6 `raetoLaunchConfig` is mutually exclusive with all
|
|
200
|
+
other tails; Raeto requires QuoteOnly, zero LP/developer fees and allowed quotes.
|
|
201
|
+
`validateRaetoLaunchPlan(plan)` checks **every** market and throws
|
|
202
|
+
`INVALID_RAETO_PLAN`, including for wrong profiles/adapters, schemas or quotes.
|
|
203
|
+
It adds no UFG token/reward/proxy restrictions.
|
|
204
|
+
|
|
205
|
+
`raetoFeeCollectorV1Abi` is generated from verified standard-output and includes
|
|
206
|
+
`shareBps()`, `owed(address)`, `launchToken()`, `quoteAsset()`,
|
|
207
|
+
`setShareBps(uint16)`, `claimRaeto(address)` and the exact three Raeto events.
|
|
208
|
+
See [fee ownership and collection semantics](launch-lifecycle.md#configure-raeto).
|
|
209
|
+
|
|
210
|
+
`test/fixtures/raeto-registry-readback.json` preserves admission bytes/receipts,
|
|
211
|
+
runtime hashes, factory metadata, verified ABI provenance and real factory
|
|
212
|
+
`eth_call` share-menu results at **101,180,179**
|
|
213
|
+
(`0xe778e5d89ca2cab5843eedeb8c27b10f5463313d4b95b8971986ac72e297933c`).
|
|
214
|
+
The deployed source commit is `a39c958` (go-live record `02e5cf3`), **not** the
|
|
215
|
+
later local `80ea8c8` share-range change. The generator proves hook creation bytes
|
|
216
|
+
equal the SDK's existing fixed and zero-royalty dynamic bytecode.
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
# Offline, deterministic regeneration from saved evidence (Node 24+):
|
|
220
|
+
node --experimental-transform-types scripts/generate-raeto-presets.mjs
|
|
221
|
+
# Explicit read-only refresh, checking the preserved go-live records:
|
|
222
|
+
node --experimental-transform-types scripts/generate-raeto-presets.mjs \
|
|
223
|
+
--readback /path/to/black-market
|
|
224
|
+
pnpm build
|
|
225
|
+
node --test test/integration/raeto.live.test.mjs
|
|
226
|
+
```
|
|
138
227
|
|
|
139
228
|
## Choose a fee tier
|
|
140
229
|
|
|
@@ -313,6 +402,26 @@ From the checkout root, `pnpm test` runs offline tests and `pnpm examples` perfo
|
|
|
313
402
|
read-only deployed discovery. The following checks require separate infrastructure;
|
|
314
403
|
run write-capable checks only with explicit permission on disposable services.
|
|
315
404
|
|
|
405
|
+
### Auto-compounding read-only checks
|
|
406
|
+
|
|
407
|
+
After `pnpm build`, compare both profiles and fee modes with the live collector
|
|
408
|
+
factory's metadata/decoder and the reference Python encoder (no signing or sends):
|
|
409
|
+
|
|
410
|
+
```sh
|
|
411
|
+
BLACK_MARKET_REFERENCE_ROOT=/path/to/black-market \
|
|
412
|
+
node --test test/integration/auto-compound.live.test.mjs
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
The reference checkout must contain `scripts/auto_compound_config.py` and its
|
|
416
|
+
Python dependencies. Regenerate the frozen deployment modules offline with:
|
|
417
|
+
|
|
418
|
+
```sh
|
|
419
|
+
node --experimental-transform-types scripts/generate-auto-compound-presets.mjs
|
|
420
|
+
# Explicitly refresh readback from a new pinned L2 header plus preserved admission evidence:
|
|
421
|
+
node --experimental-transform-types scripts/generate-auto-compound-presets.mjs \
|
|
422
|
+
--readback /path/to/black-market
|
|
423
|
+
```
|
|
424
|
+
|
|
316
425
|
### UFG owned-fork check
|
|
317
426
|
|
|
318
427
|
Run Anvil and the test in separate terminals; stop Anvil afterward:
|
package/examples/.env.example
CHANGED
|
@@ -37,6 +37,3 @@ NFT_BASE_URI=
|
|
|
37
37
|
# EXAMPLE_MAX_CALLDATA_BYTES=
|
|
38
38
|
# EXAMPLE_HEADROOM_BPS=1500
|
|
39
39
|
#
|
|
40
|
-
# Robinhood aggregate simulation gas-used budget defaults to 50M. Override only for
|
|
41
|
-
# a provider supporting that budget; buy-output calibration needs activation coverage.
|
|
42
|
-
# EXAMPLE_SIMULATION_GAS_CAP=100000000
|
package/examples/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Run the examples
|
|
2
2
|
|
|
3
|
-
These commands use the checkout's built `@black-market/sdk` **0.
|
|
3
|
+
These commands use the checkout's built `@black-market/sdk` **0.16.0** and viem.
|
|
4
4
|
Use **Node 24+** for direct TypeScript execution. Start with the one-market
|
|
5
|
-
`launch-erc20-abyss.ts`; larger cases
|
|
5
|
+
`launch-erc20-abyss.ts`; larger cases require staged preparation and a bounded activation.
|
|
6
6
|
For valuation, token ordering, ranges, and buy protection, read the
|
|
7
7
|
[launch guide](../docs/launch-lifecycle.md#price-the-launch).
|
|
8
8
|
|
|
@@ -20,7 +20,7 @@ chmod 600 .env
|
|
|
20
20
|
Launch wrappers load `.env` from the working directory with `process.loadEnvFile`.
|
|
21
21
|
Existing environment values take precedence. Values are literal; shell interpolation
|
|
22
22
|
is not applied. Use the matching SDK version when copying wrappers into a consumer project:
|
|
23
|
-
`pnpm add @black-market/sdk@0.
|
|
23
|
+
`pnpm add @black-market/sdk@0.16.0 viem`.
|
|
24
24
|
Copy `launch-example.ts`, `launch-example-support.ts`, and `launch-example-kyber.ts` with the wrapper.
|
|
25
25
|
|
|
26
26
|
### Configure the environment
|
|
@@ -44,7 +44,6 @@ Copy `launch-example.ts`, `launch-example-support.ts`, and `launch-example-kyber
|
|
|
44
44
|
| `EXAMPLE_ACCOUNT_GAS_CAP` | Optional wallet/account transaction gas-envelope ceiling. |
|
|
45
45
|
| `EXAMPLE_MAX_CALLDATA_BYTES` | Optional whole-transaction byte ceiling. |
|
|
46
46
|
| `EXAMPLE_HEADROOM_BPS` | Gas headroom, default `1500`; accepted range 0–10,000. |
|
|
47
|
-
| `EXAMPLE_SIMULATION_GAS_CAP` | Optional aggregate simulation-used gas ceiling; no SDK-invented default window. |
|
|
48
47
|
|
|
49
48
|
Configure **exactly one** of `PRIVATE_KEY` and `EXAMPLE_KEYSTORE_PATH`.
|
|
50
49
|
A keystore must be a regular file owned by your user with owner-only permissions.
|
|
@@ -117,19 +116,20 @@ node examples/launch-erc20-abyss.ts --resume "launch-results/<original-run-dir>"
|
|
|
117
116
|
|
|
118
117
|
| Mode | Reads / writes | Identity |
|
|
119
118
|
| --- | --- | --- |
|
|
120
|
-
| No flags | Live discovery, funding quotes, preparation,
|
|
119
|
+
| No flags | Live discovery, funding quotes, preparation, local economic review and gas-budget checks; unsigned, no API writes | Fresh plan/run directory |
|
|
121
120
|
| `--broadcast` | Signs, spends, stages/uploads metadata, deploys, verifies, and publishes; no further prompt | **Fresh plan**, not the preceding dry run |
|
|
122
121
|
| `--resume <original-run-dir>` | May sign remaining steps or finish publication | Retained plan, receipts, mode, confirmation policy, and API session |
|
|
123
122
|
|
|
124
|
-
Dry-run needs the signer source, RPC/API, and sufficient funds for
|
|
123
|
+
Dry-run needs the signer source, RPC/API, and sufficient funds for current input/gas-budget checks.
|
|
125
124
|
Review its economics, then review the fresh broadcast output too. Mode flags cannot
|
|
126
125
|
be combined or duplicated. Resume is an execution authorization; omit `--broadcast`.
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
Every launch transaction uses the native ceiling,32M total on4663. Capacity profiles
|
|
128
|
+
only choose mode/chunks and reject oversized activation; exact local ordered math
|
|
129
|
+
protects opening buys. Multiple markets or conversion funding always stage.
|
|
130
|
+
There is no launch simulation, including Kyber. Routers enforce conversion minima
|
|
131
|
+
and deadlines on-chain; `assessment.ready` is not a receipt or guaranteed execution.
|
|
132
|
+
See [coverage and migration](../docs/lifecycle-gas-profiles.md).
|
|
133
133
|
|
|
134
134
|
### Fund opening buys
|
|
135
135
|
|
|
@@ -252,14 +252,10 @@ export function exampleError(code, message, details = {}) {
|
|
|
252
252
|
return Object.assign(new Error(message), { name: "LaunchExampleError", code, ...details });
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
/**
|
|
256
|
-
export function rpcRequestSignal(signal
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// Cold nested-fork state fetches can exceed 30 seconds. Bound each request,
|
|
260
|
-
// including instrumented controlled simulation; never retry a source broadcast.
|
|
261
|
-
const timeout = AbortSignal.timeout(120_000);
|
|
262
|
-
return cleanup ? timeout : AbortSignal.any([signal, timeout]);
|
|
255
|
+
/** Bound each request and preserve interruption; launch planning owns no fork cleanup. */
|
|
256
|
+
export function rpcRequestSignal(signal) {
|
|
257
|
+
signal.throwIfAborted();
|
|
258
|
+
return AbortSignal.any([signal, AbortSignal.timeout(120_000)]);
|
|
263
259
|
}
|
|
264
260
|
|
|
265
261
|
|
|
@@ -540,7 +536,6 @@ export async function readExampleConfiguration(sdk, redactor, env = process.env)
|
|
|
540
536
|
chainTransactionGasLimit: gasCap("EXAMPLE_CHAIN_GAS_CAP"),
|
|
541
537
|
rpcTransactionGasLimit: gasCap("EXAMPLE_RPC_GAS_CAP"),
|
|
542
538
|
accountTransactionGasLimit: gasCap("EXAMPLE_ACCOUNT_GAS_CAP"),
|
|
543
|
-
rpcTotalSimulationGasLimit: gasCap("EXAMPLE_SIMULATION_GAS_CAP"),
|
|
544
539
|
maxCalldataBytes: integer("EXAMPLE_MAX_CALLDATA_BYTES", undefined, 1, Number.MAX_SAFE_INTEGER),
|
|
545
540
|
headroomBps: integer("EXAMPLE_HEADROOM_BPS", 1500, 0, 10000),
|
|
546
541
|
provenance: { scope: "user-ceilings", note: "Optional local tightening restrictions, not verified provider or account limits" },
|
|
@@ -78,7 +78,7 @@ function rpcClient(url, artifacts, signal, label) {
|
|
|
78
78
|
// the example RPC client is admitted identically to the UI it validates.
|
|
79
79
|
if (endpoint.hostname === "rpc.mainnet.chain.robinhood.com") headers.Origin = "https://abyss.trading";
|
|
80
80
|
return { async request({ method, params = [] }) {
|
|
81
|
-
const requestSignal = rpcRequestSignal(signal
|
|
81
|
+
const requestSignal = rpcRequestSignal(signal);
|
|
82
82
|
const started = Date.now();
|
|
83
83
|
try {
|
|
84
84
|
const response = await fetch(endpoint, {
|
|
@@ -90,7 +90,6 @@ function rpcClient(url, artifacts, signal, label) {
|
|
|
90
90
|
const body = await response.json();
|
|
91
91
|
if (body.error) throw exampleError(body.error.code ?? "RPC_ERROR", `${label} ${method}: ${body.error.message}`, { data: body.error.data, cause: body.error });
|
|
92
92
|
if (!("result" in body)) throw exampleError("INVALID_RPC_RESPONSE", `${label} ${method}: result was omitted`, { data: body });
|
|
93
|
-
if (method === "eth_simulateV1") artifacts.event("rpc-observation", { backend: label, method, params, result: body.result, elapsedMs: Date.now() - started });
|
|
94
93
|
return body.result;
|
|
95
94
|
} catch (error) {
|
|
96
95
|
artifacts.event("rpc-error", { backend: label, method, params, elapsedMs: Date.now() - started, error: errorEvidence(error) });
|
|
@@ -307,21 +306,9 @@ async function constructPlan({ client, fixture, scenario, sdk, artifacts, signal
|
|
|
307
306
|
market.retainedSupplyOpeningValuationUsdX18 = ratio.numerator * retainedSupply * market.quoteUsdX18 /
|
|
308
307
|
(ratio.denominator * 10n ** BigInt(market.quoteDecimals));
|
|
309
308
|
}
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (activationStep?.success && activationStep.returnData) {
|
|
314
|
-
const receipt = decodeFunctionResult({ abi: sdk.launchLifecycleAbi,
|
|
315
|
-
functionName: activationTransaction.kind === "atomic" ? "launchAtomic" : "activateLaunch", data: activationStep.returnData });
|
|
316
|
-
assert.equal(receipt.planHash.toLowerCase(), planned.planHash.toLowerCase(), "Economic receipt exact plan");
|
|
317
|
-
assert.equal(receipt.tokenOut.length, planned.plan.buys.length, "Economic receipt ordered outputs");
|
|
318
|
-
assert.equal(receipt.quoteSpent.length, planned.plan.buys.length, "Economic receipt ordered spending");
|
|
319
|
-
orderedOutputs = receipt.tokenOut.map((tokenOut, index) => ({ tokenOut, quoteSpent: receipt.quoteSpent[index] }));
|
|
320
|
-
buyEvidence = "simulated-execution";
|
|
321
|
-
} else if (planned.simulation.backend === "profiled" && planned.simulation.gasProfile) {
|
|
322
|
-
orderedOutputs = planned.simulation.gasProfile.initialBuys;
|
|
323
|
-
buyEvidence = "local-exact-curve";
|
|
324
|
-
} else throw exampleError("MISSING_ECONOMIC_OUTPUTS", "Economic review requires ordered buy outputs from exact execution or the covered local curve");
|
|
309
|
+
const orderedOutputs = planned.assessment.gasProfile?.initialBuys;
|
|
310
|
+
if (!orderedOutputs) throw exampleError("MISSING_ECONOMIC_OUTPUTS", "Economic review requires the supported exact local opening curve");
|
|
311
|
+
const buyEvidence = "local-exact-curve";
|
|
325
312
|
assert.equal(orderedOutputs.length, planned.plan.buys.length, "Economic review ordered outputs");
|
|
326
313
|
const reviewedBuys = planned.plan.buys.map((buy, index) => {
|
|
327
314
|
const { tokenOut, quoteSpent } = orderedOutputs[index];
|
|
@@ -346,7 +333,7 @@ async function constructPlan({ client, fixture, scenario, sdk, artifacts, signal
|
|
|
346
333
|
[{ marketIndex, feeMode: spec.feeMode ?? 0, protocolFeeDenominator: selected.v4.envelope.protocolFeeDenominator,
|
|
347
334
|
treasury: selected.v4.envelope.protocolTreasury, developerBeneficiary: selected.v4.envelope.beneficiary, developerFeeBps: 0 }] : []) },
|
|
348
335
|
initialBuy: { slippageBps: BUY_SLIPPAGE_BPS, funding: planned.plan.funding, orderedBuys: planned.plan.buys, reviewedBuys, evidence: buyEvidence,
|
|
349
|
-
observedBlockNumber: planned.
|
|
336
|
+
observedBlockNumber: planned.assessment.blockNumber, observedBlockHash: planned.assessment.blockHash },
|
|
350
337
|
planHash: planned.planHash, finalizedPlan: finalizedPlan,
|
|
351
338
|
};
|
|
352
339
|
const reviewHash = economicReviewHash(economicReview);
|
|
@@ -485,7 +472,6 @@ function limitSource(fixture, artifacts) {
|
|
|
485
472
|
chainGasLimit: policy.chainTransactionGasLimit === undefined ? undefined : BigInt(policy.chainTransactionGasLimit),
|
|
486
473
|
rpcGasLimit: policy.rpcTransactionGasLimit === undefined ? undefined : BigInt(policy.rpcTransactionGasLimit),
|
|
487
474
|
accountGasLimit: policy.accountTransactionGasLimit === undefined ? undefined : BigInt(policy.accountTransactionGasLimit),
|
|
488
|
-
maxSimulationGas: policy.rpcTotalSimulationGasLimit === undefined ? undefined : BigInt(policy.rpcTotalSimulationGasLimit),
|
|
489
475
|
maxCalldataBytes: policy.maxCalldataBytes, headroomBps: policy.headroomBps,
|
|
490
476
|
};
|
|
491
477
|
artifacts.event("execution-limits", { limits, provenance: policy.provenance });
|
|
@@ -517,12 +503,10 @@ async function executePlan({ client, fixture, planned, sdk, artifacts, signal, l
|
|
|
517
503
|
assert.ok(functionName, "Native-input conversion cases do not permit unrelated approval/cancellation writes");
|
|
518
504
|
const args = next.kind === "begin" ? [planned.plan, sdk.LifecycleMode.Staged] : next.kind === "prepare" ? [planned.plan, next.marketStart, next.marketCount] : [planned.plan];
|
|
519
505
|
assert.equal(next.data.toLowerCase(), encodeFunctionData({ abi: sdk.launchLifecycleAbi, functionName, args }).toLowerCase(), "Exact finalized-plan calldata");
|
|
520
|
-
assert.ok(next.gas !== undefined && (next.gasPrice !== undefined || next.maxFeePerGas !== undefined && next.maxPriorityFeePerGas !== undefined) && next.
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const
|
|
524
|
-
assert.ok(next.gas === next.admission.limits.executionGasCeiling && (ceiling === undefined || next.gas <= ceiling), "Launch gas must equal the native ceiling and fit supplied restrictions");
|
|
525
|
-
const calldataCap = next.admission.limits.maxCalldataBytes;
|
|
506
|
+
assert.ok(next.gas !== undefined && (next.gasPrice !== undefined || next.maxFeePerGas !== undefined && next.maxPriorityFeePerGas !== undefined) && next.assessment?.ready === true, "Actual next transaction needs a current gas budget");
|
|
507
|
+
const ceiling = next.assessment.limits.transactionGasCeiling;
|
|
508
|
+
assert.ok(next.gas === next.assessment.limits.executionGasCeiling && (ceiling === undefined || next.gas <= ceiling), "Launch gas must equal the native ceiling and fit supplied restrictions");
|
|
509
|
+
const calldataCap = next.assessment.limits.maxCalldataBytes;
|
|
526
510
|
assert.ok(calldataCap === undefined || (next.data.length - 2) / 2 <= calldataCap, "Exact calldata must fit any supplied cap");
|
|
527
511
|
const envelope = transactionEnvelope(next);
|
|
528
512
|
const wire = { ...envelope };
|
|
@@ -890,10 +874,10 @@ async function executeExample({ fixture, privateKey, scenario, sdk, artifacts, s
|
|
|
890
874
|
const { planned, predictedToken, economicReview, reviewHash } = await constructPlan({ client, fixture, scenario, sdk, artifacts, signal, limits, metadata, image });
|
|
891
875
|
const { plan } = planned;
|
|
892
876
|
artifacts.save("planning.json", planned);
|
|
893
|
-
artifacts.event("execution-plan", { mode: planned.mode,
|
|
877
|
+
artifacts.event("execution-plan", { mode: planned.mode, assessment: planned.assessment, prerequisites: planned.prerequisites, transactions: planned.transactions });
|
|
894
878
|
if (scenario.mode === "staged") assert.equal(planned.mode, "staged", "Explicit staged mode is retained");
|
|
895
879
|
addressEqual(planned.predictedToken, predictedToken, "Planner token prediction");
|
|
896
|
-
if (!planned.
|
|
880
|
+
if (!planned.assessment.ready) throw exampleError(planned.assessment.code ?? "PLAN_NOT_READY", planned.assessment.reason ?? "Refresh the launch review before continuing.", { assessment: planned.assessment });
|
|
897
881
|
const usd = (value) => `${value / UNIT}.${(value % UNIT).toString().padStart(18, "0")}`;
|
|
898
882
|
const fundingSummary = economicReview.quotes.every((quote) => quote.conversion.nativeWrap === true)
|
|
899
883
|
? "payable native wrap"
|
|
@@ -1089,7 +1073,7 @@ export async function resumeLaunchExample({ fixture, privateKey, sdk, artifacts,
|
|
|
1089
1073
|
if (![sdk.LifecyclePhase.Preparing, sdk.LifecyclePhase.Ready, sdk.LifecyclePhase.Active].includes(progress.canonical.phase)) {
|
|
1090
1074
|
throw exampleError("RESUME_PHASE_UNSUPPORTED", "Resume requires canonical Preparing, Ready or Active; an unstarted or cancelled launch must never be relaunched");
|
|
1091
1075
|
}
|
|
1092
|
-
if (!planned.
|
|
1076
|
+
if (!planned.assessment.ready) throw exampleError(planned.assessment.code ?? "PLAN_NOT_READY", planned.assessment.reason ?? "Refresh the unfinished launch review before continuing.", { assessment: planned.assessment });
|
|
1093
1077
|
Object.assign(artifacts.result.chain, { planHash: planned.planHash, launchId: planned.launchId, predictedToken: planned.predictedToken });
|
|
1094
1078
|
// Canonical receipts restore the begin/deployment logs needed by verifyChain.
|
|
1095
1079
|
for (const reference of references) {
|