@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 +121 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +132 -34
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/scaffold.d.ts.map +1 -1
- package/dist/commands/scaffold.js +46 -2
- package/dist/commands/scaffold.js.map +1 -1
- package/dist/main.js +5 -2
- package/dist/main.js.map +1 -1
- package/dist/ownerops.d.ts +12 -0
- package/dist/ownerops.d.ts.map +1 -1
- package/dist/ownerops.js +153 -3
- package/dist/ownerops.js.map +1 -1
- package/dist/riskgate.d.ts +10 -0
- package/dist/riskgate.d.ts.map +1 -1
- package/dist/riskgate.js +81 -4
- package/dist/riskgate.js.map +1 -1
- package/package.json +6 -6
- package/skill/SKILL.md +13 -6
- package/skill/reference/code-projects.md +13 -6
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":"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,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -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
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
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
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
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
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
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}) —
|
|
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 ? `
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
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`);
|