@manifoldxyz/dropkit 0.4.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.
package/dist/index.d.cts CHANGED
@@ -112,6 +112,6 @@ type MintButtonProps = UseMintOptions & {
112
112
  };
113
113
  declare function MintButton(props: MintButtonProps): ReactNode;
114
114
 
115
- declare const VERSION = "0.4.0";
115
+ declare const VERSION = "0.4.1";
116
116
 
117
117
  export { type CrossChainInfo, CrossChainOption, DropInfo, MintButton, type MintButtonProps, MintConfig, MintEvent, MintResult, type MintState, MintStateName, Money, type PayOption, PayWithPicker, type PayWithPickerProps, ReasonCode, Route, RpcUrls, type UseMintOptions, VERSION, WalletInfo, useMint, usePayOptions };
package/dist/index.d.ts CHANGED
@@ -112,6 +112,6 @@ type MintButtonProps = UseMintOptions & {
112
112
  };
113
113
  declare function MintButton(props: MintButtonProps): ReactNode;
114
114
 
115
- declare const VERSION = "0.4.0";
115
+ declare const VERSION = "0.4.1";
116
116
 
117
117
  export { type CrossChainInfo, CrossChainOption, DropInfo, MintButton, type MintButtonProps, MintConfig, MintEvent, MintResult, type MintState, MintStateName, Money, type PayOption, PayWithPicker, type PayWithPickerProps, ReasonCode, Route, RpcUrls, type UseMintOptions, VERSION, WalletInfo, useMint, usePayOptions };
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  manifoldClaimAdapter,
21
21
  openConnectModal,
22
22
  parseMintReceipt,
23
+ recordClaimMint,
23
24
  reducer,
24
25
  selectMaxQuantity,
25
26
  selectTotal,
@@ -27,7 +28,7 @@ import {
27
28
  switchToChain,
28
29
  toReason,
29
30
  waitForDeposit
30
- } from "./chunk-SUJQB3SL.js";
31
+ } from "./chunk-MXKJAZDW.js";
31
32
 
32
33
  // src/react/useMint.ts
33
34
  import { useCallback, useEffect, useReducer, useRef, useState } from "react";
@@ -599,6 +600,10 @@ function seconds(v, field) {
599
600
  if (v > BigInt(Number.MAX_SAFE_INTEGER)) throw new MintError("INVALID_CONFIG", `${field} is too large for a unix timestamp`, { field });
600
601
  return Number(v);
601
602
  }
