@artblocks/abx-cli 0.1.0-alpha.29 → 0.1.0-alpha.30

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,126 @@
1
1
  # @artblocks/abx-cli
2
2
 
3
+ ## 0.1.0-alpha.30
4
+
5
+ ### Minor Changes
6
+
7
+ - 993e095: `--dry-run` now **simulates** the transaction instead of only describing it.
8
+
9
+ Every write command routes through one risk gate, so all of them gained this at once. A dry run
10
+ `eth_call`s the prepared transaction against current state and adds one line:
11
+
12
+ ```
13
+ simulation ✓ would succeed (eth_call against current state)
14
+ simulation ✗ would REVERT — FieldLocked()
15
+ sending this now would burn gas and change nothing.
16
+ ```
17
+
18
+ This matters most for a **multicall** — `attach`'s batched pairs, `deploy-code`'s setup — because a
19
+ multicall is one transaction, so simulating it exercises the whole sequence atomically, against real
20
+ state, with no fork involved.
21
+
22
+ It reports **unknown**, never a false green, whenever it cannot prove anything: no signer to simulate
23
+ as, a contract deploy, a target with no code yet, or an unreachable node.
24
+
25
+ Revert reasons decode to the contract's own error name (`RoyaltyTooHigh()`) where the node returns
26
+ revert data. Several public endpoints return none — in that case the output says so plainly and names
27
+ what a bare revert usually is, rather than viem's "reverted for an unknown reason", which reads like a
28
+ decoding failure on our side.
29
+
30
+ - 993e095: `deploy-code --copies` now supports `--image-renderer` / `--attributes-renderer` — a **true fully
31
+ on-chain ERC-1155 edition**.
32
+
33
+ ```bash
34
+ abx deploy-code --copies open --image-renderer 0x… --attributes-renderer 0x… --onchain-uri \
35
+ --name "…" --symbol …
36
+ ```
37
+
38
+ Open supply, minted over time by anyone you let mint, image and traits computed by your Solidity
39
+ renderers, `uri(id)` assembled on chain. No resolver, no render runner, no bucket, nothing to keep
40
+ running — the same zero-infrastructure lane the ERC-721 side has had, on the edition twin.
41
+
42
+ - `--script` is now **optional** on this command. A renderer-only edition stores no program and has no
43
+ `animation_url`; passing both a script and renderers composes (an on-chain live view _and_ an
44
+ on-chain still), exactly as on the 721 lane.
45
+ - The same guard applies as at 721 deploy time: a renderer address with no code is refused, because
46
+ pointing a field at one reverts every `uri()` in the collection.
47
+ - `--image-base` is still refused with `--copies` — it needs the effect runner to write a still per id
48
+ — and now says so, and names the lane that does work.
49
+
50
+ This was never a contract limit: `EditionCode` composes the same `OnChainMetadata` extension and URI
51
+ renderer slots as `SeriesCode`. Only the CLI flags were unported, and a reporter who asked the natural
52
+ question — "can I get a real on-chain-rendered 1155 with no server?" — read the blanket refusal as a
53
+ protocol answer and shipped an ERC-721 workaround instead. `contracts/test/EditionOnChainRender.t.sol`
54
+ now pins the claim end to end.
55
+
56
+ Reported in the 2026-08-24 field notes.
57
+
58
+ ### Patch Changes
59
+
60
+ - 993e095: `abx doctor` checks whether each RPC endpoint agrees with itself about your wallet's nonce.
61
+
62
+ `pending` is by definition at least `latest` on a coherent node. An endpoint that hasn't caught up
63
+ with its own head answers lower — measured on `sepolia.base.org` right after a confirmed write — and
64
+ the next command's first send re-uses a spent nonce. `doctor` reported that exact endpoint healthy in
65
+ that exact condition.
66
+
67
+ Sends are already protected (they floor at `max(pending, latest)`); this names the endpoint instead of
68
+ silently routing around it.
69
+
70
+ The check needs a wallet that has actually sent something — a fresh wallet reads 0 everywhere and
71
+ proves nothing — so on that path it prints `nonce coherence: unknown` rather than passing on no
72
+ evidence. A check that goes green without a signal is the same false green as an RPC answering `[]`
73
+ because it pruned its logs.
74
+
75
+ - 993e095: `deploy-code`, `deploy-code --copies` and `deploy-series` now state their permanent decisions on a real
76
+ send, not only under `--dry-run`.
77
+
78
+ The supply cap and the royalty rate — including the `⚠ default` marker when you didn't choose one —
79
+ were printed in the deploy _plan_, which only runs for `--dry-run`. A creator going straight to `--send`
80
+ learned afterwards, from `abx state`, that their collection carries a 5% royalty to the deploying wallet.
81
+ That is a real economic default to discover after the fact on a demo nobody meant to monetize. The
82
+ success readout now carries the same line the plan does.
83
+
84
+ The default itself is unchanged: 5% to the creator is the right default for a launch, and a lane-specific
85
+ 0% would silently strip royalties from projects deployed the same way for real.
86
+
87
+ Reported in the 2026-08-24 field notes.
88
+
89
+ - 993e095: `abx set-field --representation renderer` no longer writes a value the chain cannot decode.
90
+
91
+ A `renderer` field is stored as `abi.encode(address)` and the on-chain metadata renderer decodes it
92
+ before it can compute the field. `--value` was written to chain verbatim, so passing a plain 20-byte
93
+ address — the same shape `deploy-code --image-renderer` takes — landed 20 bytes where 32 were needed,
94
+ and **every `tokenURI` in the collection reverted**. It read like a protocol bug rather than a bad
95
+ write: `contractField("image")` still returned the right representation and a right-looking address,
96
+ and re-pointing at the renderer the collection was deployed with didn't fix it (that write had the
97
+ same wrong shape).
98
+
99
+ `set-field` now normalizes and validates the structured representations before sending:
100
+
101
+ - `--representation renderer` accepts the field renderer's plain `0x` address and abi-encodes it, or
102
+ an already-canonical 32-byte word. Any other length — or a 32-byte word with non-zero high bytes —
103
+ is refused with a message that says what to pass.
104
+ - `--representation reader` / `reader-gzip` must be `abi.encode(address reader, address pointer)`;
105
+ anything else is refused and points at `--file`, which encodes it correctly for you.
106
+ - A `renderer` value pointing at an address with **no code** is refused, the same guard
107
+ `deploy-code --image-renderer` already applied at deploy time.
108
+ - After a field write lands, `set-field` calls `tokenURI` once and says whether it still resolves —
109
+ so a renderer that reverts for its own reasons is reported against the write that exposed it,
110
+ with the recovery command.
111
+
112
+ Already-broken collections are recoverable, and were never permanently damaged: re-run the same
113
+ `set-field` on the current CLI (the field is only frozen by an explicit `abx lock-field`).
114
+
115
+ Reported in the 2026-08-24 field notes, from four projects shipped on Base Sepolia.
116
+
117
+ - Updated dependencies [549a32d]
118
+ - Updated dependencies [993e095]
119
+ - @artblocks/abx-token-api@0.1.0-alpha.25
120
+ - @artblocks/abx-sdk@0.1.0-alpha.22
121
+ - @artblocks/abx-indexer@0.1.0-alpha.23
122
+ - @artblocks/abx-storage@0.1.0-alpha.22
123
+
3
124
  ## 0.1.0-alpha.29
