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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,73 @@
1
1
  # @artblocks/abx-cli
2
2
 
3
+ ## 0.1.0-alpha.28
4
+
5
+ ### Patch Changes
6
+
7
+ - 84ca9dd: Off-chain fixes from the 2026-08-19 production-readiness audit
8
+ (`reviews/2026-08/production-readiness-audit.md`). All are off-chain — no contract changed and no
9
+ address moved; the three NatSpec-precision items the audit also raised ride the next redeploy batch
10
+ instead (`docs/10-backlog.md` → _Contracts — the next redeploy batch_, B47).
11
+
12
+ **SDK — `HexColor` decode now masks to 24 bits, matching the chain (L-1).** `decodeScalarParam` for a
13
+ `HexColor` value greater than `0xFFFFFF` returned `#1ffffff` (7+ hex digits); the on-chain
14
+ `TokenDataLib.decodeScalar` masks with `& 0xffffff` and returns `#ffffff`. The governed write validates
15
+ `v <= 0xFFFFFF`, but the raw owner setter does not, so an out-of-domain value can be stored and later
16
+ governed by a `HexColor` schema — and the two serving planes would then decode it differently, splitting
17
+ `inputsHash`. The SDK now masks identically. Pinned on both sides so it cannot drift again:
18
+ `decodeScalarParam('HexColor', 0x1ffffffn) === '#ffffff'` (SDK) and the twin `test_DecodeScalars`
19
+ assertion in `contracts/test/FieldRenderer.t.sol`.
20
+
21
+ **SDK — gateway-prefix projection no longer trims (L-7).** `projectGatewayPrefix` dropped the `.trim()`
22
+ on the on-chain `abx_gateway_*` value: the deployed `_gatewayPrefix` returns the stored bytes verbatim,
23
+ so trimming here made the two planes disagree on a whitespace-padded prefix. The field store rejects an
24
+ empty value, so a set field is always non-empty. Clean prefixes (every real one) are unaffected.
25
+
26
+ **SDK — `permissionlessSalt` docstring hardened (L-3).** Now states explicitly: never use it for a
27
+ pre-published or pre-funded address — a third party can occupy the predicted address first with their own
28
+ `InitParams`. For any reserved address, use `saltFor` (its deployer-bound prefix is front-run-proof). No
29
+ behavior change; the shipped CLI/skill already deploy through `saltFor`.
30
+
31
+ **CLI — the edition schema advisory calls out a holder-writable `seed` by name (L-2).**
32
+ `editionSchemaAdvisory` already warned that a `TokenOwner` param on an edition is shared per-id
33
+ (last-writer-wins); it now adds a sharper note when that param is `seed`, because the normally-immutable
34
+ generative seed becomes re-rollable by _any_ holder of the id — changing the artwork for every
35
+ co-holder. The on-chain behavior is deliberately unchanged (the reassignable-seed feature is
36
+ buyer-verifiable via `paramSchema("seed")`); the guardrail is this warning, not a contract restriction.
37
+ A controller contract on the `Address` leg remains the way to govern it.
38
+
39
+ - 84ca9dd: Finish the burn + royalty-cap surfacing, from the 2026-08-20 w6 agent sandbox sweep. All off-chain —
40
+ no contract changed, no address moved; the on-chain features were verified working end to end (a cold
41
+ agent deployed `--burnable --royalty-cap 42`, minted, burned, and proved the cap enforced on Sepolia).
42
+ The sweep's convergent finding was that the two new **permanent** deploy-time decisions were invisible
43
+ after you set them; this makes them visible everywhere they're decided or read, and adds the owner's
44
+ missing reduce lever.
45
+
46
+ - **New: `abx set-royalty-cap <address> --cap <0-10000>`** — the owner's reduce-only royalty-ceiling
47
+ lever (`RoyaltyExtension.reduceMaxRoyaltyBps`), the "after" the deploy-time "reduce-only after"
48
+ promise never had. Both ways the chain refuses are checked locally before signing: a value that
49
+ wouldn't decrease (`RoyaltyCapNotReduced`) or that would drop below the live royalty rate
50
+ (`RoyaltyCapBelowRoyalty`). SDK: `prepareReduceMaxRoyaltyBps`.
51
+ - **The deploy readout now shows `royalty cap` and `burnable` on every lane** (1/1, series, code, and
52
+ all three edition twins), whenever set. Critically it flags an **auto-raised** cap
53
+ (`royalty cap 25% (auto-raised to fit the royalty)`): omitting `--royalty-cap` while setting a
54
+ royalty above 10% silently raises the permanent ceiling to match, which was previously invisible.
55
+ - **`abx state` now surfaces `royaltyCap` and `burnable`** (human + `--json`), the post-deploy
56
+ verification surface, for both the 721 and edition readouts.
57
+ - **The skill documents the royalty cap** — the identity decision (`decisions.md`), the confirm-
58
+ identity step (`SKILL.md`), and a new `set-royalty-cap` owner-op row (`operating.md`); previously the
59
+ reduce-only ceiling feature had zero skill coverage.
60
+ - **Help/doc corrections:** `set-royalty --help` range `0-1000`→`0-10000` (stale from the hard-cap
61
+ era); `deploy-series --help` now lists `--royalty-cap`/`--burnable`; `deploy --help` states the cap
62
+ auto-raises; `abx inspect`'s trait-feasibility deep-dive points at public docs, not a repo path.
63
+
64
+ - Updated dependencies [84ca9dd]
65
+ - Updated dependencies [84ca9dd]
66
+ - @artblocks/abx-sdk@0.1.0-alpha.20
67
+ - @artblocks/abx-indexer@0.1.0-alpha.21
68
+ - @artblocks/abx-storage@0.1.0-alpha.20
69
+ - @artblocks/abx-token-api@0.1.0-alpha.23
70
+
3
71
  ## 0.1.0-alpha.27
