@artblocks/abx-cli 0.1.0-alpha.21 → 0.1.0-alpha.22

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 (69) hide show
  1. package/CHANGELOG.md +852 -0
  2. package/assets/renderer-scaffold/README.md +2 -2
  3. package/assets/renderer-scaffold/src/MyRenderer.sol +2 -2
  4. package/assets/renderer-scaffold/src/interfaces/IAbxFieldRenderer.sol +1 -1
  5. package/assets/renderer-scaffold/src/interfaces/IAbxParams.sol +2 -2
  6. package/assets/renderer-scaffold/test/MyRenderer.t.sol +1 -1
  7. package/dist/commands/deploy.d.ts +30 -17
  8. package/dist/commands/deploy.d.ts.map +1 -1
  9. package/dist/commands/deploy.js +234 -97
  10. package/dist/commands/deploy.js.map +1 -1
  11. package/dist/commands/project.d.ts +16 -0
  12. package/dist/commands/project.d.ts.map +1 -1
  13. package/dist/commands/project.js +150 -10
  14. package/dist/commands/project.js.map +1 -1
  15. package/dist/commands/reads.js +2 -2
  16. package/dist/commands/reads.js.map +1 -1
  17. package/dist/commands/scaffold.d.ts +3 -1
  18. package/dist/commands/scaffold.d.ts.map +1 -1
  19. package/dist/commands/scaffold.js +64 -20
  20. package/dist/commands/scaffold.js.map +1 -1
  21. package/dist/commands/service.js +1 -1
  22. package/dist/commands/service.js.map +1 -1
  23. package/dist/commands/submit-app.d.ts +58 -0
  24. package/dist/commands/submit-app.d.ts.map +1 -0
  25. package/dist/commands/submit-app.js +512 -0
  26. package/dist/commands/submit-app.js.map +1 -0
  27. package/dist/config.d.ts +1 -15
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +18 -1
  30. package/dist/config.js.map +1 -1
  31. package/dist/flag-allowlists.d.ts.map +1 -1
  32. package/dist/flag-allowlists.js +5 -1
  33. package/dist/flag-allowlists.js.map +1 -1
  34. package/dist/flags.d.ts +4 -0
  35. package/dist/flags.d.ts.map +1 -1
  36. package/dist/flags.js +23 -0
  37. package/dist/flags.js.map +1 -1
  38. package/dist/main.js +125 -37
  39. package/dist/main.js.map +1 -1
  40. package/dist/mintpage.d.ts.map +1 -1
  41. package/dist/mintpage.js +29 -4
  42. package/dist/mintpage.js.map +1 -1
  43. package/dist/output.d.ts +32 -1
  44. package/dist/output.d.ts.map +1 -1
  45. package/dist/output.js +74 -9
  46. package/dist/output.js.map +1 -1
  47. package/dist/ownerops.d.ts +101 -13
  48. package/dist/ownerops.d.ts.map +1 -1
  49. package/dist/ownerops.js +357 -89
  50. package/dist/ownerops.js.map +1 -1
  51. package/dist/preview.d.ts +1 -1
  52. package/dist/preview.js +1 -1
  53. package/dist/schema.d.ts +18 -0
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +37 -2
  56. package/dist/schema.js.map +1 -1
  57. package/dist/served.js +1 -1
  58. package/dist/update-check.d.ts.map +1 -1
  59. package/dist/update-check.js +9 -3
  60. package/dist/update-check.js.map +1 -1
  61. package/package.json +6 -6
  62. package/skill/SKILL.md +62 -32
  63. package/skill/reference/code-projects.md +78 -24
  64. package/skill/reference/creator-token.md +16 -3
  65. package/skill/reference/decisions.md +59 -13
  66. package/skill/reference/hosting.md +1 -1
  67. package/skill/reference/operating.md +33 -13
  68. package/skill/reference/setup.md +1 -1
  69. package/skill/reference/troubleshooting.md +16 -6
package/dist/main.js CHANGED
@@ -14,7 +14,7 @@
14
14
  * abx demo deploy a 1/1 to Sepolia, index it, and serve it
15
15
  * abx deploy [--image ..] deploy + index a 1/1 (--image to custody your own bytes; --no-mint to defer)
16
16
  * --copies <n|open> routes to the ERC-1155 edition twin instead — copies of the
17
- * SAME artwork (an open edition, with --copies open, is the flagship edition product)
17
+ * SAME work (an open edition, with --copies open, is the flagship edition product)
18
18
  * abx deploy-series a multi-token image Series from a folder of media; --copies <n|open> makes it
19
19
  * an edition (N ids from the folder × copies each) — see `abx help deploy-series`
20
20
  * abx predict [--salt ..] pre-compute a deploy address (reserve / vanity it before signing); --copies-aware
@@ -32,7 +32,8 @@
32
32
  * never hand-build a resolver path)
33
33
  * abx tokens <address> every token's owner + seed + params, from chain alone (--json for the machine
34
34
  * path); on an edition, supply/maxSupply per id instead of an owner
35
- * abx configure-param <addr> <id> <key> <value> set a governed PostParam (typed encode; any lane)
35
+ * abx configure-param <addr> <id> <key> <value> set a governed PostParam (typed encode; any lane)
36
+ * abx submit-app <collection> list a deployed ABX collection in the App Store (optional, after deploy)
36
37
  * abx set-param-hooks <addr> wire/clear a SeriesCode's configure/augment/transfer param hooks
37
38
  * abx render <addr> [id…] effect-runner repair lane: render missing stills/traits
38
39
  * (enqueues via ABX_EFFECTS_URL when a runner is up, else inline)
@@ -41,7 +42,7 @@
41
42
  * (required unless a 1/1-edition) + --amount (copies of that id, default 1)
42
43
  * abx set-max-supply <addr> edition-only: lower ONE id's ERC-1155 supply cap (the per-id twin of
43
44
  * set-max-invocations) — --token-id <n> --cap <n> (never "open"; caps only decrease)
44
- * abx ping-uri <addr> edition-only, permissionless: re-emit the native URI event for --token-ids
45
+ * abx ping-uri <addr> edition-only, owner-only: re-emit the native URI event for --token-ids
45
46
  * <csv|range> after a re-point, so URI-only indexers/marketplaces re-index
46
47
  * abx refresh <addr> ask marketplaces to (re)index a token's metadata
47
48
  * abx transfer <addr> sell/transfer a token · set-admin: hand over contract ownership