4
125
 
5
126
  ### Minor Changes
@@ -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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"}
@@ -18,7 +18,7 @@ import { basename, extname, join as joinPath, resolve as resolvePath } from 'nod
18
18
  import { DEFAULT_CHAIN_KEY, DEP_RESOLUTION, METADATA_FIELD as F, contentIdFromLocator, METADATA_REPRESENTATION as R, analyzeScript, assertChainId, checkRegistryDeps, dependencySetupCalls, deployOneOfOne, deploySeries, deployOneOfOneEdition, deployEditionImage, discoverDeployBlock, encodeFieldRenderer, encodeTag, expectedChainComplete, makeHotSender, makePublicClient, makeWalletClient, normalizeAttributes, onchainUriSetupCalls, oneOfOneImageAbi, oneOfOneEditionAbi, parseTraitPairs, planResume, predictClone, probeSeedSource, prepareCodeSetup, prepareDeployOneOfOne, prepareDeploySeries, prepareDeploySeriesCode, prepareDeployOneOfOneEdition, prepareDeployEditionImage, prepareDeployEditionCode, redactRpcUrl, resolveChain, resolveDepRegistryPointer, resolveGenerator, probeTransferValidator, resolveRecommendedTransferValidator, resolveRpcUrl, resolveSeedSource, resolveSeriesCodeFactory, saltFor, seriesCodeAbi, seriesCodeFactoryAbi, tryReadContract, AbxServiceClient, } from '@artblocks/abx-sdk';
