@artblocks/abx-cli 0.1.0-alpha.16 → 0.1.0-alpha.17

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.
@@ -222,6 +222,20 @@ export declare function cmdSetField(address: string | undefined, flags: Flags):
222
222
  * - computed keys (`artifacts`, `abx_provenance`) are refused — they're the manifest, not inputs.
223
223
  * Scope: token (`--token`, default 0) or `--collection`. Any signing lane. Owner-only.
224
224
  */
225
+ /**
226
+ * Attach one or more artifacts. Several `<key> <uri>` pairs in one invocation become **one
227
+ * transaction**.
228
+ *
229
+ * That batching is a safety fix, not a convenience (backlog B20). The CLI's most-documented flow —
230
+ * mint, then attach each artifact, then refresh — sent one transaction per step with no all-or-nothing
231
+ * boundary, so a failure partway through left a permanently half-written token that cannot be
232
+ * un-minted. An integrator hit exactly this and folded 8 operations into 1 transaction using the SDK's
233
+ * `batchOps`, which the CLI already shipped and did not use. Now it does: N pairs are one
234
+ * `multicall`, so either every artifact lands or none does.
235
+ *
236
+ * A single pair passes through `batchOps` untouched, so the one-artifact case sends the identical
237
+ * transaction it always did.
238
+ */
225
239
  export declare function cmdAttach(rest: string[], flags: Flags): Promise<void>;
226
240
  export declare function cmdLockField(address: string | undefined, flags: Flags): Promise<void>;
227
241
  /** Point a token's URI resolution at an on-chain renderer (or clear it with `--off`).
@@ -1 +1 @@
1
- {"version":3,"file":"ownerops.d.ts","sourceRoot":"","sources":["../src/ownerops.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAeL,cAAc,EAmBd,KAAK,kBAAkB,EAoBvB,KAAK,aAAa,EAIlB,KAAK,OAAO,EACZ,KAAK,GAAG,EACR,KAAK,iBAAiB,EAEvB,MAAM,oBAAoB,CAAC;AA+B5B,OAAO,EAA4B,KAAK,IAAI,EAAmB,KAAK,aAAa,EAAC,MAAM,aAAa,CAAC;AAGtG,OAAO,EAAmC,KAAK,YAAY,EAAC,MAAM,aAAa,CAAC;AAWhF,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAWhD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAevD;AAWD;;gGAEgG;AAChG,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAMD,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAIhD;AA2GD;sGACsG;AACtG,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1E;AAID;;;;;;;;GAQG;AACH;;;4GAG4G;AAC5G;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAiBrG;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgGhH;AAGD,QAAA,MAAM,UAAU,+CAAgD,CAAC;AACjE,KAAK,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAQ5C,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAMnE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE/F;AAOD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/G;AAED;uEACuE;AACvE,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAItG;AAED;+FAC+F;AAC/F,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAevH;AAED,uGAAuG;AACvG,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlG;AAOD,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBtF;AAMD;2EAC2E;AAC3E,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3F;AAED,oGAAoG;AACpG,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnG;AAED,iFAAiF;AACjF,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvF;AAED,oEAAoE;AACpE,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzF;AAGD;;;;mFAImF;AACnF,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAK1F,CAAC;AAEF;sFACsF;AACtF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,iBAAiB,EAAE,CAI1E;AAED,+EAA+E;AAC/E,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjG;AAmBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BzF;AAGD,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAO1F;AAMD,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7F;AAID,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhG;AAGD;;mDAEmD;AACnD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5F;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAC,GAC/D,OAAO,CAkCT;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDtH;AAGD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAElD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAI7D;AA4BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAahD;AAED;+FAC+F;AAC/F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAc1E;AAED;;;;;;;;;;;GAWG;AACH;;;;;;GAMG;AAKH,eAAO,MAAM,wBAAwB,QAAY,CAAC;AAClD,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAIrD,gHAAgH;AAChH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAK9E;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB;IACD,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC;CACxB,CAQA;AA8CD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CASjF;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAOnD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,aAAa,EACnB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAC,CAAC,CAgBxD;AAyBD,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,KAAK;AACZ,0DAA0D;AAC1D,KAAK,GAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAsE,GAC3G,OAAO,CAAC,IAAI,CAAC,CAoBf;AAQD,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgF1F;AAGD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG3E;AAwCD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAa3F;AAGD;;;6EAG6E;AAC7E,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB7F;AAGD;;mEAEmE;AACnE,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAazF;AAGD,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1F;AAyGD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DjG;AAED;yFACyF;AACzF,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAyC5F;AAED;oGACoG;AACpG,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB3F;AAUD;+FAC+F;AAC/F,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,EAAE,CAiBxF;AAED;iEACiE;AACjE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE3F;AAgBD,2FAA2F;AAC3F,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB7G"}
1
+ {"version":3,"file":"ownerops.d.ts","sourceRoot":"","sources":["../src/ownerops.ts"],"names":[],"mappings":"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"}
package/dist/ownerops.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * served state reflects the change. The agent picks the lane; the human only
7
7
  * approves (wallet lane) or it's the env key (hot lane).
8
8
  */
