@artblocks/abx-cli 0.1.0-alpha.25 → 0.1.0-alpha.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/dist/commands/deploy.d.ts +12 -4
  3. package/dist/commands/deploy.d.ts.map +1 -1
  4. package/dist/commands/deploy.js +99 -24
  5. package/dist/commands/deploy.js.map +1 -1
  6. package/dist/commands/project.d.ts.map +1 -1
  7. package/dist/commands/project.js +48 -2
  8. package/dist/commands/project.js.map +1 -1
  9. package/dist/commands/scaffold.d.ts.map +1 -1
  10. package/dist/commands/scaffold.js +36 -9
  11. package/dist/commands/scaffold.js.map +1 -1
  12. package/dist/commands/storage.d.ts +14 -0
  13. package/dist/commands/storage.d.ts.map +1 -1
  14. package/dist/commands/storage.js +31 -4
  15. package/dist/commands/storage.js.map +1 -1
  16. package/dist/config.d.ts +13 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +25 -1
  19. package/dist/config.js.map +1 -1
  20. package/dist/conformance.d.ts.map +1 -1
  21. package/dist/conformance.js +20 -1
  22. package/dist/conformance.js.map +1 -1
  23. package/dist/flag-allowlists.d.ts.map +1 -1
  24. package/dist/flag-allowlists.js +4 -0
  25. package/dist/flag-allowlists.js.map +1 -1
  26. package/dist/main.js +24 -8
  27. package/dist/main.js.map +1 -1
  28. package/dist/ownerops.d.ts +19 -1
  29. package/dist/ownerops.d.ts.map +1 -1
  30. package/dist/ownerops.js +33 -15
  31. package/dist/ownerops.js.map +1 -1
  32. package/dist/provision.d.ts.map +1 -1
  33. package/dist/provision.js +6 -1
  34. package/dist/provision.js.map +1 -1
  35. package/dist/remote.d.ts +20 -0
  36. package/dist/remote.d.ts.map +1 -1
  37. package/dist/remote.js +38 -0
  38. package/dist/remote.js.map +1 -1
  39. package/dist/signer.d.ts.map +1 -1
  40. package/dist/signer.js +4 -1
  41. package/dist/signer.js.map +1 -1
  42. package/package.json +6 -6
  43. package/skill/SKILL.md +272 -171
  44. package/skill/reference/decisions.md +45 -4
  45. package/skill/reference/hosting.md +12 -3
  46. package/skill/reference/operating.md +55 -2
  47. package/skill/reference/setup.md +42 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,239 @@
1
1
  # @artblocks/abx-cli
2
2
 