19
19
  import { DIRECT_URL_BACKENDS, contentTypeFromPath, decideImageContentLane, hashContent, isTurboArweave, resolveBackend, validateRenderStorageCombo, } from '@artblocks/abx-storage';
20
20
  import { DEFAULT_PORT, contentHash, generateContent, resolveBaseUrl, startTokenApiServer } from '@artblocks/abx-token-api';
21
- import { encodeFunctionData, toHex, zeroAddress } from 'viem';
21
+ import { encodeFunctionData, getAddress, toHex, zeroAddress } from 'viem';
22
22
  import { CHAIN, explorerBase, assertTurboFundsForUpload, backendResolution, collectContentLocators, ensureArweaveIdentityForUpload, factoryAddress, faucetHint, localIndexer, loopbackBaseUrl, noteArweavePlan, noteStorageReadiness, rendererAddress, seriesFactoryAddress, oneOfOneEditionFactoryAddress, editionFactoryAddress, editionCodeFactoryAddress, storageOptions, storageOverrides, storageSignerChoice, } from '../config.js';
23
23
  import { parseDepFlag } from '../deps.js';
24
24
  import { allowUnreadableOnchain, isDryRun, parseSaltFlag, refuseStrayFlags, warnSignWithoutFor } from '../flags.js';
@@ -2163,6 +2163,12 @@ export async function cmdDeploySeriesBody(flags, emit) {
2163
2163
  blockNumber = result.blockNumber;
2164
2164
  ok(`deployed ${clone}`);
2165
2165
  }
2166
+ // The permanent decisions, on the path that actually sent them — the plan line above is
2167
+ // dry-run-only, so a creator going straight to --send never saw their royalty rate (5% to the
2168
+ // deploying wallet by default) until they thought to read `abx state`.
2169
+ info(`permanent: size ${count} · royalty ${royaltyBps / 100}%${flags['royalty-bps'] === undefined ? ' ⚠ default' : ''} → the deploying wallet` +
2170
+ ` · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}` +
2171
+ dim(' (rate is changeable with `abx set-royalty`; the CAP only ever goes down)'));
2166
2172
  emit(jsonSafe({ command: 'deploy-series', address: clone, chain: CHAIN, chainId: resolveChain(CHAIN).id, factory, deployBlock: blockNumber, name, symbol }));
2167
2173
  step('Index it — replay the event spine from chain');
2168
2174
  const indexer = localIndexer();