9
- import { assertChainId, ensureChunkStore as sdkEnsureChunkStore, predictFixedPriceMinter, encodeReader, makePublicClient, makeWalletClient, oneOfOneImageAbi, seriesImageAbi, abxFixedPriceMinterAbi, deployFixedPriceMinter, prepareConfigureSale, preparePurchase, planChunks, planContentTxs, prepareLockContractField, prepareLockContractURI, prepareLockTokenField, prepareLockTokenURI, prepareMint, prepareSeriesMintMany, prepareSetMinter, prepareSetMaxInvocations, prepareSetPrimaryPayee, prepareSetPaused, prepareSetContractField, prepareSetContractURIBase, prepareSetContractURIOverride, prepareSetContractURIRenderer, prepareSetParamHooks, prepareSetParamSchema, prepareRetireParam, readParamSchema, PARAM_TYPES, prepareSetRoyalty, prepareSetTokenField, prepareSetTokenURIBase, prepareSetTokenURIOverride, prepareSetTokenURIRenderer, prepareSetTransferValidator, prepareTransfer, prepareTransferOwnership, readCreatorTokenStatus, resolveRecommendedTransferValidator, RECOMMENDED_TRANSFER_VALIDATOR, KNOWN_CHAIN_KEYS, resolveChain, resolveRpcUrl, redactRpcUrl, DEFAULT_CHAIN_KEY, stageContent, encodeTag, METADATA_FIELD as F, METADATA_REPRESENTATION as R, } from '@artblocks/abx-sdk';
9
+ import { assertChainId, ensureChunkStore as sdkEnsureChunkStore, predictFixedPriceMinter, encodeReader, makePublicClient, makeWalletClient, oneOfOneImageAbi, seriesImageAbi, abxFixedPriceMinterAbi, deployFixedPriceMinter, prepareConfigureSale, preparePurchase, planChunks, planContentTxs, prepareLockContractField, prepareLockContractURI, prepareLockTokenField, prepareLockTokenURI, prepareMint, prepareSeriesMintMany, prepareSetMinter, prepareSetMaxInvocations, prepareSetPrimaryPayee, prepareSetPaused, prepareSetContractField, prepareSetContractURIBase, prepareSetContractURIOverride, prepareSetContractURIRenderer, prepareSetParamHooks, prepareSetParamSchema, prepareRetireParam, readParamSchema, PARAM_TYPES, prepareSetRoyalty, prepareSetTokenField, batchOps, prepareSetTokenURIBase, prepareSetTokenURIOverride, prepareSetTokenURIRenderer, prepareSetTransferValidator, prepareTransfer, prepareTransferOwnership, readCreatorTokenStatus, resolveRecommendedTransferValidator, RECOMMENDED_TRANSFER_VALIDATOR, KNOWN_CHAIN_KEYS, resolveChain, resolveRpcUrl, redactRpcUrl, DEFAULT_CHAIN_KEY, stageContent, encodeTag, METADATA_FIELD as F, METADATA_REPRESENTATION as R, } from '@artblocks/abx-sdk';
10
10
  import { SelfHostIndexer } from '@artblocks/abx-indexer';
