@artblocks/abx-cli 0.1.0-alpha.61 → 0.1.0-alpha.63

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.
@@ -918,9 +918,9 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
918
918
  throw new Error('--onchain-image needs --image <path> (the bytes to put on-chain)');
919
919
  // On-chain staging is a SEQUENCE (chunk write(s) → the deploy that references the manifest)
920
920
  // where each tx's receipt feeds the next, so it can't be signed offline in one run.
921
- if (lane === 'unsigned' || lane === 'sponsor') {
921
+ if (lane === 'unsigned') {
922
922
  throw new Error('Staging an on-chain image (--onchain-image) needs interactive signing — each chunk tx feeds ' +
923
- "the next. Use the hot lane (a funded key) or --sign (browser wallet); --unsigned and the initial --sponsor beta do not stage content.");
923
+ 'the next. Use the hot lane (a funded key), --sign (browser wallet), or --sponsor; --unsigned cannot stage content.');
924
924
  }
925
925
  step('Stage on-chain image');
926
926
  if (dryRun) {
@@ -1185,6 +1185,32 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
1185
1185
  ok(`deployed ${clone}`);
1186
1186
  info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
1187
1187
  }
1188
+ else if (lane === 'sponsor' && onchainImage) {
1189
+ info(`your ABX creator wallet will stage ${approvals - 1} image transaction(s), then deploy the collection in one authorization session.`);
1190
+ const session = await openSponsoredSession(CHAIN);
1191
+ let r;
1192
+ try {
1193
+ if (flags.for && flags.for.toLowerCase() !== session.address.toLowerCase()) {
1194
+ throw new Error(`The ABX creator wallet ${session.address} is not the required signer ${flags.for}.`);
1195
+ }
1196
+ deployerAddr = session.address;
1197
+ const { field, note } = await stageImageField(flags.image, parseCompress(flags.compress), sessionStagingSender(session));
1198
+ bakedImage = field;
1199
+ info(note);
1200
+ const { clone: predicted, params, salt, contentNote } = await buildForDeployer(session.address);
1201
+ info(contentNote);
1202
+ info(noMint ? 'mint: deferred — mint later with `abx mint`' : `mint: token #0 → ${session.address} at deploy`);
1203
+ const sent = await session.send(prepareDeployOneOfOne({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted }));
1204
+ r = { txHash: sent.txHash, blockNumber: sent.receipt.blockNumber };
1205
+ clone = predicted;
1206
+ }
1207
+ finally {
1208
+ session.close();
1209
+ }
1210
+ blockNumber = r.blockNumber;
1211
+ ok(`deployed ${clone}`);
1212
+ info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
1213
+ }
1188
1214
  else if (lane === 'sign' && remoteEthUpload) {
1189
1215
  // wallet lane + Arweave uploads paid by the CONNECTING wallet's Turbo credits (--storage-signer
1190
1216
  // eth + --sign). ONE session signs each upload's data-item (personal_sign, no gas) AND the deploy
@@ -1391,7 +1417,7 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
1391
1417
  // own function rather than threaded into `cmdDeployBody` with `if (copies)` branches throughout —
1392
1418
  // so the 721 lane, above, stays provably byte-identical whether or not editions exist.
1393
1419
  //
1394
- // `--onchain-image` (chunk-store staging) works in the hot and wallet lanes. The cold/unsigned lane
1420
+ // `--onchain-image` (chunk-store staging) works in the hot, wallet, and sponsored lanes. The cold/unsigned lane
1395
1421
  // is refused because each staged chunk transaction feeds the next; it cannot produce one independent
1396
1422
  // offline bundle. Every other custody/signing combination the 1/1 lane supports works identically.
1397
1423
  // (`DEPLOY_EDITION_FLAGS` — the allowlist this function's `refuseStrayFlags` checks against — is
@@ -1444,9 +1470,9 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1444
1470
  // every lineage, 721 and edition alike. The wallet lane CAN do it (one session signs the chunk
1445
1471
  // writes and the deploy); this edition path was hot-lane-only purely because it lacked that
1446
1472
  // session branch, which it now has.
1447
- if (onchainImage && (lane === 'unsigned' || lane === 'sponsor')) {
1473
+ if (onchainImage && lane === 'unsigned') {
1448
1474
  throw new Error('Staging an on-chain image (--onchain-image) needs interactive signing — each chunk tx feeds ' +
1449
- "the next. Use the hot lane (a funded key) or --sign (browser wallet); --unsigned and the initial --sponsor beta do not stage content.");
1475
+ 'the next. Use the hot lane (a funded key), --sign (browser wallet), or --sponsor; --unsigned cannot stage content.');
1450
1476
  }
1451
1477
  const previewDeployer = dryRun ? await resolvePreviewDeployer(flags, lane) : null;
1452
1478
  const publicClient = makePublicClient({ chainKey: CHAIN });
@@ -1734,6 +1760,30 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1734
1760
  ok(`deployed ${clone}`);
1735
1761
  info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
1736
1762
  }