@@ -4057,6 +4063,14 @@ export async function cmdDeployCodeBody(flags, emit) {
4057
4063
  if (discovered !== null)
4058
4064
  deployBlock = discovered;
4059
4065
  ok(`SeriesCode live: ${clone} ${dim(`(from block ${deployBlock})`)}`);
4066
+ // Every PERMANENT deploy decision, said out loud on the path that actually sent one. These lines
4067
+ // existed only under --dry-run, so a creator who went straight to --send learned their supply cap
4068
+ // and their royalty rate afterwards, from `abx state` — the royalty in particular, because 5% to
4069
+ // the deployer is a real economic default nobody asked for on a testnet demo. Reported from the
4070
+ // field on alpha.29. Same markers as the dry-run's plan line, so the two read identically.
4071
+ info(`permanent: max ${max}${maxProvided ? '' : ' ⚠ default'} · royalty ${royaltyBps / 100}%${royaltyProvided ? '' : ' ⚠ default'} → the deploying wallet` +
4072
+ ` · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}` +
4073
+ dim(` (rate is changeable with \`abx set-royalty\`; the CAP only ever goes down, and \`max\` only ever goes down)`));
4060
4074
  // Emitted here rather than at the end: a code deploy is TWO transactions, and if the second (setup)
4061
4075
  // fails, the address of the live-but-incomplete contract is the single most valuable thing a caller
4062
4076
  // can be told — it is exactly the input `--resume <address>` takes to finish the job.
@@ -4181,10 +4195,28 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4181
4195
  if (flags['code-dir']) {
4182
4196
  throw new Error('--code-dir is not yet supported for edition code deploys (--copies) — use --script (on-chain chunks) instead. Tracked as a follow-up.');
4183
4197
  }
4184
- if (!flags.script)
4185
- throw new Error(usage);
4186
- if (flags['image-renderer'] || flags['attributes-renderer'] || flags['image-base']) {
4187
- throw new Error('--image-renderer/--attributes-renderer/--image-base are not yet supported for edition code deploys (--copies). Tracked as a follow-up.');
4198
+ // --image-base stays refused: unlike the renderer flags it is not a field write, it needs the
4199
+ // effect runner's per-token still + the url-template's `{id}` substitution over an id SPACE rather
4200
+ // than a token sequence. That port is real work; these two were not.
4201
+ if (flags['image-base']) {
4202
+ throw new Error('--image-base is not wired for edition code deploys (--copies) yet — it needs the effect runner to write a\n' +
4203
+ ' still per id, which the edition lane does not drive. The two flags beside it DO work here:\n' +
4204
+ ' `--image-renderer 0x.. --attributes-renderer 0x.. --onchain-uri` computes image + traits in Solidity, on\n' +
4205
+ ' chain, with nothing to render or host. Otherwise use --public-base-url and a resolver.');
4206
+ }
4207
+ // The in-chain Solidity renderer lane, same as the 721 twin: EditionCode composes the same
4208
+ // OnChainMetadata extension and the same URI-renderer slots, so `image`/`attributes` at a
4209
+ // `renderer` representation resolve through the canonical metadata renderer with no server in the
4210
+ // graph. Proven end-to-end in contracts/test/EditionOnChainRender.t.sol. A 2026-08-24 field report
4211
+ // read the old blanket refusal as a PROTOCOL limit and shipped a 721 workaround for what should
4212
+ // have been a true 1155.
4213
+ const imageRendererFlag = flags['image-renderer'] ? String(flags['image-renderer']) : undefined;
4214
+ const attributesRendererFlag = flags['attributes-renderer'] ? String(flags['attributes-renderer']) : undefined;
4215
+ const hasProgram = !!flags.script;
4216
+ const hasFieldRenderers = !!(imageRendererFlag || attributesRendererFlag);
4217
+ if (!hasProgram && !hasFieldRenderers) {
4218
+ throw new Error(`${usage}\n (or, for a FULLY on-chain Solidity render with no program: --copies <n|open> --image-renderer 0x.. ` +
4219
+ `[--attributes-renderer 0x..] --onchain-uri)`);
4188
4220
  }
4189
4221
  // Not a scope cut — semantically refused: EditionCode has no TokenOwner-leg delegation to opt
4190
4222
  // out of. Its Params auth leg generalizes to "any holder" (balanceOf(sender, id) > 0) instead of
@@ -4270,18 +4302,26 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4270
4302
  let metadataRenderer = zeroAddress;
4271
4303
  if (onChainUri) {
4272
4304
  step('On-chain URI');
4273
- const knownGenerator = resolveGenerator(chainId, flags.generator);
4274
- if (!knownGenerator) {
4275
- throw new Error(`--onchain-uri needs the canonical AbxGenerator for '${CHAIN}', and none is configured. Set ABX_GENERATOR / --generator, ` +
4276
- `or check the shipped manifest (packages/sdk/src/deployments.ts).`);
4277
- }
4278
- generator = knownGenerator;
4279
- if (!dryRun) {
4280
- const generatorCode = await publicClient.getCode({ address: generator });
4281
- if (!generatorCode || generatorCode === '0x')
4282
- throw new Error(`the configured generator ${generator} has no code on '${CHAIN}' — check ABX_GENERATOR / --generator / the RPC endpoint.`);
4283
- }
4284
- info(dryRun ? `would point animation_url at the canonical generator ${generator} (computed on-chain)` : `animation_url computes ON-CHAIN via the canonical generator ${generator}`);
4305
+ // A renderer-only edition has no program, so no animation_url and no generator. Resolving one
4306
+ // anyway and baking the leg would point the metadata renderer at a document with no script —
4307
+ // and `onchainUriSetupCalls` treats a zero generator as exactly this signal, omitting the leg.
4308
+ if (hasProgram) {
4309
+ const knownGenerator = resolveGenerator(chainId, flags.generator);
4310
+ if (!knownGenerator) {
4311
+ throw new Error(`--onchain-uri needs the canonical AbxGenerator for '${CHAIN}', and none is configured. Set ABX_GENERATOR / --generator, ` +
4312
+ `or check the shipped manifest (packages/sdk/src/deployments.ts).`);
4313
+ }
4314
+ generator = knownGenerator;
4315
+ if (!dryRun) {
4316
+ const generatorCode = await publicClient.getCode({ address: generator });
4317
+ if (!generatorCode || generatorCode === '0x')
4318
+ throw new Error(`the configured generator ${generator} has no code on '${CHAIN}' — check ABX_GENERATOR / --generator / the RPC endpoint.`);
4319
+ }
4320
+ info(dryRun ? `would point animation_url at the canonical generator ${generator} (computed on-chain)` : `animation_url computes ON-CHAIN via the canonical generator ${generator}`);
4321
+ }
4322
+ else {
4323
+ info('renderer-only — no program, so no animation_url; the Solidity renderer(s) ARE the work');
4324
+ }
4285
4325
  metadataRenderer = dryRun ? (rendererAddress(flags.renderer) ?? zeroAddress) : await ensureRenderer(flags.renderer);
4286
4326
  info(metadataRenderer === zeroAddress
4287
4327
  ? 'would deploy the canonical metadata renderer first, then set the URI renderers to it in the setup multicall'
@@ -4335,16 +4375,63 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4335
4375
  }
4336
4376
  }
4337
4377
  step('Content');
4338
- const scriptPath = flags.script;
4339
- const source = readFileSync(resolvePath(scriptPath), 'utf8');
4340
- const scriptChunks = planOnChainScript(source);
4341
- ok(`script ${new TextEncoder().encode(source).length} bytes → ${scriptChunks.length} on-chain chunk(s)`);
4378
+ let scriptChunks = [];
4379
+ let contentSummary;
4380
+ if (hasProgram) {
4381
+ const source = readFileSync(resolvePath(flags.script), 'utf8');
4382
+ scriptChunks = planOnChainScript(source);
4383
+ contentSummary = `script ${Buffer.byteLength(source, 'utf8')} bytes → ${scriptChunks.length} on-chain chunk(s)`;
4384
+ ok(contentSummary);
4385
+ }
4386
+ else {
4387
+ // Renderer-only: the Solidity contract IS the content. Nothing is stored on this token.
4388
+ contentSummary = `renderer-only — ${[imageRendererFlag && 'image', attributesRendererFlag && 'attributes'].filter(Boolean).join(' + ')} computed in Solidity; no program stored`;
4389
+ ok(contentSummary);
4390
+ }
4342
4391
  const contractFields = [];
4343
4392
  if (flags.description)
4344
4393
  contractFields.push({ field: encodeTag(F.description), representation: encodeTag(R.inline), value: toHex(String(flags.description)) });
4345
4394
  if (flags['external-url'])
4346
4395
  contractFields.push({ field: encodeTag(F.externalUrl), representation: encodeTag(R.inline), value: toHex(String(flags['external-url'])) });
4347
4396
  contractFields.push(...authorshipContractFields(flags), ...gatewayContractFields(flags));
4397
+ // The two `renderer`-representation fields. Same guard as the 721 lane: a real deploy REFUSES a
4398
+ // codeless address (pointing a field at one reverts every uri() in the collection); a dry run
4399
+ // probes best-effort so a preview without an RPC still works.
4400
+ for (const [flagName, fieldKey, what] of [
4401
+ ['image-renderer', F.image, 'an IAbxFieldRenderer returning image/svg+xml on-chain'],
4402
+ ['attributes-renderer', F.attributes, 'an IAbxFieldRenderer returning an application/json traits array'],
4403
+ ]) {
4404
+ const raw = flagName === 'image-renderer' ? imageRendererFlag : attributesRendererFlag;
4405
+ if (!raw)
4406
+ continue;
4407
+ if (!/^0x[0-9a-fA-F]{40}$/.test(raw))
4408
+ throw new Error(`--${flagName} must be a 0x address (${what}, e.g. a SeedSvgRenderer fork).`);
4409
+ const addr = getAddress(raw);
4410
+ if (dryRun) {
4411
+ let present = null;
4412
+ try {
4413
+ const c = await publicClient.getCode({ address: addr });
4414
+ present = !!c && c !== '0x';
4415
+ }
4416
+ catch {
4417
+ present = null;
4418
+ }
4419
+ if (present === false)
4420
+ warn(`--${flagName} ${bold(addr)} has NO code on '${CHAIN}' — that is NOT a deployed renderer. A real deploy REFUSES it.`);
4421
+ else
4422
+ info(`collection ${fieldKey} → on-chain field-renderer ${bold(addr)} ${dim(present ? '(computed on-chain; code present ✓)' : '(computed on-chain — a real deploy VERIFIES this is deployed and refuses if not)')}`);
4423
+ }
4424
+ else {
4425
+ const code = await publicClient.getCode({ address: addr });
4426
+ if (!code || code === '0x')
4427
+ throw new Error(`--${flagName} ${addr} has no code on '${CHAIN}' — it must be a DEPLOYED IAbxFieldRenderer (${what}), not a placeholder. Deploy the renderer first (\`abx scaffold-renderer\`).`);
4428
+ info(`collection ${fieldKey} → on-chain field-renderer ${bold(addr)} ${dim('(computed on-chain, embedded in uri(); code present ✓)')}`);
4429
+ }
4430
+ contractFields.push({ field: encodeTag(fieldKey), representation: encodeTag(R.renderer), value: encodeFieldRenderer(addr) });
4431
+ }
4432
+ if (hasFieldRenderers && !onChainUri) {
4433
+ warn('--image-renderer/--attributes-renderer compute fields ON-CHAIN, but without --onchain-uri the URI renderers are never wired, so uri() still resolves through your resolver and nothing reads them. Add --onchain-uri.');
4434
+ }
4348
4435
  const onchainUriLegs = onChainUri ? onchainUriSetupCalls({ generator, metadataRenderer }) : [];
4349
4436
  step('Deploy');
4350
4437
  const lane = laneFromFlags(flags);
@@ -4432,9 +4519,9 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4432
4519
  // Second site of the same missing binding as the plan line above — and the worse one: this is
4433
4520
  // the REAL deploy path, so `deploy-code --copies` threw at the confirmation prompt, after the
4434
4521
  // wallet and factory work was already done.
4435
- `About to deploy an edition code project "${name}" (${symbol}) — script ${Buffer.byteLength(source, 'utf8')} bytes → ${scriptChunks.length} chunk(s); ` +
4522
+ `About to deploy an edition code project "${name}" (${symbol}) — ${contentSummary}; ` +
4436
4523
  `up to ${max} id(s) × ${editionSize === 0n ? 'open' : editionSize.toString()} cop${editionSize === 1n ? 'y' : 'ies'} each; ` +
4437
- `${onChainUri ? `tokenURI ON-CHAIN via the renderer (generator ${generator})` : `resolver base ${baseUrl}`}; ` +
4524
+ `${onChainUri ? `uri() ON-CHAIN via the renderer${generator === zeroAddress ? ' (no program, no animation_url)' : ` (generator ${generator})`}` : `resolver base ${baseUrl}`}; ` +
4438
4525
  `mint: ${mintCount > 0 ? `${mintCount} id(s) × ${mintAmount} at deploy` : 'deferred'}; approvals: ${approvals} wallet approval(s); owner+royalty: your wallet @ ${royaltyBps / 100}%.` +
4439
4526
  (transferValidator !== zeroAddress ? ` ERC-1155C: enrolled at deploy, permanently (validator ${transferValidator}).` : ''), flags);
4440
4527
  }