11
11
  import { encodeScalarParam, encodeTag as encodeTagSdk, isAccepted, prepareConfigureTokenParam, prepareConfigureTokenParamData, prepareSetContractParam, prepareSetContractParamData, seriesCodeAbi, } from '@artblocks/abx-sdk';
12
12
  import { hasParamEnumeration } from './onchain-uri.js';
@@ -16,9 +16,10 @@ import { toHex as toHexSdk } from 'viem';
16
16
  import { readFileSync } from 'node:fs';
17
17
  import { basename, resolve as resolvePath } from 'node:path';
18
18
  import { gzipSync } from 'node:zlib';
19
- import { formatEther, getAddress, isAddress, parseEther, toHex, zeroAddress } from 'viem';
19
+ import { decodeEventLog, formatEther, getAddress, isAddress, parseEther, toHex, zeroAddress } from 'viem';
20
20
  import { fixedPriceMinterAddress } from './config.js';
21
21
  import { openWalletSession, signTx } from './signer.js';
22
+ import { withJson } from './jsonout.js';
22
23
  import { resolveRemote, serviceClient } from './remote.js';
23
24
  import { positionalArgs, unknownFlags } from './flags.js';
24
25
  import { parseSchemaSpecs, describeSchema } from './schema.js';
@@ -99,6 +100,15 @@ function requireFlag(flags, name, usage) {
99
100
  }
100
101
  /** Run a prepared write through the chosen lane, then re-index if the project is known.
101
102
  * Returns whether anything was BROADCAST (false on the cold lane — the tx was only printed). */
