@black-market/sdk 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Abyss](assets/splash.png)
1
+ ![Abyss](https://raw.githubusercontent.com/abysshopper/black-market-node-sdk/main/assets/splash.png)
2
2
 
3
3
  # @black-market/sdk
4
4
 
@@ -59,30 +59,50 @@ Staged preparation does **not** split activation: minting, permanent locking,
59
59
  every initial buy, and public opening remain one transaction. Unavailable
60
60
  stateful simulation or execution-limit evidence prevents executable admission.
61
61
 
62
- See the [launch lifecycle guide](docs/launch-lifecycle.md) for codecs, saved-plan
63
- review, salt mining, simulation, recovery, and stable-author fee claims.
64
- [`examples/`](examples/README.md) includes unsigned review and explicitly authorized
65
- local-chain execution. `LaunchApiClient` optionally handles signed metadata
66
- sessions and publication; it does not create or broadcast a chain launch.
62
+ See the [launch lifecycle guide](https://github.com/abysshopper/black-market-node-sdk/blob/main/docs/launch-lifecycle.md)
63
+ for codecs, saved-plan review, salt mining, simulation, recovery, and stable-author
64
+ fee claims. [`examples/`](https://github.com/abysshopper/black-market-node-sdk/tree/main/examples)
65
+ also includes read-only discovery and unsigned saved-plan review. `LaunchApiClient`
66
+ handles signed metadata sessions and publication; it does not broadcast a chain launch.
67
67
 
68
- ## Create one local smoke token
68
+ ## Launch examples: one command per case
69
69
 
70
- Use the [owned-fixture smoke guide](docs/launch-lifecycle.md#individual-token-creation-smoke)
71
- to prepare a current-chain fork, then run one catalogue case:
70
+ **Running any command below deliberately signs, spends funds, launches a token,
71
+ and publishes through your configured API. Mainnet execution is irreversible.**
72
+ No flags, parameters, fixture files, default private keys or API skips are used.
73
+
74
+ Setup once with **Node 24+**: install dependencies (`pnpm install` in this repository,
75
+ or `pnpm add @black-market/sdk viem` in a consumer), copy
76
+ [`examples/.env.example`](https://github.com/abysshopper/black-market-node-sdk/blob/main/examples/.env.example)
77
+ to `.env` in your working directory, and set your funded wallet's `PRIVATE_KEY`
78
+ and actual `LAUNCH_API_URL`. Existing process environment wins over `.env`.
79
+ Consumer projects may copy the example files plus both shared helpers into `examples/`;
80
+ the implementation imports the installed public `@black-market/sdk` package.
72
81
 
73
82
  ```sh
74
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json --list
75
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json \
76
- --case erc20-v4-basic --output /tmp/node-launch-one \
77
- --execute --api-url http://127.0.0.1:18763
83
+ node examples/launch-erc20-v4.mjs
84
+ node examples/launch-erc20-abyss.mjs
85
+ node examples/launch-erc404-v4.mjs
86
+ node examples/launch-erc404-abyss.mjs
87
+ node examples/launch-erc20-staking-v4.mjs
88
+ node examples/launch-erc20-dividends-abyss.mjs
89
+ node examples/launch-erc20-burn-mixed.mjs
90
+ node examples/launch-erc404-dividends-mixed.mjs
78
91
  ```
79
92
 
80
- Without `--execute`, this only saves an unsigned finalized plan—no simulation
81
- transactions, signing, API session or launch. Execution verifies the actual token,
82
- markets, permanent custody, buys and API publication/indexing. `--chain-only`
83
- explicitly skips the API and is not an end-to-end pass. Every run uses a fresh
84
- directory with redacted evidence retained on failure; no source-chain rollback,
85
- production write, package publishing or git push is performed.
93
+ Run only the case you intend to launch. `RPC_URL` defaults to the SDK official
94
+ chain-4663 mainnet endpoint. Optional `SIMULATION_RPC_URL` selects a separate owned
95
+ loopback Anvil for SDK controlled simulation; otherwise actual native `eth_simulateV1`
96
+ support is required. Admission failures do not change mode or economics.
97
+ Gas/calldata defaults are **EXAMPLE ceilings, not verified provider/account limits**.
98
+ Full setup, exact case economics, optional environment caps, and recovery are in the
99
+ [example guide](https://github.com/abysshopper/black-market-node-sdk/blob/main/examples/README.md#individual-token-creation).
100
+
101
+ Every run creates a fresh `launch-results/<timestamp-case-random>/` and retains
102
+ redacted logs, plans, signed transaction hashes **before broadcast**, and real receipts
103
+ even on failure. Only `private-recovery.json` (mode `0600`) stores raw signed bytes,
104
+ API signatures and capabilities. **Do not blindly rerun after an ambiguous broadcast**;
105
+ inspect the retained hash first. There is no broadcast retry, relaunch or source rollback.
86
106
 
87
107
  ## Networks and configuration
88
108
 
@@ -135,7 +155,7 @@ LAUNCH_API_TEST_PRIVATE_KEY="$DISPOSABLE_TEST_PRIVATE_KEY" pnpm test:api:write
135
155
  defaults to the mainnet orchestrator above and must match the service signing domain.
136
156
  No image store, indexed launch, funded wallet, or chain write is required. These
137
157
  sessions prove HTTP metadata behavior, not image publication or a chain launch.
138
- Service requirements are in the [API integration section](docs/launch-lifecycle.md#real-http-api-integration).
158
+ Service requirements are in the [API integration section](https://github.com/abysshopper/black-market-node-sdk/blob/main/docs/launch-lifecycle.md#real-http-api-integration).
139
159
 
140
160
  ## License
141
161
 
@@ -286,93 +286,72 @@ real-graph refusals/reorg/cancellation with the same fixture environment. See
286
286
  [example instructions](../examples/README.md#actual-owned-fixture-proof) for the explicit
287
287
  local-execution opt-in and required files.
288
288
 
289
- ## Individual token creation smoke
290
-
291
- `pnpm smoke:launch` builds the SDK and runs `examples/smoke-launch.mjs` for **one**
292
- case from an explicit `black-market.launch-smoke-fixture.v1` file. The
293
- [shared local setup and eight case commands](../../black-market/docs/sdk-launch-smoke.md)
294
- create separate owned loopback execution/simulation Anvil instances on chain `4663`
295
- using the current deployed graph, not a replacement launcher. Use a real loopback
296
- API with application storage and an indexer configured for that same execution chain.
297
- No default live endpoint, private key, source-chain snapshot rollback or production
298
- write is used. The older whole-suite Solidity-exported proof remains separate.
299
-
300
- ```sh
301
- pnpm smoke:launch --help
302
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json --list
303
-
304
- # Default plan-only: registry/provenance reads, token prediction and offchain salt mining.
305
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json \
306
- --case erc20-staking-v4 --output /tmp/node-staking-plan
307
-
308
- # Actual metadata signature/session, launch, custody/buy checks, publication and token GET.
309
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json \
310
- --case erc20-staking-v4 --output /tmp/node-staking-launch \
311
- --execute --api-url http://127.0.0.1:18763 --publish-timeout-seconds 90
312
-
313
- # API omitted by explicit choice, not a full end-to-end pass.
314
- pnpm smoke:launch --fixture /tmp/sdk-smoke/fixture.json \
315
- --case erc404-abyss --output /tmp/node-erc404-chain --execute --chain-only
316
- ```
317
-
318
- `--list` reads only the fixture catalogue, with no RPC, signature or write. A default
319
- run persists the finalized portable `plan.json` and reports **“Plan prepared; launch
320
- not executed”**, `scope: "plan-only"`, `execution: "not-run"` and API `not-run`.
321
- Only `--execute` permits SDK `planLaunch`/controlled-fork simulation, metadata signing,
322
- session creation and `eth_sendTransaction` from the fixture's unlocked Anvil creator.
323
- Every endpoint must be an explicit loopback root and the fixture must declare
324
- `fixtureOnly: true`; execution/simulation ports must differ. An API endpoint can come
325
- from `fixture.apiUrl` or `--api-url`, never the production SDK default.
326
- Local execution and instrumented simulation RPC HTTP calls have a bounded
327
- 120-second per-request timeout to accommodate cold nested-fork state reads; they
328
- are not retried. API requests retain their separate timeout and publication deadline.
329
-
330
- All eight cases cover ERC20/ERC404, staking/dividends, token-only burn, atomic/staged
331
- execution, V4/Abyss/mixed markets and one through five permanent positions. Profiles
332
- are registry-discovered: V4 must be admitted bound topology/config `5`; Abyss must be
333
- the adapter's exact `profileId(3)` QUOTE_ORACLE/config `1`, not the first Abyss entry.
334
- The runner uses exact frozen V4 treasury/denominator/author terms, explicit developer
335
- rate `0`, measured local gas/calldata caps, current-block deadline and NativeWrap
336
- funding. ERC20 supply is `1_000_000e18`; ERC404 supply is `10_000e18` with `100e18`
337
- NFT units. It finalizes hook salts and saves the random identity before any write,
338
- never switching mode, dropping positions/buys or changing economics to obtain admission.
289
+ ## Individual token creation examples
290
+
291
+ Eight independent `examples/launch-erc20-*.mjs` / `launch-erc404-*.mjs` files invoke
292
+ the shared `runLaunchExample(caseObject)` using fixed economics and no parameters or
293
+ fixture files. See the [example guide](../examples/README.md#individual-token-creation)
294
+ for the eight one-line commands and setup-once working-directory `.env`.
295
+ Node 24+ loads `.env` once, with existing process environment taking precedence.
296
+ `PRIVATE_KEY` and `LAUNCH_API_URL` are required before RPC/signing/API work; there is
297
+ no default key, guessed API or API-omission mode. Running a case deliberately authorizes
298
+ real local signing, source-chain transactions and API publication; mainnet writes are
299
+ irreversible. The official SDK chain-4663 RPC is the default.
300
+
301
+ The implementation imports public `@black-market/sdk`, resolves `getAddresses(4663)`,
302
+ derives the creator from the key and discovers the actual admitted profiles. V4 requires
303
+ bound topology/config `5`; Abyss requires exact adapter `profileId(3)` QUOTE_ORACLE/config
304
+ `1`. It verifies wrapped-native binding/decimals and registered P1 oracle `(1,4096)`.
305
+ All eight original token/reward/venue/position/mode cases retain their exact economics:
306
+ ERC20 `1_000_000e18` supply; ERC404 `10_000e18` supply / `100e18` NFT unit; selected
307
+ staking/dividends and token-only burn; one through five permanent positions and ordered
308
+ native-wrap opening buys. It saves identity/finalized salts/plans before execution and
309
+ never changes mode, drops positions/buys or overrides failed admission.
310
+ Optional `NFT_BASE_URI` provides an ERC404 base URI you actually host; its default is
311
+ empty, with real NFT units/mirror behavior but no claim of hosted NFT metadata.
312
+
313
+ Optional `SIMULATION_RPC_URL` uses the canonical SDK controlled fork on a separate
314
+ owned disposable loopback Anvil. Otherwise real native sequential `eth_simulateV1` is
315
+ required. Only the simulation fork is reset/impersonated/reverted. Source RPC requests
316
+ have a 120-second bound and are not retried. Default gas `16000000`, calldata `131072`
317
+ and headroom `1000` bps are explicitly **EXAMPLE ceilings, not verified provider/account
318
+ limits**; the chain cap is bounded by observed block gas limits. Environment overrides
319
+ are documented in the example guide and remain subject to full SDK admission.
339
320
 
340
321
  Execution rechecks chain/creator/destination and exact finalized calldata before each
341
- send. Submitted envelopes/hashes are persisted **before** receipt polling; included
342
- receipts are preserved **before** status/provenance assertions and require one canonical
343
- confirmation. Verification reads actual Active state, token runtime/name/symbol/factory
344
- kind/reward binding, ERC404 unit/URI/mirror, canonical opened markets, permanent V4 sealed
345
- custody/Abyss lock terms, fee policies and ordered activation buys.
346
-
347
- The API session uses the SDK attribution schema with full EIP-712 domain and the same
348
- name/symbol as the token, signed via owned Anvil `eth_signTypedData_v4`. Only the actual
349
- atomic/activate transaction hash is published. Genuine `LaunchPublishPending` HTTP `202`
350
- responses are polled within the configured deadline, respecting `Retry-After`; all other
351
- errors fail immediately. Success additionally requires an actual optimistic/final session
352
- matching that token/hash and an actual `/api/v1/launches/<token>?chainId=4663` representation
353
- with matching creator, provenance and metadata. An API that cannot index `LaunchActivated`
354
- must fail honestly; the runner does not manufacture projections or claim chain-only as
355
- end-to-end success.
356
-
357
- Every run requires a fresh exclusive `--output` directory (its parent must exist):
322
+ send. Exact admitted envelopes are signed locally; computed hashes and unsigned
323
+ envelopes are saved **before** the single raw broadcast, and included receipts are
324
+ saved before status/provenance assertions. One canonical confirmation is required.
325
+ Actual verification covers Active state, factory/token runtime/name/symbol/kind/rewards,
326
+ ERC404 unit/URI/mirror, opened markets, sealed V4 custody/permanent Abyss lock terms,
327
+ fee policies and ordered activation buys.
328
+
329
+ Actual SDK API metadata staging uses locally signed full-domain attribution. Only the
330
+ real activation hash is published. Genuine pending-indexer HTTP `202` is polled within
331
+ 90 seconds respecting `Retry-After`; other failures are not retried. Success requires
332
+ an optimistic/final session and real indexed `/api/v1/launches/<token>?chainId=4663`
333
+ DTO with matching creator/token/hash/metadata. Missing/incompatible indexing fails
334
+ honestly without manufacturing projections, skipping API or launching another token.
335
+
336
+ Every run automatically creates fresh `launch-results/<timestamp-case-random>/`:
358
337
 
359
338
  | Artifact | Evidence |
360
339
  | --- | --- |
361
- | `events.jsonl` | Timestamped SDK/case/stage events, RPC/API errors, simulation backend/steps/gas, timing and canonical observations. |
362
- | `plan.json` | Full finalized SDK portable economic plan, written before execution. |
363
- | `receipts.json` | Every submitted exact envelope/hash and subsequently observed receipt/reference, including failures. |
364
- | `result.json` | `black-market.launch-smoke-result.v1`, scope, terminal passed/failed stage, chain/API observations, causal stacks and revert data. |
365
- | `private-recovery.json` | Mode `0600`; the only file retaining API authorization signature and one-time capability. Do not share or commit it. |
366
-
367
- Public artifacts recursively redact signatures, keys, capability/auth values and URL
368
- credentials/query secrets while retaining public transaction calldata, hashes, selector
369
- and revert bytes. Profile/draft/identity/planning/progress files provide additional
370
- redacted context. Configuration, admission, transaction, publication and interruption
371
- failures exit nonzero and preserve available evidence. The source chain is **not**
372
- reverted, cancelled or relaunched after failure; only the SDK's separate simulation fork
373
- restores its isolated simulation snapshots. Recover from stored evidence before deciding
374
- to run a new case. Runner diagnostic unit tests are `test/smoke-launch.test.mjs`; they do
375
- not replace actual fixture/API execution.
340
+ | `events.jsonl` | Timestamped case/stage events, RPC/API errors, admission/simulation and actual chain observations. |
341
+ | `plan.json` | Full finalized portable SDK plan saved before execution. |
342
+ | `receipts.json` | Exact signed-envelope hashes retained pre-broadcast, followed by real receipts/references. |
343
+ | `result.json` | `black-market.launch-example-result.v1`, end-to-end status, failure stage and causal evidence. |
344
+ | `published-token.json` | Actual indexed API representation. |
345
+ | `private-recovery.json` | Mode `0600`; signed raw bytes, API signature and one-time capability. Never share/commit. |
346
+
347
+ Public artifacts redact known keys/signatures/raw bytes/capabilities/auth values and
348
+ endpoint secrets while retaining public calldata/hashes/revert bytes. Configuration,
349
+ admission, broadcast, publication and interruption failures exit nonzero and preserve
350
+ evidence. No source rollback, cancellation, broadcast retry or relaunch occurs.
351
+ Inspect retained transaction hashes before deciding to run a new case after an
352
+ ambiguous send. `test/launch-example.test.mjs` covers offline signing/retention/config
353
+ boundaries only, not actual chain/API proof. The older independent whole-graph local
354
+ Solidity-exported proof remains separate.
376
355
 
377
356
  ## Real HTTP API integration
378
357
 
@@ -0,0 +1,20 @@
1
+ # Copy to .env in the directory from which you run node (Node 24+).
2
+ # Running a launch-*.mjs file deliberately signs, spends funds and publishes.
3
+ PRIVATE_KEY=
4
+ LAUNCH_API_URL=
5
+
6
+ # Optional: blank uses the SDK official Robinhood chain-4663 mainnet RPC.
7
+ RPC_URL=
8
+ # Optional: separate owned loopback Anvil used only for SDK controlled simulation.
9
+ # Blank selects the actual RPC native eth_simulateV1 backend.
10
+ SIMULATION_RPC_URL=
11
+ # Optional ERC404 NFT metadata base URI that you actually host; blank means empty URI.
12
+ NFT_BASE_URI=
13
+
14
+ # Optional EXAMPLE ceilings, NOT verified provider/account limits.
15
+ # Chain cap is also bounded by every observed block gas limit.
16
+ # EXAMPLE_CHAIN_GAS_CAP=16000000
17
+ # EXAMPLE_RPC_GAS_CAP=16000000
18
+ # EXAMPLE_ACCOUNT_GAS_CAP=16000000
19
+ # EXAMPLE_MAX_CALLDATA_BYTES=131072
20
+ # EXAMPLE_HEADROOM_BPS=1000
@@ -0,0 +1,223 @@
1
+ # Examples
2
+
3
+ The launch examples use the installed public `@black-market/sdk` package and viem,
4
+ including when copied into a consumer project. The deployed chain-4663 graph uses
5
+ pool-bound V4 config 5 and canonical Abyss config 1. Discovery is read-only; running
6
+ a fixed launch example with configured wallet/API deliberately executes real writes.
7
+
8
+ | Script | Behavior |
9
+ | --- | --- |
10
+ | `quickstart.mjs` | Reads the current mainnet orchestrator, checks its registry binding, and discovers admitted profiles. No wallet or writes. |
11
+ | `launch.mjs` | Reviews/reconstructs an explicit saved plan and selected atomic/staged mode; optional offchain config-5 salt mining. Prints simulation, progress, and an admitted unsigned next transaction when evidence permits. |
12
+ | `generate-lifecycle-commitment-fixture.mjs` | Independent offline ABI reference for current config-4/Abyss commitment bytes/hash/identity, not a deployment or executable launch. |
13
+ | `launch-lifecycle-smoke.mjs` | Actual SDK launch/recovery/custody/fee operations, only on an explicitly authorized owned disposable loopback graph. |
14
+ | `launch-erc20-*.mjs`, `launch-erc404-*.mjs` | Eight independent zero-parameter launch cases with actual SDK admission, local signing, chain verification and mandatory API publication/indexing. |
15
+
16
+ ## Deployed read-only discovery
17
+
18
+ ```sh
19
+ pnpm install
20
+ pnpm examples
21
+ # Optional: RPC_URL=https://your-robinhood-rpc pnpm examples
22
+ ```
23
+
24
+ `CHAIN_ID` defaults to `4663`. Local `31337` and workbench `46631` require a matching
25
+ RPC and explicit `LAUNCH_ORCHESTRATOR`, `LAUNCH_IMPLEMENTATION_REGISTRY`, and
26
+ `LAUNCH_FEE_OWNER_REGISTRY`. The example checks RPC chain identity and registry binding.
27
+ Profile discovery verifies live registry admission and certified dependencies; it does
28
+ not build/sign a launch, choose a developer fee, or select market economics.
29
+
30
+ ## Unsigned saved-plan review
31
+
32
+ Supply full `LaunchPlanV1` JSON using the selected RPC's current deployment:
33
+
34
+ ```sh
35
+ pnpm build
36
+ node examples/launch.mjs \
37
+ --plan plan.json --rpc https://rpc.mainnet.chain.robinhood.com/ --mode staged --mine
38
+ ```
39
+
40
+ `--mine` finalizes config-5 salts offchain and prints the final plan. Persist that exact
41
+ commitment before begin. `--receipts receipts.json` and `--confirmations N` restore
42
+ canonical recovery context. The CLI never signs, submits source-chain transactions,
43
+ uploads metadata, or publishes a launch. Modes never fall back silently.
44
+
45
+ Executable admission additionally requires current matching execution-limit evidence
46
+ (`--limits current-limits.json`) and sequential `eth_simulateV1`, or an explicitly
47
+ supplied **separate disposable loopback fork** (`--fork-rpc URL`). Limits must include
48
+ chain/account/core/observed-block/hash provenance and actual chain/RPC/account/calldata
49
+ caps; encode bigint values as decimal strings. Missing facts produce provisional/refused
50
+ admission, not invented provider/account policy. See the
51
+ [lifecycle guide](../docs/launch-lifecycle.md#execution-constraints-and-stateful-simulation).
52
+
53
+ ## Real HTTP metadata sessions
54
+
55
+ The real HTTP integration suite uses the public `LaunchApiClient` against a separately
56
+ running service. Reads are unsigned; metadata-session writes require a disposable key
57
+ and an owned loopback service with real application storage:
58
+
59
+ ```sh
60
+ LAUNCH_API_TEST_URL=http://127.0.0.1:18763 pnpm test:api
61
+ LAUNCH_API_TEST_URL=http://127.0.0.1:18763 \
62
+ LAUNCH_API_TEST_PRIVATE_KEY="$DISPOSABLE_TEST_PRIVATE_KEY" pnpm test:api:write
63
+ ```
64
+
65
+ These are metadata-only session tests, not token deployment or image/transaction
66
+ publication. No image store, indexer, wallet balance, or chain transaction is needed.
67
+ See [service prerequisites](../docs/launch-lifecycle.md#real-http-api-integration).
68
+
69
+ ## Individual token creation
70
+
71
+ **Running one of these files signs and broadcasts a real launch and writes to your
72
+ configured API. Mainnet execution is irreversible and spends real funds.** Choose
73
+ one command per intended launch; there are no flags, parameters or fixture files.
74
+
75
+ ### Setup once
76
+
77
+ Use **Node 24+**. In this repository run `pnpm install`. In a consumer project install
78
+ both public dependencies with `pnpm add @black-market/sdk viem` (or
79
+ `npm install @black-market/sdk viem`) and copy the selected files with
80
+ `launch-example.mjs` and `launch-example-support.mjs` into `examples/`.
81
+ Copy `examples/.env.example` to `.env` in the directory you will run commands from:
82
+
83
+ ```sh
84
+ cp examples/.env.example .env
85
+ chmod 600 .env
86
+ ```
87
+
88
+ Edit `.env` once:
89
+
90
+ ```dotenv
91
+ PRIVATE_KEY=
92
+ LAUNCH_API_URL=
93
+ RPC_URL=
94
+ SIMULATION_RPC_URL=
95
+ ```
96
+
97
+ Set `PRIVATE_KEY` to **your funded EOA's** 32-byte hex key and `LAUNCH_API_URL` to
98
+ your actual HTTPS or owned loopback API service root. There is no default wallet,
99
+ public development key, guessed API URL, or silent API skip. The API needs actual
100
+ application storage and an indexer observing the same chain as the execution RPC.
101
+ Existing environment variables take precedence over the working-directory `.env`,
102
+ loaded once using Node's native `process.loadEnvFile`. No shell interpolation is used.
103
+
104
+ Blank `RPC_URL` uses the SDK official Robinhood chain-4663 mainnet endpoint; HTTPS
105
+ providers and explicit owned loopback HTTP execution RPCs are supported.
106
+ The creator is derived locally from the key, and the deployment/WETH addresses come
107
+ from `getAddresses(4663)`. The runner checks chain identity, EOA and deployed core,
108
+ discovers admitted profiles, verifies the actual wrapped-native binding and reads
109
+ the registered P1 `(1,4096)` oracle configuration. No fixture defines these facts.
110
+ Optional `NFT_BASE_URI` supplies your actually hosted ERC404 NFT metadata base URI.
111
+ Blank uses an empty base URI: NFT units/mirror behavior remain real, but the example
112
+ does not claim hosted NFT metadata exists.
113
+
114
+ Blank `SIMULATION_RPC_URL` selects the actual SDK native sequential `eth_simulateV1`
115
+ backend. Set it only to a **separate owned disposable loopback Anvil** for the canonical
116
+ SDK controlled fork; only this simulation environment is reset/impersonated/reverted.
117
+ Unsupported native simulation, insufficient funds or failed admission stop before API
118
+ staging/broadcast. There is no mode fallback, admission override or reduced case.
119
+
120
+ ### Commands and fixed cases
121
+
122
+ ```sh
123
+ node examples/launch-erc20-v4.mjs
124
+ node examples/launch-erc20-abyss.mjs
125
+ node examples/launch-erc404-v4.mjs
126
+ node examples/launch-erc404-abyss.mjs
127
+ node examples/launch-erc20-staking-v4.mjs
128
+ node examples/launch-erc20-dividends-abyss.mjs
129
+ node examples/launch-erc20-burn-mixed.mjs
130
+ node examples/launch-erc404-dividends-mixed.mjs
131
+ ```
132
+
133
+ | File suffix | Token / rewards | Markets and permanent positions | Mode / opening buys |
134
+ | --- | --- | --- | --- |
135
+ | `erc20-v4` | ERC20 / none | V4: 1 | atomic / 1 |
136
+ | `erc20-abyss` | ERC20 / none | Abyss: 1 | atomic / 1 |
137
+ | `erc404-v4` | ERC404 / none | V4: 1 | staged / 1 |
138
+ | `erc404-abyss` | ERC404 / none | Abyss: 1 | atomic / 1 |
139
+ | `erc20-staking-v4` | ERC20 / staking | V4: 2 | staged / 2 |
140
+ | `erc20-dividends-abyss` | ERC20 / dividends | Abyss: 3 | staged / 1 |
141
+ | `erc20-burn-mixed` | ERC20 / token-only burn 3000 bps | dual-fee V4: 2; Abyss: 1 | staged / 1 per market |
142
+ | `erc404-dividends-mixed` | ERC404 / dividends | V4: 2; Abyss: 3 | staged / 1 per market |
143
+
144
+ ERC20 supply is `1_000_000e18`; ERC404 supply is `10_000e18`, NFT unit `100e18`.
145
+ Positions retain `1000e18` liquidity and the case's exact ranges. Each ordered buy
146
+ spends up to `0.001 ETH` through native-wrap funding. Rewards use 4000 bps where
147
+ selected; token-only burn is 3000 bps in the burn case. V4 uses frozen registered
148
+ treasury/author terms with developer rate `0`; executor fee is 275 bps.
149
+ Hook salts/random identities are finalized and saved before execution.
150
+
151
+ ### Example execution ceilings
152
+
153
+ Defaults are **EXAMPLE ceilings, not verified provider or account limits**:
154
+ chain/RPC/account gas `16000000`, calldata `131072` bytes, headroom `1000` bps.
155
+ The chain cap is additionally bounded by every observed block gas limit. If your
156
+ provider/account policy differs, configure decimal environment values:
157
+ `EXAMPLE_CHAIN_GAS_CAP`, `EXAMPLE_RPC_GAS_CAP`, `EXAMPLE_ACCOUNT_GAS_CAP`,
158
+ `EXAMPLE_MAX_CALLDATA_BYTES`, `EXAMPLE_HEADROOM_BPS`. These do not bypass SDK admission.
159
+
160
+ ### Evidence and failure recovery
161
+
162
+ Each run automatically creates `launch-results/<timestamp-case-random>/`; there is
163
+ no user output option. Inspect `result.json`, `events.jsonl`, finalized `plan.json`,
164
+ `receipts.json` and `published-token.json`. Exact admitted wallet envelopes are signed
165
+ locally; computed hashes and unsigned envelopes are durably retained as
166
+ `broadcast-attempt` **before the one raw broadcast**. Real receipts are saved before
167
+ status/canonical-state assertions. No unlocked-account signing or sending is used.
168
+ Public evidence redacts known keys, signatures, signed raw bytes, API capabilities,
169
+ authorization values and RPC endpoint credentials. Only `private-recovery.json`
170
+ (mode `0600`) retains raw signed transactions and one-time API recovery material;
171
+ never share or commit it. `launch-results/` is ignored.
172
+
173
+ Every case requires actual API metadata staging, publication using the activation
174
+ hash, and an indexed DTO matching token/creator/hash/metadata. Genuine pending-indexer
175
+ HTTP `202` responses are polled for up to 90 seconds respecting `Retry-After`;
176
+ other API failures are not retried or converted to partial success. Broadcast/API
177
+ failures retain logs/hashes and exit nonzero. The runner never retries a raw send,
178
+ relaunches, cancels or rolls back the source chain. **Do not blindly rerun after an
179
+ ambiguous broadcast**: inspect the durable transaction hash on chain first.
180
+ See [chain/API invariants](../docs/launch-lifecycle.md#individual-token-creation-examples).
181
+
182
+ ### Owned-local wallet verification helpers
183
+
184
+ `launch-example-support.mjs` exports
185
+ `createLocalLaunchWallet({privateKey,creator,chainId,orchestrator,client,redactor})`
186
+ and `submitSignedRecorded({transaction,wallet,client,wait,artifacts,signal})`.
187
+ `client.request({method,params})` is an explicit RPC adapter; `transaction` carries
188
+ `id`, `kind`, and exact unsigned `wire` chain/from/to/data/value/gas fields plus
189
+ optional nonce/fees/type/accessList. `wait(hash)` returns a real receipt.
190
+ The signer exposes `address`, `signTypedData(typedData)` and `signTransaction(wire)`
191
+ returning `{wire,rawTransaction,transactionHash}`. Retain the result privately.
192
+ Use `RunArtifacts(output,caseId,redactor)` with `Redactor` and a fresh directory for
193
+ durable evidence; call `initialize()` before work and `finish(status,error)` afterward.
194
+ The shared `runLaunchExample(caseObject)` in `launch-example.mjs` takes the same fixed
195
+ case objects as the eight files, loads environment and auto-creates its output.
196
+ Offline diagnostic tests are in `test/launch-example.test.mjs`; they do not claim
197
+ real launch or API-indexer proof.
198
+
199
+
200
+ ## Actual owned-fixture proof
201
+
202
+ The manifest must declare `fixtureOnly: true`, exact reviewed graph addresses, and
203
+ `executionLimits.provenance.scope: "controlled-local-measurement"`. The plan file
204
+ contains Solidity-exported `plans` with encoded-plan/hash/identity/token vectors.
205
+ Do not pass a mined mainnet manifest as a writable fixture.
206
+
207
+ ```sh
208
+ pnpm build
209
+ LAUNCH_LIFECYCLE_RPC_URL=http://127.0.0.1:18555 \
210
+ LAUNCH_LIFECYCLE_FORK_RPC_URL=http://127.0.0.1:18556 \
211
+ LAUNCH_LIFECYCLE_ALLOW_LOCAL_EXECUTION=1 \
212
+ node examples/launch-lifecycle-smoke.mjs manifest.json sdk-plans.json
213
+ ```
214
+
215
+ This explicitly authorized command executes disposable fixture transactions and
216
+ restores snapshots per plan/mode. It exercises ordered buys, canonical Active state,
217
+ permanent custody, typed deployment provenance, V3 no-argument `claimAndSplit()`,
218
+ reserved owner/developer balances, and authenticated author claims. Cursor completion
219
+ and payment success stay separate.
220
+
221
+ For chain boundary regressions, also set `LAUNCH_LIFECYCLE_MANIFEST` and
222
+ `LAUNCH_LIFECYCLE_FIXTURES`, then run `node --test test/lifecycle-chain.test.mjs` with
223
+ the same local-execution environment. Ordinary `pnpm test` does not authorize chain writes.
@@ -0,0 +1,49 @@
1
+ import { encodeAbiParameters, keccak256, parseAbiParameters, stringToHex } from "viem";
2
+ import { writeFile } from "node:fs/promises";
3
+
4
+ // Independent wire-format reference: does not import the SDK encoder under test.
5
+ const wire = "(uint256 chainId,address orchestrator,address creator,uint256 nonce,(uint8 kind,uint8 rewardMode,string name,string symbol,uint256 supply,uint256 nftUnit,string metadataURI,bytes32 salt,address inventoryRecipient,bool burnOnCancel) token,(address asset,uint256 amount,uint8 kind,address inputAsset,uint256 inputAmount,address target,bytes data)[] funding,(address asset,uint16 ownerBps,uint16 rewardsBps,uint16 burnBps)[] feeAssets,(bytes32 adapterId,bytes32 profileId,address quoteAsset,uint256 tokenBudget,uint32 configVersion,bytes config)[] markets,(uint32 marketIndex,uint256 quoteAmountIn,uint256 minTokenOut,address recipient,uint160 sqrtPriceLimitX96)[] buys,uint256 deadline,uint16 executorFeeBps) plan";
6
+ const address = (value) => `0x${value.toString(16).padStart(40, "0")}`;
7
+ const bytes32 = (value) => `0x${value.toString(16).padStart(64, "0")}`;
8
+ const zero = address(0);
9
+ const plan = {
10
+ chainId: 31337n, orchestrator: address(0xf0), creator: address(0xa0), nonce: 2n ** 192n + 17n,
11
+ token: { kind: 1, rewardMode: 1, name: "Lifecycle commitment 🜁", symbol: "LCV", supply: 10n ** 27n,
12
+ nftUnit: 100n * 10n ** 18n, metadataURI: "ipfs://lifecycle-vector/", salt: bytes32(0x1234), inventoryRecipient: address(0xa0), burnOnCancel: true },
13
+ funding: [
14
+ { asset: address(0x20), amount: 500_000_001n, kind: 0, inputAsset: address(0x20), inputAmount: 500_000_001n, target: zero, data: "0x" },
15
+ { asset: address(0x30), amount: 10n ** 20n, kind: 1, inputAsset: address(0x30), inputAmount: 10n ** 20n, target: zero, data: "0x" },
16
+ ],
17
+ feeAssets: [
18
+ { asset: address(0x10), ownerBps: 8000, rewardsBps: 0, burnBps: 2000 },
19
+ { asset: address(0x20), ownerBps: 6000, rewardsBps: 4000, burnBps: 0 },
20
+ { asset: address(0x30), ownerBps: 6000, rewardsBps: 4000, burnBps: 0 },
21
+ ],
22
+ markets: [
23
+ { adapterId: bytes32(1), profileId: bytes32(11), quoteAsset: address(0x20), tokenBudget: 4n * 10n ** 26n, configVersion: 4,
24
+ config: encodeAbiParameters(parseAbiParameters("(uint16,uint24,int24,uint160,uint24,uint8,uint8,address,bool,bytes32,bytes32,bytes32,address,uint16,(int24,int24,uint128,bytes32,uint256)[])"), [[4, 3000, 60, 2n ** 96n, 10000, 0, 6, address(0xa0), true, keccak256(encodeAbiParameters(parseAbiParameters("uint24,uint16"), [17, 4096])), bytes32(11), bytes32(21), address(0xd0), 250, [[60, 120, 10n ** 18n, bytes32(1), 10n ** 24n]]]]) },
25
+ { adapterId: bytes32(2), profileId: bytes32(12), quoteAsset: address(0x30), tokenBudget: 5n * 10n ** 26n, configVersion: 1,
26
+ config: encodeAbiParameters(parseAbiParameters("(uint8,uint24,bytes32,uint160,(int24,int24,uint128,uint256)[])"), [[3, 3000, bytes32(0x55), 2n ** 96n, [[60, 120, 10n ** 18n, 10n ** 24n]]]]) },
27
+ ],
28
+ buys: [
29
+ { marketIndex: 1, quoteAmountIn: 13n * 10n ** 18n, minTokenOut: 1n, recipient: address(0xb1), sqrtPriceLimitX96: 2n ** 96n - 1n },
30
+ { marketIndex: 0, quoteAmountIn: 20_000_000n, minTokenOut: 2n, recipient: address(0xb2), sqrtPriceLimitX96: 2n ** 96n - 1n },
31
+ { marketIndex: 1, quoteAmountIn: 7n * 10n ** 18n, minTokenOut: 3n, recipient: address(0xb3), sqrtPriceLimitX96: 2n ** 96n - 1n },
32
+ ],
33
+ deadline: 2_000_000_000n, executorFeeBps: 275,
34
+ };
35
+ const domain = keccak256(stringToHex("BLACK_MARKET_LAUNCH_PLAN_V1"));
36
+ const fixture = {
37
+ schema: "black-market.launch-lifecycle-commitment-vector.v1", description: "Portable reviewed config-4/Abyss economic wire vector, not a deployed launch. Both modes commit identical economics.",
38
+ plan, encodedPlan: encodeAbiParameters(parseAbiParameters(wire), [plan]),
39
+ planHash: keccak256(encodeAbiParameters(parseAbiParameters(`bytes32 domain,${wire}`), [domain, plan])),
40
+ launchId: keccak256(encodeAbiParameters(parseAbiParameters("uint256,address,address,uint256"), [plan.chainId, plan.orchestrator, plan.creator, plan.nonce])),
41
+ domain, modes: ["atomic", "staged"],
42
+ };
43
+ const json = `${JSON.stringify(fixture, (_key, value) => typeof value === "bigint" ? value.toString() : value, 2)}\n`;
44
+ const outputs = process.argv.slice(2);
45
+ if (outputs.length === 0) process.stdout.write(json);
46
+ else {
47
+ for (const output of outputs) await writeFile(output, json);
48
+ console.log(JSON.stringify({ generated: outputs, planHash: fixture.planHash, launchId: fixture.launchId }));
49
+ }
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc20-abyss-basic", description: "ERC20, one canonical Abyss position, atomic opening",
5
+ tokenKind: 0, rewardMode: 0, mode: "atomic",
6
+ markets: [{ venue: "abyss", positions: 1 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc20-burn-mixed", description: "Burn policy, dual-fee V4 and Abyss markets for one token",
5
+ tokenKind: 0, rewardMode: 0, mode: "staged", burnBps: 3000,
6
+ markets: [{ venue: "v4", positions: 2, feeMode: 1 }, { venue: "abyss", positions: 1 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc20-dividends-abyss", description: "Holder dividends and three canonical Abyss positions",
5
+ tokenKind: 0, rewardMode: 2, mode: "staged",
6
+ markets: [{ venue: "abyss", positions: 3 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc20-staking-v4", description: "Staking rewards, two V4 positions and two ordered opening buys",
5
+ tokenKind: 0, rewardMode: 1, mode: "staged",
6
+ markets: [{ venue: "v4", positions: 2 }], buysPerMarket: 2,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc20-v4-basic", description: "ERC20, one pool-bound V4 position, atomic opening",
5
+ tokenKind: 0, rewardMode: 0, mode: "atomic",
6
+ markets: [{ venue: "v4", positions: 1 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc404-abyss", description: "ERC404 NFT units and metadata, atomic canonical Abyss",
5
+ tokenKind: 1, rewardMode: 0, mode: "atomic",
6
+ markets: [{ venue: "abyss", positions: 1 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc404-dividends-mixed", description: "ERC404 holder dividends, both venues and five permanent positions",
5
+ tokenKind: 1, rewardMode: 2, mode: "staged",
6
+ markets: [{ venue: "v4", positions: 2 }, { venue: "abyss", positions: 3 }], buysPerMarket: 1,
7
+ });
@@ -0,0 +1,7 @@
1
+ import { runLaunchExample } from "./launch-example.mjs";
2
+
3
+ await runLaunchExample({
4
+ id: "erc404-v4", description: "ERC404 NFT units and metadata, staged pool-bound V4",
5
+ tokenKind: 1, rewardMode: 0, mode: "staged",
6
+ markets: [{ venue: "v4", positions: 1 }], buysPerMarket: 1,
7
+ });