4
72
 
5
73
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACL,KAAK,OAAO,EAMZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,YAAY,EAKjB,KAAK,qBAAqB,EAmD3B,MAAM,oBAAoB,CAAC;AAY5B,OAAO,EAAC,KAAK,GAAG,EAAyC,MAAM,MAAM,CAAC;AACtE,OAAO,EAGL,KAAK,gBAAgB,EAmBtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAyB,KAAK,KAAK,EAA8E,MAAM,aAAa,CAAC;AAgE5I,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAC,CAGzE,CAAC;AACF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOrD;AAQD;;;gEAGgE;AAChE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQ3D;AAED;;;0CAG0C;AAC1C,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;oFACoF;AACpF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED;;;;;GAKG;AACH;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAShH;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,GAAG,IAAI,CASzG;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAWxD;AAID,wBAAsB,YAAY,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9F;AAUD,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBpE;AAKD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkB1E;AAID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBxE;AAOD,eAAO,MAAM,gBAAgB,GAAI,OAAO,GAAG,KAAG,iBAI5C,CAAC;AAEH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,iBAO9C,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,KAAG,iBAI1C,CAAC;AAEH;sFACsF;AACtF,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,iBAIvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,GAAG,SAAS,EAC3B,WAAW,MAAM,KAChB,iBAID,CAAC;AA6DH,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,OAAsC,CAAC;AAEhF;;;;;;;;GAQG;AACH;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAGvF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAY/E;AAED;mGACmG;AACnG,MAAM,MAAM,eAAe,GAAG;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAAC,CAAC;AAExG,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,gBAAgB,EAC3B,KAAK,UAAO,EAAE,gEAAgE;AAC9E,OAAO,UAAQ,EAAE,gFAAgF;AACjG,SAAS,CAAC,EAAE,eAAe,EAAE,wEAAwE;AACrG,UAAU,CAAC,EAAE,MAAM,EAAE,uFAAuF;AAC5G,YAAY,GAAE,KAAU,GACvB,OAAO,CAAC;IAAC,WAAW,EAAE,iBAAiB,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,CAAC,CAkGlE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,gBAAgB,EAAE,CAQlE;AAED,6GAA6G;AAC7G,eAAO,MAAM,qBAAqB,GAAI,OAAO,gBAAgB,EAAE,KAAG,iBAIhE,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAY/D;AAED;oEACoE;AACpE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAGtG;AAED;kGACkG;AAClG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAExD;AAED,kGAAkG;AAClG,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAInF;AAGD,wBAAsB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,iBAiBhE;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,iBA4nBhH;AAkBD,wBAAsB,4BAA4B,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAmW1H;AAgBD,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,EAAE,GAAG,iBAAiB,KAAG,qBAKnE,CAAC;AAEH,wBAAsB,eAAe,CAAC,KAAK,EAAE,KAAK,iBAMjD;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,iBAwiBjG;AAeD,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAkcvH;AAkED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAgB7D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAmB1D;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBxH;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDlH;AAED;iGACiG;AACjG,eAAO,MAAM,iBAAiB,aAmB5B,CAAC;AAGH,eAAO,MAAM,mBAAmB,UAU/B,CAAC;AAEF,eAAO,MAAM,YAAY,aAKvB,CAAC;AAEH,eAAO,MAAM,mBAAmB,aAM9B,CAAC;AASH,eAAO,MAAM,oBAAoB,aAAqG,CAAC;AACvI,eAAO,MAAM,2BAA2B,aAAqE,CAAC;AAE9G,wBAAsB,aAAa,CAAC,KAAK,EAAE,KAAK,iBAiB/C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,iBA4mC/F;AAmBD,eAAO,MAAM,yBAAyB,aAkBpC,CAAC;AAEH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAoXtH;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,OAAO,EACf,QAAQ,GAAE,MAAM,GAAG,OAAgB,GAClC,OAAO,CAAC,OAAO,CAAC,CAmClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAoDlB"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -188,6 +188,8 @@ export function deployCommandLine(flags, salt) {
188
188
  bool('onchain-image');
