@manifoldxyz/dropkit 0.3.0 → 0.4.1

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.
@@ -37,7 +37,7 @@ function friendlyErrorMessage(error) {
37
37
  if (isMintError(error)) {
38
38
  if (error.reason === "INSUFFICIENT_FUNDS") return _nullishCoalesce(fundsMessage(collect(error.cause)), () => ( error.message));
39
39
  if (error.reason !== "RPC_ERROR" && error.reason !== "SIMULATION_REVERTED") return error.message;
40
- if (error.reason === "SIMULATION_REVERTED" && error.domain === "relay") return error.message;
40
+ if (error.reason === "SIMULATION_REVERTED" && (error.domain === "relay" || error.domain === "tl-stacks")) return error.message;
41
41
  if (error.reason === "SIMULATION_REVERTED" && (error.message === "The token refused the approval." || error.message === "The drop is no longer available for this quantity.")) return error.message;
42
42
  }
43
43
  const errors = collect(error);
@@ -89,6 +89,7 @@ var UNSUPPORTED_REASONS = [
89
89
  "UNKNOWN_EXTENSION",
90
90
  "AMBIGUOUS_EXTENSION",
91
91
  "CLAIM_NOT_FOUND",
92
+ "DROP_NOT_FOUND",
92
93
  "SIGNATURE_CLAIM",
93
94
  "INVALID_CONFIG",
94
95
  "CONNECT_WIDGET_TOO_OLD"
@@ -118,7 +119,7 @@ var MintError = class extends Error {
118
119
 
119
120
  /** INVALID_CONFIG only: dotted path of the bad field, e.g. "mint.args[1]" or "price". */
120
121
 
121
- /** 'relay': the message is Relay's decoded destination revert, shown as-is. */
122
+ /** 'relay' or 'tl-stacks': the message is a decoded destination revert, shown as-is. */
122
123
 
123
124
  constructor(reason, message, opts) {
124
125
  super(message, _optionalChain([opts, 'optionalAccess', _6 => _6.cause]) === void 0 ? void 0 : { cause: opts.cause });
@@ -263,7 +264,12 @@ function reducer(state, event) {
263
264
  }
264
265
  case "DROP_LOADED": {
265
266
  if (event.gen !== state.readGen) return state;
266
- const next = { ...state, drop: event.drop, now: Math.max(state.now, event.now) };
267
+ let next = { ...state, drop: event.drop, now: Math.max(state.now, event.now) };
268
+ const oldKey = _optionalChain([state, 'access', _12 => _12.drop, 'optionalAccess', _13 => _13.walletKey]);
269
+ const newKey = event.drop.walletKey;
270
+ if (oldKey !== void 0 && newKey !== void 0 && oldKey !== newKey) {
271
+ next = { ...next, walletRead: null, walletGen: state.walletGen + 1 };
272
+ }
267
273
  if (inFlight) return { ...next, pendingRefresh: true };
268
274
  return isIdle(next) ? settle(clampQuantity(next), false) : clampQuantity(next);
269
275
  }
@@ -317,7 +323,7 @@ function reducer(state, event) {
317
323
  case "TX_SUBMITTED":
318
324
  return step(state, event.attemptId, "confirming");
319
325
  case "ATTEMPT_SUCCEEDED":
320
- return _optionalChain([state, 'access', _12 => _12.attempt, 'optionalAccess', _13 => _13.attemptId]) === event.attemptId ? {
326
+ return _optionalChain([state, 'access', _14 => _14.attempt, 'optionalAccess', _15 => _15.attemptId]) === event.attemptId ? {
321
327
  ...state,
322
328
  name: "success",
323
329
  reason: null,
@@ -328,7 +334,7 @@ function reducer(state, event) {
328
334
  readGen: state.readGen + 1
329
335
  } : state;
330
336
  case "ATTEMPT_FAILED": {
331
- if (_optionalChain([state, 'access', _14 => _14.attempt, 'optionalAccess', _15 => _15.attemptId]) !== event.attemptId) return state;
337
+ if (_optionalChain([state, 'access', _16 => _16.attempt, 'optionalAccess', _17 => _17.attemptId]) !== event.attemptId) return state;
332
338
  const { reason, message } = event;
333
339
  const done = { ...state, reason, message, attempt: null, result: null };
334
340
  if (INELIGIBLE_REASONS.includes(reason)) {
@@ -362,7 +368,7 @@ function reducer(state, event) {
362
368
  }
363
369
  var STEP_ORDER = ["switching-chain", "approving", "minting", "confirming"];
364
370
  function step(state, attemptId, name) {
365
- if (_optionalChain([state, 'access', _16 => _16.attempt, 'optionalAccess', _17 => _17.attemptId]) !== attemptId) return state;
371
+ if (_optionalChain([state, 'access', _18 => _18.attempt, 'optionalAccess', _19 => _19.attemptId]) !== attemptId) return state;
366
372
  if (STEP_ORDER.indexOf(name) <= STEP_ORDER.indexOf(state.name)) return state;
367
373
  return { ...state, name, reason: null, message: null };
368
374
  }
@@ -432,7 +438,7 @@ var CHAIN_NAMES = {
432
438
  84532: "Base Sepolia"
433
439
  };
434
440
  function chainName(chainId) {
435
- return _nullishCoalesce(_nullishCoalesce(CHAIN_NAMES[chainId], () => ( _optionalChain([CHAINS, 'access', _18 => _18[chainId], 'optionalAccess', _19 => _19.name]))), () => ( `chain ${String(chainId)}`));
441
+ return _nullishCoalesce(_nullishCoalesce(CHAIN_NAMES[chainId], () => ( _optionalChain([CHAINS, 'access', _20 => _20[chainId], 'optionalAccess', _21 => _21.name]))), () => ( `chain ${String(chainId)}`));
436
442
  }
437
443
  var TRANSPORT_TIMEOUT_MS = 8e3;
438
444
  function getChain(chainId) {
@@ -476,7 +482,7 @@ function shouldFallback(err) {
476
482
  }
477
483
  function createReadClient(opts) {
478
484
  const chain = getChain(opts.chainId);
479
- const urls = [_optionalChain([opts, 'access', _20 => _20.rpcUrls, 'optionalAccess', _21 => _21[opts.chainId]]), opts.useBridge ? BRIDGE_URLS[opts.chainId] : void 0, chain.rpcUrls.default.http[0]].filter(
485
+ const urls = [_optionalChain([opts, 'access', _22 => _22.rpcUrls, 'optionalAccess', _23 => _23[opts.chainId]]), opts.useBridge ? BRIDGE_URLS[opts.chainId] : void 0, chain.rpcUrls.default.http[0]].filter(
480
486
  (u, i, all) => !!u && all.indexOf(u) === i
481
487
  );
482
488
  const transport = ({ chain: c, pollingInterval }) => {
@@ -545,7 +551,7 @@ function register(state, opts) {
545
551
  }
546
552
  function startLoad(state) {
547
553
  const connect = win().ManifoldConnect;
548
- if (_optionalChain([connect, 'optionalAccess', _22 => _22.capabilities, 'optionalAccess', _23 => _23.includes, 'call', _24 => _24("open")])) return Promise.resolve(connect.ready).then(() => void 0);
554
+ if (_optionalChain([connect, 'optionalAccess', _24 => _24.capabilities, 'optionalAccess', _25 => _25.includes, 'call', _26 => _26("open")])) return Promise.resolve(connect.ready).then(() => void 0);
549
555
  const hasScript = Array.from(document.querySelectorAll("script[src]")).some((s) => isManifoldConnectScript(s.src));
550
556
  if (hasScript || document.querySelector('[data-widget="m-connect"]')) {
551
557
  return Promise.reject(new MintError("CONNECT_WIDGET_TOO_OLD", TOO_OLD));
@@ -571,7 +577,7 @@ function startLoad(state) {
571
577
  script.src = `${CONNECT_BASE_URL}/connect.umd.min.js`;
572
578
  script.async = true;
573
579
  script.addEventListener("load", () => {
574
- const ready = _optionalChain([win, 'call', _25 => _25(), 'access', _26 => _26.ManifoldConnect, 'optionalAccess', _27 => _27.ready]);
580
+ const ready = _optionalChain([win, 'call', _27 => _27(), 'access', _28 => _28.ManifoldConnect, 'optionalAccess', _29 => _29.ready]);
575
581
  if (!ready) return reject(new MintError("CONNECT_WIDGET_TOO_OLD", TOO_OLD));
576
582
  Promise.resolve(ready).then(() => resolve(), reject);
577
583
  });
@@ -585,13 +591,13 @@ function loadConnectWidget(opts) {
585
591
  const page = pageState();
586
592
  const existing = w[LOADER_KEY];
587
593
  if (existing) {
588
- if (_optionalChain([page, 'access', _28 => _28.load, 'optionalAccess', _29 => _29.promise]) !== existing) {
594
+ if (_optionalChain([page, 'access', _30 => _30.load, 'optionalAccess', _31 => _31.promise]) !== existing) {
589
595
  const div = _nullishCoalesce(document.querySelector(`[data-widget="m-connect"][data-connect-id="${CONNECT_ID}"]`), () => ( void 0));
590
596
  page.load = {
591
597
  promise: existing,
592
- networks: _nullishCoalesce(_optionalChain([div, 'optionalAccess', _30 => _30.dataset, 'access', _31 => _31.network, 'optionalAccess', _32 => _32.split, 'call', _33 => _33(","), 'access', _34 => _34.filter, 'call', _35 => _35(Boolean), 'access', _36 => _36.map, 'call', _37 => _37(Number)]), () => ( [])),
598
+ networks: _nullishCoalesce(_optionalChain([div, 'optionalAccess', _32 => _32.dataset, 'access', _33 => _33.network, 'optionalAccess', _34 => _34.split, 'call', _35 => _35(","), 'access', _36 => _36.filter, 'call', _37 => _37(Boolean), 'access', _38 => _38.map, 'call', _39 => _39(Number)]), () => ( [])),
593
599
  // The default id is a placeholder, not a choice: a caller's real id may still replace it.
594
- projectId: _optionalChain([div, 'optionalAccess', _38 => _38.dataset, 'access', _39 => _39.walletConnectProjectId]) === DEFAULT_WALLETCONNECT_PROJECT_ID ? void 0 : _optionalChain([div, 'optionalAccess', _40 => _40.dataset, 'access', _41 => _41.walletConnectProjectId]),
600
+ projectId: _optionalChain([div, 'optionalAccess', _40 => _40.dataset, 'access', _41 => _41.walletConnectProjectId]) === DEFAULT_WALLETCONNECT_PROJECT_ID ? void 0 : _optionalChain([div, 'optionalAccess', _42 => _42.dataset, 'access', _43 => _43.walletConnectProjectId]),
595
601
  div,
596
602
  nodes: []
597
603
  };
@@ -611,7 +617,7 @@ function loadConnectWidget(opts) {
611
617
  p.catch(() => {
612
618
  if (w[LOADER_KEY] === p) delete w[LOADER_KEY];
613
619
  if (page.load === state) page.load = void 0;
614
- for (const node of state.nodes) _optionalChain([node, 'access', _42 => _42.parentNode, 'optionalAccess', _43 => _43.removeChild, 'call', _44 => _44(node)]);
620
+ for (const node of state.nodes) _optionalChain([node, 'access', _44 => _44.parentNode, 'optionalAccess', _45 => _45.removeChild, 'call', _46 => _46(node)]);
615
621
  state.nodes.length = 0;
616
622
  state.div = void 0;
617
623
  });
@@ -642,11 +648,11 @@ function openConnectModal() {
642
648
  }
643
649
  function getAccount() {
644
650
  const p = win().ManifoldEthereumProvider;
645
- const address = _optionalChain([p, 'optionalAccess', _45 => _45.selectedAddress, 'optionalCall', _46 => _46()]);
646
- let chainId = _optionalChain([p, 'optionalAccess', _47 => _47.chainId, 'optionalCall', _48 => _48()]);
651
+ const address = _optionalChain([p, 'optionalAccess', _47 => _47.selectedAddress, 'optionalCall', _48 => _48()]);
652
+ let chainId = _optionalChain([p, 'optionalAccess', _49 => _49.chainId, 'optionalCall', _50 => _50()]);
647
653
  if (chainId === void 0 || chainId === null) {
648
654
  try {
649
- chainId = _optionalChain([p, 'optionalAccess', _49 => _49.browserChainId, 'optionalCall', _50 => _50()]);
655
+ chainId = _optionalChain([p, 'optionalAccess', _51 => _51.browserChainId, 'optionalCall', _52 => _52()]);
650
656
  } catch (e3) {
651
657
  chainId = void 0;
652
658
  }
@@ -665,7 +671,7 @@ function subscribeAccount(cb) {
665
671
  }
666
672
  function eip1193() {
667
673
  const p = win().ManifoldEthereumProvider;
668
- const provider = _optionalChain([(_nullishCoalesce(_optionalChain([p, 'optionalAccess', _51 => _51.provider, 'optionalCall', _52 => _52(true)]), () => ( _optionalChain([p, 'optionalAccess', _53 => _53.browserProvider, 'optionalCall', _54 => _54()])))), 'optionalAccess', _55 => _55.provider]);
674
+ const provider = _optionalChain([(_nullishCoalesce(_optionalChain([p, 'optionalAccess', _53 => _53.provider, 'optionalCall', _54 => _54(true)]), () => ( _optionalChain([p, 'optionalAccess', _55 => _55.browserProvider, 'optionalCall', _56 => _56()])))), 'optionalAccess', _57 => _57.provider]);
669
675
  if (!provider) throw new MintError("CHAIN_SWITCH_FAILED", "No wallet is connected.");
670
676
  return provider;
671
677
  }
@@ -705,7 +711,7 @@ async function getConnectedBalance(address, chainId) {
705
711
  clearTimeout(timer);
706
712
  }
707
713
  }
708
- var code = (e) => _optionalChain([e, 'optionalAccess', _56 => _56.code]);
714
+ var code = (e) => _optionalChain([e, 'optionalAccess', _58 => _58.code]);
709
715
  var hexChainId = (chainId) => `0x${chainId.toString(16)}`;
710
716
  var sendSwitchRequest = (provider, chainId) => provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hexChainId(chainId) }] });
711
717
  var sendAddRequest = (provider, chainId) => {
@@ -834,7 +840,7 @@ var UINT32_MAX = 4294967295;
834
840
  async function getJson(fetchFn, url, signal, what) {
835
841
  let res;
836
842
  try {
837
- _optionalChain([signal, 'optionalAccess', _57 => _57.throwIfAborted, 'call', _58 => _58()]);
843
+ _optionalChain([signal, 'optionalAccess', _59 => _59.throwIfAborted, 'call', _60 => _60()]);
838
844
  res = await fetchFn(url, signal ? { signal } : void 0);
839
845
  } catch (cause) {
840
846
  throw new MintError("ALLOWLIST_UNAVAILABLE", `Could not reach the allowlist service (${what}).`, { cause });
@@ -895,13 +901,13 @@ async function loadEntries(fetchFn, api, instanceId, recipient, scoped) {
895
901
  });
896
902
  }
897
903
  async function fetchMerkleEntries(args) {
898
- if (_optionalChain([args, 'access', _59 => _59.signal, 'optionalAccess', _60 => _60.aborted])) {
904
+ if (_optionalChain([args, 'access', _61 => _61.signal, 'optionalAccess', _62 => _62.aborted])) {
899
905
  throw new MintError("ALLOWLIST_UNAVAILABLE", "The allowlist request was cancelled.", { cause: args.signal.reason });
900
906
  }
901
907
  const fetchFn = _nullishCoalesce(args.fetch, () => ( ((input, init) => globalThis.fetch(input, init))));
902
908
  const key = `${args.api}|${args.instanceId}|${args.recipient.toLowerCase()}`;
903
909
  let scoped = scopeCaches.get(args.scope);
904
- if (!scoped || _optionalChain([scoped, 'access', _61 => _61.signal, 'optionalAccess', _62 => _62.aborted])) {
910
+ if (!scoped || _optionalChain([scoped, 'access', _63 => _63.signal, 'optionalAccess', _64 => _64.aborted])) {
905
911
  scoped = { signal: args.signal, instances: /* @__PURE__ */ new Map(), entries: /* @__PURE__ */ new Map() };
906
912
  scopeCaches.set(args.scope, scoped);
907
913
  }
@@ -973,9 +979,9 @@ function revertData(e) {
973
979
  const d2 = x.data;
974
980
  return _viem.isHex.call(void 0, d2) && d2.length >= 10 || typeof d2 === "object" && d2 !== null && _viem.isHex.call(void 0, d2.data);
975
981
  });
976
- const d = _optionalChain([hit, 'optionalAccess', _63 => _63.data]);
982
+ const d = _optionalChain([hit, 'optionalAccess', _65 => _65.data]);
977
983
  if (_viem.isHex.call(void 0, d)) return d;
978
- const inner = _optionalChain([d, 'optionalAccess', _64 => _64.data]);
984
+ const inner = _optionalChain([d, 'optionalAccess', _66 => _66.data]);
979
985
  return _viem.isHex.call(void 0, inner) ? inner : void 0;
980
986
  }
981
987
  function decodeRevert(e) {
@@ -984,8 +990,8 @@ function decodeRevert(e) {
984
990
  if (data) {
985
991
  try {
986
992
  const d = _viem.decodeErrorResult.call(void 0, { abi: EXTENSION_ERRORS_ABI, data });
987
- if (d.errorName === "Error" && typeof _optionalChain([d, 'access', _65 => _65.args, 'optionalAccess', _66 => _66[0]]) === "string") return d.args[0];
988
- if (d.errorName === "Panic") return `Panic(${String(_optionalChain([d, 'access', _67 => _67.args, 'optionalAccess', _68 => _68[0]]))})`;
993
+ if (d.errorName === "Error" && typeof _optionalChain([d, 'access', _67 => _67.args, 'optionalAccess', _68 => _68[0]]) === "string") return d.args[0];
994
+ if (d.errorName === "Panic") return `Panic(${String(_optionalChain([d, 'access', _69 => _69.args, 'optionalAccess', _70 => _70[0]]))})`;
989
995
  return d.errorName;
990
996
  } catch (e5) {
991
997
  return `reverted with unknown error ${data.slice(0, 10)}`;
@@ -1109,7 +1115,7 @@ async function loadDrop(ctx, config) {
1109
1115
  const fee = await rpc(
1110
1116
  () => client.readContract({ address: extension, abi: EXTENSION_COMMON_ABI, functionName: isAllowlist(claim) ? "MINT_FEE_MERKLE" : "MINT_FEE" })
1111
1117
  );
1112
- const native = _nullishCoalesce(_optionalChain([client, 'access', _69 => _69.chain, 'optionalAccess', _70 => _70.nativeCurrency]), () => ( { symbol: "ETH", decimals: 18 }));
1118
+ const native = _nullishCoalesce(_optionalChain([client, 'access', _71 => _71.chain, 'optionalAccess', _72 => _72.nativeCurrency]), () => ( { symbol: "ETH", decimals: 18 }));
1113
1119
  let unitPrice;
1114
1120
  let paymentToken = null;
1115
1121
  if (claim.erc20 === _viem.zeroAddress) {
@@ -1206,7 +1212,7 @@ async function loadWallet(ctx, config, args) {
1206
1212
  data
1207
1213
  };
1208
1214
  }
1209
- var sameClaim = (a, b) => a.chainId === b.chainId && a.creatorContract.toLowerCase() === b.creatorContract.toLowerCase() && a.instanceId === b.instanceId && _optionalChain([a, 'access', _71 => _71.extension, 'optionalAccess', _72 => _72.toLowerCase, 'call', _73 => _73()]) === _optionalChain([b, 'access', _74 => _74.extension, 'optionalAccess', _75 => _75.toLowerCase, 'call', _76 => _76()]);
1215
+ var sameClaim = (a, b) => a.chainId === b.chainId && a.creatorContract.toLowerCase() === b.creatorContract.toLowerCase() && a.instanceId === b.instanceId && _optionalChain([a, 'access', _73 => _73.extension, 'optionalAccess', _74 => _74.toLowerCase, 'call', _75 => _75()]) === _optionalChain([b, 'access', _76 => _76.extension, 'optionalAccess', _77 => _77.toLowerCase, 'call', _78 => _78()]);
1210
1216
  async function buildPlan(ctx, attempt, wallet) {
1211
1217
  const { config, quantity } = attempt;
1212
1218
  if (!Number.isInteger(quantity) || quantity < 1 || quantity > MAX_MINT_COUNT) {
@@ -1362,6 +1368,43 @@ function parseMintReceipt(logs, { tokenContract, recipient }) {
1362
1368
  return [...out].map(([tokenId, amount]) => ({ contract, tokenId, amount }));
1363
1369
  }
1364
1370
 
1371
+ // src/core/mint-record.ts
1372
+ var APPS_API = "https://apps.api.manifoldxyz.dev";
1373
+ var isRecord2 = (v) => typeof v === "object" && v !== null;
1374
+ var appIds = /* @__PURE__ */ new Map();
1375
+ async function loadAppId(fetchFn, instanceId) {
1376
+ const res = await fetchFn(`${APPS_API}/public/instance/data?id=${encodeURIComponent(instanceId)}`, { keepalive: true });
1377
+ if (!res.ok) throw new Error(`instance data HTTP ${res.status}`);
1378
+ const body = await res.json();
1379
+ const appId = isRecord2(body) ? body.appId : void 0;
1380
+ if (typeof appId !== "number" && typeof appId !== "string") throw new Error("instance data has no appId");
1381
+ return String(appId);
1382
+ }
1383
+ function appIdFor(fetchFn, instanceId) {
1384
+ const hit = appIds.get(instanceId);
1385
+ if (hit) return hit;
1386
+ const p = loadAppId(fetchFn, instanceId);
1387
+ appIds.set(instanceId, p);
1388
+ p.catch(() => {
1389
+ if (appIds.get(instanceId) === p) appIds.delete(instanceId);
1390
+ });
1391
+ return p;
1392
+ }
1393
+ function recordClaimMint(args) {
1394
+ const fetchFn = _nullishCoalesce(args.fetch, () => ( ((input, init) => globalThis.fetch(input, init))));
1395
+ const send = async () => {
1396
+ let appId = "";
1397
+ try {
1398
+ appId = await appIdFor(fetchFn, args.instanceId);
1399
+ } catch (e6) {
1400
+ }
1401
+ const query = new URLSearchParams({ appId, instanceId: args.instanceId, hash: args.hash });
1402
+ await fetchFn(`${APPS_API}/public/instance/tx?${query.toString()}`, { method: "POST", keepalive: true });
1403
+ };
1404
+ return send().catch(() => void 0);
1405
+ }
1406
+
1407
+
1365
1408
 
1366
1409
 
1367
1410
 
@@ -1396,5 +1439,5 @@ function parseMintReceipt(logs, { tokenContract, recipient }) {
1396
1439
 
1397
1440
 
1398
1441
 
1399
- exports.friendlyErrorMessage = friendlyErrorMessage; exports.UNSUPPORTED_REASONS = UNSUPPORTED_REASONS; exports.REASON_CODES = REASON_CODES; exports.MintError = MintError; exports.isMintError = isMintError; exports.isRejection = isRejection; exports.toReason = toReason; exports.chainName = chainName; exports.getChain = getChain; exports.createReadClient = createReadClient; exports.loadConnectWidget = loadConnectWidget; exports.openConnectModal = openConnectModal; exports.getAccount = getAccount; exports.subscribeAccount = subscribeAccount; exports.getWalletClient = getWalletClient; exports.waitForDeposit = waitForDeposit; exports.getConnectedBalance = getConnectedBalance; exports.switchToChain = switchToChain; exports.requestSwitch = requestSwitch; exports.requestAddChain = requestAddChain; exports.getWalletProvider = getWalletProvider; exports.findExtension = findExtension; exports.manifoldClaimAdapter = manifoldClaimAdapter; exports.MINT_STATES = MINT_STATES; exports.CLICKABLE_STATES = CLICKABLE_STATES; exports.IN_FLIGHT_STATES = IN_FLIGHT_STATES; exports.MAX_QUANTITY = MAX_QUANTITY; exports.initialState = initialState; exports.reducer = reducer; exports.selectMaxQuantity = selectMaxQuantity; exports.selectTotal = selectTotal; exports.canAct = canAct; exports.parseMintReceipt = parseMintReceipt;
1400
- //# sourceMappingURL=chunk-OO6QQT3M.cjs.map
1442
+ exports.friendlyErrorMessage = friendlyErrorMessage; exports.UNSUPPORTED_REASONS = UNSUPPORTED_REASONS; exports.REASON_CODES = REASON_CODES; exports.MintError = MintError; exports.isMintError = isMintError; exports.isRejection = isRejection; exports.toReason = toReason; exports.chainName = chainName; exports.getChain = getChain; exports.createReadClient = createReadClient; exports.loadConnectWidget = loadConnectWidget; exports.openConnectModal = openConnectModal; exports.getAccount = getAccount; exports.subscribeAccount = subscribeAccount; exports.getWalletClient = getWalletClient; exports.waitForDeposit = waitForDeposit; exports.getConnectedBalance = getConnectedBalance; exports.switchToChain = switchToChain; exports.requestSwitch = requestSwitch; exports.requestAddChain = requestAddChain; exports.getWalletProvider = getWalletProvider; exports.MINT_STATES = MINT_STATES; exports.CLICKABLE_STATES = CLICKABLE_STATES; exports.IN_FLIGHT_STATES = IN_FLIGHT_STATES; exports.MAX_QUANTITY = MAX_QUANTITY; exports.initialState = initialState; exports.reducer = reducer; exports.selectMaxQuantity = selectMaxQuantity; exports.selectTotal = selectTotal; exports.canAct = canAct; exports.findExtension = findExtension; exports.manifoldClaimAdapter = manifoldClaimAdapter; exports.parseMintReceipt = parseMintReceipt; exports.recordClaimMint = recordClaimMint;
1443
+ //# sourceMappingURL=chunk-X4P6BUV4.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/dropkit/dropkit/packages/react/dropkit/dist/chunk-X4P6BUV4.cjs","../src/core/friendly-errors.ts","../src/core/errors.ts","../src/core/machine.ts","../src/core/rpc/index.ts","../src/core/wallet/index.ts","../src/core/adapters/manifold-claim/index.ts","../src/core/adapters/manifold-claim/abis.ts","../src/core/adapters/manifold-claim/merkle.ts","../src/core/adapters/receipt.ts","../src/core/mint-record.ts"],"names":["hasCode","code","formatUnits","getAddress"],"mappings":"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","file":"/home/runner/work/dropkit/dropkit/packages/react/dropkit/dist/chunk-X4P6BUV4.cjs","sourcesContent":[null,"import { isMintError } from './errors';\n\nconst GENERIC = 'Transaction failed. Please try again. If it fails again, please contact support.';\nconst REVERTED = 'Transaction reverted';\nconst record = (value: unknown): Record<string, unknown> | undefined =>\n value !== null && typeof value === 'object' ? value as Record<string, unknown> : undefined;\nconst text = (value: unknown): string => typeof value === 'string' ? value.toLowerCase() : '';\n\ntype Seen = { name: unknown; code: unknown; message: string; cancelled: unknown; replacement: unknown };\n\n// Inspect both common provider envelopes, with identity tracking for cyclic causes.\nfunction collect(error: unknown): Seen[] {\n const pending: unknown[] = [error];\n const seen = new Set<object>();\n const errors: Seen[] = [];\n while (pending.length) {\n const e = record(pending.pop());\n if (!e || seen.has(e)) continue;\n seen.add(e);\n const data = record(e.data);\n errors.push({\n name: e.name, code: e.code, cancelled: e.cancelled, replacement: e.replacement,\n message: [e.message, e.shortMessage, isMintError(e) ? undefined : e.reason, data?.message].map(text).join('\\n'),\n });\n pending.push(e.cause, data?.originalError);\n }\n return errors;\n}\n\nfunction fundsMessage(errors: Seen[]): string | null {\n const hasText = (phrase: string): boolean => errors.some(e => e.message.includes(phrase));\n // Gas-specific funds must win, including when only a nested cause supplies the gas detail.\n if (hasText('insufficient funds for gas')) {\n return 'Your wallet does not have enough funds to pay for gas fees. Please try again with a different wallet or add more funds to your wallet.';\n }\n if (errors.some(e => e.name === 'InsufficientFundsError' || e.code === 'INSUFFICIENT_FUNDS') ||\n hasText('insufficient funds') || hasText('balance too low to proceed')) {\n return 'Your wallet does not have enough funds to complete this transaction. Please try again with a different wallet or add more funds to your wallet.';\n }\n return null;\n}\n\n/** Display text only: never mutate the error or classify its reason/state. Not a public export. */\nexport function friendlyErrorMessage(error: unknown): string {\n if (isMintError(error)) {\n // Only a recognized provider cause is reworded; a funds error without one keeps its own text.\n if (error.reason === 'INSUFFICIENT_FUNDS') return fundsMessage(collect(error.cause)) ?? error.message;\n if (error.reason !== 'RPC_ERROR' && error.reason !== 'SIMULATION_REVERTED') return error.message;\n // Relay's decoded destination revert (\"Invalid amount\", \"ClaimInactive\") is already the useful text.\n if (error.reason === 'SIMULATION_REVERTED' && (error.domain === 'relay' || error.domain === 'tl-stacks')) return error.message;\n // These are hook-owned domain messages, not provider diagnostics or decoded revert text.\n if (error.reason === 'SIMULATION_REVERTED' && (\n error.message === 'The token refused the approval.' ||\n error.message === 'The drop is no longer available for this quantity.'\n )) return error.message;\n }\n\n const errors = collect(error);\n const hasText = (phrase: string): boolean => errors.some(e => e.message.includes(phrase));\n const hasName = (name: string): boolean => errors.some(e => e.name === name);\n const hasCode = (code: string | number): boolean => errors.some(e => e.code === code);\n\n // Wording and precedence ported from client-sdk @7eac330 adapters/{viem,ethers5}-adapter/utils.ts.\n // Existing 4001/ChainMismatch handling remains in toReason, ahead of this formatter.\n if (hasName('UserRejectedRequestError') || hasCode('ACTION_REJECTED') || hasCode(4001) ||\n hasText('user denied transaction signature') || hasText('userrefusedondevice') ||\n hasText('rejected transaction') || hasText('user rejected') ||\n errors.some(e => e.message.includes('cancelled') && !e.cancelled)) {\n return 'Transaction Rejected';\n }\n if (hasCode(4902)) return 'Network not available in wallet';\n const replaced = errors.find(e => e.name === 'TransactionReplacedError' || e.code === 'TRANSACTION_REPLACED');\n if (replaced?.cancelled) return 'Transaction was cancelled';\n if (replaced?.replacement) return 'Transaction was replaced with a new transaction (usually due to speed up)';\n if (hasText('ledger')) return 'Error with Ledger device. Please ensure device is connected and unlocked';\n // Either message field is sufficient evidence; a bare -32002 is not.\n if (errors.some(e => e.code === -32002 && e.message.includes('pending'))) {\n return 'Transaction already pending in wallet. Please check your wallet';\n }\n if (hasText('invalid amount')) return 'Price calculation is incorrect, contact support!';\n const funds = fundsMessage(errors);\n if (funds) return funds;\n if (hasName('NonceTooLowError') || hasName('NonceExhaustedError') || hasText('nonce too low')) {\n return 'Transaction nonce is too low. Please try again';\n }\n if (hasName('FeeCapTooLowError') || hasText('max fee per gas less than block base fee')) {\n return 'Gas price too low for current network conditions. Please try again';\n }\n if (hasName('TimeoutError') || hasCode('TIMEOUT') || hasText('timeout')) {\n return 'Transaction timed out. Your wallet connection is having issues. Disconnect and reconnect your wallet, then please try again';\n }\n if (hasText('network disconnected')) return 'Network connection lost. Please check your internet connection and try again';\n if (hasName('ChainMismatchError') || hasText('wrong network')) return 'Wrong network selected. Please switch to the correct network';\n if (hasText('erc20: transfer amount exceeds balance')) {\n return 'You do not have the required amount of ERC20 tokens to complete this transaction.';\n }\n if (hasName('EstimateGasExecutionError') || hasCode('UNPREDICTABLE_GAS_LIMIT') || hasText('cannot estimate gas')) {\n return 'Unable to estimate gas for transaction. The transaction may fail. Please try again.';\n }\n if (hasName('ContractFunctionExecutionError') || hasCode('CALL_EXCEPTION')) {\n return 'Transaction failed due to contract execution error';\n }\n if (hasName('ContractFunctionRevertedError') || hasName('ExecutionRevertedError') || hasText('revert')) return REVERTED;\n if (hasName('TransactionExecutionError')) return 'Transaction execution failed';\n if (hasCode('NETWORK_ERROR') || hasName('HttpRequestError') || hasText('network')) return 'Network error occurred';\n return isMintError(error) && error.reason === 'SIMULATION_REVERTED' ? REVERTED : GENERIC;\n}\n","import { friendlyErrorMessage } from './friendly-errors';\n\n// Interface contract (orchestrator-owned). Spec: #ui-ux-flow state table.\n\nexport const UNSUPPORTED_REASONS = [\n 'UNKNOWN_EXTENSION',\n 'AMBIGUOUS_EXTENSION',\n 'CLAIM_NOT_FOUND',\n 'DROP_NOT_FOUND',\n 'SIGNATURE_CLAIM',\n 'INVALID_CONFIG',\n 'CONNECT_WIDGET_TOO_OLD',\n] as const;\n\nexport const INELIGIBLE_REASONS = ['NOT_ON_ALLOWLIST', 'ALLOWLIST_USED', 'WALLET_LIMIT', 'SIMULATION_REVERTED'] as const;\n\nexport const ERROR_REASONS = [\n 'USER_REJECTED',\n 'TX_REVERTED',\n 'RATE_LIMITED',\n 'RPC_ERROR',\n 'CHAIN_SWITCH_FAILED',\n 'ALLOWLIST_UNAVAILABLE',\n // Relay cross-chain mint (spec relay-cross-chain-mint #execute-click).\n 'BRIDGE_UNAVAILABLE',\n 'BRIDGE_REFUNDED',\n 'BRIDGE_FAILED',\n 'BRIDGE_TIMEOUT',\n] as const;\n\n/** insufficient-funds carries this reason so data-reason is never empty in that state. */\nexport const FUNDS_REASONS = ['INSUFFICIENT_FUNDS'] as const;\n\nexport type UnsupportedReason = (typeof UNSUPPORTED_REASONS)[number];\nexport type IneligibleReason = (typeof INELIGIBLE_REASONS)[number];\nexport type ErrorReason = (typeof ERROR_REASONS)[number];\nexport type ReasonCode = UnsupportedReason | IneligibleReason | ErrorReason | (typeof FUNDS_REASONS)[number];\n\nexport const REASON_CODES: readonly ReasonCode[] = [\n ...UNSUPPORTED_REASONS,\n ...INELIGIBLE_REASONS,\n ...ERROR_REASONS,\n ...FUNDS_REASONS,\n];\n\n/**\n * Thrown by adapters, rpc and wallet code; the hook maps it to the matching state.\n * `message` is plain English and, for INVALID_CONFIG, names the exact bad field\n * (e.g. `mint.args[1] \"{qty}\" is not a known placeholder`).\n */\nexport class MintError extends Error {\n readonly reason: ReasonCode;\n /** INVALID_CONFIG only: dotted path of the bad field, e.g. \"mint.args[1]\" or \"price\". */\n readonly field?: string;\n /** 'relay' or 'tl-stacks': the message is a decoded destination revert, shown as-is. */\n readonly domain?: 'relay' | 'tl-stacks';\n constructor(reason: ReasonCode, message: string, opts?: { field?: string; cause?: unknown; domain?: 'relay' | 'tl-stacks' }) {\n super(message, opts?.cause === undefined ? undefined : { cause: opts.cause });\n this.name = 'MintError';\n this.reason = reason;\n if (opts?.field !== undefined) this.field = opts.field;\n if (opts?.domain !== undefined) this.domain = opts.domain;\n }\n}\n\nexport function isMintError(e: unknown): e is MintError {\n return e instanceof MintError;\n}\n\nexport function notImplemented(story: string): never {\n throw new Error(`not implemented (${story})`);\n}\n\nexport function isRejection(error: unknown): boolean {\n for (let e = error as { code?: unknown; cause?: unknown } | undefined, depth = 0; e && depth < 8; depth++) {\n if (e.code === 4001) return true;\n e = e.cause as typeof e;\n }\n return false;\n}\n\n/** MintError keeps its reason; a bare wallet rejection becomes USER_REJECTED; anything else is an RPC error. */\nexport function toReason(e: unknown): { reason: ReasonCode; message: string } {\n if (isMintError(e)) return { reason: e.reason, message: friendlyErrorMessage(e) };\n if (isRejection(e)) return { reason: 'USER_REJECTED', message: 'You rejected the request.' };\n for (let cause = e as { name?: string; cause?: unknown } | undefined, depth = 0; cause && depth < 8; depth++) {\n if (cause.name === 'ChainMismatchError') return { reason: 'CHAIN_SWITCH_FAILED', message: 'The wallet network changed before the transaction was sent.' };\n cause = cause.cause as typeof cause;\n }\n return { reason: 'RPC_ERROR', message: friendlyErrorMessage(e) };\n}\n","// Interface contract (orchestrator-owned). Implementation: story s3.\n// Pure reducer, no I/O, no Date.now(): time arrives in events.\nimport { formatUnits } from 'viem';\nimport type { Address, Attempt, DropInfo, MintResult, Money, Route } from './types';\nimport { INELIGIBLE_REASONS } from './errors';\nimport type { ErrorReason, ReasonCode, UnsupportedReason } from './errors';\nimport type { WalletRead } from './adapters/types';\n\nexport const MINT_STATES = [\n 'loading',\n 'unsupported',\n 'upcoming',\n 'ended',\n 'sold-out',\n 'disconnected',\n 'connecting',\n 'live',\n 'ineligible',\n 'insufficient-funds',\n 'switching-chain',\n 'approving',\n 'minting',\n 'confirming',\n 'success',\n 'error',\n] as const;\nexport type MintStateName = (typeof MINT_STATES)[number];\n\n/** States where mint() does something (spec: Clickable column). */\nexport const CLICKABLE_STATES: readonly MintStateName[] = ['disconnected', 'live', 'success', 'error'];\n/** An attempt is in flight; reads/prop changes are deferred (pendingRefresh) until a terminal state. */\nexport const IN_FLIGHT_STATES: readonly MintStateName[] = ['switching-chain', 'approving', 'minting', 'confirming'];\n\n/** uint16 mintCount cap on Manifold extensions; also the global quantity cap. */\nexport const MAX_QUANTITY = 65535;\n\nexport type Account = { address: Address; chainId: number };\n\n/** The wallet's chain cannot cover the Relay quote (spec R3). */\nexport type PayShort = { chainId: number; symbol: string; name: string };\n\nexport type MachineState = {\n name: MintStateName;\n reason: ReasonCode | null;\n /** Plain-English text for reason (decoded revert for SIMULATION_REVERTED / TX_REVERTED). */\n message: string | null;\n /** Generation of the current drop read; DROP_* events with another gen are ignored. */\n readGen: number;\n /** Generation of the current wallet read; bumped by ACCOUNT_CHANGED. WALLET_* with another gen are ignored. */\n walletGen: number;\n drop: DropInfo | null;\n account: Account | null;\n walletRead: WalletRead | null;\n /**\n * Set by ATTEMPT_FAILED for ineligible / insufficient-funds reasons. Sticky: survives drop refreshes and is\n * cleared by the next WALLET_LOADED, ACCOUNT_CHANGED, config LOAD or RESET.\n */\n blocked: Derived | null;\n quantity: number;\n attempt: Attempt | null;\n result: MintResult | null;\n /** Set when a read/account/quantity change arrived during an in-flight attempt. */\n pendingRefresh: boolean;\n /** Monotonic Unix seconds: the maximum accepted DROP_LOADED / TICK time. */\n now: number;\n /** Relay may mint this drop for this wallet (set by WALLET_LOADED). */\n crossChain: boolean;\n /** A Relay route read for the current walletGen is in flight: show loading, not insufficient-funds. */\n routePending: boolean;\n /** How the current wallet pays. null = no route read (direct by default). */\n route: Route | null;\n /** Set when the wallet's chain cannot cover the Relay quote. */\n short: PayShort | null;\n};\n\nexport type MachineEvent =\n /**\n * Sets readGen = gen. kind 'refresh' (30s timer, visibilitychange): keeps the known drop on screen.\n * kind 'config' (mount, config/recipient change): clears drop + walletRead, bumps walletGen, shows 'loading'.\n */\n | { type: 'LOAD'; gen: number; kind: 'config' | 'refresh' }\n | { type: 'DROP_LOADED'; gen: number; drop: DropInfo; now: number }\n | { type: 'DROP_UNSUPPORTED'; gen: number; reason: UnsupportedReason; message: string }\n | { type: 'READ_FAILED'; gen: number; reason: ErrorReason; message: string }\n /** Wallet connected / switched account / switched chain / disconnected (null). Bumps walletGen. */\n | { type: 'ACCOUNT_CHANGED'; account: Account | null }\n /**\n * crossChain: Relay may mint this drop. routePending: a ROUTE_LOADED for this walletGen will follow\n * (the wallet is on another pay chain), so the drop-chain funds check must wait for it.\n */\n | { type: 'WALLET_LOADED'; gen: number; read: WalletRead; crossChain?: boolean; routePending?: boolean }\n /** Result of the Relay route read for walletGen `gen`. Stale gens are ignored. */\n | { type: 'ROUTE_LOADED'; gen: number; route: Route | null; short: PayShort | null }\n | { type: 'WALLET_FAILED'; gen: number; reason: ErrorReason; message: string }\n | { type: 'CONNECT_STARTED' }\n | { type: 'CONNECT_DISMISSED' }\n | { type: 'TICK'; now: number }\n | { type: 'SET_QUANTITY'; quantity: number }\n /** resume: re-attach to a paid Relay request (spec R12); accepted from any idle state. */\n | { type: 'ATTEMPT_STARTED'; attempt: Attempt; resume?: boolean }\n | { type: 'SWITCHING_CHAIN'; attemptId: number }\n | { type: 'APPROVING'; attemptId: number }\n | { type: 'MINT_PROMPTED'; attemptId: number }\n | { type: 'TX_SUBMITTED'; attemptId: number }\n | { type: 'ATTEMPT_SUCCEEDED'; attemptId: number; result: MintResult }\n | { type: 'ATTEMPT_FAILED'; attemptId: number; reason: ReasonCode; message: string }\n /**\n * Click in success/error: clears result/error/walletRead, sets readGen = gen, bumps walletGen and\n * re-derives; with an account it shows 'loading' until the fresh WALLET_LOADED (AC-15).\n */\n | { type: 'RESET'; gen: number };\n\nexport function initialState(opts?: { quantity?: number }): MachineState {\n return {\n name: 'loading',\n reason: null,\n message: null,\n readGen: 0,\n walletGen: 0,\n drop: null,\n account: null,\n walletRead: null,\n blocked: null,\n quantity: toQuantity(opts?.quantity ?? 1, MAX_QUANTITY),\n attempt: null,\n result: null,\n pendingRefresh: false,\n now: 0,\n crossChain: false,\n routePending: false,\n route: null,\n short: null,\n };\n}\n\nconst NO_ROUTE = { crossChain: false, routePending: false, route: null, short: null } as const;\nconst PICK_ANOTHER = 'Pick another network to pay from.';\n\n/** Floor, then clamp to [1, max]. NaN becomes 1. */\nfunction toQuantity(q: number, max: number): number {\n if (Number.isNaN(q)) return 1;\n return Math.max(1, Math.min(Math.floor(q), max));\n}\n\n/** An attempt is in flight from ATTEMPT_STARTED until success/error, including the 'live' gap before the first step. */\nfunction isInFlight(s: MachineState): boolean {\n return s.attempt !== null || IN_FLIGHT_STATES.includes(s.name);\n}\n\n/** Names that are re-derived from data on every change (rule 2). */\nfunction isIdle(s: MachineState): boolean {\n return !isInFlight(s) && s.name !== 'connecting' && s.name !== 'success' && s.name !== 'error';\n}\n\ntype Derived = Pick<MachineState, 'name' | 'reason' | 'message'>;\n\nfunction derive(s: MachineState, unsupported: boolean): Derived {\n const named = (name: MintStateName): Derived => ({ name, reason: null, message: null });\n const { drop, walletRead } = s;\n if (unsupported) return { name: 'unsupported', reason: s.reason, message: s.message };\n if (drop === null) return named('loading');\n if (drop.endTime !== null && drop.endTime <= s.now) return named('ended');\n if (drop.maxSupply !== null && drop.maxSupply > 0n && drop.totalMinted >= drop.maxSupply) return named('sold-out');\n if (drop.startTime !== null && drop.startTime > s.now) return named('upcoming');\n if (s.account === null) return named('disconnected');\n if (walletRead === null) return named('loading');\n if (s.blocked !== null) return s.blocked;\n if (walletRead.ineligible !== null) {\n return { name: 'ineligible', reason: walletRead.ineligible.reason, message: walletRead.ineligible.message };\n }\n // Relay route (spec #machine-changes): pending -> loading, relay -> live, short wallet chain -> insufficient-funds.\n if (s.routePending) return named('loading');\n if (s.route?.kind === 'relay') return named('live');\n if (s.short !== null) {\n return { name: 'insufficient-funds', reason: 'INSUFFICIENT_FUNDS', message: `Not enough ${s.short.symbol} on ${s.short.name}. ${PICK_ANOTHER}` };\n }\n const total = selectTotal(s);\n if (total !== null) {\n const { native, erc20 } = total;\n if (native.value + walletRead.gasReserve > walletRead.balances.native) {\n const more = s.crossChain ? ` ${PICK_ANOTHER}` : '';\n return { name: 'insufficient-funds', reason: 'INSUFFICIENT_FUNDS', message: `Not enough ${native.symbol} to cover the mint.${more}` };\n }\n // A null ERC20 balance means the adapter could not read it; the simulation catches a real shortfall.\n if (erc20 !== null && walletRead.balances.erc20 !== null && erc20.value > walletRead.balances.erc20) {\n return { name: 'insufficient-funds', reason: 'INSUFFICIENT_FUNDS', message: `Not enough ${erc20.symbol} to cover the mint.` };\n }\n }\n return named('live');\n}\n\n/** Re-derive the name when idle; otherwise keep it. `unsupported` stays sticky until a new read result replaces it. */\nfunction settle(s: MachineState, unsupported = s.name === 'unsupported'): MachineState {\n if (!isIdle(s)) return s;\n return { ...s, ...derive(s, unsupported) };\n}\n\n/** Shrink quantity when new data lowers the cap. Never raises it. */\nfunction clampQuantity(s: MachineState): MachineState {\n const quantity = toQuantity(s.quantity, selectMaxQuantity(s) ?? MAX_QUANTITY);\n return quantity === s.quantity ? s : { ...s, quantity };\n}\n\n/**\n * Rules (all are tested):\n * 1. Stale results: DROP_LOADED / DROP_UNSUPPORTED / READ_FAILED with gen !== readGen, WALLET_LOADED /\n * WALLET_FAILED with gen !== walletGen, and attempt events whose attemptId !== attempt?.attemptId\n * return the SAME state object (reference-equal).\n * 2. Derivation when idle (no attempt, not connecting/success/error), in priority order:\n * unsupported (DROP_UNSUPPORTED) > loading (no drop) > ended (endTime !== null && endTime <= now)\n * > sold-out (maxSupply !== null && maxSupply > 0n && totalMinted >= maxSupply)\n * > upcoming (startTime !== null && startTime > now) > disconnected (account null)\n * > loading (account set, no walletRead for the current walletGen)\n * > ineligible (walletRead.ineligible) > insufficient-funds (selectTotal vs walletRead.balances,\n * native leg includes walletRead.gasReserve) > live.\n * Wrong chain is NOT a derived state: live stays live; switching happens on click.\n * 3. TICK only changes time and time never goes backward (now = max(now, event.now)); it can flip\n * upcoming -> live/disconnected and live -> ended, never ended -> anything.\n * 4. CONNECT_STARTED from disconnected -> connecting. CONNECT_DISMISSED from connecting -> derived\n * (disconnected). ACCOUNT_CHANGED with an account while connecting -> derived (loading until WALLET_LOADED).\n * 5. ATTEMPT_STARTED is accepted only from live. The attempt is frozen; name stays 'live' until the\n * first step event (SWITCHING_CHAIN -> switching-chain, APPROVING -> approving,\n * MINT_PROMPTED -> minting, TX_SUBMITTED -> confirming). Steps only move forward in that order\n * (skips allowed); a duplicate or backward step returns the SAME state object.\n * 6. During IN_FLIGHT_STATES: LOAD, ACCOUNT_CHANGED, SET_QUANTITY, TICK, DROP_LOADED and WALLET_LOADED\n * do not change name/attempt; they store data where applicable and set pendingRefresh = true\n * (TICK only updates now). ACCOUNT_CHANGED still bumps walletGen.\n * 7. ATTEMPT_SUCCEEDED -> success with result. ATTEMPT_FAILED maps by reason category:\n * INELIGIBLE_REASONS -> ineligible, INSUFFICIENT_FUNDS -> insufficient-funds (both stored in `blocked`,\n * sticky until the next WALLET_LOADED / ACCOUNT_CHANGED / config LOAD / RESET, and not clickable),\n * ERROR_REASONS -> error. All clear attempt. In success/error, reads still update data but name\n * stays until RESET. Every success and every submitted error clears the drop and invalidates its\n * read generation, so RESET cannot become live until a post-terminal DROP_LOADED and a fresh\n * WALLET_LOADED arrive.\n * 8. SET_QUANTITY clamps to [1, selectMaxQuantity(state) ?? MAX_QUANTITY]; non-integers floor.\n * 9. READ_FAILED (current gen) when idle -> error with reason/message.\n */\nexport function reducer(state: MachineState, event: MachineEvent): MachineState {\n const inFlight = isInFlight(state);\n // A failed read/wallet result: error when idle or connecting, deferred in flight, ignored in success/error.\n const failed = (reason: ErrorReason, message: string): MachineState => {\n if (inFlight) return { ...state, pendingRefresh: true };\n if (state.name === 'success' || state.name === 'error') return state;\n return { ...state, name: 'error', reason, message };\n };\n\n switch (event.type) {\n case 'LOAD': {\n if (event.kind === 'refresh') {\n const next = { ...state, readGen: event.gen };\n return inFlight ? { ...next, pendingRefresh: true } : settle(next);\n }\n // A config change is a read boundary: nothing from the previous drop or wallet may stay actionable.\n const next = { ...state, ...NO_ROUTE, readGen: event.gen, drop: null, walletRead: null, blocked: null, walletGen: state.walletGen + 1 };\n return inFlight ? { ...next, pendingRefresh: true } : settle(next, false);\n }\n case 'DROP_LOADED': {\n if (event.gen !== state.readGen) return state;\n let next = { ...state, drop: event.drop, now: Math.max(state.now, event.now) };\n // A drop that sets walletKey (tl-stacks) says which wallet reads still describe it. A changed key drops the\n // read and bumps the generation, so a read started for the old stage is ignored. Other drops never set it.\n const oldKey = state.drop?.walletKey;\n const newKey = event.drop.walletKey;\n if (oldKey !== undefined && newKey !== undefined && oldKey !== newKey) {\n next = { ...next, walletRead: null, walletGen: state.walletGen + 1 };\n }\n if (inFlight) return { ...next, pendingRefresh: true };\n return isIdle(next) ? settle(clampQuantity(next), false) : clampQuantity(next);\n }\n case 'DROP_UNSUPPORTED': {\n if (event.gen !== state.readGen) return state;\n if (inFlight) return { ...state, pendingRefresh: true };\n if (state.name === 'success' || state.name === 'error') return state;\n return { ...state, name: 'unsupported', reason: event.reason, message: event.message };\n }\n case 'READ_FAILED':\n return event.gen !== state.readGen ? state : failed(event.reason, event.message);\n case 'ACCOUNT_CHANGED': {\n const next = { ...state, ...NO_ROUTE, account: event.account, walletRead: null, blocked: null, walletGen: state.walletGen + 1 };\n if (inFlight) return { ...next, pendingRefresh: true };\n // Connecting only ends when an account arrives; a null account keeps the connect UI open.\n if (state.name === 'connecting') return event.account === null ? next : settle({ ...next, name: 'loading' }, false);\n return settle(next);\n }\n case 'WALLET_LOADED': {\n if (event.gen !== state.walletGen) return state;\n // A refresh keeps the last route on screen until the new ROUTE_LOADED replaces it.\n const route = event.routePending\n ? { routePending: state.route === null && state.short === null, route: state.route, short: state.short }\n : { routePending: false, route: null, short: null };\n const next = { ...state, ...route, crossChain: event.crossChain ?? false, walletRead: event.read, blocked: null };\n return inFlight ? { ...next, pendingRefresh: true } : settle(clampQuantity(next));\n }\n case 'ROUTE_LOADED': {\n if (event.gen !== state.walletGen) return state;\n const next = { ...state, routePending: false, route: event.route, short: event.short };\n return inFlight ? { ...next, pendingRefresh: true } : settle(next);\n }\n case 'WALLET_FAILED':\n return event.gen !== state.walletGen ? state : failed(event.reason, event.message);\n case 'CONNECT_STARTED':\n return state.name === 'disconnected' && state.attempt === null\n ? { ...state, name: 'connecting', reason: null, message: null }\n : state;\n case 'CONNECT_DISMISSED':\n return state.name === 'connecting' ? settle({ ...state, name: 'disconnected' }, false) : state;\n case 'TICK':\n return settle({ ...state, now: Math.max(state.now, event.now) });\n case 'SET_QUANTITY': {\n const next = { ...state, quantity: toQuantity(event.quantity, selectMaxQuantity(state) ?? MAX_QUANTITY) };\n return inFlight ? { ...next, pendingRefresh: true } : settle(next);\n }\n case 'ATTEMPT_STARTED':\n if (state.attempt !== null) return state;\n // A resume re-attaches to a deposit that already left the wallet, so it may start from any idle state.\n if (event.resume === true) return IN_FLIGHT_STATES.includes(state.name) ? state : { ...state, attempt: event.attempt };\n return state.name === 'live' ? { ...state, attempt: event.attempt } : state;\n case 'SWITCHING_CHAIN':\n return step(state, event.attemptId, 'switching-chain');\n case 'APPROVING':\n return step(state, event.attemptId, 'approving');\n case 'MINT_PROMPTED':\n return step(state, event.attemptId, 'minting');\n case 'TX_SUBMITTED':\n return step(state, event.attemptId, 'confirming');\n case 'ATTEMPT_SUCCEEDED':\n return state.attempt?.attemptId === event.attemptId\n ? { ...state, name: 'success', reason: null, message: null, attempt: null, result: event.result,\n drop: null, readGen: state.readGen + 1 }\n : state;\n case 'ATTEMPT_FAILED': {\n if (state.attempt?.attemptId !== event.attemptId) return state;\n const { reason, message } = event;\n const done = { ...state, reason, message, attempt: null, result: null };\n if ((INELIGIBLE_REASONS as readonly string[]).includes(reason)) {\n return { ...done, name: 'ineligible', blocked: { name: 'ineligible', reason, message } };\n }\n if (reason === 'INSUFFICIENT_FUNDS') {\n return { ...done, name: 'insufficient-funds', blocked: { name: 'insufficient-funds', reason, message } };\n }\n // Reads before the receipt cannot establish post-transaction freshness.\n return { ...done, name: 'error', drop: state.name === 'confirming' ? null : state.drop,\n readGen: state.name === 'confirming' ? state.readGen + 1 : state.readGen };\n }\n case 'RESET': {\n if (state.name !== 'success' && state.name !== 'error') return state;\n // The wallet data is stale after an attempt: re-read it before the button can be live again (AC-15).\n const next = {\n ...state,\n readGen: event.gen,\n ...NO_ROUTE,\n walletRead: null,\n blocked: null,\n walletGen: state.walletGen + 1,\n result: null,\n pendingRefresh: false,\n };\n // Leave the terminal name so settle() treats the state as idle.\n return settle(clampQuantity({ ...next, name: 'loading' }), false);\n }\n }\n}\n\n/** Attempt steps in lifecycle order; the pre-step 'live' gap ranks below all of them. */\nconst STEP_ORDER: readonly MintStateName[] = ['switching-chain', 'approving', 'minting', 'confirming'];\n\nfunction step(state: MachineState, attemptId: number, name: MintStateName): MachineState {\n if (state.attempt?.attemptId !== attemptId) return state;\n if (STEP_ORDER.indexOf(name) <= STEP_ORDER.indexOf(state.name)) return state;\n return { ...state, name, reason: null, message: null };\n}\n\n/**\n * min(remaining supply, branch limit, MAX_QUANTITY). Remaining supply = maxSupply - totalMinted when\n * maxSupply is a positive bigint. Branch limit = walletRead.maxQuantity when not null.\n * null only when no drop is loaded.\n */\nexport function selectMaxQuantity(state: MachineState): number | null {\n const { drop, walletRead } = state;\n if (drop === null) return null;\n let max = MAX_QUANTITY;\n if (drop.maxSupply !== null && drop.maxSupply > 0n) {\n const remaining = drop.maxSupply - drop.totalMinted;\n if (remaining < BigInt(max)) max = remaining > 0n ? Number(remaining) : 0;\n }\n if (walletRead !== null && walletRead.maxQuantity !== null) {\n max = Math.min(max, Math.max(0, Math.floor(walletRead.maxQuantity)));\n }\n return max;\n}\n\n/**\n * Totals for state.quantity, fee included.\n * native price: native = (unitPrice + unitFee) * q (pricePer 'total': unitPrice + unitFee * q).\n * ERC20 price: native = unitFee * q, erc20 = unitPrice * q (or unitPrice when pricePer 'total').\n * null when no drop. Money.formatted uses viem formatUnits.\n */\nexport function selectTotal(state: MachineState): { native: Money; erc20: Money | null } | null {\n const { drop } = state;\n if (drop === null) return null;\n const q = BigInt(state.quantity);\n const price = drop.unitPrice;\n const fee = drop.unitFee;\n const priceTotal = drop.pricePer === 'total' ? price.value : price.value * q;\n if (drop.paymentToken !== null) {\n return {\n native: money(fee.value * q, fee),\n erc20: money(priceTotal, price),\n };\n }\n // pricePer 'total': the fee is still per unit.\n return { native: money(priceTotal + fee.value * q, price), erc20: null };\n}\n\nfunction money(value: bigint, like: Money): Money {\n return { value, decimals: like.decimals, symbol: like.symbol, formatted: formatUnits(value, like.decimals) };\n}\n\nexport function canAct(state: MachineState): boolean {\n return state.attempt === null && CLICKABLE_STATES.includes(state.name);\n}\n","// Interface contract (orchestrator-owned). Implementation: story s4. Spec D7 + #api-endpoints.\nimport { createPublicClient, http, type Chain, type EIP1193RequestFn, type PublicClient, type Transport } from 'viem';\nimport { apeChain, base, baseSepolia, mainnet, optimism, sepolia, shape } from 'viem/chains';\nimport type { RpcUrls } from '../types';\nimport { MintError } from '../errors';\n\n/** Manifold read bridge per chain (allowlisted contracts + methods only; no receipts). */\nexport const BRIDGE_URLS: Readonly<Record<number, string>> = {\n 1: 'https://bridge.manifoldxyz.dev/rpc',\n 11155111: 'https://sepolia.bridge.manifoldxyz.dev/rpc',\n 8453: 'https://base.bridge.manifoldxyz.dev/rpc',\n 10: 'https://optimism.bridge.manifoldxyz.dev/rpc',\n 360: 'https://shape.bridge.manifoldxyz.dev/rpc',\n 33139: 'https://apechain.bridge.manifoldxyz.dev/rpc',\n};\n\nconst CHAINS: Readonly<Record<number, Chain>> = {\n [mainnet.id]: mainnet,\n [sepolia.id]: sepolia,\n [base.id]: base,\n [optimism.id]: optimism,\n [shape.id]: shape,\n [apeChain.id]: apeChain,\n // Relay pay chain for Sepolia drops only: never a drop chain, no Manifold bridge.\n [baseSepolia.id]: baseSepolia,\n};\n\nconst CHAIN_NAMES: Readonly<Record<number, string>> = {\n 1: 'Ethereum',\n 8453: 'Base',\n 10: 'Optimism',\n 360: 'Shape',\n 33139: 'ApeChain',\n 11155111: 'Sepolia',\n 84532: 'Base Sepolia',\n};\n\n/** Short display name for a chain (\"Base\", \"Optimism\"); falls back to viem's name or the id. */\nexport function chainName(chainId: number): string {\n return CHAIN_NAMES[chainId] ?? CHAINS[chainId]?.name ?? `chain ${String(chainId)}`;\n}\n\n/** Per-transport request timeout; a slow endpoint falls through to the next one. */\nconst TRANSPORT_TIMEOUT_MS = 8_000;\n\n/** viem chain for an id; throws MintError('INVALID_CONFIG', ..., { field: 'chainId' }) when unknown. */\nexport function getChain(chainId: number): Chain {\n const chain = CHAINS[chainId];\n if (!chain) {\n throw new MintError('INVALID_CONFIG', `chainId ${String(chainId)} is not supported`, { field: 'chainId' });\n }\n return chain;\n}\n\n/** Codes reserved for request/user failures remain final, even under an internal-error wrapper. */\nconst TERMINAL_CODES: ReadonlySet<number> = new Set([3, -32602, -32003, 4001, 4100, 4200, 4900, 4901, 4902]);\n/** Endpoint/routing errors can be answered by another server, unless they also carry execution evidence. */\nconst FALLBACK_CODES: ReadonlySet<number> = new Set([-32700, -32600, -32601, -32001, -32002, -32004, -32005, 429]);\nconst EXECUTION_WORDING = /execution reverted|execution error|\\breverted?\\b|out of gas|invalid opcode|insufficient funds|nonce too low|gas required exceeds/i;\nconst UPSTREAM_WORDING = /\\btimeout\\b|\\btimed out\\b|\\btoo many requests\\b|\\brate limit\\b|\\brequest limit reached\\b|\\b(?:exceeded.*capacity|capacity.*exceeded)\\b|\\bheader not found\\b|\\binternal (?:json-rpc )?(?:server )?error\\b|\\bnon-200 status code:\\s*['\"]?503\\b/i;\nconst TRANSPORT_ERROR_NAMES: ReadonlySet<string> = new Set(['HttpRequestError', 'TimeoutError', 'SocketClosedError', 'WebSocketRequestError']);\n\n/** Inspect nested provider payloads without mistaking a diagnostic request id for EVM return data. */\nfunction carriesExecutionEvidence(value: unknown, seen = new Set<object>()): boolean {\n if (typeof value === 'string') return /^(?:Reverted\\s+)?0x(?:[a-f\\d]{2})*$/i.test(value) || EXECUTION_WORDING.test(value);\n if (!value || typeof value !== 'object' || seen.has(value)) return false;\n seen.add(value);\n const e = value as Record<string, unknown>;\n if (typeof e.code === 'number' && TERMINAL_CODES.has(e.code)) return true;\n if (typeof e.message === 'string' && EXECUTION_WORDING.test(e.message)) return true;\n return ['data', 'error', 'originalError', 'cause', 'result'].some((key) => carriesExecutionEvidence(e[key], seen));\n}\n\n/** Execution evidence anywhere in the ancestry wins. Unknown failures are final, not blanket retries. */\nfunction shouldFallback(err: unknown): boolean {\n let retry = false;\n const seen = new Set<object>();\n for (let e = err; e && typeof e === 'object' && !seen.has(e); ) {\n seen.add(e);\n const error = e as Record<string, unknown>;\n // viem's message embeds request metadata. Prefer provider details to avoid matching request content.\n const message = typeof error.details === 'string' ? error.details : typeof error.shortMessage !== 'string' ? error.message : '';\n if (typeof message === 'string' && EXECUTION_WORDING.test(message)) return false;\n if (carriesExecutionEvidence(error.data)) return false;\n if (typeof error.code === 'number' && TERMINAL_CODES.has(error.code)) return false;\n if (error.name === 'ContractFunctionRevertedError' || error.name === 'ExecutionRevertedError') return false;\n if (typeof error.name === 'string' && TRANSPORT_ERROR_NAMES.has(error.name)) retry = true;\n if (typeof error.code === 'number' && FALLBACK_CODES.has(error.code)) retry = true;\n if (typeof message === 'string' && UPSTREAM_WORDING.test(message)) retry = true;\n e = error.cause;\n }\n return retry;\n}\n\n/**\n * Read client with ordered fallback: rpcUrls[chainId] -> BRIDGE_URLS[chainId] (only when useBridge) ->\n * the chain's default public RPC. A request that fails for a reason that belongs to the endpoint (HTTP error,\n * timeout, rate limit, -32004 Not allowed, recognized internal/server-error or relayed 503 wording,\n * \"header not found\", -32099 capacity) is retried on\n * the next; when all fail it throws MintError('RPC_ERROR') and logs a console hint to pass rpcUrls.\n * Execution results (reverts, identified by revert data or revert wording, and request/user-determined codes)\n * are NOT retried: they surface as-is. See shouldFallback.\n */\nexport function createReadClient(opts: { chainId: number; rpcUrls?: RpcUrls; useBridge: boolean }): PublicClient {\n const chain = getChain(opts.chainId);\n const urls = [opts.rpcUrls?.[opts.chainId], opts.useBridge ? BRIDGE_URLS[opts.chainId] : undefined, chain.rpcUrls.default.http[0]].filter(\n (u, i, all): u is string => !!u && all.indexOf(u) === i,\n );\n\n // Own Transport (not viem's fallback): viem wraps every transport error that is not a viem BaseError,\n // which would hide the MintError('RPC_ERROR') this contract requires.\n const transport: Transport = ({ chain: c, pollingInterval }) => {\n const transports = urls.map((url) => http(url, { timeout: TRANSPORT_TIMEOUT_MS, retryCount: 0 })({ chain: c, pollingInterval, retryCount: 0, timeout: TRANSPORT_TIMEOUT_MS }));\n const request = (async (args: { method: string; params?: unknown }) => {\n let last: unknown;\n for (const t of transports) {\n try {\n return await t.request(args);\n } catch (err) {\n if (!shouldFallback(err)) throw err;\n last = err;\n }\n }\n console.warn(`dropkit: all RPC endpoints failed for chain ${String(opts.chainId)}; pass rpcUrls={{ ${String(opts.chainId)}: '<your RPC url>' }} to <MintButton>.`);\n throw new MintError('RPC_ERROR', `All RPC endpoints failed for chain ${String(opts.chainId)}`, { cause: last });\n }) as EIP1193RequestFn;\n return {\n config: { key: 'dropkit-fallback', name: 'Dropkit fallback', request, retryCount: 0, retryDelay: 0, timeout: TRANSPORT_TIMEOUT_MS, type: 'fallback' },\n request,\n value: {},\n };\n };\n\n return createPublicClient({ chain, transport }) as PublicClient;\n}\n","// Interface contract (orchestrator-owned). Implementation: story s4. Spec #state-management\n// \"Connect widget lifecycle\" + Q20 (no getProvider; use ManifoldEthereumProvider).\nimport { createWalletClient, custom, getAddress, publicActions, type Address, type EIP1193Provider, type Hex, type WalletClient } from 'viem';\nimport type { Account } from '../machine';\nimport { MintError } from '../errors';\nimport { getChain } from '../rpc';\n\nexport const CONNECT_WIDGET_VERSION = '6.5.0';\nexport const CONNECT_BASE_URL = `https://connect.manifoldxyz.dev/${CONNECT_WIDGET_VERSION}`;\nexport const CONNECT_ID = 'mint-button';\n/** Event names copied from @manifoldxyz/frontend-provider-types (not imported). */\nexport const ADDRESS_CHANGED = 'ethereum-address-changed';\nexport const CHAIN_CHANGED = 'frontend-provider-chain-changed';\nexport const LOADER_KEY = '__manifoldMintConnectLoader';\n/** Manifold's WalletConnect project id, used when no caller passes one so the WalletConnect option always shows. */\nexport const DEFAULT_WALLETCONNECT_PROJECT_ID = 'a03ac1695f309dc8d756e7b4006e5e7d';\n\nexport type ConnectOptions = { chainIds: number[]; walletConnectProjectId?: string };\n\ntype ConnectGlobal = { version?: string; capabilities?: string[]; ready?: Promise<unknown> };\ntype EthProviderGlobal = {\n selectedAddress?: () => string | undefined;\n chainId?: () => number | undefined;\n provider?: (withSigner?: boolean) => { provider?: EIP1193Provider } | undefined;\n browserChainId?: () => number | undefined;\n browserProvider?: () => { provider?: EIP1193Provider } | undefined;\n};\nconst STATE_KEY = '__manifoldMintConnectStateV1';\ntype LoadState = { promise: Promise<void>; networks: number[]; projectId?: string; div?: HTMLElement; nodes: Node[] };\ntype PageState = { load?: LoadState; pendingModal?: Promise<'connected' | 'dismissed'> };\ntype Win = Window & { [LOADER_KEY]?: Promise<void>; [STATE_KEY]?: PageState; ManifoldConnect?: ConnectGlobal; ManifoldEthereumProvider?: EthProviderGlobal };\nconst win = () => window as unknown as Win;\n// Lazily accessed so importing this module never reads window during SSR.\nconst pageState = (): PageState => (win()[STATE_KEY] ??= {});\n\nconst TOO_OLD = 'A Manifold connect widget older than 6.4.0 is already on this page; update it or remove it so dropkit can load ' + CONNECT_WIDGET_VERSION + '.';\n\nconst MANIFOLD_HOST = /(^|\\.)(manifoldxyz\\.dev|manifold\\.xyz)$/;\n\n/** Only Manifold connect-widget bundles count as an old widget: connect.manifoldxyz.dev, or connect.umd*.js on a Manifold host. */\nfunction isManifoldConnectScript(src: string): boolean {\n try {\n const url = new URL(src, document.baseURI);\n return url.hostname === 'connect.manifoldxyz.dev' || (MANIFOLD_HOST.test(url.hostname) && /\\/connect\\.umd[^/]*\\.js$/.test(url.pathname));\n } catch {\n return false;\n }\n}\n\nfunction applyState(state: LoadState): void {\n if (!state.div) return;\n const network = state.networks.join(',');\n // Connect 6.4 remounts on every attribute mutation, even an identical value.\n if (state.div.dataset.network !== network) state.div.dataset.network = network;\n // A caller's id wins; otherwise keep a host page's own id, else use Manifold's default.\n const projectId = state.projectId ?? state.div.dataset.walletConnectProjectId ?? DEFAULT_WALLETCONNECT_PROJECT_ID;\n if (state.div.dataset.walletConnectProjectId !== projectId) state.div.dataset.walletConnectProjectId = projectId;\n}\n\n/** Adds a caller's chains (first-call order) and promotes the first nonempty project id; a conflicting later id only warns. */\nfunction register(state: LoadState, opts: ConnectOptions): void {\n for (const id of opts.chainIds) if (!state.networks.includes(id)) state.networks.push(id);\n const id = opts.walletConnectProjectId;\n if (id) {\n if (!state.projectId) state.projectId = id;\n else if (state.projectId !== id) {\n console.warn(`dropkit: walletConnectProjectId \"${id}\" ignored; this page already uses \"${state.projectId}\" for the shared connect widget.`);\n }\n }\n applyState(state);\n}\n\nfunction startLoad(state: LoadState): Promise<void> {\n const connect = win().ManifoldConnect;\n if (connect?.capabilities?.includes('open')) return Promise.resolve(connect.ready).then(() => undefined);\n\n const hasScript = Array.from(document.querySelectorAll('script[src]')).some((s) => isManifoldConnectScript((s as HTMLScriptElement).src));\n if (hasScript || document.querySelector('[data-widget=\"m-connect\"]')) {\n return Promise.reject(new MintError('CONNECT_WIDGET_TOO_OLD', TOO_OLD));\n }\n\n return new Promise<void>((resolve, reject) => {\n const css = document.createElement('link');\n css.rel = 'stylesheet';\n css.href = `${CONNECT_BASE_URL}/connect.css`;\n document.head.appendChild(css);\n state.nodes.push(css);\n\n const div = document.createElement('div');\n div.hidden = true;\n div.style.display = 'none';\n div.dataset.widget = 'm-connect';\n div.dataset.connectId = CONNECT_ID;\n div.dataset.autoReconnect = 'true';\n div.dataset.enableNetworkSwitching = 'true';\n state.div = div;\n applyState(state);\n document.body.appendChild(div);\n state.nodes.push(div);\n\n const script = document.createElement('script');\n script.src = `${CONNECT_BASE_URL}/connect.umd.min.js`;\n script.async = true;\n script.addEventListener('load', () => {\n const ready = win().ManifoldConnect?.ready;\n if (!ready) return reject(new MintError('CONNECT_WIDGET_TOO_OLD', TOO_OLD));\n Promise.resolve(ready).then(() => resolve(), reject);\n });\n script.addEventListener('error', () => reject(new MintError('RPC_ERROR', `Could not load the Manifold connect widget from ${CONNECT_BASE_URL}`)));\n document.head.appendChild(script);\n state.nodes.push(script);\n });\n}\n\n/**\n * Idempotent across buttons, React Strict Mode and repeated calls: the promise is stored on\n * window[LOADER_KEY] BEFORE anything is appended. Order: window.ManifoldConnect lists 'open' -> reuse;\n * else an existing Manifold connect script tag or [data-widget=\"m-connect\"] -> reject MintError('CONNECT_WIDGET_TOO_OLD')\n * and inject nothing; else inject CONNECT_BASE_URL/connect.umd.min.js + connect.css and one hidden\n * <div data-widget=\"m-connect\" data-connect-id=\"mint-button\" data-auto-reconnect=\"true\"\n * data-enable-network-switching=\"true\" data-network=\"<ids joined by ,>\" [data-wallet-connect-project-id]>,\n * then await window.ManifoldConnect.ready. Every caller (also after load) adds its chains to the one widget's\n * data-network and may promote the first nonempty project id. A failed load clears window[LOADER_KEY] and\n * removes the nodes it created, so the next call retries.\n */\nexport function loadConnectWidget(opts: ConnectOptions): Promise<void> {\n const w = win();\n const page = pageState();\n const existing = w[LOADER_KEY];\n if (existing) {\n // Adopt a legacy promise without replacing it or taking ownership of its DOM.\n if (page.load?.promise !== existing) {\n const div = document.querySelector<HTMLElement>(`[data-widget=\"m-connect\"][data-connect-id=\"${CONNECT_ID}\"]`) ?? undefined;\n page.load = {\n promise: existing,\n networks: div?.dataset.network?.split(',').filter(Boolean).map(Number) ?? [],\n // The default id is a placeholder, not a choice: a caller's real id may still replace it.\n projectId: div?.dataset.walletConnectProjectId === DEFAULT_WALLETCONNECT_PROJECT_ID ? undefined : div?.dataset.walletConnectProjectId,\n div,\n nodes: [],\n };\n }\n register(page.load, opts);\n return existing;\n }\n let resolve!: () => void;\n let reject!: (reason: unknown) => void;\n const p = new Promise<void>((res, rej) => { resolve = res; reject = rej; });\n const state: LoadState = { promise: p, networks: [], nodes: [] };\n // Publish before DOM insertion: synchronous observers and other copies must see the same load.\n page.load = state;\n w[LOADER_KEY] = p;\n p.catch(() => {\n if (w[LOADER_KEY] === p) delete w[LOADER_KEY];\n if (page.load === state) page.load = undefined;\n for (const node of state.nodes) node.parentNode?.removeChild(node);\n state.nodes.length = 0;\n state.div = undefined;\n });\n register(state, opts);\n try {\n startLoad(state).then(resolve, reject);\n } catch (error) {\n reject(error);\n }\n return p;\n}\n\n/**\n * Dispatches m-connect:open {connectId: CONNECT_ID}; resolves with the next m-connect:closed reason.\n * Calls made before that close share one pending promise and one listener.\n */\nexport function openConnectModal(): Promise<'connected' | 'dismissed'> {\n const page = pageState();\n if (page.pendingModal) return page.pendingModal;\n const p = new Promise<'connected' | 'dismissed'>((resolve) => {\n const onClosed = (e: Event) => {\n const detail = (e as CustomEvent<{ connectId?: string; reason?: string }>).detail ?? {};\n if (detail.connectId !== undefined && detail.connectId !== CONNECT_ID) return;\n window.removeEventListener('m-connect:closed', onClosed);\n page.pendingModal = undefined;\n resolve(detail.reason === 'connected' ? 'connected' : 'dismissed');\n };\n window.addEventListener('m-connect:closed', onClosed);\n });\n page.pendingModal = p;\n window.dispatchEvent(new CustomEvent('m-connect:open', { detail: { connectId: CONNECT_ID } }));\n return p;\n}\n\n/**\n * From window.ManifoldEthereumProvider.selectedAddress()/chainId(); null when not connected.\n * When the wallet is on a chain outside the widget's data-network, chainId() is undefined, so the\n * chain falls back to browserChainId() (the wallet's real chain, updated before CHAIN_CHANGED fires).\n * chainId() wins when present; a throwing browserChainId() counts as unknown (null).\n */\nexport function getAccount(): Account | null {\n const p = win().ManifoldEthereumProvider;\n const address = p?.selectedAddress?.();\n let chainId = p?.chainId?.();\n if (chainId === undefined || chainId === null) {\n try {\n chainId = p?.browserChainId?.();\n } catch {\n chainId = undefined;\n }\n }\n if (!address || chainId === undefined || chainId === null) return null;\n return { address: getAddress(address), chainId: Number(chainId) };\n}\n\n/** Calls cb(getAccount()) on ADDRESS_CHANGED and CHAIN_CHANGED window events. Returns unsubscribe. */\nexport function subscribeAccount(cb: (account: Account | null) => void): () => void {\n const handler = () => cb(getAccount());\n window.addEventListener(ADDRESS_CHANGED, handler);\n window.addEventListener(CHAIN_CHANGED, handler);\n return () => {\n window.removeEventListener(ADDRESS_CHANGED, handler);\n window.removeEventListener(CHAIN_CHANGED, handler);\n };\n}\n\nfunction eip1193(): EIP1193Provider {\n const p = win().ManifoldEthereumProvider;\n const provider = (p?.provider?.(true) ?? p?.browserProvider?.())?.provider;\n if (!provider) throw new MintError('CHAIN_SWITCH_FAILED', 'No wallet is connected.');\n return provider;\n}\n\n/** viem WalletClient over (ManifoldEthereumProvider.provider(true) ?? browserProvider()).provider. */\nexport function getWalletClient(chainId: number): WalletClient {\n const provider = eip1193();\n // viem's custom() forwards a second options argument; wallet providers take exactly one.\n const request = ((args: Parameters<EIP1193Provider['request']>[0]) => provider.request(args)) as EIP1193Provider['request'];\n return createWalletClient({ chain: getChain(chainId), transport: custom({ request }) });\n}\n\nexport type DepositOutcome = 'mined' | 'reverted' | 'unknown';\n\n/**\n * Waits for a Relay deposit through the wallet's own provider (D14). Only a reverted receipt is final;\n * anything else ('unknown': no receipt in time) keeps polling Relay, same as claim-widgets.\n */\nexport async function waitForDeposit(chainId: number, hash: Hex, timeoutMs = 120_000): Promise<DepositOutcome> {\n try {\n const receipt = await getWalletClient(chainId).extend(publicActions).waitForTransactionReceipt({ hash, confirmations: 1, timeout: timeoutMs });\n return receipt.status === 'reverted' ? 'reverted' : 'mined';\n } catch {\n return 'unknown';\n }\n}\n\n/** A wallet that never answers must not wedge the button (N3). Mutable for tests. */\nexport const WALLET_READ_TIMEOUT = { ms: 10_000 };\n\n/**\n * Native balance of `address` on `chainId`, read through the connected wallet's own provider (spec D14):\n * the wallet is the only provider Dropkit can count on for a chain other than the drop chain.\n * Throws MintError('CHAIN_SWITCH_FAILED') when the wallet is not on `chainId`.\n */\nexport async function getConnectedBalance(address: Address, chainId: number): Promise<bigint> {\n const provider = eip1193();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new MintError('RPC_ERROR', 'The wallet did not report a balance in time.')), WALLET_READ_TIMEOUT.ms);\n });\n try {\n return await Promise.race([\n (async () => {\n const current = Number(await provider.request({ method: 'eth_chainId' }));\n if (current !== chainId) {\n throw new MintError('CHAIN_SWITCH_FAILED', `The wallet is on chain ${String(current)}, not ${String(chainId)}.`);\n }\n const hex = await provider.request({ method: 'eth_getBalance', params: [address, 'latest'] });\n return BigInt(hex as string);\n })(),\n timeout,\n ]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nconst code = (e: unknown): unknown => (e as { code?: unknown } | null)?.code;\n\ntype Eip1193Request = EIP1193Provider['request'];\nconst hexChainId = (chainId: number): Hex => `0x${chainId.toString(16)}`;\n\n/** The one wallet_switchEthereumChain request body, shared by switchToChain and requestSwitch. */\nconst sendSwitchRequest = (provider: { request: Eip1193Request }, chainId: number) =>\n provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: hexChainId(chainId) }] });\n\n/** The one wallet_addEthereumChain request body (from getChain), shared by switchToChain and requestAddChain. */\nconst sendAddRequest = (provider: { request: Eip1193Request }, chainId: number) => {\n const chain = getChain(chainId);\n return provider.request({\n method: 'wallet_addEthereumChain',\n params: [\n {\n chainId: hexChainId(chainId),\n chainName: chain.name,\n nativeCurrency: chain.nativeCurrency,\n rpcUrls: [...chain.rpcUrls.default.http],\n ...(chain.blockExplorers ? { blockExplorerUrls: [chain.blockExplorers.default.url] } : {}),\n },\n ],\n });\n};\n\n/** 4001 -> USER_REJECTED; anything else -> CHAIN_SWITCH_FAILED. */\nfunction chainRequestError(e: unknown, chainId: number): MintError {\n if (code(e) === 4001) return new MintError('USER_REJECTED', 'You rejected the network switch.', { cause: e });\n return new MintError('CHAIN_SWITCH_FAILED', `Could not switch the wallet to chain ${String(chainId)}.`, { cause: e });\n}\n\n/**\n * wallet_switchEthereumChain; on error code 4902 wallet_addEthereumChain (from getChain) then switch again.\n * 4001 -> MintError('USER_REJECTED'); anything else -> MintError('CHAIN_SWITCH_FAILED').\n */\nexport async function switchToChain(chainId: number): Promise<void> {\n getChain(chainId);\n const provider = eip1193();\n try {\n try {\n await sendSwitchRequest(provider, chainId);\n } catch (e) {\n if (code(e) !== 4902) throw e;\n await sendAddRequest(provider, chainId);\n await sendSwitchRequest(provider, chainId);\n }\n } catch (e) {\n throw chainRequestError(e, chainId);\n }\n}\n\n/**\n * Sends wallet_switchEthereumChain and nothing else (one wallet request, for the cart).\n * Error 4902 (unknown chain) returns { needsAdd: true } and sends nothing more; the caller adds the chain on its own click.\n * 4001 -> MintError('USER_REJECTED'); anything else -> MintError('CHAIN_SWITCH_FAILED').\n */\nexport async function requestSwitch(chainId: number): Promise<{ needsAdd: boolean }> {\n getChain(chainId);\n const provider = eip1193();\n try {\n await sendSwitchRequest(provider, chainId);\n return { needsAdd: false };\n } catch (e) {\n if (code(e) === 4902) return { needsAdd: true };\n throw chainRequestError(e, chainId);\n }\n}\n\n/** Sends wallet_addEthereumChain and nothing else. Same error mapping as requestSwitch. */\nexport async function requestAddChain(chainId: number): Promise<void> {\n getChain(chainId);\n const provider = eip1193();\n try {\n await sendAddRequest(provider, chainId);\n } catch (e) {\n throw chainRequestError(e, chainId);\n }\n}\n\n/** The connected wallet's EIP-1193 provider (the one getWalletClient wraps). Throws MintError('CHAIN_SWITCH_FAILED') when none. */\nexport function getWalletProvider(): EIP1193Provider {\n return eip1193();\n}\n","// Manifold Edition claim adapter. Spec #how, #data-models section 3, D3/D10. Calls the extension contract directly.\nimport {\n BaseError,\n ContractFunctionRevertedError,\n decodeErrorResult,\n encodeFunctionData,\n formatUnits,\n getAddress,\n isAddress,\n isHex,\n zeroAddress,\n zeroHash,\n type Hex,\n type PublicClient,\n} from 'viem';\nimport type { Address, DropInfo, ManifoldClaimConfig, Money } from '../../types';\nimport type { AdapterContext, HoldingsQuery, MintAdapter, MintPlan, WalletRead } from '../types';\nimport { MintError } from '../../errors';\nimport {\n CLAIM_1155_V5_ABI,\n CLAIM_1155_V7_ABI,\n CLAIM_721_V5_ABI,\n CLAIM_721_V7_ABI,\n CREATOR_ABI,\n ERC1155_BALANCE_ABI,\n ERC721_BALANCE_ABI,\n ERC20_ABI,\n EXTENSION_COMMON_ABI,\n EXTENSION_ERRORS_ABI,\n} from './abis';\nimport { fetchMerkleEntries, type MerkleEntry } from './merkle';\n\nexport type ExtensionSpec = '721' | '1155';\nexport type ExtensionAbi = 'Claim721V5Optimization' | 'Claim1155V5Optimization' | 'Claim721V7' | 'Claim1155V7';\nexport type ExtensionEntry = { chainId: number; address: Address; generation: 'V6' | 'V7' | 'V8'; spec: ExtensionSpec; abi: ExtensionAbi };\n\nconst V6_721: Address = '0x1eb73fee2090fb1c20105d5ba887e3c3ba14a17e';\nconst V6_1155: Address = '0x04ba6cf3c5aa6d4946f5b7f7adf111012a9fac65';\nconst V7_721: Address = '0x23aa05a271debffaa3d75739af5581f744b326e4';\nconst V7_1155: Address = '0x26bbea7803dcac346d5f5f135b57cf2c752a02be';\nconst V8_721: Address = '0x5889e848b2423344f7969bc158100c07595c0137';\nconst V8_1155: Address = '0x88438f4d4b8516e758a319ad16924da60e1e56cc';\n\nconst v6 = (chainId: number): ExtensionEntry[] => [\n { chainId, address: V6_721, generation: 'V6', spec: '721', abi: 'Claim721V5Optimization' },\n { chainId, address: V6_1155, generation: 'V6', spec: '1155', abi: 'Claim1155V5Optimization' },\n];\nconst v7 = (chainId: number): ExtensionEntry[] => [\n { chainId, address: V7_721, generation: 'V7', spec: '721', abi: 'Claim721V7' },\n { chainId, address: V7_1155, generation: 'V7', spec: '1155', abi: 'Claim1155V7' },\n];\n\n/**\n * Embedded registry keyed by (chainId, lowercase address). Bytecode measured with eth_getCode:\n * mainnet, Base, Optimism have V6 + V7 (identical code hashes); Shape has V7 + V8 ERC-1155 (no V6, no V8 ERC-721);\n * Sepolia has all six. V8 has no code on mainnet, Base or Optimism. ApeChain has none of the six.\n */\nexport const EXTENSIONS: readonly ExtensionEntry[] = [\n ...v6(1),\n ...v7(1),\n ...v6(8453),\n ...v7(8453),\n ...v6(10),\n ...v7(10),\n ...v7(360),\n { chainId: 360, address: V8_1155, generation: 'V8', spec: '1155', abi: 'Claim1155V7' },\n ...v6(11155111),\n ...v7(11155111),\n { chainId: 11155111, address: V8_721, generation: 'V8', spec: '721', abi: 'Claim721V7' },\n { chainId: 11155111, address: V8_1155, generation: 'V8', spec: '1155', abi: 'Claim1155V7' },\n];\n\nexport function findExtension(chainId: number, address: Address): ExtensionEntry | undefined {\n const a = address.toLowerCase();\n return EXTENSIONS.find((e) => e.chainId === chainId && e.address === a);\n}\n\nexport const MERKLE_API = 'https://apps.api.manifoldxyz.dev';\n\n/** uint16 mintCount cap of mintProxy. */\nconst MAX_MINT_COUNT = 65535;\n/** Gas units kept aside in WalletRead.gasReserve: an estimate, simulate() is the authoritative check. */\nconst GAS_UNITS_BASE = 100_000n;\nconst GAS_UNITS_PER_TOKEN = 150_000n;\nconst GAS_UNITS_APPROVE = 60_000n;\n\n// ---------- claim decoding ----------\n\ntype Claim = {\n total: bigint;\n totalMax: bigint;\n walletMax: bigint;\n startDate: bigint;\n endDate: bigint;\n merkleRoot: Hex;\n cost: bigint;\n erc20: Address;\n /** null on V6 (no signature claims). */\n signingAddress: Address | null;\n /** ERC-1155 token id minted by this claim (not the Manifold instance id); null for ERC-721. */\n tokenId: bigint | null;\n};\n\ntype Resolved = { entry: ExtensionEntry; claim: Claim; fee: bigint; creator: Address; instanceId: bigint };\n\n/** Carried from readDrop to readWallet (keyed by the DropInfo object) so readWallet does not re-discover. */\nconst dropResolved = new WeakMap<DropInfo, Resolved>();\n\n/** Carried from readWallet to buildPlan in WalletRead.data. */\ntype WalletData = {\n brand: typeof WALLET_DATA_BRAND;\n resolved: Resolved;\n config: ManifoldClaimConfig;\n recipient: Address;\n /** Allowlist only: unused (mintIndex, proof) pairs for the recipient. */\n unused: MerkleEntry[];\n};\nconst WALLET_DATA_BRAND = Symbol('manifold-claim-wallet-data');\nconst isWalletData = (d: unknown): d is WalletData => typeof d === 'object' && d !== null && (d as WalletData).brand === WALLET_DATA_BRAND;\n\nconst isAllowlist = (claim: Claim) => claim.merkleRoot !== zeroHash;\n\n// ---------- errors ----------\n\n/** Contract-level failure of an eth_call (revert or empty return), as opposed to a transport failure. */\nfunction isContractFailure(e: unknown): boolean {\n if (!(e instanceof BaseError)) return false;\n return e.walk((x) => x instanceof ContractFunctionRevertedError || (x as Error).name === 'ContractFunctionZeroDataError') !== null;\n}\n\nfunction toRpcError(e: unknown): MintError {\n if (e instanceof MintError) return e;\n const msg = e instanceof BaseError ? e.shortMessage : e instanceof Error ? e.message : String(e);\n return new MintError('RPC_ERROR', `RPC request failed: ${msg}`, { cause: e });\n}\n\nasync function rpc<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (e) {\n throw toRpcError(e);\n }\n}\n\n/** Raw revert bytes anywhere in a viem error chain. */\nfunction revertData(e: BaseError): Hex | undefined {\n const hit = e.walk((x) => {\n const d = (x as { data?: unknown }).data;\n return (isHex(d) && d.length >= 10) || (typeof d === 'object' && d !== null && isHex((d as { data?: unknown }).data));\n });\n const d = (hit as { data?: unknown } | null)?.data;\n if (isHex(d)) return d;\n const inner = (d as { data?: unknown } | undefined)?.data;\n return isHex(inner) ? inner : undefined;\n}\n\n/** Decoded revert text for a failed simulation, or null when the error is not a revert. */\nfunction decodeRevert(e: unknown): string | null {\n if (!(e instanceof BaseError)) return null;\n const data = revertData(e);\n if (data) {\n try {\n const d = decodeErrorResult({ abi: EXTENSION_ERRORS_ABI, data });\n if (d.errorName === 'Error' && typeof d.args?.[0] === 'string') return d.args[0];\n if (d.errorName === 'Panic') return `Panic(${String(d.args?.[0])})`;\n return d.errorName;\n } catch {\n return `reverted with unknown error ${data.slice(0, 10)}`;\n }\n }\n const named = e.walk((x) => ['ExecutionRevertedError', 'InsufficientFundsError'].includes((x as Error).name));\n return named instanceof BaseError ? named.shortMessage : null;\n}\n\n// ---------- reads ----------\n\nconst money = (value: bigint, decimals: number, symbol: string): Money => ({ value, decimals, symbol, formatted: formatUnits(value, decimals) });\n\nfunction timestamp(v: bigint, field: string): number | null {\n if (v === 0n) return null;\n if (v > BigInt(Number.MAX_SAFE_INTEGER)) throw new MintError('RPC_ERROR', `Claim ${field} does not fit a safe integer`);\n return Number(v);\n}\n\nfunction parseConfig(config: ManifoldClaimConfig): { creator: Address; instanceId: bigint; extension: Address | undefined } {\n if (!isAddress(config.creatorContract, { strict: false })) {\n throw new MintError('INVALID_CONFIG', 'creatorContract is not a valid address.', { field: 'creatorContract' });\n }\n if (config.extension !== undefined && !isAddress(config.extension, { strict: false })) {\n throw new MintError('INVALID_CONFIG', 'extension is not a valid address.', { field: 'extension' });\n }\n if (typeof config.instanceId !== 'string' || !/^\\d+$/.test(config.instanceId)) {\n throw new MintError('INVALID_CONFIG', 'instanceId must be a non-negative integer string.', { field: 'instanceId' });\n }\n return {\n creator: getAddress(config.creatorContract),\n instanceId: BigInt(config.instanceId),\n extension: config.extension === undefined ? undefined : getAddress(config.extension),\n };\n}\n\nconst notFound = (config: ManifoldClaimConfig) =>\n new MintError('CLAIM_NOT_FOUND', `No Manifold claim ${config.instanceId} found on ${config.creatorContract}.`);\n\n/** getClaim with the exact ABI for the entry. Contract failures throw CLAIM_NOT_FOUND, transport failures RPC_ERROR. */\nasync function readClaim(client: PublicClient, entry: ExtensionEntry, creator: Address, instanceId: bigint, config: ManifoldClaimConfig): Promise<Claim> {\n const address = getAddress(entry.address);\n const args = [creator, instanceId] as const;\n try {\n switch (entry.abi) {\n case 'Claim721V5Optimization': {\n const c = await client.readContract({ address, abi: CLAIM_721_V5_ABI, functionName: 'getClaim', args });\n return { ...base(c), signingAddress: null, tokenId: null };\n }\n case 'Claim1155V5Optimization': {\n const c = await client.readContract({ address, abi: CLAIM_1155_V5_ABI, functionName: 'getClaim', args });\n return { ...base(c), signingAddress: null, tokenId: c.tokenId };\n }\n case 'Claim721V7': {\n const c = await client.readContract({ address, abi: CLAIM_721_V7_ABI, functionName: 'getClaim', args });\n return { ...base(c), signingAddress: c.signingAddress, tokenId: null };\n }\n case 'Claim1155V7': {\n const c = await client.readContract({ address, abi: CLAIM_1155_V7_ABI, functionName: 'getClaim', args });\n return { ...base(c), signingAddress: c.signingAddress, tokenId: c.tokenId };\n }\n }\n } catch (e) {\n // Uninitialized claims revert as ClaimNotInitialized() (0x7f07ad49) or Error(\"Claim not initialized\"); both land here.\n if (isContractFailure(e)) throw notFound(config);\n throw toRpcError(e);\n }\n}\n\nfunction base(c: {\n total: number;\n totalMax: number;\n walletMax: number;\n startDate: number;\n endDate: number;\n merkleRoot: Hex;\n cost: bigint;\n erc20: Address;\n}): Omit<Claim, 'signingAddress' | 'tokenId'> {\n return {\n total: BigInt(c.total),\n totalMax: BigInt(c.totalMax),\n walletMax: BigInt(c.walletMax),\n startDate: BigInt(c.startDate),\n endDate: BigInt(c.endDate),\n merkleRoot: c.merkleRoot,\n cost: c.cost,\n erc20: c.erc20,\n };\n}\n\nasync function hasCode(client: PublicClient, address: Address): Promise<boolean> {\n const code = await rpc(() => client.getCode({ address: getAddress(address) }));\n return code !== undefined && code !== '0x';\n}\n\nconst unknownExtension = (address: Address, why: string) => new MintError('UNKNOWN_EXTENSION', `Extension ${address} ${why}.`);\n\nasync function resolveExtension(ctx: AdapterContext, config: ManifoldClaimConfig): Promise<{ entry: ExtensionEntry; claim: Claim }> {\n const { creator, instanceId, extension } = parseConfig(config);\n const { client } = ctx;\n\n if (extension) {\n const entry = findExtension(config.chainId, extension);\n if (!entry) throw unknownExtension(extension, `is not a supported Manifold claim extension on chain ${config.chainId}`);\n if (!(await hasCode(client, extension))) throw unknownExtension(extension, 'has no contract code on this chain');\n return { entry, claim: await readClaim(client, entry, creator, instanceId, config) };\n }\n\n // Auto-discovery: registered extensions of the creator contract that are in the registry for this chain.\n let registered: readonly Address[];\n try {\n registered = await client.readContract({ address: creator, abi: CREATOR_ABI, functionName: 'getExtensions' });\n } catch (e) {\n if (isContractFailure(e)) throw notFound(config);\n throw toRpcError(e);\n }\n const candidates = [...new Set(registered.map((a) => a.toLowerCase()))]\n .map((a) => findExtension(config.chainId, a as Address))\n .filter((e): e is ExtensionEntry => e !== undefined);\n const found = await Promise.all(\n candidates.map(async (entry) => {\n if (!(await hasCode(client, entry.address))) return null;\n try {\n return { entry, claim: await readClaim(client, entry, creator, instanceId, config) };\n } catch (e) {\n if (e instanceof MintError && e.reason === 'CLAIM_NOT_FOUND') return null;\n throw e;\n }\n }),\n );\n const hits = found.filter((f): f is { entry: ExtensionEntry; claim: Claim } => f !== null);\n if (hits.length === 0) throw notFound(config);\n if (hits.length > 1) {\n throw new MintError(\n 'AMBIGUOUS_EXTENSION',\n `Claim ${config.instanceId} exists on ${hits.length} extensions (${hits.map((h) => h.entry.address).join(', ')}). Set config.extension.`,\n );\n }\n return hits[0]!;\n}\n\nasync function loadDrop(ctx: AdapterContext, config: ManifoldClaimConfig): Promise<{ drop: DropInfo; resolved: Resolved }> {\n const { entry, claim } = await resolveExtension(ctx, config);\n if (claim.signingAddress !== null && claim.signingAddress !== zeroAddress) {\n throw new MintError('SIGNATURE_CLAIM', 'This claim mints with a signature (redemption code), which this button does not support.');\n }\n const { client } = ctx;\n const extension = getAddress(entry.address);\n const fee = await rpc(() =>\n client.readContract({ address: extension, abi: EXTENSION_COMMON_ABI, functionName: isAllowlist(claim) ? 'MINT_FEE_MERKLE' : 'MINT_FEE' }),\n );\n\n const native = client.chain?.nativeCurrency ?? { symbol: 'ETH', decimals: 18 };\n let unitPrice: Money;\n let paymentToken: Address | null = null;\n if (claim.erc20 === zeroAddress) {\n unitPrice = money(claim.cost, native.decimals, native.symbol);\n } else {\n paymentToken = getAddress(claim.erc20);\n const token = paymentToken;\n const [symbol, decimals] = await rpc(() =>\n Promise.all([\n client.readContract({ address: token, abi: ERC20_ABI, functionName: 'symbol' }),\n client.readContract({ address: token, abi: ERC20_ABI, functionName: 'decimals' }),\n ]),\n );\n unitPrice = money(claim.cost, decimals, symbol);\n }\n\n const drop: DropInfo = {\n chainId: config.chainId,\n unitPrice,\n unitFee: money(fee, native.decimals, native.symbol),\n totalMinted: claim.total,\n maxSupply: claim.totalMax === 0n ? null : claim.totalMax,\n startTime: timestamp(claim.startDate, 'startDate'),\n endTime: timestamp(claim.endDate, 'endDate'),\n isAllowlist: isAllowlist(claim),\n paymentToken,\n pricePer: 'unit',\n };\n const { creator, instanceId } = parseConfig(config);\n const resolved = { entry, claim, fee, creator, instanceId };\n dropResolved.set(drop, resolved);\n return { drop, resolved };\n}\n\nasync function loadWallet(\n ctx: AdapterContext,\n config: ManifoldClaimConfig,\n args: { payer: Address; recipient: Address; quantity: number; drop: DropInfo },\n): Promise<WalletRead> {\n const { creator, instanceId } = parseConfig(config);\n const { client } = ctx;\n const resolved = dropResolved.get(args.drop) ?? (await loadDrop(ctx, config)).resolved;\n const { entry, claim } = resolved;\n const extension = getAddress(entry.address);\n const payer = getAddress(args.payer);\n const recipient = getAddress(args.recipient);\n\n let walletMinted: bigint | null = null;\n let walletMax: bigint | null = null;\n let allowlistRemaining: number | null = null;\n let maxQuantity: number | null = null;\n let ineligible: WalletRead['ineligible'] = null;\n let unused: MerkleEntry[] = [];\n\n if (isAllowlist(claim)) {\n // Branch 1: allowlist ignores walletMax and limits by unused mint indices; proofs are for the recipient.\n const entries = await fetchMerkleEntries({ scope: ctx.cacheScope ?? args.drop, api: MERKLE_API, instanceId: config.instanceId, recipient, fetch: ctx.fetch, signal: ctx.signal });\n if (entries.length > 0) {\n const minted = await rpc(() =>\n client.readContract({\n address: extension,\n abi: EXTENSION_COMMON_ABI,\n functionName: 'checkMintIndices',\n args: [creator, instanceId, entries.map((e) => e.mintIndex)],\n }),\n );\n unused = entries.filter((_, i) => minted[i] === false);\n }\n allowlistRemaining = unused.length;\n maxQuantity = unused.length;\n if (entries.length === 0) {\n ineligible = { reason: 'NOT_ON_ALLOWLIST', message: 'This wallet is not on the allowlist.' };\n } else if (unused.length === 0) {\n ineligible = { reason: 'ALLOWLIST_USED', message: 'This wallet has already used all its allowlist spots.' };\n }\n } else if (claim.walletMax > 0n) {\n // Branch 2: public with a wallet limit, counted against the recipient.\n walletMax = claim.walletMax;\n walletMinted = BigInt(\n await rpc(() => client.readContract({ address: extension, abi: EXTENSION_COMMON_ABI, functionName: 'getTotalMints', args: [recipient, creator, instanceId] })),\n );\n const left = walletMax > walletMinted ? walletMax - walletMinted : 0n;\n maxQuantity = Number(left);\n if (left === 0n) ineligible = { reason: 'WALLET_LIMIT', message: `This wallet has already minted its limit of ${walletMax}.` };\n }\n // Branch 3: public with walletMax = 0 is unlimited. getTotalMints reverts there, so it is never called.\n\n const token = claim.erc20 === zeroAddress ? null : getAddress(claim.erc20);\n const [native, erc20, gasPrice] = await rpc(() =>\n Promise.all([\n client.getBalance({ address: payer }),\n token ? client.readContract({ address: token, abi: ERC20_ABI, functionName: 'balanceOf', args: [payer] }) : Promise.resolve(null),\n client.getGasPrice(),\n ]),\n );\n const gasUnits = GAS_UNITS_BASE + GAS_UNITS_PER_TOKEN * BigInt(Math.max(1, args.quantity)) + (token ? GAS_UNITS_APPROVE : 0n);\n\n const data: WalletData = { brand: WALLET_DATA_BRAND, resolved, config, recipient, unused };\n return {\n walletMinted,\n walletMax,\n allowlistRemaining,\n maxQuantity,\n ineligible,\n balances: { native, erc20 },\n gasReserve: gasPrice * gasUnits,\n data,\n };\n}\n\n// ---------- plan + simulate ----------\n\nconst sameClaim = (a: ManifoldClaimConfig, b: ManifoldClaimConfig) =>\n a.chainId === b.chainId &&\n a.creatorContract.toLowerCase() === b.creatorContract.toLowerCase() &&\n a.instanceId === b.instanceId &&\n a.extension?.toLowerCase() === b.extension?.toLowerCase();\n\nasync function buildPlan(ctx: AdapterContext, attempt: Parameters<MintAdapter<ManifoldClaimConfig>['buildPlan']>[1], wallet: WalletRead): Promise<MintPlan> {\n const { config, quantity } = attempt;\n if (!Number.isInteger(quantity) || quantity < 1 || quantity > MAX_MINT_COUNT) {\n throw new MintError('INVALID_CONFIG', `quantity must be an integer from 1 to ${MAX_MINT_COUNT}.`, { field: 'quantity' });\n }\n const { creator, instanceId } = parseConfig(config);\n const recipient = getAddress(attempt.recipient);\n const payer = getAddress(attempt.payer);\n\n // Proofs belong to the recipient they were fetched for; anything else is re-read.\n let data = wallet.data;\n if (!isWalletData(data) || !sameClaim(data.config, config) || data.recipient !== recipient) {\n const drop = (await loadDrop(ctx, config)).drop;\n data = (await loadWallet(ctx, config, { payer, recipient, quantity, drop })).data;\n }\n if (!isWalletData(data)) throw new MintError('RPC_ERROR', 'Wallet read produced no plan data.');\n const { entry, claim, fee } = data.resolved;\n const extension = getAddress(entry.address);\n\n let mintIndices: number[] = [];\n let merkleProofs: (readonly Hex[])[] = [];\n if (isAllowlist(claim)) {\n if (quantity > data.unused.length) {\n throw new MintError('WALLET_LIMIT', `Only ${data.unused.length} allowlist spot(s) left for this wallet.`);\n }\n const picked = data.unused.slice(0, quantity);\n mintIndices = picked.map((p) => p.mintIndex);\n merkleProofs = picked.map((p) => p.proof);\n }\n\n const qty = BigInt(quantity);\n const erc20 = claim.erc20 === zeroAddress ? null : getAddress(claim.erc20);\n const cost = claim.cost * qty;\n const value = fee * qty + (erc20 ? 0n : cost);\n\n let approve: MintPlan['approve'] = null;\n if (erc20 && cost > 0n) {\n const allowance = await rpc(() => ctx.client.readContract({ address: erc20, abi: ERC20_ABI, functionName: 'allowance', args: [payer, extension] }));\n if (allowance < cost) {\n approve = {\n token: erc20,\n spender: extension,\n amount: cost,\n tx: { to: erc20, data: encodeFunctionData({ abi: ERC20_ABI, functionName: 'approve', args: [extension, cost] }), value: 0n },\n };\n }\n }\n\n return {\n approve,\n mint: {\n to: extension,\n data: encodeFunctionData({\n abi: EXTENSION_COMMON_ABI,\n functionName: 'mintProxy',\n args: [creator, instanceId, quantity, mintIndices, merkleProofs.map((p) => [...p]), recipient],\n }),\n value,\n },\n tokenContract: creator,\n };\n}\n\n/**\n * Extension generations whose deployed mintProxy mints to mintFor and checks proofs and walletMax\n * against mintFor (spec D12, verified from Sourcify source on chain 1). V8 has no verified source.\n */\nexport const RELAY_VERIFIED: readonly ExtensionEntry['generation'][] = ['V6', 'V7'];\n\n/**\n * What counts a recipient's holdings of this claim (cart settlement). getTotalMints answers only for a non-allowlist\n * claim with a wallet limit; the extension reverts otherwise (\"Can only retrieve for non-merkle claims with\n * walletMax\", seen on Sepolia V7). Every other claim uses the token balance on the creator contract (ERC-1155 by the\n * claim's token id, which is not the instance id). null when the drop did not come from readDrop.\n */\nfunction holdingsQueryFor(drop: DropInfo, purpose: 'settle' | 'display' = 'settle'): HoldingsQuery | null {\n const resolved = dropResolved.get(drop);\n if (!resolved) return null;\n const { entry, claim, creator, instanceId } = resolved;\n if (purpose === 'display') {\n // What the wallet holds of THIS drop now: an 1155 token balance counts transfers in and out. A 721 balance\n // counts the whole contract, so a 721 drop shows mints from this drop where the extension can count them\n // (non-allowlist claims with a wallet limit), else the contract balance.\n if (entry.spec === '1155') {\n if (claim.tokenId === null) return null;\n return { kind: 'balance-1155', creatorContract: creator, tokenId: claim.tokenId.toString() };\n }\n if (!isAllowlist(claim) && claim.walletMax > 0n) {\n return { kind: 'total-mints', extension: getAddress(entry.address), creatorContract: creator, instanceId: instanceId.toString() };\n }\n return { kind: 'balance-721', creatorContract: creator };\n }\n if (!isAllowlist(claim) && claim.walletMax > 0n) {\n return { kind: 'total-mints', extension: getAddress(entry.address), creatorContract: creator, instanceId: instanceId.toString() };\n }\n if (entry.spec === '1155') {\n if (claim.tokenId === null) return null;\n return { kind: 'balance-1155', creatorContract: creator, tokenId: claim.tokenId.toString() };\n }\n return { kind: 'balance-721', creatorContract: creator };\n}\n\nasync function readHoldings(ctx: AdapterContext, query: HoldingsQuery, recipient: Address): Promise<bigint> {\n const { client } = ctx;\n const owner = getAddress(recipient);\n switch (query.kind) {\n case 'total-mints':\n return BigInt(\n await rpc(() =>\n client.readContract({\n address: getAddress(query.extension),\n abi: EXTENSION_COMMON_ABI,\n functionName: 'getTotalMints',\n args: [owner, getAddress(query.creatorContract), BigInt(query.instanceId)],\n }),\n ),\n );\n case 'balance-1155':\n return rpc(() =>\n client.readContract({ address: getAddress(query.creatorContract), abi: ERC1155_BALANCE_ABI, functionName: 'balanceOf', args: [owner, BigInt(query.tokenId)] }),\n );\n case 'balance-721':\n return rpc(() => client.readContract({ address: getAddress(query.creatorContract), abi: ERC721_BALANCE_ABI, functionName: 'balanceOf', args: [owner] }));\n }\n}\n\nexport const manifoldClaimAdapter: MintAdapter<ManifoldClaimConfig> = {\n holdingsQuery: holdingsQueryFor,\n readHoldings,\n supportsRelay: (drop) => {\n const resolved = dropResolved.get(drop);\n return resolved !== undefined && RELAY_VERIFIED.includes(resolved.entry.generation) && drop.paymentToken === null;\n },\n readDrop: async (ctx, config) => (await loadDrop(ctx, config)).drop,\n readWallet: loadWallet,\n buildPlan,\n simulate: async (ctx, attempt, plan) => {\n try {\n await ctx.client.call({ account: getAddress(attempt.payer), to: plan.mint.to, data: plan.mint.data, value: plan.mint.value });\n } catch (e) {\n const text = decodeRevert(e);\n if (text === null) throw toRpcError(e);\n throw new MintError('SIMULATION_REVERTED', text, { cause: e });\n }\n },\n};\n","// Embedded viem ABI fragments for the supported Manifold Edition claim extensions (spec #data-models section 3).\n// Source: @manifoldxyz/claim-contracts 3.3.0 (src/abis). getClaim is the only function whose shape differs:\n// 721 and 1155 tuples differ within one generation (721 has contractVersion/identical, 1155 has tokenId),\n// and V7 adds signingAddress. Each (generation, spec) gets its own exact fragment; nothing is decoded by position.\nimport { parseAbi } from 'viem';\n\nexport const CLAIM_721_V5_ABI = parseAbi([\n 'function getClaim(address creatorContractAddress, uint256 instanceId) view returns ((uint32 total, uint32 totalMax, uint32 walletMax, uint48 startDate, uint48 endDate, uint8 storageProtocol, uint8 contractVersion, bool identical, bytes32 merkleRoot, string location, uint256 cost, address paymentReceiver, address erc20) claim)',\n]);\n\nexport const CLAIM_1155_V5_ABI = parseAbi([\n 'function getClaim(address creatorContractAddress, uint256 instanceId) view returns ((uint32 total, uint32 totalMax, uint32 walletMax, uint48 startDate, uint48 endDate, uint8 storageProtocol, bytes32 merkleRoot, string location, uint256 tokenId, uint256 cost, address paymentReceiver, address erc20) claim)',\n]);\n\nexport const CLAIM_721_V7_ABI = parseAbi([\n 'function getClaim(address creatorContractAddress, uint256 instanceId) view returns ((uint32 total, uint32 totalMax, uint32 walletMax, uint48 startDate, uint48 endDate, uint8 storageProtocol, uint8 contractVersion, bool identical, bytes32 merkleRoot, string location, uint256 cost, address paymentReceiver, address erc20, address signingAddress) claim)',\n]);\n\nexport const CLAIM_1155_V7_ABI = parseAbi([\n 'function getClaim(address creatorContractAddress, uint256 instanceId) view returns ((uint32 total, uint32 totalMax, uint32 walletMax, uint48 startDate, uint48 endDate, uint8 storageProtocol, bytes32 merkleRoot, string location, uint256 tokenId, uint256 cost, address paymentReceiver, address erc20, address signingAddress) claim)',\n]);\n\n/** Identical on all four extension ABIs. */\nexport const EXTENSION_COMMON_ABI = parseAbi([\n 'function MINT_FEE() view returns (uint256)',\n 'function MINT_FEE_MERKLE() view returns (uint256)',\n 'function getTotalMints(address minter, address creatorContractAddress, uint256 instanceId) view returns (uint32)',\n 'function checkMintIndices(address creatorContractAddress, uint256 instanceId, uint32[] mintIndices) view returns (bool[] minted)',\n 'function mintProxy(address creatorContractAddress, uint256 instanceId, uint16 mintCount, uint32[] mintIndices, bytes32[][] merkleProofs, address mintFor) payable',\n]);\n\n/** Custom errors used by the V7 generation, plus the two built-in Solidity errors. */\nexport const EXTENSION_ERRORS_ABI = parseAbi([\n 'error Error(string message)',\n 'error Panic(uint256 code)',\n 'error ClaimInactive()',\n 'error ClaimNotInitialized()',\n 'error ExpiredSignature()',\n 'error FailedToTransfer()',\n 'error InvalidAirdrop()',\n 'error InvalidInput()',\n 'error InvalidInstance()',\n 'error InvalidSignature()',\n 'error InvalidStartDate()',\n 'error InvalidStorageProtocol()',\n 'error MustUseSignatureMinting()',\n 'error TokenDNE()',\n 'error TooManyRequested()',\n]);\n\n/** Creator core: registered extensions, for auto-discovery. */\nexport const CREATOR_ABI = parseAbi(['function getExtensions() view returns (address[])']);\n\nexport const ERC20_ABI = parseAbi([\n 'function symbol() view returns (string)',\n 'function decimals() view returns (uint8)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n]);\n\n/** Creator contract balances, for holdings counts (cart settlement). */\nexport const ERC1155_BALANCE_ABI = parseAbi(['function balanceOf(address account, uint256 id) view returns (uint256)']);\nexport const ERC721_BALANCE_ABI = parseAbi(['function balanceOf(address owner) view returns (uint256)']);\n","// Manifold public merkle API client (spec #api-endpoints, D10). Two calls per allowlist wallet read:\n// instance data (merkleTreeId, appId) then merkleInfo for the recipient. All HTTP goes through ctx.fetch.\nimport { MintError } from '../../errors';\nimport type { Address } from '../../types';\n\nexport type MerkleEntry = { mintIndex: number; proof: readonly `0x${string}`[] };\n\nconst UINT32_MAX = 0xffffffff;\n\ntype Fetch = typeof fetch;\n\nasync function getJson(fetchFn: Fetch, url: string, signal: AbortSignal | undefined, what: string): Promise<unknown> {\n let res: Response;\n try {\n signal?.throwIfAborted();\n res = await fetchFn(url, signal ? { signal } : undefined);\n } catch (cause) {\n throw new MintError('ALLOWLIST_UNAVAILABLE', `Could not reach the allowlist service (${what}).`, { cause });\n }\n if (res.status === 429) throw new MintError('RATE_LIMITED', 'The allowlist service is rate limiting requests. Try again shortly.');\n if (!res.ok) throw new MintError('ALLOWLIST_UNAVAILABLE', `The allowlist service has no data for this claim (${what}: HTTP ${res.status}).`);\n try {\n return await res.json();\n } catch (cause) {\n throw new MintError('ALLOWLIST_UNAVAILABLE', `The allowlist service returned an unreadable response (${what}).`, { cause });\n }\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null;\n\ntype Instance = { merkleTreeId: string | number; appId: string | number };\n\n/** Both API caches belong to a hook/config lifetime, not a refresh or another consumer. */\ntype ScopeCache = {\n signal: AbortSignal | undefined;\n instances: Map<string, Promise<Instance>>;\n entries: Map<string, Promise<MerkleEntry[]>>;\n};\nconst scopeCaches = new WeakMap<object, ScopeCache>();\n\nfunction memo<T>(cache: Map<string, Promise<T>>, key: string, signal: AbortSignal | undefined, load: () => Promise<T>): Promise<T> {\n const hit = cache.get(key);\n if (hit) return hit;\n const p = withSignal(load(), signal);\n cache.set(key, p);\n p.catch(() => {\n if (cache.get(key) === p) cache.delete(key);\n });\n return p;\n}\n\n/** Reject and evict cancelled loads even if an injected fetch ignores the shared lifetime signal. */\nfunction withSignal<T>(p: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return p;\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(new MintError('ALLOWLIST_UNAVAILABLE', 'The allowlist request was cancelled.', { cause: signal.reason }));\n p.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort));\n if (signal.aborted) return onAbort();\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nasync function loadInstance(fetchFn: Fetch, api: string, instanceId: string, signal: AbortSignal | undefined): Promise<Instance> {\n const instance = await getJson(fetchFn, `${api}/public/instance/data?id=${instanceId}`, signal, 'instance data');\n const publicData = isRecord(instance) ? instance.publicData : undefined;\n const allowlist = isRecord(publicData) ? publicData.instanceAllowlist : undefined;\n const merkleTreeId = isRecord(allowlist) ? allowlist.merkleTreeId : undefined;\n const appId = isRecord(instance) ? instance.appId : undefined;\n if ((typeof merkleTreeId !== 'number' && typeof merkleTreeId !== 'string') || (typeof appId !== 'number' && typeof appId !== 'string')) {\n throw new MintError('ALLOWLIST_UNAVAILABLE', 'The allowlist for this claim is not published yet.');\n }\n return { merkleTreeId, appId };\n}\n\nasync function loadEntries(fetchFn: Fetch, api: string, instanceId: string, recipient: Address, scoped: ScopeCache): Promise<MerkleEntry[]> {\n const { signal } = scoped;\n const { merkleTreeId, appId } = await memo(scoped.instances, `${api}|${instanceId}`, signal, () => loadInstance(fetchFn, api, instanceId, signal));\n const url = `${api}/public/merkleTree/${encodeURIComponent(String(merkleTreeId))}/merkleInfo?address=${recipient}&appId=${encodeURIComponent(String(appId))}`;\n const body = await getJson(fetchFn, url, signal, 'merkle info');\n if (!Array.isArray(body)) throw new MintError('ALLOWLIST_UNAVAILABLE', 'The allowlist service returned an unexpected response.');\n return body.map((row): MerkleEntry => {\n const proof = isRecord(row) ? row.merkleProof : undefined;\n const value = isRecord(row) ? row.value : undefined;\n if (\n !Array.isArray(proof) ||\n !proof.every((p) => typeof p === 'string' && /^0x[0-9a-fA-F]{64}$/.test(p)) ||\n typeof value !== 'number' ||\n !Number.isInteger(value) ||\n value < 0 ||\n value > UINT32_MAX\n ) {\n throw new MintError('ALLOWLIST_UNAVAILABLE', 'The allowlist service returned an unexpected response.');\n }\n return { mintIndex: value, proof: proof as `0x${string}`[] };\n });\n}\n\n/** (mintIndex, proof) pairs for `recipient` on the claim's allowlist. [] = not on the list. */\nexport async function fetchMerkleEntries(args: {\n scope: object;\n api: string;\n instanceId: string;\n recipient: Address;\n fetch: Fetch | undefined;\n signal: AbortSignal | undefined;\n}): Promise<MerkleEntry[]> {\n if (args.signal?.aborted) {\n throw new MintError('ALLOWLIST_UNAVAILABLE', 'The allowlist request was cancelled.', { cause: args.signal.reason });\n }\n const fetchFn: Fetch = args.fetch ?? ((input, init) => globalThis.fetch(input, init));\n const key = `${args.api}|${args.instanceId}|${args.recipient.toLowerCase()}`;\n let scoped = scopeCaches.get(args.scope);\n // A reused scope with a fresh lifetime must not inherit an aborted load or stale instance data.\n if (!scoped || scoped.signal?.aborted) {\n scoped = { signal: args.signal, instances: new Map(), entries: new Map() };\n scopeCaches.set(args.scope, scoped);\n }\n const cache = scoped;\n const entries = await memo(cache.entries, key, cache.signal, () => loadEntries(fetchFn, args.api, args.instanceId, args.recipient, cache));\n return entries.slice();\n}\n","// Shared receipt parsing (orchestrator-owned, spec #edge-cases \"Receipt has other Transfer logs\").\nimport { decodeAbiParameters, getAddress, zeroAddress } from 'viem';\nimport type { Address, MintedToken } from '../types';\nimport type { ParseReceiptArgs, ReceiptLog } from './types';\n\n// keccak256 of the event signatures\nexport const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';\nexport const TRANSFER_SINGLE_TOPIC = '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62';\nexport const TRANSFER_BATCH_TOPIC = '0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb';\n\nconst topicAddress = (t: string | undefined): Address | null =>\n t && t.length === 66 ? getAddress(`0x${t.slice(26)}`) : null;\n\n/**\n * Mints to recipient emitted by tokenContract: ERC721 Transfer (4 topics), ERC1155 TransferSingle and\n * TransferBatch, with from = 0x0 and to = recipient. Batch ids/amounts are zipped (lengths must match,\n * else the log is skipped); duplicate token ids are aggregated; order of first appearance is kept.\n */\nexport function parseMintReceipt(logs: readonly ReceiptLog[], { tokenContract, recipient }: ParseReceiptArgs): MintedToken[] {\n const contract = getAddress(tokenContract);\n const to = getAddress(recipient);\n const out = new Map<bigint, bigint>();\n const add = (id: bigint, amount: bigint) => out.set(id, (out.get(id) ?? 0n) + amount);\n for (const log of logs) {\n if (getAddress(log.address) !== contract) continue;\n const [t0, t1, t2, t3] = log.topics;\n if (t0 === TRANSFER_TOPIC && log.topics.length === 4) {\n if (topicAddress(t1) !== zeroAddress || topicAddress(t2) !== to || !t3) continue;\n add(BigInt(t3), 1n);\n } else if (t0 === TRANSFER_SINGLE_TOPIC && log.topics.length === 4) {\n if (topicAddress(t2) !== zeroAddress || topicAddress(t3) !== to) continue;\n const [id, value] = decodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], log.data);\n add(id, value);\n } else if (t0 === TRANSFER_BATCH_TOPIC && log.topics.length === 4) {\n if (topicAddress(t2) !== zeroAddress || topicAddress(t3) !== to) continue;\n const [ids, values] = decodeAbiParameters([{ type: 'uint256[]' }, { type: 'uint256[]' }], log.data);\n if (ids.length !== values.length) continue;\n ids.forEach((id, i) => add(id, values[i]!));\n }\n }\n return [...out].map(([tokenId, amount]) => ({ contract, tokenId, amount }));\n}\n","// Manifold's mint record for a claim mint, the same request the Manifold claim widget sends\n// (claim-widgets src/api/apps.ts postTransaction, called from src/lib/transactionsFlow/steps/mint.tsx).\n//\n// After a mint transaction is sent, the widget calls POST {apps API}/public/instance/tx with appId, instanceId and\n// hash in the query string. dropkit sends the same request so its claim mints are recorded like the widget's.\n//\n// Fire and forget: it never throws, never delays the mint, and is not cancelled by unmount (keepalive, no lifetime\n// signal), so a collector who closes the tab right after sending still gets recorded.\nimport type { Hex } from './types';\n\nexport const APPS_API = 'https://apps.api.manifoldxyz.dev';\n\ntype Fetch = typeof fetch;\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null;\n\n/** instanceId -> the claim's Studio appId, for the page lifetime. Failed lookups are evicted so the next mint retries. */\nconst appIds = new Map<string, Promise<string>>();\n\nasync function loadAppId(fetchFn: Fetch, instanceId: string): Promise<string> {\n const res = await fetchFn(`${APPS_API}/public/instance/data?id=${encodeURIComponent(instanceId)}`, { keepalive: true });\n if (!res.ok) throw new Error(`instance data HTTP ${res.status}`);\n const body: unknown = await res.json();\n const appId = isRecord(body) ? body.appId : undefined;\n if (typeof appId !== 'number' && typeof appId !== 'string') throw new Error('instance data has no appId');\n return String(appId);\n}\n\nfunction appIdFor(fetchFn: Fetch, instanceId: string): Promise<string> {\n const hit = appIds.get(instanceId);\n if (hit) return hit;\n const p = loadAppId(fetchFn, instanceId);\n appIds.set(instanceId, p);\n p.catch(() => {\n if (appIds.get(instanceId) === p) appIds.delete(instanceId);\n });\n return p;\n}\n\n/**\n * Sends Manifold's mint record for a claim mint. `instanceId` is the claim's instance id (the widget sends\n * publicData.claimIndex, falling back to the Studio id; both equal the on-chain claim index dropkit is configured\n * with). The appId is looked up from the public instance data. If that lookup fails the record still goes out with\n * an empty appId: the hash identifies the mint, and the request keeps the widget's shape (appId key present).\n */\nexport function recordClaimMint(args: { instanceId: string; hash: Hex; fetch?: Fetch }): Promise<void> {\n const fetchFn: Fetch = args.fetch ?? ((input, init) => globalThis.fetch(input, init));\n const send = async () => {\n let appId = '';\n try {\n appId = await appIdFor(fetchFn, args.instanceId);\n } catch {\n /* send with an empty appId */\n }\n const query = new URLSearchParams({ appId, instanceId: args.instanceId, hash: args.hash });\n await fetchFn(`${APPS_API}/public/instance/tx?${query.toString()}`, { method: 'POST', keepalive: true });\n };\n return send().catch(() => undefined);\n}\n\n/** Tests only. */\nexport const resetMintRecordCache = (): void => appIds.clear();\n"]}