@@ -4461,14 +4548,11 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4461
4548
  if (shownAddr)
4462
4549
  info(`deterministic address: ${shownAddr}`);
4463
4550
  info(`name "${name}" · symbol ${symbol} · max ${max} id(s) · royalty ${royaltyBps / 100}% · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}`);
4464
- // `source` is what this lane read; there has never been a `bytes` binding here, so this line
4465
- // threw a ReferenceError for every `deploy-code --copies … --dry-run` — the dry run crashed at the
4466
- // last step of the plan it was printing. Byte length, not UTF-16 code units, matching the 721 twin.
4467
- info(`content: script ${Buffer.byteLength(source, 'utf8')} bytes → ${scriptChunks.length} on-chain chunk(s)`);
4551
+ info(`content: ${contentSummary}`);
4468
4552
  printSeedSourcePlan(seedSource, chainId);
4469
4553
  info(`PostParam schema(s): ${schemas.length ? schemas.map((s) => describeSchema(s)).join(', ') : 'none'}`);
4470
4554
  info(`mint: ${mintCount > 0 ? `${mintCount} id(s) × ${mintAmount} cop${mintAmount === 1n ? 'y' : 'ies'} → ${deployer ?? 'your wallet'} at deploy` : 'deferred (mint later / external minter)'}`);