103
+ /**
104
+ * Every owner-op's send choke point. Returns the {@link SignResult} when a tx was broadcast, else
105
+ * `null` (dry run, or the cold lane which prints a tx instead of sending one).
106
+ *
107
+ * It used to return a bare boolean. It returns the result now because a caller sometimes needs the
108
+ * *receipt* — `abx mint --json` has to report which token id was actually minted, and the only
109
+ * authoritative answer is the Transfer log the mint emitted. Callers that only asked "did it send?"
110
+ * keep working: `null` is falsy, and a result object is truthy.
111
+ */
102
112
  async function runWrite(address, provider, flags, expectedSigner) {
103
113
  // --dry-run: preview the exact tx and send NOTHING. This is the shared choke point for every
104
114
  // owner-op, so --dry-run is uniform across them — it must never fall through to a real send just
@@ -113,7 +123,7 @@ async function runWrite(address, provider, flags, expectedSigner) {
113
123
  if (expectedSigner)
114
124
  console.log(` ${dim('owner'.padEnd(12))} ${expectedSigner}`);
115
125
  console.log(dim(`\n Re-run without --dry-run to send (lane: ${laneFromFlags(flags)}).\n`));
116
- return false;
126
+ return null;
117
127
  }
118
128
  await assertChainId(CHAIN); // verify the RPC really is CHAIN before any irreversible write
119
129
  const result = await signTx(provider, {
@@ -125,9 +135,9 @@ async function runWrite(address, provider, flags, expectedSigner) {
125
135
  signUrlFile: flags['sign-url-file'],
126
136
  });
127
137
  if (!result)
128
- return false; // cold lane — nothing broadcast
138
+ return null; // cold lane — nothing broadcast
129
139
  await reindexIfKnown(address, flags);
130
- return true;
140
+ return result;
131
141
  }
132
142
  async function reindexIfKnown(address, flags) {
133
143
  const indexer = new SelfHostIndexer();
@@ -487,24 +497,84 @@ export async function cmdLockDependencies(address, flags) {
487
497
  // it mints the next sequential token id (metadata = token id): bare (one), or `--count <n>`
488
498
  // (n in order). Owner or an authorized minter signs.
489
499
  export async function cmdMint(address, flags) {
490
- const usage = 'abx mint <address> [--to 0x…] [--count <n>] [--sign|--unsigned]';
500
+ const usage = 'abx mint <address> [--to 0x…] [--count <n>] [--json] [--sign|--unsigned]';
491
501
  const contract = requireAddress(address, usage);
492
- const owner = await read(contract, 'owner');
493
- const to = flags.to ?? owner; // default: pre-mint to the admin
494
- let tx;
495
- if (flags.count !== undefined && flags.count !== 'true') {
496
- const count = BigInt(flags.count);
497
- console.log(dim(` minting ${count} Series tokens in order → ${to}`));
498
- tx = prepareSeriesMintMany({ contract, to, count, chainId: chainId() });
502
+ // `--json`: the TOKEN ID is the value a program came for, and it was previously only obtainable by
503
+ // regex-scraping coloured prose (B19). It is read from the mint's own Transfer logs rather than by
504
+ // re-reading `nextTokenId` afterwards — a concurrent mint would make that answer wrong, and a
505
+ // number that is usually right is worse than no number.
506
+ return withJson(flags, async () => {
507
+ const owner = await read(contract, 'owner');
508
+ const to = flags.to ?? owner; // default: pre-mint to the admin
509
+ let tx;
510
+ let count = 1n;
511
+ if (flags.count !== undefined && flags.count !== 'true') {
512
+ count = BigInt(flags.count);
513
+ console.log(dim(` minting ${count} Series tokens in order → ${to}`));
514
+ tx = prepareSeriesMintMany({ contract, to, count, chainId: chainId() });
515
+ }
516
+ else {
517
+ // Bare mint: the `mint(address)` selector is shared by the 1/1 (token #0) and a
518
+ // Series (next sequential token) — one path serves both.
519
+ console.log(dim(` minting token → ${to}${flags.to ? '' : ' (owner — pass --to for a buyer)'}`));
520
+ tx = prepareMint({ contract, to, chainId: chainId() });
521
+ }
522
+ const result = await runWrite(contract, tx, flags, owner);
523
+ const tokenIds = result ? await mintedTokenIds(contract, result.txHash) : [];
524
+ if (result && tokenIds.length) {
525
+ console.log(` ${green('✓')} minted token${tokenIds.length > 1 ? 's' : ''} ${bold(tokenIds.map((t) => '#' + t).join(', '))} → ${to}`);
526
+ }
527
+ console.log(dim(` next: \`abx refresh ${contract}\` so marketplaces pick up the new token.`));
528
+ return {
529
+ contract,
530
+ chainId: chainId(),
531
+ to,
532
+ // `sent: false` is the dry-run and cold-lane answer — an empty tokenIds with no explanation
533
+ // would read as a failed mint.
534
+ sent: !!result,
535
+ txHash: result?.txHash ?? null,
536
+ blockNumber: result ? String(result.blockNumber) : null,
537
+ tokenIds,
538
+ requestedCount: Number(count),
539
+ };
540
+ });
541
+ }
542
+ /**
543
+ * The token ids a mint actually created, decoded from its receipt's `Transfer(from=0x0)` logs.
544
+ *
545
+ * Authoritative by construction: the ids come from the transaction that minted them, so a
546
+ * `--count N` batch reports all N and a concurrent mint elsewhere cannot skew the answer. Returns
547
+ * `[]` rather than throwing if the receipt can't be read — a mint that landed on-chain must not be
548
+ * reported as failed because a follow-up read hiccuped.
549
+ */
550
+ async function mintedTokenIds(contract, txHash) {
551
+ try {
552
+ const publicClient = makePublicClient({ chainKey: CHAIN });
553
+ const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
554
+ const ids = [];
555
+ for (const log of receipt.logs) {
556
+ if (log.address.toLowerCase() !== contract.toLowerCase())
557
+ continue;
558
+ try {
559
+ const decoded = decodeEventLog({ abi: oneOfOneImageAbi, data: log.data, topics: log.topics });
560
+ if (decoded.eventName !== 'Transfer')
561
+ continue;
562
+ const args = decoded.args;
563
+ if (args.from && args.from !== zeroAddress)
564
+ continue; // a transfer, not a mint
565
+ const id = args.id ?? args.tokenId;
566
+ if (id !== undefined)
567
+ ids.push(id.toString());
568
+ }
569
+ catch {
570
+ continue; // a log from another interface on the same contract
571
+ }
572
+ }
573
+ return ids.sort((a, b) => Number(BigInt(a) - BigInt(b)));
499
574
  }
500
- else {
501
- // Bare mint: the `mint(address)` selector is shared by the 1/1 (token #0) and a
502
- // Series (next sequential token) — one path serves both.
503
- console.log(dim(` minting token → ${to}${flags.to ? '' : ' (owner — pass --to for a buyer)'}`));
504
- tx = prepareMint({ contract, to, chainId: chainId() });
575
+ catch {
576
+ return [];
505
577
  }
506
- await runWrite(contract, tx, flags, owner);
507
- console.log(dim(` next: \`abx refresh ${contract}\` so marketplaces pick up the new token.`));
508
578
  }
509
579
  // ── series owner ops (minter set · supply cap · primary payee) ────────────────
510
580
  // The multi-token knobs. All owner-only; each runs through the same signing lane +
@@ -1119,9 +1189,25 @@ export async function cmdSetField(address, flags) {
1119
1189
  * - computed keys (`artifacts`, `abx_provenance`) are refused — they're the manifest, not inputs.
1120
1190
  * Scope: token (`--token`, default 0) or `--collection`. Any signing lane. Owner-only.
1121
1191
  */
1192
+ /**
1193
+ * Attach one or more artifacts. Several `<key> <uri>` pairs in one invocation become **one
1194
+ * transaction**.
1195
+ *
1196
+ * That batching is a safety fix, not a convenience (backlog B20). The CLI's most-documented flow —
1197
+ * mint, then attach each artifact, then refresh — sent one transaction per step with no all-or-nothing
1198
+ * boundary, so a failure partway through left a permanently half-written token that cannot be
1199
+ * un-minted. An integrator hit exactly this and folded 8 operations into 1 transaction using the SDK's
1200
+ * `batchOps`, which the CLI already shipped and did not use. Now it does: N pairs are one
1201
+ * `multicall`, so either every artifact lands or none does.
1202
+ *
1203
+ * A single pair passes through `batchOps` untouched, so the one-artifact case sends the identical
1204
+ * transaction it always did.
1205
+ */
1122
1206
  export async function cmdAttach(rest, flags) {
1123
- const usage = 'abx attach <address> <key> <ipfs://… | ar://… | https://…> [--file <path>] [--collection | --token 0] [--sign|--unsigned] [--dry-run]';
1124
- const [address, key, uri] = positionalArgs(rest);
1207
+ const usage = 'abx attach <address> <key> <ipfs://… | ar://… | https://…> [<key> <uri> …] [--file <path>] [--collection | --token 0] [--sign|--unsigned] [--dry-run]';
1208
+ const [address, ...pairArgs] = positionalArgs(rest);
1209
+ const key = pairArgs[0];
1210
+ const uri = pairArgs[1];
1125
1211
  // Warn (never throw) on an unrecognized flag — a typo or a hopeful `--mime-type` otherwise no-ops
1126
1212
  // INVISIBLY (round-1: an agent passed `--mime-type` and it was silently swallowed). mimeType is
1127
1213
  // declared from the URL extension, not a flag; say so.
@@ -1156,19 +1242,44 @@ export async function cmdAttach(rest, flags) {
1156
1242
  // Locator path (the common case): auto-detect the representation, refuse an unrecognized scheme
1157
1243
  // loudly (never silently store a bad value) — fail fast before any RPC. Derive the declared
1158
1244
  // mimeType from the extension.
1159
- const representation = representationForLocator(uri);
1160
- if (!representation) {
1161
- throw new Error(`"${uri}" isn't a recognized file locator. Use ipfs://… (pinned/IPFS), ar://… (Arweave), or https://… . ` +
1162
- 'To store literal text or raw bytes on-chain instead, use `abx set-field`.');
1245
+ // Every `<key> <uri>` pair, validated BEFORE anything is sent — a batch that would revert partway
1246
+ // is exactly what this command now exists to prevent, so a bad locator in pair 5 must stop pair 1.
1247
+ if (pairArgs.length % 2 !== 0) {
1248
+ throw new Error(`attach takes <key> <uri> PAIRS; got ${pairArgs.length} positional argument(s) after the address. ` +
1249
+ `Last one seen: "${pairArgs[pairArgs.length - 1]}".`);
1250
+ }
1251
+ const pairs = [];
1252
+ for (let i = 0; i < pairArgs.length; i += 2) {
1253
+ const k = pairArgs[i];
1254
+ const u = pairArgs[i + 1];
1255
+ assertSettableField(k);
1256
+ const rep = representationForLocator(u);
1257
+ if (!rep) {
1258
+ throw new Error(`"${u}" isn't a recognized file locator. Use ipfs://… (pinned/IPFS), ar://… (Arweave), or https://… . ` +
1259
+ 'To store literal text or raw bytes on-chain instead, use `abx set-field`.');
1260
+ }
1261
+ pairs.push({ key: k, uri: u, representation: rep, mimeType: contentTypeFromPath(u) });
1163
1262
  }
1263
+ // A key repeated within one batch would have the later write silently win — the same
1264
+ // full-column-upsert hazard that bit `register` and `lock-field`. Refuse instead.
1265
+ const dupes = pairs.map((p) => p.key).filter((k, i, a) => a.indexOf(k) !== i);
1266
+ if (dupes.length) {
1267
+ throw new Error(`the same key appears twice in one batch: ${[...new Set(dupes)].join(', ')}. ` +
1268
+ 'Each field holds ONE active value, so the last write would silently win — attach them separately if that is really what you want.');
1269
+ }
1270
+ const representation = pairs[0].representation;
1164
1271
  const owner = await read(contract, 'owner');
1165
- const mimeType = contentTypeFromPath(uri);
1166
- if (mimeType === 'application/octet-stream') {
1167
- console.log(yellow(' ⚠ ') +
1168
- dim(`no file extension in "${uri.slice(0, 64)}" → declared type will be application/octet-stream. `) +
1169
- dim('Point the URI at the file itself (…/master.tiff, …/coa.pdf) so collectors get the right type.'));
1272
+ for (const p of pairs) {
1273
+ if (p.mimeType === 'application/octet-stream') {
1274
+ console.log(yellow(' ⚠ ') +
1275
+ dim(`no file extension in "${p.uri.slice(0, 64)}" → declared type will be application/octet-stream. `) +
1276
+ dim('Point the URI at the file itself (…/master.tiff, …/coa.pdf) so collectors get the right type.'));
1277
+ }
1278
+ }
1279
+ const mimeType = pairs[0].mimeType;
1280
+ for (const p of pairs) {
1281
+ console.log(` attaching ${bold(p.key)} ${dim(`(${p.mimeType}, ${p.representation})`)} to ${scope}: ${dim(p.uri)}`);
1170
1282
  }
1171
- console.log(` attaching ${bold(key)} ${dim(`(${mimeType}, ${representation})`)} to ${scope}: ${dim(uri)}`);
1172
1283
  // Where it surfaces. This used to be one dim line, and it read as a footnote rather than as a
1173
1284
  // dependency: an integrator attached five audio stems to a fully-on-chain token, paid to store
1174
1285
  // them, and found `tokenURI` listed none of them — "paid for, stored on-chain, and invisible".
@@ -1179,25 +1290,37 @@ export async function cmdAttach(rest, flags) {
1179
1290
  const uriBase = await read(contract, 'tokenURIBase').catch(() => '');
1180
1291
  const artifactsPath = `/t/${chainId()}/${contract}/${flags.token ?? '0'}`;
1181
1292
  if (uriBase && uriBase.trim() !== '') {
1182
- console.log(dim(` → listed in this project's resolver artifacts (${artifactsPath} and /data/${key}); a bare on-chain tokenURI carries reserved fields plus abx_params only.`));
1293
+ console.log(dim(` → listed in this project's resolver artifacts (${artifactsPath} and /data/<key>); a bare on-chain tokenURI carries reserved fields plus abx_params only.`));
1183
1294
  }
1184
1295
  else {
1185
1296
  console.log(yellow(' ⚠ ') +
1186
1297
  `this project resolves ON-CHAIN (no resolver base baked in), and the on-chain document carries reserved fields plus the computed ${bold('abx_params')} block only — ` +
1187
- `so ${bold(key)} will NOT appear in ${bold('tokenURI')}. The bytes are stored and provable, but nothing surfaces them to a marketplace or wallet. ` +
1298
+ `so ${pairs.map((p) => bold(p.key)).join(', ')} will NOT appear in ${bold('tokenURI')}. The bytes are stored and provable, but nothing surfaces them to a marketplace or wallet. ` +
1188
1299
  dim('(Configured params DO appear on-chain — attachments are the surface that needs a resolver.)'));
1189
1300
  console.log(dim(` to make attached artifacts visible, point the project at a resolver (${bold('abx deploy-resolver')}, or a managed one via ${bold('abx add <addr> --remote <name>')}) — it serves the listing at ${artifactsPath}.`));
1190
1301
  }
1191
- const buildTx = () => collection
1192
- ? prepareSetContractField({ contract, field: key, representation, value: toHex(uri), chainId: chainId() })
1193
- : prepareSetTokenField({ contract, tokenId: BigInt(flags.token ?? '0'), field: key, representation, value: toHex(uri), chainId: chainId() });
1194
- const sent = await runWrite(contract, buildTx(), flags, owner);
1302
+ // ONE transaction for the whole set. `batchOps` folds a same-target run into a `multicall` and
1303
+ // passes a lone op through untouched, so a single attach is byte-identical to before.
1304
+ const ops = pairs.map((p) => collection
1305
+ ? prepareSetContractField({ contract, field: p.key, representation: p.representation, value: toHex(p.uri), chainId: chainId() })
1306
+ : prepareSetTokenField({ contract, tokenId: BigInt(flags.token ?? '0'), field: p.key, representation: p.representation, value: toHex(p.uri), chainId: chainId() }));
1307
+ const batched = batchOps(ops);
1308
+ if (batched.length !== 1) {
1309
+ // Defensive: every op here targets the same contract and carries no value, so batchOps must
1310
+ // return exactly one tx. If that ever changes, fail loudly rather than send a partial set.
1311
+ throw new Error(`attach expected to batch ${ops.length} op(s) into one transaction, got ${batched.length}`);
1312
+ }
1313
+ if (pairs.length > 1) {
1314
+ console.log(dim(` ${pairs.length} artifacts → ONE transaction (all-or-nothing: a revert lands none of them, so no half-written token).`));
1315
+ }
1316
+ const sent = await runWrite(contract, batched[0], flags, owner);
1195
1317
  if (sent) {
1196
1318
  const id = flags.token ?? '0';
1197
- console.log(` ${green('✓')} attached — ${bold(key)} joins ${scope}'s ${bold('artifacts')} manifest (stored on-chain, anchored).\n` +
1319
+ const names = pairs.map((p) => bold(p.key)).join(', ');
1320
+ console.log(` ${green('✓')} attached — ${names} join${pairs.length > 1 ? '' : 's'} ${scope}'s ${bold('artifacts')} manifest (stored on-chain, anchored).\n` +
1198
1321
  dim(` verify (a resolver serves the complete listing): `) +
1199
- `curl <your-resolver>/t/${chainId()}/${contract}/${id}` +
1200
- dim(` ${collection ? '' : `→ artifacts[].key "${key}"; /data/${key} fetches it`}\n`) +
1322
+ `abx tokenuri ${contract}${id === '0' ? '' : ` --token ${id}`} --fetch` +
1323
+ dim(` ${collection ? '' : `→ artifacts[].key ${pairs.map((p) => `"${p.key}"`).join(', ')}; /data/<key> fetches each`}\n`) +
1201
1324
  dim(` (The complete file listing is a resolver surface — the bare on-chain tokenURI enumerates reserved fields plus abx_params. Params never need a resolver; attachments do.)\n`));
1202
1325
  }
1203
1326
  }