1763
+ else if (lane === 'sponsor' && onchainImage) {
1764
+ info(`your ABX creator wallet will stage ${approvals - 1} image transaction(s), then deploy the edition in one authorization session.`);
1765
+ const session = await openSponsoredSession(CHAIN);
1766
+ let r;
1767
+ try {
1768
+ if (flags.for && flags.for.toLowerCase() !== session.address.toLowerCase()) {
1769
+ throw new Error(`The ABX creator wallet ${session.address} is not the required signer ${flags.for}.`);
1770
+ }
1771
+ deployerAddr = session.address;
1772
+ await stageOnChainImage(sessionStagingSender(session));
1773
+ const { clone: predicted, params, salt, contentNote } = await buildForDeployer(session.address);
1774
+ info(contentNote);
1775
+ info(mintAmount > 0n ? `mint: ${mintAmount} cop${mintAmount === 1n ? 'y' : 'ies'} of #0 → ${session.address} at deploy` : 'mint: deferred — mint later with `abx mint`');
1776
+ const sent = await session.send(prepareDeployOneOfOneEdition({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted }));
1777
+ r = { txHash: sent.txHash, blockNumber: sent.receipt.blockNumber };
1778
+ clone = predicted;
1779
+ }
1780
+ finally {
1781
+ session.close();
1782
+ }
1783
+ blockNumber = r.blockNumber;
1784
+ ok(`deployed ${clone}`);
1785
+ info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
1786
+ }
1737
1787
  else {
1738
1788
  // wallet lane without staging, or the cold lane: a single deploy tx.
1739
1789
  info(onChainUri ? 'a wallet will become the owner; the token resolves from chain — no URI base is baked in.' : `a wallet will become the owner; URIs point at ${baseUrl}`);
@@ -1832,7 +1882,7 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1832
1882
  // Mint timing: `--mint-all` / `--mint-count N` / default deferred (deploy → warm → mint).
1833
1883
  // `--minter` delegates minting; `--primary-payee` declares sale proceeds. Content is
1834
1884
  // deployer-independent (hashes / inline bytes / chunk manifests don't depend on the clone
1835
- // address), so it's prepared once; --onchain-image staging runs on the hot or wallet lane
1885
+ // address), so it's prepared once; --onchain-image staging runs on the hot, wallet, or sponsored lane
1836
1886
  // (the cold lane can't stage interactively — same as the 1/1).
1837
1887
  export const tokenFieldOf = (tokenId, f) => ({
1838
1888
  tokenId,
@@ -1910,9 +1960,9 @@ export async function cmdDeploySeriesBody(flags, emit) {
1910
1960
  // Staging is a SEQUENCE (chunk write(s) → the deploy that references each manifest) where each
1911
1961
  // receipt feeds the next, so it can't be signed offline in one pass — reject the cold lane
1912
1962
  // up front (same rule as the 1/1's --onchain-image).
1913
- if (onchainImage && (lane === 'unsigned' || lane === 'sponsor')) {
1963
+ if (onchainImage && lane === 'unsigned') {
1914
1964
  throw new Error('Staging on-chain images (--onchain-image) needs interactive signing — each chunk tx feeds ' +
1915
- "the next. Use the hot lane (a funded key) or --sign (browser wallet); --unsigned and the initial --sponsor beta do not stage content.");
1965
+ 'the next. Use the hot lane (a funded key), --sign (browser wallet), or --sponsor; --unsigned cannot stage content.');
1916
1966
  }
1917
1967
  // Whole-collection WRITE-cost guard: a set of many small files can still sum to an expensive
1918
1968
  // on-chain deploy, so flag the total once, up front. This is a cost signal only — the READ gate is
@@ -2326,6 +2376,25 @@ export async function cmdDeploySeriesBody(flags, emit) {
2326
2376
  }
2327
2377
  ok(`deployed ${clone}`);
2328
2378
  }
2379
+ else if (lane === 'sponsor' && onchainImage) {
2380
+ info(`your ABX creator wallet will stage ${approvals - 1} image transaction(s), then deploy the series in one authorization session.`);
2381
+ const session = await openSponsoredSession(CHAIN);
2382
+ try {
2383
+ if (flags.for && flags.for.toLowerCase() !== session.address.toLowerCase()) {
2384
+ throw new Error(`The ABX creator wallet ${session.address} is not the required signer ${flags.for}.`);
2385
+ }
2386
+ deployerAddr = session.address;
2387
+ await buildFields(sessionStagingSender(session));
2388
+ const { clone: predicted, params, salt } = await buildForDeployer(session.address);
2389
+ const sent = await session.send(prepareDeploySeries({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted }));
2390
+ clone = predicted;
2391
+ blockNumber = sent.receipt.blockNumber;
2392
+ }
2393
+ finally {
2394
+ session.close();
2395
+ }
2396
+ ok(`deployed ${clone}`);
2397
+ }
2329
2398
  else if (lane === 'sign' && remoteEthUpload) {
2330
2399
  // wallet lane + Arweave uploads paid by the CONNECTING wallet's Turbo credits: ONE session signs
2331
2400
  // each token's upload data-item (personal_sign, no gas) AND the deploy tx. Uploads are deferred to
@@ -2480,7 +2549,7 @@ export async function cmdDeploySeriesBody(flags, emit) {
2480
2549
  //
2481
2550
  // Custody matches the 721 Series lane: off-chain per-file uploads, O(1) uniform-extension directory
2482
2551
  // templates under `--onchain-uri`, inline SVG, hosted resolution, and `--onchain-image` chunk staging.
2483
- // The last uses hot or wallet signing; cold/unsigned staging is refused because each chunk feeds the
2552
+ // The last uses hot, wallet, or sponsored signing; cold/unsigned staging is refused because each chunk feeds the
2484
2553
  // next transaction.
2485
2554
  // (`DEPLOY_SERIES_EDITION_FLAGS` is declared further down, beside `DEPLOY_EDITION_FLAGS` — see that
2486
2555
  // const's own note on why.)
@@ -2535,10 +2604,10 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2535
2604
  const compress = parseCompress(flags.compress);
2536
2605
  // Staging is a SEQUENCE (chunk writes → the deploy that references each manifest) where every tx's
2537
2606
  // receipt feeds the next, so it can't be signed offline in one run. Refused on the cold lane for the
2538
- // same reason on every lineage, 721 and edition alike; hot + wallet both work.
2539
- if (onchainImage && (lane === 'unsigned' || lane === 'sponsor')) {
2607
+ // same reason on every lineage, 721 and edition alike; hot + wallet + sponsor all work.
2608
+ if (onchainImage && lane === 'unsigned') {
2540
2609
  throw new Error('Staging on-chain images (--onchain-image) needs interactive signing — each chunk tx feeds ' +
2541
- "the next. Use the hot lane (a funded key) or --sign (browser wallet); --unsigned and the initial --sponsor beta do not stage content.");
2610
+ 'the next. Use the hot lane (a funded key), --sign (browser wallet), or --sponsor; --unsigned cannot stage content.');
2542
2611
  }
2543
2612
  const publicClient = makePublicClient({ chainKey: CHAIN });
2544
2613
  await assertChainId(CHAIN, { allowUnreachable: dryRun });
@@ -2924,6 +2993,29 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2924
2993
  ok(`deployed ${clone}`);
2925
2994
  info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
2926
2995
  }
2996
+ else if (lane === 'sponsor' && onchainImage) {
2997
+ info(`your ABX creator wallet will stage ${approvals - 1} image transaction(s), then deploy the edition series in one authorization session.`);
2998
+ const session = await openSponsoredSession(CHAIN);
2999
+ let r;
3000
+ try {
3001
+ if (flags.for && flags.for.toLowerCase() !== session.address.toLowerCase()) {
3002
+ throw new Error(`The ABX creator wallet ${session.address} is not the required signer ${flags.for}.`);
3003
+ }
3004
+ deployerAddr = session.address;
3005
+ await buildFields(sessionStagingSender(session));
3006
+ const { clone: predicted, params, salt } = await buildForDeployer(session.address);
3007
+ info(`mint: ${effectiveMintCount > 0 ? `${effectiveMintCount} id(s) × ${mintAmount} cop${mintAmount === 1n ? 'y' : 'ies'} → ${session.address} at deploy` : 'deferred'}`);
3008
+ const sent = await session.send(prepareDeployEditionImage({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted }));
3009
+ r = { txHash: sent.txHash, blockNumber: sent.receipt.blockNumber };
3010
+ clone = predicted;
3011
+ }
3012
+ finally {
3013
+ session.close();
3014
+ }
3015
+ blockNumber = r.blockNumber;
3016
+ ok(`deployed ${clone}`);
3017
+ info(`tx ${explorerBase()}/tx/${r.txHash} (block ${blockNumber})`);
3018
+ }
2927
3019
  else {
2928
3020
  info(onChainUri ? 'a wallet will become the owner; the tokens resolve from chain — no URI base is baked in.' : `a wallet will become the owner; URIs point at ${baseUrl}`);
2929
3021
  const result = await signTx(async (signer) => {