4471
- info(`transactions: 2 — deploy + setup multicall (script chunks${schemas.length ? ' + schemas' : ''}${onChainUri ? ' + on-chain URI wiring' : ''}${mintCount > 0 ? ' + reserve mints' : ''})`);
4555
+ info(`transactions: 2 — deploy + setup multicall (${[scriptChunks.length ? 'script chunks' : null, schemas.length ? 'schemas' : null, onChainUri ? 'on-chain URI wiring' : null, mintCount > 0 ? 'reserve mints' : null].filter(Boolean).join(' + ') || 'nothing else'})`);
4472
4556
  info(`approvals ${approvals} wallet approval(s)`); // parity with the 721 code twin — it had this only in the --confirm sentence
4473
4557
  if (!explicitSalt && deployer) {
4474
4558
  console.log(`\n ${bold('salt')} ${g(salt)}`);
@@ -4519,21 +4603,35 @@ export async function cmdDeployEditionCodeBody(flags, emit) {
4519
4603
  if (discovered !== null)
4520
4604
  deployBlock = discovered;
4521
4605
  ok(`EditionCode live: ${clone} ${dim(`(from block ${deployBlock})`)}`);
4606
+ // Same permanent-decisions readout the 721 code lane prints — the plan line above is dry-run-only.
4607
+ info(`permanent: max ${max} id(s) · royalty ${royaltyBps / 100}%${flags['royalty-bps'] === undefined ? ' ⚠ default' : ''} → the deploying wallet` +
4608
+ ` · cap ${maxRoyaltyBps / 100}%${burnable ? ' · burnable' : ''}` +
4609
+ dim(' (rate is changeable with `abx set-royalty`; the CAP only ever goes down)'));
4522
4610
  emit(jsonSafe({ command: 'deploy-code', kind: 'edition-code', copies: editionSize.toString(), address: clone, chain: CHAIN, chainId, factory, deployBlock, name, symbol, onChainUri }));
4523
4611
  step('Index');
4524
4612
  await registerAndIndexLocally(clone, { 'from-block': deployBlock.toString(), factory, label: name });
4525
4613
  if (onChainUri) {
4526
4614
  step('On-chain URI');
4527
4615
  ok(`uri()/contractURI() resolve ON-CHAIN via the renderer ${metadataRenderer} — any RPC returns the metadata, no server in the graph`);
4528
- info(`animation_url computes on-chain via the generator ${generator} — it enumerates this token's params from chain, so there is no key list to maintain`);
4616
+ if (hasProgram)
4617
+ info(`animation_url computes on-chain via the generator ${generator} — it enumerates this token's params from chain, so there is no key list to maintain`);
4618
+ else
4619
+ info(`renderer-only — image + attributes computed on-chain by your Solidity renderer(s); no animation_url · ${g('fully on-chain')}, zero dependency outside the EVM${editionSize === 0n ? ' — and the edition stays OPEN, so anyone may keep minting copies' : ''}`);
4529
4620
  console.log(` ${bold(`abx tokenuri ${clone} --token 0`)} ${dim('# reads uri(0) + decodes the JSON straight from the contract')}`);
4530
4621
  }
4531
4622
  const isRemoteBase = !/^https?:\/\/(localhost|127\.0\.0\.1)\b/i.test(baseUrl);
4532
- console.log(`\n${g('Edition code project deployed.')} ${dim(onChainUri ? 'tokenURI is on-chain; a resolver remains the kinder serving path (live view + thumbnail publishing):' : 'It resolves through your resolver — keep it running:')}`);
4533
- if (isRemoteBase)
4534
- console.log(` ${bold(`abx add ${clone} --remote`)} ${dim('# register with the hosted resolver')}`);
4535
- else
4536
- console.log(` ${bold('abx serve')} ${dim('# stand up the resolver locally')}`);
4623
+ const rendererOnlyOnChain = onChainUri && !hasProgram;
4624
+ console.log(`\n${g('Edition code project deployed.')} ${dim(rendererOnlyOnChain
4625
+ ? 'Nothing to run: image, traits and uri() all resolve from the chain. There is no still to render and no resolver to keep alive.'
4626
+ : onChainUri
4627
+ ? 'tokenURI is on-chain; a resolver remains the kinder serving path (live view + thumbnail publishing):'
4628
+ : 'It resolves through your resolver — keep it running:')}`);
4629
+ if (!rendererOnlyOnChain) {
4630
+ if (isRemoteBase)
4631
+ console.log(` ${bold(`abx add ${clone} --remote`)} ${dim('# register with the hosted resolver')}`);
4632
+ else
4633
+ console.log(` ${bold('abx serve')} ${dim('# stand up the resolver locally')}`);
4634
+ }
4537
4635
  console.log(` ${bold(`abx mint ${clone} --token-id <id> --amount <n>`)} ${dim('# mint more copies of an id')}`);
4538
4636
  console.log(` ${bold(`abx minter configure ${clone} --token-id <id> --price <eth> --allocation <n>`)} ${dim('# set up a priced sale for one id')}`);
4539
4637
  console.log(` ${bold(`abx refresh ${clone}`)} ${dim('# nudge marketplaces once metadata is live')}\n`);