603
+ function priceFor(drop, phase) {
604
+ const presalePrice = phase === DROP_PHASE.PRESALE || phase === DROP_PHASE.NOT_STARTED && drop.presaleDuration > 0n;
605
+ return { presalePrice, unitPrice: presalePrice ? drop.presaleCost : drop.publicCost };
606
+ }
602
607
  async function readDrop(ctx, config) {
603
608
  validateTlStacksConfig(config);
604
609
  throwIfAborted(ctx);
@@ -616,9 +621,7 @@ async function readDrop(ctx, config) {
616
621
  if (drop.currencyAddress !== zeroAddress2) {
617
622
  bad("nftContract", `is sold for an ERC-20 (${drop.currencyAddress}). Dropkit supports drops priced in the native token only.`);
618
623
  }
619
- const hasPresale = drop.presaleDuration > 0n;
620
- const presalePrice = phase === DROP_PHASE.PRESALE || phase === DROP_PHASE.NOT_STARTED && hasPresale;
621
- const unitPrice = presalePrice ? drop.presaleCost : drop.publicCost;
624
+ const { presalePrice, unitPrice } = priceFor(drop, phase);
622
625
  const startTime = seconds(drop.startTime, "startTime");
623
626
  const presaleEnd = seconds(drop.startTime + drop.presaleDuration, "presaleDuration");
624
627
  const soldOut = drop.supply === 0n;
@@ -815,6 +818,20 @@ function decodeTlRevert(e) {
815
818
  }
816
819
  async function simulate(ctx, attempt, plan) {
817
820
  throwIfAborted(ctx);
821
+ const { config } = attempt;
822
+ const nft = getAddress3(config.nftContract);
823
+ const [drop, phaseRaw, fee] = await Promise.all([
824
+ readStacks(ctx, config, "getDrop", [nft]),
825
+ readStacks(ctx, config, "getDropPhase", [nft]),
826
+ readStacks(ctx, config, "protocolFee")
827
+ ]);
828
+ if (drop.currencyAddress !== zeroAddress2) {
829
+ throw new MintError("SIMULATION_REVERTED", "This drop is now sold for a token instead of the native currency, so it cannot be minted here. Reload the page.", { domain: "tl-stacks" });
830
+ }
831
+ const current = BigInt(attempt.quantity) * (priceFor(drop, Number(phaseRaw)).unitPrice + fee);
832
+ if (current !== plan.mint.value) {
833
+ throw new MintError("SIMULATION_REVERTED", TL_MESSAGES.InsufficientFunds, { domain: "tl-stacks" });
834
+ }
818
835
  try {
819
836
  await io(ctx, () => ctx.client.call({ account: attempt.payer, to: plan.mint.to, data: plan.mint.data, value: plan.mint.value }));
820
837
  } catch (e) {
@@ -1395,6 +1412,8 @@ var contractAdapter = { readDrop: readDrop2, readWallet: readWallet2, buildPlan:
1395
1412
  // src/react/useMint.ts
1396
1413
  var REFRESH_MS = 3e4;
1397
1414
  var TICK_MS = 1e3;
1415
+ var BOUNDARY_RETRY_MS = 3e3;
1416
+ var BOUNDARY_RETRY_MAX = 10;
1398
1417
  var ASYNC_STATES = ["loading", "connecting", "switching-chain", "approving", "minting", "confirming"];
1399
1418
  function isAsyncState(name) {
1400
1419
  return ASYNC_STATES.includes(name);
@@ -1496,6 +1515,7 @@ function useMint(options) {
1496
1515
  const accountKeyRef = useRef(null);
1497
1516
  const connectingRef = useRef(false);
1498
1517
  const pendingRefreshRef = useRef(false);
1518
+ const boundaryRetryRef = useRef(null);
1499
1519
  const pendingQuantityRef = useRef(null);
1500
1520
  const widgetFailRef = useRef(null);
1501
1521
  const widgetLoadRef = useRef(null);
@@ -1707,6 +1727,7 @@ function useMint(options) {
1707
1727
  assertPayer();
1708
1728
  dispatch({ type: "MINT_PROMPTED", attemptId: attempt.attemptId });
1709
1729
  const hash = await submit(plan.mint);
1730
+ if (cfg.type === "manifold-claim") void recordClaimMint({ instanceId: cfg.instanceId, hash });
1710
1731
  assertActive();
1711
1732
  dispatch({ type: "TX_SUBMITTED", attemptId: attempt.attemptId });
1712
1733
  emit("tx-submitted", { state: "confirming", reason: null, txHash: hash, quantity: attempt.quantity, chainId: attempt.chainId });
@@ -1753,6 +1774,7 @@ function useMint(options) {
1753
1774
  throw new MintError("BRIDGE_FAILED", `Relay could not complete the mint paid on ${where}${why}.${noRefund}`);
1754
1775
  }
1755
1776
  const fillHash = status.txHashes[0] ?? null;
1777
+ if (fillHash && cfg.type === "manifold-claim") void recordClaimMint({ instanceId: cfg.instanceId, hash: fillHash });
1756
1778
  let tokens = [];
1757
1779
  if (fillHash) {
1758
1780
  try {
@@ -1967,6 +1989,8 @@ function useMint(options) {
1967
1989
  mounted.current = true;
1968
1990
  return () => {
1969
1991
  mounted.current = false;
1992
+ if (boundaryRetryRef.current) clearTimeout(boundaryRetryRef.current);
1993
+ boundaryRetryRef.current = null;
1970
1994
  lifeRef.current?.controller.abort();
1971
1995
  lifeRef.current = null;
1972
1996
  };
@@ -2168,6 +2192,22 @@ function useMint(options) {
2168
2192
  document.removeEventListener("visibilitychange", onVisible);
2169
2193
  };
2170
2194
  }, [refreshNow]);
2195
+ const retryWhileStale = useCallback(
2196
+ (staleKey, life) => {
2197
+ if (staleKey === void 0) return;
2198
+ const step = (tries) => {
2199
+ if (tries >= BOUNDARY_RETRY_MAX || !mounted.current || lifeRef.current !== life || stateRef.current.drop?.walletKey !== staleKey) return;
2200
+ if (boundaryRetryRef.current) clearTimeout(boundaryRetryRef.current);
2201
+ boundaryRetryRef.current = setTimeout(() => {
2202
+ boundaryRetryRef.current = null;
2203
+ if (!mounted.current || lifeRef.current !== life) return;
2204
+ void refreshNow().then(() => step(tries + 1));
2205
+ }, BOUNDARY_RETRY_MS);
2206
+ };
2207
+ step(0);
2208
+ },
2209
+ [refreshNow]
2210
+ );
2171
2211
  const boundary = machine.drop ? [machine.drop.startTime, machine.drop.endTime, machine.drop.phaseEndsAt ?? null].some((t) => t !== null && t > machine.now) : false;
2172
2212
  useEffect(() => {
2173
2213
  if (!boundary) return;
@@ -2176,10 +2216,13 @@ function useMint(options) {
2176
2216
  const now = nowSec();
2177
2217
  const crossed = s.drop && [s.drop.startTime, s.drop.endTime, s.drop.phaseEndsAt ?? null].some((t) => t !== null && t > s.now && t <= now);
2178
2218
  dispatch({ type: "TICK", now });
2179
- if (crossed) void refreshNow();
2219
+ if (crossed) {
2220
+ const life = lifeRef.current;
2221
+ void refreshNow().then(() => life && retryWhileStale(s.drop?.walletKey, life));
2222
+ }
2180
2223
  }, TICK_MS);
2181
2224
  return () => clearInterval(timer);
2182
- }, [boundary, dispatch, refreshNow]);
2225
+ }, [boundary, dispatch, refreshNow, retryWhileStale]);
2183
2226
  const prevName = useRef(null);
2184
2227
  useEffect(() => {
2185
2228
  const name = widgetFail ? isUnsupported(widgetFail.reason) ? "unsupported" : "error" : machine.name;
@@ -2433,7 +2476,7 @@ function MintButton(props) {
2433
2476
  }
2434
2477
 
2435
2478
  // src/index.ts
2436
- var VERSION = "0.4.0";
2479
+ var VERSION = "0.4.1";
2437
2480
  export {
2438
2481
  CLICKABLE_STATES,
2439
2482
  MAX_QUANTITY,