189
189
  str('compress', flags.compress);
190
190
  str('royalty-bps', flags['royalty-bps']);
191
+ str('royalty-cap', flags['royalty-cap']);
192
+ bool('burnable');
191
193
  bool('no-mint');
192
194
  str('721c', flags['721c'] === 'true' ? 'recommended' : flags['721c']); // bare --721c ≡ recommended
193
195
  str('backend', flags.backend);
@@ -237,6 +239,8 @@ export function deploySeriesCommandLine(flags, salt) {
237
239
  str('minter', flags.minter);
238
240
  str('primary-payee', flags['primary-payee']);
239
241
  str('royalty-bps', flags['royalty-bps']);
242
+ str('royalty-cap', flags['royalty-cap']);
243
+ bool('burnable');
240
244
  str('721c', flags['721c'] === 'true' ? 'recommended' : flags['721c']); // bare --721c ≡ recommended
241
245
  if (flags.sign !== undefined)
242
246
  parts.push('--sign');
@@ -279,6 +283,8 @@ export function deployCodeCommandLine(flags, salt) {
279
283
  str('minter', flags.minter);
280
284
  str('primary-payee', flags['primary-payee']);
281
285
  str('royalty-bps', flags['royalty-bps']);
286
+ str('royalty-cap', flags['royalty-cap']);
287
+ bool('burnable');
282
288
  str('721c', flags['721c'] === 'true' ? 'recommended' : flags['721c']); // bare --721c ≡ recommended
283
289
  str('backend', flags.backend);
284
290
  str('gateway', flags.gateway);
@@ -638,6 +644,15 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
638
644
  // 1500, printed "royalty 15%" in the confirmation readout, and then lost the whole deploy to a
639
645
  // RoyaltyTooHigh() revert — the expensive tx, and one the creator had already approved.
640
646
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
647
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
648
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
649
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
650
+ ? Math.max(1000, royaltyBps)
651
+ : parseRoyaltyBps(String(flags['royalty-cap']));
652
+ if (royaltyBps > maxRoyaltyBps) {
653
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
654
+ }
655
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
641
656
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
642
657
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
643
658
  // Creator traits (real OpenSea attributes). Off-chain operator metadata by default (cheap,
@@ -952,6 +967,8 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
952
967
  contractURIRenderer: renderer,
953
968
  royaltyReceiver: deployer,
954
969
  royaltyBps,
970
+ maxRoyaltyBps,
971
+ burnable,
955
972
  transferValidator,
956
973
  tokenFields,
957
974
  // authorship + rights (creator / license / …) are collection-scope on-chain fields.
@@ -991,6 +1008,8 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
991
1008
  authorshipReadout(flags).forEach((line) => info(line));
992
1009
  info(describeTraits(traits, traitsOnchain));
993
1010
  info(`royalty ${royaltyBps / 100}% → ${deployer}${flags['royalty-bps'] ? '' : dim(' (default 5%)')}`);
1011
+ info(`royalty cap ${maxRoyaltyBps / 100}%${flags['royalty-cap'] !== undefined ? '' : maxRoyaltyBps > 1000 ? dim(' (auto-raised to fit the royalty)') : dim(' (default 10%)')} ${dim('— reduce-only ceiling; lower later with `abx set-royalty-cap`')}`);
1012
+ info(`burnable ${burnable ? `yes ${dim('— holders may burn their own token')}` : `no ${dim('(no token can be destroyed)')}`}`);
994
1013
  info(contentNote);
995
1014
  info(`tokenURI base ${params.tokenURIBase || dim('(empty — resolves on-chain via the renderer)')}`);
996
1015
  // Same reasoning as above: this line derives token #0's URL from `predicted`, so it's only an
@@ -1281,6 +1300,15 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1281
1300
  const name = flags.name ?? 'ABX Edition';
1282
1301
  const symbol = flags.symbol ?? 'ABXE';
1283
1302
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
1303
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
1304
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
1305
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
1306
+ ? Math.max(1000, royaltyBps)
1307
+ : parseRoyaltyBps(String(flags['royalty-cap']));
1308
+ if (royaltyBps > maxRoyaltyBps) {
1309
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
1310
+ }
1311
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
1284
1312
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
1285
1313
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
1286
1314
  const traits = parseDeployTraits(flags);
@@ -1446,6 +1474,8 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1446
1474
  contractURIRenderer: renderer,
1447
1475
  royaltyReceiver: deployer,
1448
1476
  royaltyBps,
1477
+ maxRoyaltyBps,
1478
+ burnable,
1449
1479
  transferValidator,
1450
1480
  editionSize,
1451
1481
  primaryPayee,
@@ -1484,6 +1514,8 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1484
1514
  authorshipReadout(flags).forEach((line) => info(line));
1485
1515
  info(describeTraits(traits, traitsOnchain));
1486
1516
  info(`royalty ${royaltyBps / 100}% → ${deployer}${flags['royalty-bps'] ? '' : dim(' (default 5%)')}`);
1517
+ info(`royalty cap ${maxRoyaltyBps / 100}%${flags['royalty-cap'] !== undefined ? '' : maxRoyaltyBps > 1000 ? dim(' (auto-raised to fit the royalty)') : dim(' (default 10%)')} ${dim('— reduce-only ceiling; lower later with `abx set-royalty-cap`')}`);
1518
+ info(`burnable ${burnable ? `yes ${dim('— holders may burn their own token')}` : `no ${dim('(no token can be destroyed)')}`}`);
1487
1519
  info(contentNote);
1488
1520
  info(`tokenURI base ${params.tokenURIBase || dim('(empty — resolves on-chain via the renderer)')}`);
1489
1521
  info(`contractURI base ${params.contractURIBase || dim('(empty — resolves on-chain via the renderer)')}`);
@@ -1642,6 +1674,15 @@ export async function cmdDeploySeriesBody(flags, emit) {
1642
1674
  const name = flags.name ?? 'ABX Series';
1643
1675
  const symbol = flags.symbol ?? 'ABXS';
1644
1676
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
1677
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
1678
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
1679
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
1680
+ ? Math.max(1000, royaltyBps)
1681
+ : parseRoyaltyBps(String(flags['royalty-cap']));
1682
+ if (royaltyBps > maxRoyaltyBps) {
1683
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
1684
+ }
1685
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
1645
1686
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
1646
1687
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
1647
1688
  console.log(bold(`\n ABX Self-Host Toolkit — deploy series\n ${dim('a multi-token drop, served from chain alone')}`));
@@ -1948,6 +1989,8 @@ export async function cmdDeploySeriesBody(flags, emit) {
1948
1989
  contractURIRenderer: renderer,
1949
1990
  royaltyReceiver: deployer,
1950
1991
  royaltyBps,
1992
+ maxRoyaltyBps,
1993
+ burnable,
1951
1994
  transferValidator,
1952
1995
  maxInvocations: count,
1953
1996
  primaryPayee,
@@ -1983,7 +2026,7 @@ export async function cmdDeploySeriesBody(flags, emit) {
1983
2026
  // readout for the no-salt case).
1984
2027
  if (explicitSalt)
1985
2028
  info(`deterministic address: ${predicted}`);
1986
- info(`name "${name}" · symbol ${symbol} · size ${count} · royalty ${royaltyBps / 100}%`);
2029
+ info(`name "${name}" · symbol ${symbol} · size ${count} · royalty ${royaltyBps / 100}% · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}`);
1987
2030
  authorshipReadout(flags).forEach((line) => info(line));
1988
2031
  info(`mint: ${mintCount > 0 ? `${mintCount} token(s) in order → ${deployer} at deploy` : 'deferred (mint later / external minter)'}`);
1989
2032
  if (minter !== zeroAddress)
@@ -2203,6 +2246,15 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2203
2246
  const name = flags.name ?? 'ABX Edition Series';
2204
2247
  const symbol = flags.symbol ?? 'ABXES';
2205
2248
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
2249
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
2250
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
2251
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
2252
+ ? Math.max(1000, royaltyBps)
2253
+ : parseRoyaltyBps(String(flags['royalty-cap']));
2254
+ if (royaltyBps > maxRoyaltyBps) {
2255
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
2256
+ }
2257
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
2206
2258
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
2207
2259
  const baseUrl = flags['public-base-url'] ?? resolveBaseUrl(port);
2208
2260
  console.log(bold(`\n ABX Self-Host Toolkit — deploy edition series\n ${dim(editionSize === 0n
@@ -2489,6 +2541,8 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2489
2541
  contractURIRenderer: renderer,
2490
2542
  royaltyReceiver: deployer,
2491
2543
  royaltyBps,
2544
+ maxRoyaltyBps,
2545
+ burnable,
2492
2546
  transferValidator,
2493
2547
  maxInvocations: count,
2494
2548
  editionSize,
@@ -2529,6 +2583,8 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2529
2583
  info(`ids ${count} (id-space cap)`);
2530
2584
  info(`copies ${editionSize === 0n ? 'open (uncapped) per id' : `${editionSize} per id`}`);
2531
2585
  info(`royalty ${royaltyBps / 100}% → ${deployer}${flags['royalty-bps'] ? '' : dim(' (default 5%)')}`);
2586
+ info(`royalty cap ${maxRoyaltyBps / 100}%${flags['royalty-cap'] !== undefined ? '' : maxRoyaltyBps > 1000 ? dim(' (auto-raised to fit the royalty)') : dim(' (default 10%)')} ${dim('— reduce-only ceiling; lower later with `abx set-royalty-cap`')}`);
2587
+ info(`burnable ${burnable ? `yes ${dim('— holders may burn their own token')}` : `no ${dim('(no token can be destroyed)')}`}`);
2532
2588
  info(`tokenURI base ${params.tokenURIBase || dim('(empty — resolves on-chain via the renderer)')}`);
2533
2589
  info(`mint: ${effectiveMintCount > 0 ? `${effectiveMintCount} id(s) × ${mintAmount} cop${mintAmount === 1n ? 'y' : 'ies'} → ${deployer} at deploy` : 'deferred'}`);
2534
2590
  if (minter !== zeroAddress)
@@ -2849,7 +2905,7 @@ export const DEPLOY_CODE_FLAGS = new Set([
2849
2905
  ...AUTHORSHIP_DEPLOY_FIELDS.map(([flag]) => flag), // creator · display-notes · creator-links · license
2850
2906
  'image-base', 'attributes-renderer', 'image-renderer',
2851
2907
  // supply + mint + economics
2852
- 'max', 'mint-count', 'mint-all', 'no-mint', 'unpaused', 'minter', 'primary-payee', 'royalty-bps', '721c',
2908
+ 'max', 'mint-count', 'mint-all', 'no-mint', 'unpaused', 'minter', 'primary-payee', 'royalty-bps', 'royalty-cap', 'burnable', '721c',
2853
2909
  // params + dependencies
2854
2910
  'schema', 'no-seed', 'seed-source', 'no-delegation', 'dep', 'dep-registry',
2855
2911
  // serving lane
@@ -2878,13 +2934,13 @@ export const SHARED_DEPLOY_FLAGS = [
2878
2934
  // A 1/1 `abx deploy` accepts these (see `abx help deploy`). Anything else warns (typo'd/unsupported).
2879
2935
  export const DEPLOY_FLAGS = new Set([
2880
2936
  'image', 'name', 'symbol', 'type', 'description', 'description-onchain', 'external-url', 'traits', 'traits-onchain', 'attributes',
2881
- 'onchain-uri', 'onchain-image', 'compress', 'allow-unreadable-onchain', 'royalty-bps', 'no-mint',
2937
+ 'onchain-uri', 'onchain-image', 'compress', 'allow-unreadable-onchain', 'royalty-bps', 'royalty-cap', 'burnable', 'no-mint',
2882
2938
  ...AUTHORSHIP_DEPLOY_FIELDS.map(([flag]) => flag),
2883
2939
  ...SHARED_DEPLOY_FLAGS,
2884
2940
  ]);
2885
2941
  // `abx deploy-series` accepts these (see `abx help deploy-series`).
2886
2942
  export const DEPLOY_SERIES_FLAGS = new Set([
2887
- 'dir', 'count', 'name', 'symbol', 'description', 'external-url', 'royalty-bps', 'attributes', 'traits-onchain',
2943
+ 'dir', 'count', 'name', 'symbol', 'description', 'external-url', 'royalty-bps', 'royalty-cap', 'burnable', 'attributes', 'traits-onchain',
2888
2944
  'no-mint', 'mint-all', 'mint-count', 'unpaused', 'minter', 'primary-payee',
2889
2945
  'onchain-uri', 'onchain-image', 'compress', 'allow-unreadable-onchain', 'chunk-store',
2890
2946
  ...AUTHORSHIP_DEPLOY_FIELDS.map(([flag]) => flag),
@@ -2956,6 +3012,15 @@ export async function cmdDeployCodeBody(flags, emit) {
2956
3012
  throw new Error(`--mint-count ${mintCount} exceeds --max ${max}`);
2957
3013
  const paused = flags.unpaused === undefined;
2958
3014
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
3015
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
3016
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
3017
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
3018
+ ? Math.max(1000, royaltyBps)
3019
+ : parseRoyaltyBps(String(flags['royalty-cap']));
3020
+ if (royaltyBps > maxRoyaltyBps) {
3021
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
3022
+ }
3023
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
2959
3024
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
2960
3025
  const baseUrl = (flags['public-base-url'] ?? resolveBaseUrl(port)).replace(/\/$/, '');
2961
3026
  const hasPublicUrl = !!(flags['public-base-url'] || process.env.ABX_PUBLIC_BASE_URL);
@@ -3480,7 +3545,7 @@ export async function cmdDeployCodeBody(flags, emit) {
3480
3545
  info(`deployer: ${dim('not set')} — pass ${bold('--for 0x..')} (or set a signing key) to preview the exact deterministic address; the plan below is otherwise deployer-independent.`);
3481
3546
  if (shownAddr)
3482
3547
  info(`deterministic address: ${shownAddr}`);
3483
- info(`name "${name}" · symbol ${symbol} · max ${max}${maxProvided ? '' : ' ⚠ default — set --max N'} · royalty ${royaltyBps / 100}%${royaltyProvided ? '' : ' ⚠ default — set --royalty-bps N'}`);
3548
+ info(`name "${name}" · symbol ${symbol} · max ${max}${maxProvided ? '' : ' ⚠ default — set --max N'} · royalty ${royaltyBps / 100}%${royaltyProvided ? '' : ' ⚠ default — set --royalty-bps N'} · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}`);
3484
3549
  if (!flags.description)
3485
3550
  warn(`no --description — the on-chain metadata ships with no description (the one creators most often forget). Add --description "…" or deploy bare.`);
3486
3551
  info(`content: ${contentSummary}`);
@@ -3724,6 +3789,8 @@ export async function cmdDeployCodeBody(flags, emit) {
3724
3789
  contractURIRenderer: foldIntoInit ? metadataRenderer : zeroAddress,
3725
3790
  royaltyReceiver: owner,
3726
3791
  royaltyBps,
3792
+ maxRoyaltyBps,
3793
+ burnable,
3727
3794
  transferValidator,
3728
3795
  maxInvocations: BigInt(max),
3729
3796
  primaryPayee: flags['primary-payee'] ?? zeroAddress,
@@ -4081,7 +4148,7 @@ export async function cmdDeployCodeBody(flags, emit) {
4081
4148
  export const DEPLOY_CODE_EDITION_FLAGS = new Set([
4082
4149
  'script', 'name', 'symbol', 'description', 'external-url', 'description-onchain',
4083
4150
  ...AUTHORSHIP_DEPLOY_FIELDS.map(([flag]) => flag),
4084
- 'max', 'mint-count', 'mint-all', 'no-mint', 'mint-amount', 'unpaused', 'minter', 'primary-payee', 'royalty-bps', '721c',
4151
+ 'max', 'mint-count', 'mint-all', 'no-mint', 'mint-amount', 'unpaused', 'minter', 'primary-payee', 'royalty-bps', 'royalty-cap', 'burnable', '721c',
4085
4152
  'schema', 'no-seed', 'seed-source',
4086
4153
  'public-base-url', 'onchain-uri', 'generator', 'renderer', 'port',
4087
4154
  'sign', 'unsigned', 'for', 'salt', 'factory', 'bootstrap-factory', 'sign-url-file',
@@ -4140,6 +4207,15 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4140
4207
  }
4141
4208
  const paused = flags.unpaused === undefined;
4142
4209
  const royaltyBps = flags['royalty-bps'] === undefined ? 500 : parseRoyaltyBps(String(flags['royalty-bps']));
4210
+ // B45: owner-set royalty ceiling (bps, up to 100%), reduce-only after deploy. Defaults to 10%,
4211
+ // auto-raised to fit a higher --royalty-bps so a plausible input never errors; --royalty-cap overrides.
4212
+ const maxRoyaltyBps = flags['royalty-cap'] === undefined
4213
+ ? Math.max(1000, royaltyBps)
4214
+ : parseRoyaltyBps(String(flags['royalty-cap']));
4215
+ if (royaltyBps > maxRoyaltyBps) {
4216
+ throw new Error(`--royalty-bps ${royaltyBps / 100}% exceeds --royalty-cap ${maxRoyaltyBps / 100}%; raise the cap or lower the royalty.`);
4217
+ }
4218
+ const burnable = flags.burnable === '' || flags.burnable === 'true';
4143
4219
  const port = Number(flags.port ?? process.env.ABX_PORT ?? DEFAULT_PORT);
4144
4220
  const baseUrl = (flags['public-base-url'] ?? resolveBaseUrl(port)).replace(/\/$/, '');
4145
4221
  const hasPublicUrl = !!(flags['public-base-url'] || process.env.ABX_PUBLIC_BASE_URL);
@@ -4282,6 +4358,8 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4282
4358
  contractURIRenderer: zeroAddress,
4283
4359
  royaltyReceiver: owner,
4284
4360
  royaltyBps,
4361
+ maxRoyaltyBps,
4362
+ burnable,
4285
4363
  transferValidator,
4286
4364
  maxInvocations: BigInt(max),
4287
4365
  editionSize,
@@ -4375,7 +4453,7 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4375
4453
  info(`deployer: ${dim('not set')} — pass ${bold('--for 0x..')} to preview the exact deterministic address.`);
4376
4454
  if (shownAddr)
4377
4455
  info(`deterministic address: ${shownAddr}`);
4378
- info(`name "${name}" · symbol ${symbol} · max ${max} id(s) · royalty ${royaltyBps / 100}%`);
4456
+ info(`name "${name}" · symbol ${symbol} · max ${max} id(s) · royalty ${royaltyBps / 100}% · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}`);
4379
4457
  // `source` is what this lane read; there has never been a `bytes` binding here, so this line
4380
4458
  // threw a ReferenceError for every `deploy-code --copies … --dry-run` — the dry run crashed at the
4381
4459
  // last step of the plan it was printing. Byte length, not UTF-16 code units, matching the 721 twin.