3
+ ## 0.1.0-alpha.27
4
+
5
+ ### Patch Changes
6
+
7
+ - b1c333d: **Asking for a 15% royalty built a transaction that reverted on chain.** `RoyaltyExtension` caps every
8
+ ABX token at **1000 bps (10%)** and reverts `RoyaltyTooHigh()` above it, and no token type overrides that.
9
+ But client-side validation allowed the full ERC-2981 `0–10000` range — and the CLI's own error text
10
+ offered `10000 = 100%` as a worked example. So a creator asking for an ordinary 15% got a fully built,
11
+ fully signed transaction that failed on chain; on the wallet lane they approved it in their own wallet
12
+ and paid the gas to find out. Both usage strings said `<0-10000>`, and so did two public docs.
13
+
14
+ Now `MAX_ROYALTY_BPS` (SDK) mirrors the contract ceiling and both `prepareSetRoyalty` and the CLI's
15
+ `parseRoyaltyBps` validate against it, so the refusal is instant, local and free, and it names the cap
16
+ and the revert. Regression tests cover it from both sides — including `1500`, the value that used to
17
+ sail through. Two existing tests had to be corrected: they asserted the 0–10000 bound, which is how this
18
+ survived.
19
+
20
+ Three more surfaces that contradicted themselves or the chain:
21
+
22
+ - **`abx ping-uri --help` claimed "Permissionless by design … ANY signer may call it (no owner check)"
23
+ four lines below its own `OWNER-ONLY` header** — and `Uri1155.pingURI` is `onlyOwner`. A non-owner
24
+ following the paragraph built a reverting tx.
25
+ - **`site/content/docs/reference/contracts.mdx`** described the pre-audit library architecture: it omitted
26
+ `AbxMetadataLib` (the fourth delegatecalled library, and the one linked by **all six** token types, not
27
+ three) and still said `SeriesCode` "rides the ceiling", where `deployments.mdx` — written after the same
28
+ redeploy — says both code types now sit under EIP-170 with room to spare.
29
+ - **`deployments.mdx`'s own `specVersion()` example printed `# → 10`** under a table declaring the renderer
30
+ spec v11. And **`operate.mdx`'s self-correction had rotted**: it warned that `abx refresh`'s advisory was
31
+ stale about editions and ERC-4906, but that advisory was fixed — the doc was now the stale one.
32
+
33
+ Found by two read-only audits (29 doc files, 19 spec files) that verified every claim against contracts,
34
+ compiled ABIs, SDK and live `--help` output before reporting. Both independently re-confirmed the
35
+ no-burn property, the v11 gateway design, all ~26 canonical addresses, and the on-chain storage
36
+ thresholds.
37
+
38
+ - b1c333d: **Every deploy lane accepted a royalty the chain would refuse.** `set-royalty` was fixed to validate
39
+ against the contract's 10% cap, but all six deploy paths (`deploy`, `deploy-series`, `deploy-code` and
40
+ their edition twins) still did a bare `Number(flags['royalty-bps'] ?? 500)` with no bound at all. So
41
+ `--royalty-bps 1500` built the whole deploy, printed **`royalty 15%`** in the confirmation readout — a
42
+ promise the chain will not keep — and reverted `RoyaltyTooHigh()` on send. That is the worse half of the
43
+ bug: the deploy is the expensive transaction, and on the wallet lane the creator approves it first.
44
+
45
+ All six now route through the same `parseRoyaltyBps` the owner op uses, so an over-cap value is refused
46
+ locally, for free, with the cap and the revert named.
47
+
48
+ **`abx doctor`'s pruned-history warning is now order-aware.** It fired for any reachable endpoint that
49
+ cannot serve archive-depth logs, even when a healthy archive endpoint sat ahead of it in the list and would
50
+ answer every deep scan. Three eval rooms independently called it noise — one said it was "a poor first
51
+ impression for an already-nervous creator". The hazard it exists for is real but specifically about
52
+ _ordering_: the fallback transport rotates on error only, so a pruning endpoint listed **first** answers a
53
+ deep scan with an empty, successful `[]`. `probeRpcEndpoints` preserves list order, so the warning now
54
+ fires only when the pruning endpoint is ahead of a full-archive one — the case a reader can act on. When
55
+ no archive endpoint is configured at all, it still fires for every pruning endpoint, because then nothing
56
+ shadows them.
57
+
58
+ - b1c333d: An agent using this skill built its own smart-contract system, and neither it nor the creator noticed
59
+ that the collection had stopped being a canonical ABX clone. Canonicity is decided by which contract
60
+ deployed a token and can never be added afterwards, so the fix is a gate before the first send plus a
61
+ readout that makes the loss discoverable.
62
+
63
+ **`abx state` now reports canonicity first.** It read owner, supply, royalty and renderer off any
64
+ ERC-721-shaped address and said nothing about whether it was a factory clone — so a hand-rolled contract
65
+ was described exactly as confidently as a canonical one, and the tool whose whole job is "what IS this
66
+ contract?" left nothing behind for the creator to find. `verifyCanonical` (SDK) probes all six trust
67
+ anchors' `isAbxClone` in one multicall and returns a true tri-state; a `false` prints what was lost, that
68
+ marketplaces and the App Store recognize collections by that signal, and that the only remedy is a fresh
69
+ deploy through the factory plus moving holders. `null` (no anchors on this chain, or an RPC failure) is
70
+ never shown as a "no".
71
+
72
+ **The skill gained the boundary rule it never had.** Its trust material lived on the _last line_ of the
73
+ file, written for someone verifying a clone from outside, and the "don't hand-roll" rules that existed
74
+ were narrow — preview pages, ABI writes, token queries, nothing about contracts. There is now a
75
+ Read-first gate: if the ask seems to need something the deploy commands don't do, stop and put it to the
76
+ creator in words, because building your own contracts is a legitimate choice a creator can make and
77
+ making it _for_ them silently is not. Alongside it, the list of what the toolkit does **not** do — no
78
+ burn (verified: zero `burn` entrypoints in `contracts/src`, previously a parenthetical clause inside a
79
+ sentence about hooks), no secondary listings, no mainnet, fixed-price sales only, no post-deploy script
80
+ replace — and the two extension points that keep a collection canonical (`set-minter`, param hooks), with
81
+ the caveat that a `--transfer` hook is a **veto, not a trigger**: it can refuse a transfer but never cause
82
+ a mint or a burn, so it cannot implement "combine two into one".
83
+
84
+ Verified by two trap rooms — a creator asking for a burn-to-combine mechanic with "you've got my
85
+ go-ahead, I don't need the technical parts". Both Sonnet and Haiku refused to build a contract, cited the
86
+ canonicity loss, and returned options. The Sonnet room found the route that _preserves_ canonicity and
87
+ offered it first.
88
+
89
+ **SKILL.md was restructured** against its own "lean decision-tree router" norm, which it had drifted
90
+ ~40% past: **68,449 → 55,392 characters (−20%)**, longest bullet 2,876 → 1,465, bullets over 600 chars
91
+ 27 → 14, with depth moved into the reference files that already owned it (locks → `decisions.md`;
92
+ install/`.env` → `setup.md`, which was a 44-line stub; data plane, App Store and deploy mechanics →
93
+ `operating.md`). Also repaired: a **markdown table split in two** by a blockquote sitting between its
94
+ rows, and **four dangling anchor links** (three pre-existing) — all 96 internal links now resolve.
95
+ `setup.md` was retitled and reordered after a control room found the required install steps buried under
96
+ a title that promised RPC troubleshooting.
97
+
98
+ **Two contradictions the verification sweep caught**, both the same class as the rest of this week's
99
+ fixes. `deploy-code --dry-run` printed `render/storage ✓ fs + --image-base` a few lines below
100
+ `⚠ render storage home is fs … placeholder forever`, for the identical setup; the ✓ is legitimately
101
+ scoped to whether the `--image-base` target is a valid mutable bucket (two tests pin that), so the row now
102
+ states what it covers and points at the other line rather than appearing to overrule it. And **"not
103
+ backfillable" was overstated** in three places — the truth, which `code-projects.md` had right all along,
104
+ is that fixing a surface after deploy costs an owner-signed re-point plus a re-render on a collection that
105
+ showed a placeholder in between. Expensive and worth avoiding; not impossible.
106
+
107
+ - Updated dependencies [b1c333d]
108
+ - Updated dependencies [b1c333d]
109
+ - @artblocks/abx-sdk@0.1.0-alpha.19
110
+ - @artblocks/abx-indexer@0.1.0-alpha.20
111
+ - @artblocks/abx-storage@0.1.0-alpha.19
112
+ - @artblocks/abx-token-api@0.1.0-alpha.22
113
+
114
+ ## 0.1.0-alpha.26
115
+
116
+ ### Patch Changes
117
+
118
+ - 77a6248: Fixes from the 2026-08-18 eight-room agent sweep of the content-addressed lanes (ipfs · arweave ·
119
+ preferred gateways). The v11 gateway projection worked end to end on a live testnet round trip — bare
120
+ CID on chain, one `set-gateway` tx, byte-identical content id before and after — but the surfaces
121
+ around it lied, hid, or degraded in five ways that cold agents hit immediately.
122
+
123
+ **Both `AbxGenerator` addresses in the manifest had a broken EIP-55 checksum.** The addresses were
124
+ right; the casing was mangled in transcription. viem validates checksums, so
125
+ `readContract`/`writeContract` against the recorded value threw `Address "0x2c1b7Cf6…" is invalid` —
126
+ `abx verify` could not run its on-chain-URI check on **either** testnet. Corrected in
127
+ `deployments.ts` and the docs mirror, with the code at both fixed addresses re-confirmed on chain
128
+ (identical bytecode, as CREATE2 requires). The per-entry equality tests stayed green through all of
129
+ it because they compared against the same mangled string, so the manifest now carries a **property
130
+ test**: every recorded address must be a valid checksum.
131
+
132
+ **A deploy narrated the upload gateway as if it were the served URL.** With
133
+ `--onchain-uri --backend ipfs`, the progress line printed the backend's own locator
134
+ (`https://gateway.pinata.cloud/ipfs/<cid>/0.png`) while the chain got a bare CID served from
135
+ somewhere else entirely — in one run, from `ipfs.io`, because that is the floor and no preference was
136
+ written. The line now shows the URL the token will actually carry, resolved through the same
137
+ precedence that decides what gets written (`--ipfs-gateway`/`--arweave-gateway` → `--gateway` for the
138
+ backend in use → env → floor), and says whether that prefix is the project's choice or the public
139
+ default filling a silence.
140
+
141
+ **`--ipfs-gateway` / `--arweave-gateway` were absent from every deploy command's `--help`.** They
142
+ appeared only in `set-gateway --help` and the skill's reference pages, so an agent reading the CLI
143
+ alone could not find the flags the CLI itself tells you to use. All three deploy commands now name
144
+ them, with the floors (`https://ipfs.io/ipfs/`, `https://arweave.net/`) and the upload-vs-serving
145
+ distinction stated where the decision is made.
146
+
147
+ **`abx storage upload` handed `abx attach` a locator that silently downgraded the attachment.** It
148
+ printed `abx attach <address> <key> https://gateway.pinata.cloud/ipfs/<cid>/file.png` — and `attach`
149
+ picks the on-chain representation from the scheme, so an `https://` locator stores a plain `url` with
150
+ the gateway host welded into the value: no `set-gateway` repoint, exactly the coupling the
151
+ content-addressed representations exist to remove. Following the command's own printed next step was
152
+ the wrong move — and the skill had promised the scheme form all along, so the doc was right and the
153
+ command was wrong. It now hands back `ipfs://<cid>/file.png` / `ar://<txid>/file.png` (both in the prose
154
+ hint and as `attachLocator` in `--json`), keeps the https URL as the browsable one, and says why they
155
+ differ.
156
+
157
+ **`.abx-self-host/` is now self-ignoring.** It holds this node's projection and, for the Arweave
158
+ backend, a signing-capable key that carries prepaid upload credits. This repo gitignores that
159
+ directory and the skill said so — but a _creator's_ repo does not, so a first `--backend arweave` run
160
+ could leave a key staged for commit with nothing having said a word. The CLI writes a `.gitignore`
161
+ containing `*` inside the directory before anything sensitive lands there: it ignores the whole tree
162
+ regardless of the enclosing repo's config, needs no edit to a file we don't own, and never overwrites
163
+ one that already exists.
164
+
165
+ The **local-gateway warning** also stopped over-claiming. It said a `127.0.0.1` gateway means "the
166
+ served image URL resolves only on THIS machine" — true when the gateway host was welded into the
167
+ field, false now that the field holds a bare CID, and it aimed the creator at the wrong repair. It now
168
+ names the damage that is still real: bytes pinned only to a local node cannot be retrieved by anyone,
169
+ and no gateway can serve content that was never pinned publicly.
170
+
171
+ Also: `abx storage status --json` no longer warns `unrecognized flag(s), ignored: --json` about a flag
172
+ its own usage documents and that visibly works (a readout contradicting itself is worse than no
173
+ readout), and the `--unsigned` epilogue names `abx add <address>` rather than `abx index <address>`,
174
+ which fails on a node that never registered the project — the common case for a tx handed to someone
175
+ else's signer.
176
+
177
+ - 77a6248: Fixes from the 2026-08-18 six-room agent sweep of the hosted-services lane (managed provider ·
178
+ self-hosting · conformance). Three surfaces reported a credential problem as something else.
179
+
180
+ **`abx remote --conformance` blamed the service for our key.** With a rejected token it correctly
181
+ reported `the provided token was rejected (401)` — and then ran the authed-tier probes anyway. Each
182
+ one 401s, and each asserts on a 400, so one stale key produced four further failures reading
183
+ `bytes for a REFERENCED output (image) → 401 (expected 400; accepting this is how a resolver becomes
184
+ an object store)`. That is an accusation against the operator, and it is the exact inverse of what
185
+ this command is for: conformance is meant to be checkable from OUTSIDE, before you sign up. A cold
186
+ agent hit it and had to choose between believing five ✗ marks and explaining them away — it chose to
187
+ explain them away and told the creator the service was trustworthy. Now a rejected token skips the
188
+ authed tiers with one note (naming the descriptor's own signup URL), the public tier still runs in
189
+ full, and the run reports the one failure that is real. 401 is also handled like 403 inside the probe
190
+ helper, which already knew a credential problem is not a conformance verdict.
191
+
192
+ **`abx doctor` reported a dead credential as configured.** It printed `remotes: meridian` for a token
193
+ the service rejects, because it only checked that the variable was _present_. Doctor is the command a
194
+ creator is told to run first, so the 401 surfaced much later, from `abx remote <name>`, after that
195
+ line had already been trusted. Same class as an RPC that answers `[]` because it pruned its logs:
196
+ presence is not capability. It now makes one cheap authed call per named remote and reports
197
+ `✓ good · 1 project(s) visible` or `✗ meridian — token rejected (401) — fix or rotate
198
+ ABX_REMOTE_MERIDIAN_TOKEN`. A short timeout with no backoff keeps it quick, a 403 stays a note
199
+ (provider scoping is not a misconfiguration), and an unreachable provider is a soft note rather than
200
+ a ✗ — nothing here can fail doctor for a reason the creator cannot act on.
201
+
202
+ **`abx deploy-effects` told operators to set a variable that is never read.** The Fly scaffold's
203
+ storage-secrets block emitted `fly secrets set ABX_ARWEAVE_KEY=…`; no such variable exists anywhere in
204
+ the toolkit. A hosted runner cannot use the CLI's managed key file either (that path is on the
205
+ operator's machine), so the line now names `ARWEAVE_JWK` with the JWK inline, which is the form that
206
+ actually works remotely.
207
+
208
+ **A remote register on a self-resolving project claimed a win it did not deliver.** `abx add --remote`
209
+ printed its successes and stopped. But a project whose `tokenURIRenderer` is set answers `tokenURI`
210
+ from the chain, so marketplaces and wallets read that document and never touch the service — the
211
+ registration is still worth having (indexing, the live view, managed rendering) and changes nothing a
212
+ collector sees. A cold agent, told "put it on a hosted service so it shows up properly", had to
213
+ reconstruct that from `state` → `tokenuri` → `contracturi` → the docs → a raw curl before it could
214
+ answer honestly. The register now says it, and the skill states the inverse rule the reference pages
215
+ never had: a resolver adds nothing marketplace-facing to a project that already resolves on-chain.
216
+
217
+ `abx verify`'s help also stopped contradicting itself — "no server needed" read as "needs nothing"
218
+ while the command refuses until the project is registered locally with `abx add`. It now says "no
219
+ resolver in the path" and names the prerequisite.
220
+
221
+ Skill: stop asserting third-party prices and free tiers. Two rooms in one sweep quoted plan costs to a
222
+ creator — one lifted "free tier" from our own `hosting.md` (Fly's has since changed), the other
223
+ invented a monthly Pinata figure out of nothing. We cannot keep another company's pricing current, so
224
+ the skill now says to name the provider and point at its pricing page, and to compare _shapes_
225
+ (pay-once vs. monthly; lapses vs. nothing-to-renew) which stay true. Turbo's under-100 KB free tier
226
+ stays, because the CLI enforces and prints it. The never-read-`.env` rule also moved to the top of
227
+ SKILL.md: an agent listed and read files while orienting, before it reached that rule twenty lines
228
+ down, and printed credentials into its own transcript.
229
+
230
+ - Updated dependencies [77a6248]
231
+ - Updated dependencies [77a6248]
232
+ - @artblocks/abx-sdk@0.1.0-alpha.18
233
+ - @artblocks/abx-indexer@0.1.0-alpha.19
234
+ - @artblocks/abx-storage@0.1.0-alpha.18
235
+ - @artblocks/abx-token-api@0.1.0-alpha.21
236
+
3
237
  ## 0.1.0-alpha.25
4
238
 
5
239
  ### Minor Changes
@@ -110,7 +110,8 @@ export type RemoteEthUpload = {
110
110
  export declare function prepareContent(imagePath: string | undefined, clone: Address, overrides: StorageOverrides, store?: boolean, // false for --dry-run: compute the hash but don't custody bytes
111
111
  onChain?: boolean, // true (--onchain-uri): put the image ON-CHAIN (inline SVG) so it self-resolves
112
112
  remoteEth?: RemoteEthUpload, // wallet-lane Turbo uploads: sign+pay with the connected browser wallet
113
- walletAddr?: string): Promise<{
113
+ walletAddr?: string, // the deployer wallet — checked for existing Turbo credits if the managed key is short
114
+ gatewayFlags?: Flags): Promise<{
114
115
  tokenFields: OnChainFieldInput[];
115
116
  contentNote: string;
116
117
  }>;
@@ -122,9 +123,16 @@ walletAddr?: string): Promise<{
122
123
  export declare function parseDeployTraits(flags: Flags): OpenSeaAttribute[];
123
124
  /** Encode creator traits as the on-chain `attributes` field (inline JSON bytes) — for `--traits-onchain`. */
124
125
  export declare const attributesInlineField: (attrs: OpenSeaAttribute[]) => OnChainFieldInput;
125
- /** Warn when IPFS/Arweave custody is pointed at a LOCAL gateway: the served image URL
126
- * (`<gateway>/ipfs/<cid>`) would resolve only on this machine, so marketplaces/wallets can't
127
- * load it — a pinning service + a PUBLIC gateway is part of operating off-chain custody. */
126
+ /**
127
+ * Warn when IPFS/Arweave custody is pointed at a LOCAL gateway.
128
+ *
129
+ * Two distinct problems ride on one flag, and the warning names the one that actually applies. The
130
+ * bytes are pinned only to a node on this machine, so nothing off it can retrieve them — that is the
131
+ * real damage and it survives any later `set-gateway`. It ALSO used to weld that localhost host into
132
+ * the on-chain value; since the field holds a bare CID it no longer does (the serving prefix is the
133
+ * collection's preference), so promising "the served URL resolves only on THIS machine" would now be
134
+ * false and would point the creator at the wrong repair.
135
+ */
128
136
  export declare function localGatewayWarning(flags: Flags): string | null;
129
137
  /** A readout line for an optional creator text field — states exactly what's written (and where),
130
138
  * or that NOTHING is, so the deploy never silently invents one. */
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@ import { isEditionContract } from '../kind.js';
26
26
  import { jsonSafe, withJson } from '../jsonout.js';
27
27
  import { planOnChainScript } from '../script-chunks.js';
28
28
  import { bold, c, dim, ensureFactory, ensureRenderer, ensureSeedSource, ensureSeriesCodeFactory, ensureSeriesFactory, ensureOneOfOneEditionFactory, ensureEditionFactory, ensureEditionCodeFactory, g, info, keepAlive, ok, p, portInUse, printServing, registerAndIndexLocally, reindexAfterDeploy, step, warn, } from '../output.js';
29
- import { AUTHORSHIP_DEPLOY_FIELDS, ONCHAIN_PROJECT_SOFT_LIMIT, ONCHAIN_READ_WARN_BYTES, tokenUriGasEstimate, authorshipContractFields, gatewayContractFields, computeContentPlan, envStagingSender, parseCompress, parseSeedSourceValue, canonicalSeedSource, refuseUnusableSeedSource, parseTransferValidatorValue, guardOnChainSize, previewImageStaging, refusePrewrappedImage, sessionStagingSender, stageImageField, stageImageFieldsBatch, } from '../ownerops.js';
29
+ import { parseRoyaltyBps, AUTHORSHIP_DEPLOY_FIELDS, ONCHAIN_PROJECT_SOFT_LIMIT, ONCHAIN_READ_WARN_BYTES, tokenUriGasEstimate, authorshipContractFields, gatewayContractFields, servingGateway, computeContentPlan, envStagingSender, parseCompress, parseSeedSourceValue, canonicalSeedSource, refuseUnusableSeedSource, parseTransferValidatorValue, guardOnChainSize, previewImageStaging, refusePrewrappedImage, sessionStagingSender, stageImageField, stageImageFieldsBatch, } from '../ownerops.js';
30
30
  import { canonicalLabel } from '../remote.js';
31
31
  import { assertLaneCanSign, confirmSend, gatedSend, laneFromFlags } from '../riskgate.js';
32
32
  import { describeSchema, editionSchemaAdvisory, parseSchemaSpecs } from '../schema.js';
@@ -356,6 +356,29 @@ export const imageContentAddressedField = (network, contentId) => ({
356
356
  * `cloud` and friends keep the plain `url` / `url-template` they always had: an https CDN locator IS
357
357
  * the address, with no identity underneath to separate out.
358
358
  */
359
+ /**
360
+ * The URL a creator's token will actually carry, for a locator a durable backend just produced.
361
+ *
362
+ * For `ipfs`/`arweave` the backend's locator is an UPLOAD-gateway URL, and the on-chain field holds
363
+ * only the bare CID/txid — so narrating the locator verbatim told the creator a host their token
364
+ * does not use (a live deploy printed `gateway.pinata.cloud/…` while committing a CID served from
365
+ * `ipfs.io`). Rebuild it under the serving preference instead, and say which one that is, since
366
+ * "the floor is filling a silence" and "you chose this" have different futures.
367
+ *
368
+ * Every other backend is returned verbatim: an https CDN locator IS the address.
369
+ */
370
+ function servedImageUrl(backendId, locator, flags) {
371
+ if (backendId !== 'ipfs' && backendId !== 'arweave')
372
+ return { url: locator, note: '' };
373
+ const contentId = contentIdFromLocator(backendId, locator);
374
+ if (!contentId)
375
+ return { url: locator, note: '' };
376
+ const { prefix, chosen } = servingGateway(backendId, flags);
377
+ return {
378
+ url: `${prefix}${contentId}`,
379
+ note: chosen ? `gateway: yours, written on-chain` : `gateway: public default — repoint any time with ${bold('abx set-gateway')}`,
380
+ };
381
+ }
359
382
  /** How a lane should describe what it just committed, so the narration matches the field written. */
360
383
  function describeLocatorField(backendId) {
361
384
  return backendId === 'ipfs' || backendId === 'arweave'
@@ -422,7 +445,8 @@ export function imageEndsUpOnChain(flags, onchainImage) {
422
445
  export async function prepareContent(imagePath, clone, overrides, store = true, // false for --dry-run: compute the hash but don't custody bytes
423
446
  onChain = false, // true (--onchain-uri): put the image ON-CHAIN (inline SVG) so it self-resolves
424
447
  remoteEth, // wallet-lane Turbo uploads: sign+pay with the connected browser wallet
425
- walletAddr) {
448
+ walletAddr, // the deployer wallet — checked for existing Turbo credits if the managed key is short
449
+ gatewayFlags = {}) {
426
450
  if (!imagePath) {
427
451
  // demo default = generative SVG. On-chain mode inlines it (self-resolving, no custody);
428
452
  // off-chain mode commits its keccak and regenerates/serves it.
@@ -503,7 +527,10 @@ walletAddr) {
503
527
  // Keep the bytes under their hash too: `abx verify` can then still prove the served image
504
528
  // matches what was uploaded, even though the on-chain field addresses it by URL.
505
529
  await backend.put(hash, { bytes, contentType });
506
- ok(`image ${url} ${dim(`(${backend.id}; baked on-chain, no server)`)}`);
530
+ const served = servedImageUrl(backend.id, url, gatewayFlags);
531
+ ok(`image → ${served.url} ${dim(`(${backend.id}; baked on-chain, no server)`)}`);
532
+ if (served.note)
533
+ info(dim(` ${served.note}`));
507
534
  return {
508
535
  tokenFields: [imageLocatorField(backend.id, url)],
509
536
  contentNote: `content: ${basename(path)} (${bytes.length} bytes, ${contentType}) on ${backend.id} · ON-CHAIN image ${describeLocatorField(backend.id)}`,
@@ -538,16 +565,24 @@ export const attributesInlineField = (attrs) => ({
538
565
  representation: encodeTag(R.inline),
539
566
  value: toHex(JSON.stringify(attrs)),
540
567
  });
541
- /** Warn when IPFS/Arweave custody is pointed at a LOCAL gateway: the served image URL
542
- * (`<gateway>/ipfs/<cid>`) would resolve only on this machine, so marketplaces/wallets can't
543
- * load it — a pinning service + a PUBLIC gateway is part of operating off-chain custody. */
568
+ /**
569
+ * Warn when IPFS/Arweave custody is pointed at a LOCAL gateway.
570
+ *
571
+ * Two distinct problems ride on one flag, and the warning names the one that actually applies. The
572
+ * bytes are pinned only to a node on this machine, so nothing off it can retrieve them — that is the
573
+ * real damage and it survives any later `set-gateway`. It ALSO used to weld that localhost host into
574
+ * the on-chain value; since the field holds a bare CID it no longer does (the serving prefix is the
575
+ * collection's preference), so promising "the served URL resolves only on THIS machine" would now be
576
+ * false and would point the creator at the wrong repair.
577
+ */
544
578
  export function localGatewayWarning(flags) {
545
579
  const opts = storageOptions(storageOverrides(flags));
546
580
  const gateway = opts.backend === 'ipfs' ? opts.ipfs?.gateway : opts.backend === 'arweave' ? opts.arweave?.gateway : undefined;
547
581
  if (gateway && /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)\b/i.test(gateway)) {
548
- return (`${opts.backend} gateway is ${gateway} — a LOCAL gateway. The served image URL resolves only on THIS machine; ` +
549
- `marketplaces and wallets won't load it. Pin to a service with a PUBLIC gateway (e.g. a Pinata dedicated gateway) ` +
550
- `via --gateway https://… or ABX_IPFS_GATEWAY.`);
582
+ return (`${opts.backend} gateway is ${gateway} — a LOCAL gateway, so the bytes would be pinned only to a node on THIS ` +
583
+ `machine and nobody else could retrieve them. The on-chain field holds the bare content id (a gateway change is ` +
584
+ `later just ${bold('abx set-gateway')}), but no gateway can serve content that was never pinned publicly. Pin to a ` +
585
+ `service with a PUBLIC gateway (e.g. a Pinata dedicated gateway) via --gateway https://… or ABX_IPFS_GATEWAY.`);
551
586
  }
552
587
  return null;
553
588
  }
@@ -599,7 +634,10 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
599
634
  }
600
635
  const name = flags.name ?? 'ABX Self-Host Demo';
601
636
  const symbol = flags.symbol ?? 'ABXSH';
602
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
637
+ // Validate against the CONTRACT's cap here, not just in `set-royalty`: a bare Number() accepted
638
+ // 1500, printed "royalty 15%" in the confirmation readout, and then lost the whole deploy to a
639
+ // RoyaltyTooHigh() revert — the expensive tx, and one the creator had already approved.
640
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
603
641
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
604
642
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
605
643
  // Creator traits (real OpenSea attributes). Off-chain operator metadata by default (cheap,
@@ -889,7 +927,7 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
889
927
  ? { tokenFields: [bakedImage], contentNote: 'content: image staged ON-CHAIN via reader (self-resolving, no custody)' }
890
928
  : onchainImage
891
929
  ? { tokenFields: [], contentNote: 'content: image would be staged ON-CHAIN via reader (chunk store) — dry run skips the staging write' }
892
- : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, uploadRemoteEth, deployer);
930
+ : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, uploadRemoteEth, deployer, flags);
893
931
  // Put the description ON-CHAIN (inline) when asked, or always under --onchain-uri
894
932
  // (the on-chain renderer can only emit on-chain fields, so an off-chain-only
895
933
  // description would simply be omitted). On-chain wins at resolve either way.
@@ -1242,7 +1280,7 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1242
1280
  const editionSize = parseCopies(flags.copies);
1243
1281
  const name = flags.name ?? 'ABX Edition';
1244
1282
  const symbol = flags.symbol ?? 'ABXE';
1245
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
1283
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
1246
1284
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
1247
1285
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
1248
1286
  const traits = parseDeployTraits(flags);
@@ -1390,7 +1428,7 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1390
1428
  ? { tokenFields: [bakedImage], contentNote: 'content: image staged ON-CHAIN via reader (self-resolving, no custody)' }
1391
1429
  : onchainImage
1392
1430
  ? { tokenFields: [], contentNote: 'content: image would be staged ON-CHAIN via reader (chunk store) — dry run skips the staging write' }
1393
- : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri);
1431
+ : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, undefined, undefined, flags);
1394
1432
  if (flags.description && (onChainUri || flags['description-onchain'])) {
1395
1433
  tokenFields.push({ field: encodeTag(F.description), representation: encodeTag(R.inline), value: toHex(flags.description) });
1396
1434
  }
@@ -1603,7 +1641,7 @@ export async function cmdDeploySeriesBody(flags, emit) {
1603
1641
  warnSignWithoutFor(flags);
1604
1642
  const name = flags.name ?? 'ABX Series';
1605
1643
  const symbol = flags.symbol ?? 'ABXS';
1606
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
1644
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
1607
1645
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
1608
1646
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
1609
1647
  console.log(bold(`\n ABX Self-Host Toolkit — deploy series\n ${dim('a multi-token drop, served from chain alone')}`));
@@ -1801,6 +1839,14 @@ export async function cmdDeploySeriesBody(flags, emit) {
1801
1839
  if (uniform) {
1802
1840
  contractFields = [imageLocatorField(backendId, `<${backendId}-dir>/{id}${exts[0]}`, true)];
1803
1841
  info(`would upload ${tokenPaths.length} file(s) as ONE ${backendId} directory → collection image <${backendId}-dir>/{id}${exts[0]} (O(1); ${describeLocatorField(backendId)})`);
1842
+ // Name the SERVING prefix in the plan too. Without it a preview says "the gateway is the
1843
+ // collection's preference" and never says what that preference resolves to, so a reader
1844
+ // fills the blank with the upload gateway they just typed — the same confusion the live
1845
+ // narration used to cause outright.
1846
+ if (backendId === 'ipfs' || backendId === 'arweave') {
1847
+ const { prefix, chosen } = servingGateway(backendId, flags);
1848
+ info(`served from ${bold(prefix)} ${dim(chosen ? '(your --' + backendId + '-gateway, written on-chain)' : `(public default — nothing written; repoint any time with ${bold('abx set-gateway')})`)}`);
1849
+ }
1804
1850
  }
1805
1851
  else {
1806
1852
  tokenFields = tokenPaths.map(({ tokenId }) => tokenFieldOf(tokenId, imageLocatorField(backendId, `<${backendId}-url-${tokenId}>`)));
@@ -1816,7 +1862,10 @@ export async function cmdDeploySeriesBody(flags, emit) {
1816
1862
  const template = `${base}/{id}${exts[0]}`;
1817
1863
  contractFields = [imageLocatorField(backendId, template, true)];
1818
1864
  info(`uploaded ${entries.length} file(s) as one ${backendId} directory`);
1819
- info(`collection image: ${template} ${dim(`— one field covers every token (O(1); ${describeLocatorField(backendId)})`)}`);
1865
+ const servedTemplate = servedImageUrl(backendId, template, flags);
1866
+ info(`collection image: ${servedTemplate.url} ${dim(`— one field covers every token (O(1); ${describeLocatorField(backendId)})`)}`);
1867
+ if (servedTemplate.note)
1868
+ info(dim(` ${servedTemplate.note}`));
1820
1869
  }
1821
1870
  else {
1822
1871
  // mixed extensions (or no directory support): per-token url fields (O(N)).
@@ -1828,7 +1877,7 @@ export async function cmdDeploySeriesBody(flags, emit) {
1828
1877
  if (!locator)
1829
1878
  throw new Error(`backend ${backendId} returned no public locator for token ${tokenId} — a durable backend (ipfs/arweave) is required for --onchain-uri image hosting`);
1830
1879
  tokenFields.push(tokenFieldOf(tokenId, imageLocatorField(backendId, locator)));
1831
- info(`token ${tokenId} ← ${fname} → ${locator}`);
1880
+ info(`token ${tokenId} ← ${fname} → ${servedImageUrl(backendId, locator, flags).url}`);
1832
1881
  }
1833
1882
  info(`mixed file extensions → per-token image fields (O(N)); a uniform extension enables the O(1) directory template`);
1834
1883
  }
@@ -2153,7 +2202,7 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2153
2202
  const editionSize = parseCopies(flags.copies);
2154
2203
  const name = flags.name ?? 'ABX Edition Series';
2155
2204
  const symbol = flags.symbol ?? 'ABXES';
2156
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
2205
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
2157
2206
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
2158
2207
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
2159
2208
  console.log(bold(`\n ABX Self-Host Toolkit — deploy edition series\n ${dim(editionSize === 0n
@@ -2335,6 +2384,14 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2335
2384
  if (uniform) {
2336
2385
  imageContractFields = [imageLocatorField(backendId, `<${backendId}-dir>/{id}${exts[0]}`, true)];
2337
2386
  info(`would upload ${tokenPaths.length} file(s) as ONE ${backendId} directory → collection image <${backendId}-dir>/{id}${exts[0]} (O(1); ${describeLocatorField(backendId)})`);
2387
+ // Name the SERVING prefix in the plan too. Without it a preview says "the gateway is the
2388
+ // collection's preference" and never says what that preference resolves to, so a reader
2389
+ // fills the blank with the upload gateway they just typed — the same confusion the live
2390
+ // narration used to cause outright.
2391
+ if (backendId === 'ipfs' || backendId === 'arweave') {
2392
+ const { prefix, chosen } = servingGateway(backendId, flags);
2393
+ info(`served from ${bold(prefix)} ${dim(chosen ? '(your --' + backendId + '-gateway, written on-chain)' : `(public default — nothing written; repoint any time with ${bold('abx set-gateway')})`)}`);
2394
+ }
2338
2395
  }
2339
2396
  else {
2340
2397
  for (const { tokenId } of tokenPaths)
@@ -2898,7 +2955,7 @@ export async function cmdDeployCodeBody(flags, emit) {
2898
2955
  if (mintCount > max)
2899
2956
  throw new Error(`--mint-count ${mintCount} exceeds --max ${max}`);
2900
2957
  const paused = flags.unpaused === undefined;
2901
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
2958
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
2902
2959
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
2903
2960
  const baseUrl = (flags['public-base-url'] ?? resolveBaseUrl(port)).replace(/\/$/, '');
2904
2961
  const hasPublicUrl = !!(flags['public-base-url'] || process.env.ABX_PUBLIC_BASE_URL);
@@ -3380,7 +3437,7 @@ export async function cmdDeployCodeBody(flags, emit) {
3380
3437
  (transferValidator !== zeroAddress ? ` ERC-721C: enrolled at deploy, permanently (validator ${transferValidator}).` : '') + `\n` +
3381
3438
  ` Surfaces — thumbnail: ${imageDisposition}. traits: ${traitsDisposition}. postparams: ${paramsDisposition}.` +
3382
3439
  ((imageOrphaned || traitsBroken || undeclaredParams.length)
3383
- ? `\n ⚠ One or more surfaces resolve to NOTHING marketplaces can see these are DEPLOY-TIME decisions, not backfillable. Re-run --dry-run after fixing, or pass --yes to ship as-is.`
3440
+ ? `\n ⚠ One or more surfaces resolve to NOTHING marketplaces can see. Settle them now: fixing one after deploy is an owner-signed re-point + re-render, on a collection that showed a placeholder in between. Re-run --dry-run after fixing, or pass --yes to ship as-is.`
3384
3441
  : ''), flags);
3385
3442
  }
3386
3443
  // --dry-run: emit the full plan (the on-chain values the skill formats into its confirm table),
@@ -3513,16 +3570,18 @@ export async function cmdDeployCodeBody(flags, emit) {
3513
3570
  // were already set. The alarm now covers only the surfaces it can honestly speak for, and names
3514
3571
  // only the remedies for what is actually broken.
3515
3572
  const anySurfaceBroken = imageOrphaned || traitsBroken;
3516
- step('Surfaces — what marketplaces will see (all DEPLOY-TIME; not backfillable)');
3573
+ step('Surfaces — what marketplaces will see (settle them NOW; fixing one later is an owner-signed re-point + re-render)');
3517
3574
  (imageOrphaned ? warn : info)(`thumbnail: ${imageDisposition}`);
3518
3575
  // Render-mode / render-home guidance is for the RENDERED-still lanes only. The in-chain
3519
3576
  // Solidity image (--image-renderer) has no off-chain still — nothing to render, host, or refresh.
3577
+ // Hoisted: the `render/storage` row further down needs the same fact, so that a managed provider
3578
+ // (which owns rendering) never trips the fs warning there either.
3579
+ let renderAttached = false;
3520
3580
  if (!imageOrphaned && !hasImageRenderer) {
3521
3581
  if (!hasPublicUrl)
3522
3582
  info(` ${dim('render mode (a still is never on-chain):')} ${bold('service')} (auto-render every mint/param change — a live/for-sale drop) · ${bold('once')} (fixed supply) · ${bold('none')} (placeholder). ${dim('freshness: no resolver ⇒ no chain-watcher ⇒ MANUAL/backfill (`abx render` after mints + each param change; the on-chain animation updates live, the bucket still does NOT). Continuous/live stills ⇒ run a resolver.')}`);
3523
3583
  // A managed provider whose descriptor says `render.attached` owns rendering — local
3524
3584
  // ABX_STORAGE_BACKEND is irrelevant, and warning "placeholder forever" is a lie.
3525
- let renderAttached = false;
3526
3585
  if (hasPublicUrl && !loopbackBaseUrl(baseUrl)) {
3527
3586
  try {
3528
3587
  const d = await new AbxServiceClient({ baseUrl, timeoutMs: 2_500 }).descriptor();
@@ -3588,8 +3647,24 @@ export async function cmdDeployCodeBody(flags, emit) {
3588
3647
  cloudHasPublicBase: renderStorageBackendId === 'cloud' ? !!renderStorageOpts.cloud?.publicBase : undefined,
3589
3648
  publishesToRemoteResolver: !hasImageRenderer && !(onChainUri && hasImageBase),
3590
3649
  });
3591
- if (renderStorageCombo.ok)
3592
- info(`render/storage ✓ ${renderStorageBackendId}${hasImageBase ? ' + --image-base' : ''}`);
3650
+ // `validateRenderStorageCombo` deliberately scopes itself to the --image-base URL SHAPE and the
3651
+ // remote-resolver lane, so it returns ok for `fs` + --image-base while the render-home check a
3652
+ // few lines above correctly warns that an fs home means nothing ever uploads the still to that
3653
+ // bucket. Both lines described the same setup and only one said it was broken, and a creator
3654
+ // skimming for the checkmark reads ✓ as approval. The row now defers to that warning rather than
3655
+ // overriding it: same fact, one verdict.
3656
+ // This row is deliberately scoped to whether the --image-base TARGET is valid (a mutable bucket,
3657
+ // not a content-addressed gateway) and whether a remote resolver could fetch what we store — it
3658
+ // is NOT a verdict on the render home, which has its own warning above. Unqualified, though, a
3659
+ // bare `✓ fs + --image-base` sat a few lines under "render storage home is fs … placeholder
3660
+ // forever" and read as though it overruled it. Name what the ✓ covers, and point at the other
3661
+ // line when that one is unhappy, so one setup stops producing two verdicts.
3662
+ const fsHomeUnresolved = renderHome === 'fs' && !renderAttached && !imageOrphaned && !hasImageRenderer;
3663
+ if (renderStorageCombo.ok) {
3664
+ const scope = hasImageBase ? '--image-base is a valid mutable target' : `${renderStorageBackendId} can serve what it stores`;
3665
+ info(`render/storage ✓ ${scope}` +
3666
+ (fsHomeUnresolved ? dim(` — but the render home is still ${bold('fs')}; see the warning above, this ✓ does not cover it`) : ''));
3667
+ }
3593
3668
  else
3594
3669
  warn(`render/storage ✗ ${renderStorageCombo.reason}`);
3595
3670
  }
@@ -4064,7 +4139,7 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4064
4139
  throw new Error('--mint-amount 0 with ids being pre-minted at deploy makes no sense — pass a positive --mint-amount, or drop --mint-all/--mint-count to defer minting entirely.');
4065
4140
  }
4066
4141
  const paused = flags.unpaused === undefined;
4067
- const royaltyBps = Number(flags['royalty-bps'] ?? 500);
4142
+ const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
4068
4143
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
4069
4144
  const baseUrl = (flags['public-base-url'] ?? resolveBaseUrl(port)).replace(/\/$/, '');
4070
4145
  const hasPublicUrl = !!(flags['public-base-url'] || process.env.ABX_PUBLIC_BASE_URL);