@@ -74,12 +75,13 @@ import { cmdContractUri, cmdInspect, cmdPreview, cmdRender, cmdTokenUri, cmdToke
74
75
  import { cmdStorage } from './commands/storage.js';
75
76
  import { cmdDeployEffects, cmdDeployResolver, cmdEffects, cmdMigrate, cmdRemote, cmdServe, } from './commands/service.js';
76
77
  import { cmdDoctor, cmdMintPage, cmdScaffoldRenderer, cmdSkill } from './commands/scaffold.js';
78
+ import { cmdSubmitApp } from './commands/submit-app.js';
77
79
  import { CHAIN } from './config.js';
78
80
  import { CliError } from './errors.js';
79
81
  import { allowlistFor } from './flag-allowlists.js';
80
82
  import { parseFlags, positionalArgs, warnStrayFlags } from './flags.js';
81
83
  import { bold, c, dim, ensureRenderer, g } from './output.js';
82
- import { cmdAttach, cmdConfigureParam, cmdLockDependencies, cmdLockField, cmdLockUri, cmdMint, cmdMinterBuy, cmdMinterConfigure, cmdMinterShow, cmdPause, cmdPingUri, cmdRefresh, cmdRemoveLastDependency, cmdRetireParam, cmdSetAdmin, cmdSetContractUri, cmdSetDependency, cmdSetDependencyRegistry, cmdSetField, cmdSetMaxInvocations, cmdSetMaxSupply, cmdSetMinter, cmdSetParamHooks, cmdSetPrimaryPayee, cmdSetRenderer, cmdSetRoyalty, cmdSetSchema, cmdSetTokenUri, cmdSetTransferValidator, cmdTransfer, cmdUnpause, } from './ownerops.js';
84
+ import { cmdAttach, cmdConfigureParam, cmdLockDependencies, cmdLockParamHooks, cmdLockScript, cmdLockField, cmdLockUri, cmdMint, cmdMinterBuy, cmdMinterConfigure, cmdMinterShow, cmdPause, cmdPingUri, cmdRefresh, cmdRemoveLastDependency, cmdRetireParam, cmdSetAdmin, cmdSetContractUri, cmdSetDependency, cmdSetDependencyRegistry, cmdSetField, cmdSetMaxInvocations, cmdSetMaxSupply, cmdSetMinter, cmdSetParamHooks, cmdSetPrimaryPayee, cmdSetRenderer, cmdSetRoyalty, cmdSetSchema, cmdSetTokenUri, cmdSetTransferValidator, cmdSetSeedSource, cmdTransfer, cmdUnpause, } from './ownerops.js';
83
85
  import { DEFAULT_PREVIEW_PORT } from './preview.js';
84
86
  import { checkForCliUpdate, compareVersions, installedSkillCopies, readCliVersion, skillRefreshCommands } from './update-check.js';
85
87
  /**
@@ -214,6 +216,7 @@ async function main() {
214
216
  case 'serve': return cmdServe(flags);
215
217
  // owner operations — write + sign (hot/wallet/cold lane), then re-index
216
218
  case 'mint': return cmdMint(rest[0], flags);
219
+ case 'submit-app': return cmdSubmitApp(rest[0], flags);
217
220
  case 'set-minter': return cmdSetMinter(rest[0], flags);
218
221
  case 'set-max-invocations': return cmdSetMaxInvocations(rest[0], flags);
219
222
  case 'set-max-supply': return cmdSetMaxSupply(rest[0], flags);
@@ -226,6 +229,8 @@ async function main() {
226
229
  case 'remove-last-dependency': return cmdRemoveLastDependency(rest[0], flags);
227
230
  case 'set-dependency-registry': return cmdSetDependencyRegistry(rest[0], rest.slice(1), flags);
228
231
  case 'lock-dependencies': return cmdLockDependencies(rest[0], flags);
232
+ case 'lock-script': return cmdLockScript(rest[0], flags);
233
+ case 'lock-param-hooks': return cmdLockParamHooks(rest[0], flags);
229
234
  case 'set-primary-payee': return cmdSetPrimaryPayee(rest[0], flags);
230
235
  case 'minter': return cmdMinter(rest);
231
236
  case 'pause': return cmdPause(rest[0], flags);
@@ -239,6 +244,7 @@ async function main() {
239
244
  case 'mint-page': return cmdMintPage(rest[0], flags);
240
245
  case 'set-royalty': return cmdSetRoyalty(rest[0], flags);
241
246
  case 'set-transfer-validator': return cmdSetTransferValidator(rest[0], rest.slice(1), flags);
247
+ case 'set-seed-source': return cmdSetSeedSource(rest[0], rest.slice(1), flags);
242
248
  case 'set-field': return cmdSetField(rest[0], flags);
243
249
  case 'attach': return cmdAttach(rest, flags);
244
250
  case 'lock-field': return cmdLockField(rest[0], flags);
@@ -308,17 +314,24 @@ const COMMAND_HELP = {
308
314
  ${dim('cross-agent installer also works (not version-locked):')} ${g('npx skills add ArtBlocks/abx --skill abx-self-host')}`,
309
315
  deploy: `
310
316
  ${bold('abx deploy')} ${dim('— deploy + index a 1/1 (no server). Sends a tx in the chosen lane.')}
311
- --image <path> custody your own image (png · jpg · gif · svg · webp); else generative demo art
317
+ --image <path> custody your own image (png · jpg · gif · svg · webp); else generative demo content
312
318
  --name <s> --symbol <s> ERC-721 identity
313
319
  --description "<s>" the creator's words, served in token metadata --external-url <url>
314
320
  --description-onchain store the description ON-CHAIN (durable, reconstructable from chain alone)
315
- --artist "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --artist-links)
321
+ --creator "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --creator-links)
316
322
  --traits "K=V; K2=V2" real OpenSea traits (the marketplace trait array) --attributes <file.json> (array or {name: value} map)
317
323
  --traits-onchain store traits ON-CHAIN (inline JSON, lockable); else off-chain operator metadata (editable via ${g('abx add --traits')})
318
324
  ${g('--onchain-uri')} resolve tokenURI/contractURI FULLY ON-CHAIN (renderer assembles JSON from fields;
319
325
  image inlined as SVG, description on-chain) — the token self-resolves, no server needed
320
326
  ${g('--onchain-image')} stage ${g('--image')} bytes on-chain (chunk store) and bake a reader field INTO the deploy —
321
- large content with NO post-deploy tx (implies --onchain-uri)
327
+ content with NO post-deploy tx (implies --onchain-uri)
328
+ ${dim('READ COST decides the ceiling, not storage: tokenURI reassembles the whole document per call at')}
329
+ ${dim('~360-405k gas/KB of on-chain content, climbing with size (same for inline and reader). Under')}
330
+ ${dim('~40KB reads routinely (~15M gas); 40-100KB needs a high-gas RPC (warned); past ~100KB (~40M) it is')}
331
+ ${dim('refused — a margin below the ~120KB where geth\'s own 50M cap runs out, since hosts cap lower (')}
332
+ ${dim('override with --allow-unreadable-onchain).')}
333
+ ${g('--allow-unreadable-onchain')} ship on-chain content past ~100KB anyway. You accept that ordinary RPC tooling —
334
+ ${dim('marketplaces, indexers, other contracts — sees a revert instead of your token, and rendering needs a high-gas endpoint.')}
322
335
  ${g('--compress')} none|fastlz|gzip for --onchain-image (default none): ${g('fastlz')} = on-chain decode (stays renderable);
323
336
  ${g('gzip')} = smaller but off-chain decode only
324
337
  --royalty-bps <0-10000> default 500 (5%)
@@ -326,6 +339,8 @@ const COMMAND_HELP = {
326
339
  (${g('recommended')} = OpenSea's validator for creator-fee enforcement — only owner-initiated
327
340
  transfers + authorized sales move the token). Absent = plain ERC-721, forever (the default).
328
341
  Manage later with ${g('abx set-transfer-validator')} (re-point or suspend; never un-enroll).
342
+ ${dim('A validator must be a deployed contract that REFUSES calls it does not implement — a Safe or a bare')}
343
+ ${dim('proxy is refused before any gas, since it would enforce nothing while every read said enforcement was ON.')}
329
344
  ${g('--no-mint')} deploy without minting (warm the resolver, then ${g('abx mint')})
330
345
  --salt 0x..<64hex> deploy to a reserved / vanity address (see ${g('abx predict')})
331
346
  --public-base-url <url> bake a public resolver URL on-chain (off-chain custody REQUIRES a public URL; localhost is refused)
@@ -338,7 +353,7 @@ const COMMAND_HELP = {
338
353
  ${dim('(needs a deployer to compute anything address-dependent — pass --for 0x.. if no signing key is set)')}
339
354
  ${dim('address only prints WITH --salt (it is the only thing that pins it) — without --salt this shows the salt + how to pin it, or use `abx predict`.')}
340
355
  ${g('--confirm')} interactive y/N gate before the real send (opt-in; --yes or non-TTY proceeds)
341
- ${bold(g('--copies <n|open>'))} ${dim('routes to the ERC-1155 edition twin (OneOfOneEdition) — copies of the SAME artwork, not a unique token.')}
356
+ ${bold(g('--copies <n|open>'))} ${dim('routes to the ERC-1155 edition twin (OneOfOneEdition) — copies of the SAME work, not a unique token.')}
342
357
  ${g('open')} = an uncapped OPEN EDITION (the flagship edition product) · a number = that many copies max.
343
358
  ${g('--copies 1')} is legal (a single-copy edition) but almost never what you want — drop --copies for the plain 721 lane instead.
344
359
  Adds: ${g('--mint-amount <n>')} (copies of #0 to premint at deploy; default 1, 0 ≡ --no-mint) ·
@@ -352,14 +367,16 @@ const COMMAND_HELP = {
352
367
  --dir <folder> media directory; files sort → token ids 0,1,2,… (metadata = token id)
353
368
  --count <n> deploy fewer than the folder holds (default: all files) --name <s> --symbol <s> --royalty-bps
354
369
  mint timing: ${g('--mint-all')} (mint every token at deploy) · ${g('--mint-count')} N (first N) · ${g('--no-mint')} (defer)
355
- ${bold('image custody')} — how the artwork is stored + resolved:
356
- ${g('--onchain-image')} [--compress fastlz] bytes ON-CHAIN (chunk store) — tiny art only (~200 gas/byte)
370
+ ${bold('image custody')} — how the work is stored + resolved:
371
+ ${g('--onchain-image')} [--compress fastlz] bytes ON-CHAIN (chunk store) — small content (~200 gas/byte to write, and
372
+ ${dim('~360-405k gas/KB per tokenURI to READ, climbing with size: under ~40KB/token reads routinely, past ~100KB refused —')}
373
+ ${dim('override with')} ${g('--allow-unreadable-onchain')}${dim('. The gate is per token; a big collection of small files reads fine.)')}
357
374
  ${g('--onchain-uri --backend arweave|ipfs|cloud')} image OFF-CHAIN, JSON on-chain via the renderer — ${bold('NO server')};
358
375
  same-extension folders upload as ONE directory/manifest → a single collection url-template (O(1)).
359
376
  ${dim('cloud/S3 also needs --public-base <bucket-or-cdn-url>')}
360
377
  --public-base-url <url> hosted resolver (off-chain custody; you run a node) — for mutable metadata
361
378
  --description "<s>" · --external-url <url> collection identity, served in the metadata (set them or the description is boilerplate)
362
- --artist "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --artist-links)
379
+ --creator "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --creator-links)
363
380
  ${g('--attributes <file.json>')} ${bold('per-token marketplace traits')} (written ON-CHAIN): a JSON ARRAY indexed by token id, OR an OBJECT
364
381
  keyed by filename / token id — each value an attributes array or a ${dim('{name: value}')} map. Small/medium series;
365
382
  a huge collection should set traits post-deploy via ${g('abx set-field')} under a gas budget.
@@ -394,7 +411,7 @@ const COMMAND_HELP = {
394
411
  seed, so what you iterate on is what deploys. Routes: ${g('/')} studio (seed + params + live traits) · ${g('/grid')} N seeds at once,
395
412
  all live · ${g('/view')} the bare document. The program is re-read from disk per render, so ${bold('edit and refresh')} — no watcher.
396
413
  Unlike a still-image sweep this shows ${bold('animation')}, which is most of what a screenshot throws away.
397
- ${dim('Still do both after the art settles:')} ${g('abx inspect')} ${dim('(is it wired right?) and a testnet deploy (the faithful end-to-end).')}
414
+ ${dim('Still do both after the work settles:')} ${g('abx inspect')} ${dim('(is it wired right?) and a testnet deploy (the faithful end-to-end).')}
398
415
  ${g('abx preview')} --script art.js --schema palette:HexColor:TokenOwner
399
416
  ${g('abx preview')} --script art.js --shoot ./frames --count 12`,
400
417
  inspect: `
@@ -406,7 +423,7 @@ const COMMAND_HELP = {
406
423
  Ends with a recommended lane (fully-on-chain / resolver / directory). Run it BEFORE ${g('abx deploy-code')} to derive the
407
424
  lane instead of guessing. Deep dive: docs/research/onchain-traits-feasibility.md`,
408
425
  'scaffold-renderer': `
409
- ${bold('abx scaffold-renderer')} [<dir>] ${dim('— write a buildable Foundry project for the in-chain Solidity art lane (default dir: ./my-renderer). No tx.')}
426
+ ${bold('abx scaffold-renderer')} [<dir>] ${dim('— write a buildable Foundry project for the in-chain Solidity renderer lane (default dir: ./my-renderer). No tx.')}
410
427
  Writes: ${g('src/MyRenderer.sol')} (an ${bold('image')} renderer — a seed → SVG, tinted by a ${g('palette')} HexColor PostParam), ${g('src/MyTraits.sol')}
411
428
  (an ${bold('attributes')} renderer reading the SAME seed math, so image + traits agree), the two ABX interfaces you implement/read
412
429
  (${g('src/interfaces/')} — read ${bold('IAbxFieldRenderer.sol')} for the five invariants, above all ${bold('never revert')}), a ${g('forge test')} proving
@@ -443,11 +460,11 @@ const COMMAND_HELP = {
443
460
  ${g('key:Type:Address(0x…)')} (a CONTRACT may hold it: the controller pattern for open participation).
444
461
  Append ${g(':lock=<when>')} (ISO date, unix seconds, or ${g('now')}) to freeze the value after that time.
445
462
  ${dim('repeatable OR comma-separable (like --dep): ')}${g('--schema a --schema b')}${dim(' ≡ ')}${g('--schema a,b')}
446
- Type ∈ Bool·Select·Uint256Range·Int256Range·DecimalRange·HexColor·Timestamp·String·Bytes; Auth ∈ Artist·TokenOwner·Address (+ Or-combos).
463
+ Type ∈ Bool·Select·Uint256Range·Int256Range·DecimalRange·HexColor·Timestamp·String·Bytes; Auth ∈ Creator·TokenOwner·Address (+ Or-combos).
447
464
  ${bold('a Select declares its options')}: ${g('mood:Select[Calm|Wild|Chaotic]:TokenOwner')}; ${bold('a Range takes bounds')}: ${g('density:Uint256Range[0..100]:TokenOwner')} (Int/Decimal/Timestamp too; bounds optional)
448
465
  --description "<s>" · --external-url <url> collection identity, written as ON-CHAIN collection fields in the deploy tx
449
- --artist "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --artist-links)
450
- ${g('--image-renderer 0x..')} THE in-chain-art lane: bake the on-chain ${g('image')} to a Solidity IAbxFieldRenderer → the SVG is COMPUTED
466
+ --creator "<s>" · --license "<s>" authorship + rights, ON-CHAIN collection fields served in contractURI (also --display-notes, --creator-links)
467
+ ${g('--image-renderer 0x..')} THE in-chain-renderer lane: bake the on-chain ${g('image')} to a Solidity IAbxFieldRenderer → the SVG is COMPUTED
451
468
  on-chain from the token's seed + params (fork ${g('SeedSvgRenderer.sol')}). No ${g('--script')} needed; no bucket, no runner, no
452
469
  resolver — the marketplace still lives in ${g('tokenURI')} itself. Mutually exclusive with ${g('--image-base')} (both set ${g('image')}).
453
470
  ${g('--image-base <url>')} bake the on-chain ${g('image')} as a url-template (${g('{base}/{id}.png')}) — the marketplace thumbnail lives OFF-CHAIN at a
@@ -462,7 +479,15 @@ const COMMAND_HELP = {
462
479
  none known → warned + skipped — never blocks). Registry deps are existence-checked before deploy (best-effort;
463
480
  a CDN-served record is the normal production path, on-chain bytes are the durability floor).
464
481
  --max N supply cap (default 16) mint timing: ${g('--mint-all')} · ${g('--mint-count')} N · (default: defer, then ${g('abx mint')})
465
- --no-seed opt out of the canonical mint-time seed (seeds settle once assigned; curated pre-set seeds win)
482
+ --no-seed opt out of a mint-time seed entirely (seeds settle once assigned; curated pre-set seeds win)
483
+ ${g('--seed-source 0x..')} WHERE the mint seed comes from. Default (omit it) = the canonical ${bold('AbxSeedSource')} we deploy;
484
+ ${g('canonical')} says that out loud. Pass an address for ${bold('your own IAbxSeedSource')} — commit-reveal, a VRF
485
+ oracle, a curated queue. ${bold('Probed before any gas')}: it must answer ${g('seed(uint256,address)')} with 32 bytes,
486
+ else the deploy is refused (a bad source is silent until the first buyer, then every mint reverts).
487
+ ${dim('the canonical seed is PSEUDORANDOM — replayable after the mint, and computable DURING it (a buyer can decline an')}
488
+ ${dim('outcome; on an edition, where the BUYER names the id and the id feeds the seed, they can also shop the unminted')}
489
+ ${dim('ids): right for diversifying output, NOT strong enough for a raffle or prize draw. Need that? that is what')}
490
+ ${dim('--seed-source is for. Change it later with ')}${g('abx set-seed-source')}${dim(' (future mints only).')}
466
491
  ${g('--721c')} [recommended|0x..] opt-in ERC-721C: enroll at deploy, PERMANENTLY, with that transfer validator (absent = plain
467
492
  ERC-721 forever). ${g('recommended')} = OpenSea's creator-fee-enforcement validator. Manage: ${g('abx set-transfer-validator')}
468
493
  --backend ipfs|arweave directory-mode custody for the build upload ${g('--unpaused')} · --minter 0x.. · --primary-payee 0x..
@@ -486,7 +511,7 @@ const COMMAND_HELP = {
486
511
  Renders each ${bold('minted')} token whose still is missing at the CURRENT inputsHash (a param change re-addresses it → a plain render fills it in).
487
512
  No tokenId → sweeps all minted tokens; pass ids (${g('0 1 2')}) to target specific tokens.
488
513
  ${g('--force')} RE-RENDER even when the still already exists — the fix for a bad / blank / timed-out capture
489
- (the art is otherwise deterministic, so a plain render idempotent-skips an existing still). Overwrites it (+ republishes on --remote).
514
+ (the render is otherwise deterministic, so a plain render idempotent-skips an existing still). Overwrites it (+ republishes on --remote).
490
515
  ${g('--remote [name|url]')} register each render with a REMOTE resolver: the bytes go to ${bold('ABX_STORAGE_BACKEND')} (YOU hold them), and
491
516
  POST /v1/effect-artifacts hands the resolver the URL — it redirects there and never proxies. Traits are the
492
517
  exception: they stitch into the token JSON, so their content (≤64KB) goes to the resolver itself.
@@ -531,12 +556,12 @@ const COMMAND_HELP = {
531
556
  Reads the current schema and changes ONLY the lock, so type/auth/bounds/options are carried forward untouched.
532
557
  What it does NOT do: remove the key (a governed key stays governed forever) or erase a value already stored — that
533
558
  value keeps serving in token data. A value written under a TokenOwner/Address leg came from a collector, and the
534
- artist deliberately cannot delete it.
559
+ creator deliberately cannot delete it.
535
560
  ${g('--dry-run')} print the exact tx and send nothing`,
536
561
  'configure-param': `
537
562
  ${bold('abx configure-param')} <address> <tokenId|-> <key> <value> ${dim('— set a PostParam (typed, canonical encode). Sends a tx.')}
538
563
  Reads the on-chain schema for <key> and canonically encodes <value> (${g('#rrggbb')} for HexColor, fixed-decimal ranges,
539
- Select by label, address, bool). Auth is per the schema leg (Artist=owner · TokenOwner — delegate.xyz honored · Address).
564
+ Select by label, address, bool). Auth is per the schema leg (Creator=owner · TokenOwner — delegate.xyz honored · Address).
540
565
  A change ${bold('re-addresses renders')} → the still becomes a placeholder until you re-render (${g('abx render <addr> <id>')} or the runner).
541
566
  ${g('<tokenId> "-"')} CONTRACT scope (owner-only raw setter; schema-less keys only) — the write path of well-known params
542
567
  like ${g('display.gateway')}. ≤31 printable-ASCII chars ride as a literal bytes32; longer takes the data path.
@@ -550,12 +575,35 @@ const COMMAND_HELP = {
550
575
  resolver running the chain watcher (the ${g('abx serve')} default) sees the change on its next poll (~12s)
551
576
  and auto-re-renders on its own. Keep --remote for a watcher-disabled resolver or when seconds matter.
552
577
  signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview (encodes + shows the tx, sends nothing)`,
578
+ 'submit-app': `
579
+ ${bold('abx submit-app')} <collection> ${dim('— list a deployed ABX collection in the App Store. Optional; not part of deploy. Sends txs.')}
580
+ After ${g('abx deploy')} / ${g('deploy-series')} / ${g('deploy-code')} succeeds, offer this. It is an opt-in: factory events can
581
+ find every ABX clone, but only minting into the App Store registry makes it an app entry.
582
+ Does ${bold('not')} reuse the collection's ${g('--name')} / ${g('--description')} — those are NFT metadata. Confirm store copy
583
+ with the creator (what someone can ${bold('do')}), then run this. The connected wallet must own the collection
584
+ (or, on a retry, hold the entry token). ${g('built-on-abx')} is forced; the gated minter checks ${g('isAbxClone')} + owner.
585
+ If the collection is already claimed, skips the mint and only writes params (same as the store's ${g('/update')} page).
586
+ Metadata is split across a few signatures — one multicall of every field exceeds the chain's per-tx gas cap.
587
+ ${g('--name')} <s> listing title (required; ≤100 chars) — not the collection name unless the creator says so
588
+ ${g('--summary')} "<s>" one sentence, what someone can do (required; ≤240)
589
+ ${g('--description')} "<s>" full description (required; ≤2000)
590
+ ${g('--mark')} <s> icon monogram, ≤3 chars (default ${g('A/')})
591
+ ${g('--tone')} acid|coral|blue|violet|amber|mint icon color (default ${g('acid')})
592
+ ${g('--category')} Create|Games|"Physical world"|Records|Coordination|Utilities|"Developer tools" (default ${g('Create')})
593
+ ${g('--stage')} Live|Prototype|Concept (default ${g('Prototype')})
594
+ ${g('--url')} https://… launch URL (optional)
595
+ ${g('--url-label')} "<s>" launch button label (optional)
596
+ ${g('--image')} https://… custom icon URL (optional; otherwise the on-chain SVG from mark/tone)
597
+ ${g('--tags')} a,b,c up to 12 tags
598
+ ${g('--registry')} 0x… App Store registry (default: shipped address for this chain, or ${g('ABX_APP_STORE_REGISTRY')})
599
+ ${g('--minter')} 0x… gated minter (default: shipped address for this chain, or ${g('ABX_APP_STORE_MINTER')})
600
+ signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview (encodes + shows the txs, sends nothing)`,
553
601
  'set-param-hooks': `
554
602
  ${bold('abx set-param-hooks')} <address> ${dim('— wire/clear the three SeriesCode param-lifecycle hooks (owner-only). Sends a tx.')}
555
603
  The three optional hook addresses a PostParams project may wire (${bold('SeriesCode only')} — a 1/1 / plain Series has none):
556
604
  ${g('--configure 0x…')} write-time veto/validator — a governed ${g('configure-param')} reverts if this hook reverts
557
605
  ${g('--augment 0x…')} read-time derivation folded into tokenData — the opt-in to LIVE data (view reads chain per view)
558
- ${g('--transfer 0x…')} ownership-change lifecycle, best-effort — a revert here never blocks the transfer
606
+ ${g('--transfer 0x…')} ownership-change lifecycle, a ${bold('VETO')} — a revert here FAILS the transfer, and mints too (mint = transfer from 0x0)
559
607
  The contract has ${bold('no per-hook setter')} — it writes all three at once — so this READS the current trio and re-sends
560
608
  it with your change applied: ${bold('omit a role to keep it')}, pass an address to set it, or ${g('none')} to clear it. ${g('--clear')} clears all three.
561
609
  Run with ${bold('no flags')} to print the current hooks (mutates nothing).
@@ -578,6 +626,21 @@ const COMMAND_HELP = {
578
626
  'lock-dependencies': `
579
627
  ${bold('abx lock-dependencies')} <address> ${dim('— freeze the dependency set (list + registry pointer) FOREVER (irreversible). Sends a tx.')}
580
628
  signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')}`,
629
+ 'lock-script': `
630
+ ${bold('abx lock-script')} <address> ${dim('— freeze the on-chain program (script chunks) FOREVER (irreversible). Sends a tx.')}
631
+ ${dim('This is the lock that freezes the WORK of a code project — after it, setScriptChunk/removeLastScriptChunk revert.')}
632
+ ${dim('lock-field/lock-uri only freeze metadata; the full set for a code drop is lock-script + lock-dependencies + lock-field/lock-uri.')}
633
+ ${dim('That freezes what THIS contract stores — not necessarily what the token renders: params stay writable, and a')}
634
+ ${dim('Registry dependency fetches its bytes live from a contract the registry owner can change. Say "locked metadata", not "immutable output".')}
635
+ signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')}`,
636
+ 'lock-param-hooks': `
637
+ ${bold('abx lock-param-hooks')} <address> ${dim('— freeze the three param-lifecycle hook addresses FOREVER (irreversible). Sends a tx.')}
638
+ ${dim('The lock aimed at a BUYER, not at metadata: the transfer hook is a VETO (its revert fails a transfer, and a mint too),')}
639
+ ${dim('so until this is sent the owner holds a standing power over whether a collector can sell. After it, set-param-hooks reverts.')}
640
+ ${dim('You give up: arming a transfer veto, arming a configure veto, and re-pointing/clearing the augment hook. There is no way back.')}
641
+ ${dim('With no transfer hook set, this is how you PROVE you can never add one. A hook already set stays live — freezing the SET is not disarming it.')}
642
+ ${dim('Prints the exact three addresses it will freeze before it sends. SeriesCode/EditionCode only. Read it back with `abx state`.')}
643
+ signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview (encodes + shows the tx, sends nothing)`,
581
644
  state: `
582
645
  ${bold('abx state')} <address> ${dim('— read-only, on-chain operational snapshot (no tx, no local index).')}
583
646
  Shows owner · supply (minted / max, nextTokenId) · paused · minter · primary payee · royalty · renderer
@@ -603,7 +666,7 @@ const COMMAND_HELP = {
603
666
  ${dim('minting is sequential (by token id); repeat with different --to for an airdrop to N wallets.')}
604
667
  ${bold('editions')} ${dim('(OneOfOneEdition/EditionImage/EditionCode) mint COPIES of one id instead — --count is refused there:')}
605
668
  ${g('--token-id <n>')} which id to mint copies of. Defaults to 0 on a 1/1-edition (its only id); REQUIRED on
606
- EditionImage/EditionCode (ids are caller-named artworks — see \`abx tokens <addr>\` for existing ones)
669
+ EditionImage/EditionCode (ids are caller-named works — see \`abx tokens <addr>\` for existing ones)
607
670
  ${g('--amount <n>')} copies to mint (default 1)
608
671
  ${dim('--token-id/--amount are refused on a 721 target; --count is refused on an edition — pointed either way.')}
609
672
  signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview`,
@@ -656,12 +719,27 @@ const COMMAND_HELP = {
656
719
  'set-royalty': `
657
720
  ${bold('abx set-royalty')} <address> --bps <0-10000> [--receiver 0x..] ${dim('— change the royalty. Sends a tx.')}`,
658
721
  'set-transfer-validator': `
659
- ${bold('abx set-transfer-validator')} <address> <0x..|none|recommended> ${dim('— manage an ERC-721C collection\'s transfer validator. Owner-only. Sends a tx.')}
660
- <0x..> re-point enforcement at that validator (must be a DEPLOYED contract checked before any gas)
722
+ ${bold('abx set-transfer-validator')} <address> <0x..|none|recommended> ${dim('— manage an ERC-721C/1155C collection\'s transfer validator. Owner-only (one exception below). Sends a tx.')}
723
+ <0x..> re-point enforcement at that validator. ${dim('Must be a DEPLOYED contract AND must refuse a call it')}
724
+ ${dim('does not implement — probed before any gas, so a Safe / bare proxy / 7702-delegated EOA is refused:')}
725
+ ${dim('validateTransfer returns nothing, so such an address would enforce NOTHING while every read said ON.')}
661
726
  ${g('none')} suspend enforcement (validator → address(0); the collection STAYS enrolled)
662
727
  ${g('recommended')} the chain's recommended validator (OpenSea's, for creator-fee enforcement)
663
728
  ${dim('Only for a collection that enrolled AT DEPLOY (--721c on the deploy commands) — a plain ERC-721 is refused')}
664
729
  ${dim('up front: enrollment is a deploy-time decision and can never be added (or fully removed) later.')}
730
+ ${dim('Owner-only WHILE THERE IS AN OWNER: on a renounced collection (owner() == 0x0) ANYONE may send `none` to')}
731
+ ${dim('suspend, and NOBODY may arm a validator again — the release valve for a stuck, abandoned collection.')}
732
+ signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview (encodes + shows the tx, sends nothing)`,
733
+ 'set-seed-source': `
734
+ ${bold('abx set-seed-source')} <address> <0x..|canonical|none> ${dim('— re-point where a CODE project draws its mint seeds. Owner-only. Sends a tx.')}
735
+ <0x..> your own ${bold('IAbxSeedSource')} — commit-reveal, a VRF oracle, a curated queue. ${bold('Probed before any gas')}:
736
+ it must answer ${g('seed(uint256,address)')} with 32 bytes, or every mint would revert. Refused if it can't.
737
+ ${g('canonical')} the shared ${bold('AbxSeedSource')} ABX deploys — pseudorandom, and the default at deploy
738
+ ${g('none')} stop drawing seeds (future mints get none; a generative program expecting one renders blank)
739
+ ${dim('FUTURE MINTS ONLY — a seed settles the instant it is assigned, so nothing already minted changes. On a part-sold')}
740
+ ${dim('drop that means the collection spans two sources; the change is public (SeedSourceSet), but early buyers are not told.')}
741
+ ${dim('Code projects only (`abx deploy-code`) — an image 1/1 or Series has no seed source, and one cannot be added.')}
742
+ ${dim('Set it at birth instead with')} ${g('abx deploy-code --seed-source 0x..')}${dim('.')}
665
743
  signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')} preview (encodes + shows the tx, sends nothing)`,
666
744
  attach: `
667
745
  ${bold('abx attach')} <address> <key> <uri> [<key> <uri> …] ${dim('— attach named file(s) to a token. Sends ONE tx.')}
@@ -676,18 +754,20 @@ const COMMAND_HELP = {
676
754
  ${g('--dry-run')} preview the tx, send nothing · signing: ${g('--send')} (default, needs a hot key) · ${g('--sign')} (browser wallet, no key) · ${g('--unsigned')}
677
755
  ${dim('Need the URI first? Upload the file with')} ${g('abx storage upload <path> --backend arweave|ipfs')} ${dim('— it prints the locator to pass here.')}
678
756
  ${dim('mimeType is declared from the URL EXTENSION (…/master.tiff → image/tiff) — give the file a real extension.')}
679
- ${dim('Surfaces in a resolver\'s artifacts listing (/data/<key> fetches it); a bare on-chain tokenURI shows reserved fields + abx_params only —')}
680
- ${dim('configured params DO appear on-chain (as')} ${bold('abx_params')}${dim('); ATTACHMENTS are the surface that needs a resolver.')}
757
+ ${dim('Surfaces in a resolver\'s artifacts listing (/data/<key> fetches it); a bare on-chain tokenURI shows reserved fields only —')}
758
+ ${dim('params are chain STATE, read with')} ${bold('abx tokens')}${dim(' or tokenParamKeys/tokenParam (not projected into tokenURI); ATTACHMENTS need a resolver.')}
681
759
  ${dim('The image/animation are just reserved members of the same manifest. `artifacts` itself is COMPUTED — not settable.')}`,
682
760
  'set-field': `
683
761
  ${bold('abx set-field')} <address> --field <name> ${dim('— set an on-chain metadata field (the low-level primitive). Sends a tx.')}
684
762
  ${dim('To attach an off-chain FILE (the common case), prefer')} ${bold('abx attach')} ${dim('— it auto-picks the representation.')}
685
763
  --field <name> a reserved display field (image · description · animation_url · external_url · attributes ·
686
764
  background_color · …), a collection authorship/rights field with ${g('--collection')}
687
- (artist · display_notes · artist_links · license), OR any custom key (which becomes an
765
+ (creator · display_notes · creator_links · license), OR any custom key (which becomes an
688
766
  ${bold('artifacts')} entry). NOT ${g('artifacts')}/${g('abx_params')}/${g('abx_provenance')} (computed).
689
767
  --text "<s>" store literal UTF-8 ON-CHAIN (representation defaults ${g('inline')}) — NOT for an off-chain URL (use ${bold('attach')})
690
- --file <path> store a FILE on-chain in SSTORE2 chunks behind the shared reader (any size; multi-chunk)
768
+ --file <path> store a FILE on-chain in SSTORE2 chunks behind the shared reader (multi-chunk)
769
+ ${dim('~360-405k gas/KB per tokenURI to READ it back (climbing with size): under ~40KB reads routinely, 40-100KB needs a high-gas RPC,')}
770
+ ${dim('past ~100KB a default node refuses the read (override with')} ${g('--allow-unreadable-onchain')}${dim(').')}
691
771
  ${g('--compress')} none|fastlz|gzip for --file (default none): ${g('fastlz')} = on-chain decode, stays renderable, cheaper storage;
692
772
  ${g('gzip')} = smallest but off-chain decode only (sets the ${g('reader-gzip')} representation)
693
773
  --value 0x.. store raw bytes / hash (representation defaults keccak256)
@@ -712,7 +792,9 @@ const COMMAND_HELP = {
712
792
  'lock-uri': `
713
793
  ${bold('abx lock-uri')} <address> ${dim('— freeze the URI config (pointer + renderer) FOREVER. Sends a tx.')}
714
794
  --collection target the collection scope · else the token URI
715
- ${dim('with the fields also locked (lock-field), the resolved metadata is provably immutable.')}`,
795
+ ${dim('with the fields also locked (lock-field), the stored metadata can never change again.')}
796
+ ${dim('Locked metadata is NOT a locked OUTPUT: params have no lock, and a locked dependency POINTER can still resolve')}
797
+ ${dim('to bytes someone else controls. Some tokens live-adapt to chain state on purpose — see')} https://abx.docs.artblocks.io/protocol/owner-powers/`,
716
798
  'set-admin': `
717
799
  ${bold('abx set-admin')} <address> --to 0x.. ${dim('— hand over contract ownership. Sends a tx.')}`,
718
800
  'set-minter': `
@@ -743,10 +825,10 @@ const COMMAND_HELP = {
743
825
  ${dim('overridden is already open (its --copies default from deploy); there is nothing to set.')}
744
826
  ${dim('Refused on a 721 target (use set-max-invocations instead).')} signing: ${g('--send')} (default) · ${g('--sign')} · ${g('--unsigned')} · ${g('--dry-run')}`,
745
827
  'ping-uri': `
746
- ${bold('abx ping-uri')} <address> --token-ids <csv|range> ${dim('— edition-only, PERMISSIONLESS: re-emit the native URI event. Sends tx(s).')}
828
+ ${bold('abx ping-uri')} <address> --token-ids <csv|range> ${dim('— edition-only, OWNER-ONLY: re-emit the native URI event. Sends tx(s).')}
747
829
  Re-emits ERC-1155's native ${g('URI(string,uint256)')} event for the given ids — the fix for a marketplace/indexer that
748
830
  only honors the native event, after a contract-wide re-point (${g('abx set-token-uri')} / ${g('abx set-renderer')}) which
749
- emits only its own config event, not a per-id one. ${dim('(721 has no equivalent verb — ERC-4906 MetadataUpdate covers that case there.)')}
831
+ emits the ERC-4906 range form, not a per-id native event. ${dim('(721 has no equivalent verb — it has no native per-id URI event to re-emit.)')}
750
832
  --token-ids <csv|range> e.g. ${g('0,1,2')} or ${g('0-99')} or mixed ${g('0-9,20,25-30')}
751
833
  ${dim('Permissionless by design — it only re-emits already-public, current truth, so ANY signer may call it (no owner')}
752
834
  ${dim('check, no --for pinning). Chunks large id lists into several transactions (200 ids/tx) — each previews under --dry-run.')}
@@ -922,12 +1004,12 @@ function help() {
922
1004
  storage override (else uses config): --backend --endpoint --bucket --region --gateway --upload-url
923
1005
  signing: ${g('--send')} hot/env key (default) · ${g('--sign')} wallet page · ${g('--unsigned')} print tx
924
1006
  ${g('--dry-run')} preview (commitment · URIs · mint plan · approvals) without sending or storing — address only WITH --salt
925
- ${bold(g('--copies <n|open>'))} copies of this SAME artwork (ERC-1155 edition) instead of a unique token —
1007
+ ${bold(g('--copies <n|open>'))} copies of this SAME work (ERC-1155 edition) instead of a unique token —
926
1008
  ${g('open')} = uncapped OPEN EDITION, the flagship edition product. See ${g('abx help deploy')}.
927
1009
  ${g('abx deploy-series')} --dir <folder> deploy a ${bold('multi-token collection')} from a folder of media (one contract, N tokens)
928
1010
  mint timing: ${g('--mint-all')} | ${g('--mint-count')} N | ${g('--no-mint')} · --count N --name --symbol --royalty-bps
929
- image custody: ${g('--onchain-image')} (bytes on-chain, tiny art) ·
930
- ${g('--onchain-uri --backend arweave|ipfs|cloud')} (image off-chain, JSON on-chain, ${bold('no server')} — best for most art) ·
1011
+ image custody: ${g('--onchain-image')} (bytes on-chain, tiny content) ·
1012
+ ${g('--onchain-uri --backend arweave|ipfs|cloud')} (image off-chain, JSON on-chain, ${bold('no server')} — best for most projects) ·
931
1013
  --public-base-url <url> (hosted resolver)
932
1014
  --minter 0x.. · --primary-payee 0x.. · --unpaused · ${g('--dry-run')} · see ${g('abx help deploy-series')}
933
1015
  ${bold(g('--copies <n|open>'))} N ids from the folder × copies each (EditionImage) instead of N unique tokens
@@ -949,13 +1031,14 @@ function help() {
949
1031
  ${g('abx preview')} (--script <f> | --code-dir <d>) ${bold('while you are still making it')} — run the program on localhost, live: refresh for new seeds,
950
1032
  drive your PostParams, watch it animate. Same document the generator serves. ${g('--shoot <dir>')} for headless frames. No chain.
951
1033
  ${g('abx inspect')} <script.js> ${bold('before you pick a lane')} — static analysis (traits + on-chain reproducibility, deps, doc size → RPC viability) + a lane recommendation
952
- ${g('abx scaffold-renderer')} [<dir>] write a buildable Foundry project for the ${bold('in-chain Solidity art lane')} (seed + PostParam → on-chain SVG + traits; you forge build/test/deploy)
953
- ${g('abx deploy-code')} (--script <file> | --code-dir <dir> | ${g('--image-renderer 0x..')}) deploy a ${bold('generative / code project')} (on-chain script, a build directory, or a Solidity SVG renderer — in-chain art)
1034
+ ${g('abx scaffold-renderer')} [<dir>] write a buildable Foundry project for the ${bold('in-chain Solidity renderer lane')} (seed + PostParam → on-chain SVG + traits; you forge build/test/deploy)
1035
+ ${g('abx deploy-code')} (--script <file> | --code-dir <dir> | ${g('--image-renderer 0x..')}) deploy a ${bold('generative / code project')} (on-chain script, a build directory, or a Solidity SVG renderer — in-chain rendering)
954
1036
  ${bold('--public-base-url <url>')} OR ${bold('--onchain-uri')} · --schema key:Type:Auth · ${g('--dep')} name@version|0x.. (ordered; index 0 = the runtime) ·
955
1037
  --dep-registry 0x.. · --description "<s>" · --external-url <url> · ${g('--image-base <url>')} (off-chain thumbnails at a deterministic /{id} URL) ·
956
1038
  ${g('--attributes-renderer 0x..')} (traits on-chain) · --max N · ${g('--mint-all')}|${g('--mint-count')} N · --backend ipfs|arweave · ${g('--dry-run')}
957
1039
  ${bold(g('--copies <n|open>'))} a generative drop minted as copies (EditionCode) — v1 scope: --script only, no --dep/--code-dir/--image-renderer
958
1040
  ${g('abx configure-param')} <addr> <id> <key> <value> set a governed PostParam (typed encode; a change re-addresses the render)
1041
+ ${g('abx submit-app')} <collection> list that collection in the ABX App Store (optional, after deploy — mint + catalog copy)
959
1042
  ${g('abx set-schema')} <addr> --schema key:Type:Auth[:lock=<when>] attach or replace ONE key's schema, any time after deploy
960
1043
  ${g('abx retire-param')} <addr> <key> stop all further writes to a param, permanently (the closest thing to removing one)
961
1044
  ${g('abx set-dependency')} <addr> <index> <ref> declare/replace a code dependency (name@version via the registry pointer, or 0x.. on-chain)
@@ -968,21 +1051,26 @@ function help() {
968
1051
  ${bold('owner operations')} ${dim('— operate a project after launch')}
969
1052
  ${g('abx mint')} <addr> issue token #0 flags: [--to 0x.. (default: owner)]
970
1053
  ${dim('edition:')} ${g('--token-id <n>')} (required unless a 1/1-edition) + ${g('--amount <n>')} (copies, default 1) — ${g('--count')} refused
1054
+ ${g('abx submit-app')} <collection> list a deployed collection in the ABX App Store (opt-in; not part of deploy)
1055
+ --name --summary --description [--mark] [--tone] [--category] [--stage] [--url] [--tags]
971
1056
  ${g('abx refresh')} <addr> ask marketplaces to re-index flags: [--token 0]
972
1057
  ${g('abx transfer')} <addr> sell/transfer a token flags: --to 0x.. [--token 0 | --token-id 0]
973
1058
  ${dim('edition:')} ${g('--amount <n>')} copies + ${g('--from 0x..')} (required — many holders, no single on-chain owner)
974
1059
  ${g('abx set-max-supply')} <addr> --token-id <n> --cap <n> edition-only: lower ONE id's ERC-1155 cap (never "open" — caps only decrease)
975
- ${g('abx ping-uri')} <addr> --token-ids <csv|range> edition-only, permissionless: re-emit the native URI event after a re-point
1060
+ ${g('abx ping-uri')} <addr> --token-ids <csv|range> edition-only, owner-only: re-emit the native URI event after a re-point
976
1061
  ${g('abx set-token-uri')} <addr> re-point a token's metadata URI --uri <url>
977
1062
  ${g('abx set-contract-uri')} <addr> re-point the collection URI --uri <url>
978
1063
  ${g('abx migrate')} <addr> move off-chain state to a NEW resolver (verifies parity; no cutover) --from <old> --to <new>
979
1064
  ${g('abx set-royalty')} <addr> change royalty --bps <0-10000> [--receiver 0x..]
980
1065
  ${g('abx set-transfer-validator')} <addr> <0x..|none|recommended> manage an ERC-721C collection's validator (enrolled-at-deploy only)
1066
+ ${g('abx set-seed-source')} <addr> <0x..|canonical|none> re-point a CODE project's mint-seed source (probed; future mints only)
981
1067
  ${g('abx attach')} <addr> <key> <ipfs://…|ar://…|https://…> attach a named file → the token's ${bold('artifacts')} manifest (data plane)
982
1068
  ${g('abx set-field')} <addr> set an on-chain metadata field (low-level) --field <name> (--text "…" | --value 0x..) [--collection]
983
1069
  ${g('abx lock-field')} <addr> freeze a field forever --field <name> [--collection]
984
1070
  ${g('abx set-renderer')} <addr> toggle URI resolution on-chain ↔ off-chain [--off] [--renderer 0x..] [--collection]
985
1071
  ${g('abx lock-uri')} <addr> freeze the URI config (pointer + renderer) forever [--collection]
1072
+ ${g('abx lock-script')} <addr> freeze the on-chain program (script chunks) forever — the lock that freezes a code project's ${bold('work')}
1073
+ ${g('abx lock-param-hooks')} <addr> freeze the three hook addresses forever — the ${bold('transfer hook is a veto')}, so this is the guarantee a buyer reads
986
1074
  ${g('abx set-admin')} <addr> hand over contract ownership --to 0x..
987
1075
  ${dim('Series-only:')} ${g('abx mint')} <addr> mints the ${dim('next')} token in order (or ${g('--count')} N)
988
1076
  ${g('abx pause')} / ${g('abx unpause')} <addr> Series mint gate (paused ⇒ owner-only minting)