@manifoldxyz/dropkit 0.4.0 → 0.5.0

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.5.0";
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.5.0";
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
@@ -3,31 +3,34 @@ import {
3
3
  IN_FLIGHT_STATES,
4
4
  MAX_QUANTITY,
5
5
  MINT_STATES,
6
- MintError,
7
- REASON_CODES,
8
- UNSUPPORTED_REASONS,
9
6
  canAct,
10
- chainName,
11
- createReadClient,
12
- friendlyErrorMessage,
13
7
  getAccount,
14
- getChain,
15
8
  getConnectedBalance,
16
9
  getWalletClient,
17
10
  initialState,
18
- isMintError,
19
11
  loadConnectWidget,
20
- manifoldClaimAdapter,
21
12
  openConnectModal,
22
13
  parseMintReceipt,
14
+ recordClaimMint,
23
15
  reducer,
24
16
  selectMaxQuantity,
25
17
  selectTotal,
26
18
  subscribeAccount,
27
19
  switchToChain,
28
- toReason,
29
20
  waitForDeposit
30
- } from "./chunk-SUJQB3SL.js";
21
+ } from "./chunk-W7OBZPCY.js";
22
+ import {
23
+ MintError,
24
+ REASON_CODES,
25
+ UNSUPPORTED_REASONS,
26
+ chainName,
27
+ createReadClient,
28
+ friendlyErrorMessage,
29
+ getChain,
30
+ isMintError,
31
+ manifoldClaimAdapter,
32
+ toReason
33
+ } from "./chunk-VHAAGH7Z.js";
31
34
 
32
35
  // src/react/useMint.ts
33
36
  import { useCallback, useEffect, useReducer, useRef, useState } from "react";
@@ -599,6 +602,10 @@ function seconds(v, field) {
599
602
  if (v > BigInt(Number.MAX_SAFE_INTEGER)) throw new MintError("INVALID_CONFIG", `${field} is too large for a unix timestamp`, { field });
600
603
  return Number(v);
601
604
  }
605
+ function priceFor(drop, phase) {
606
+ const presalePrice = phase === DROP_PHASE.PRESALE || phase === DROP_PHASE.NOT_STARTED && drop.presaleDuration > 0n;
607
+ return { presalePrice, unitPrice: presalePrice ? drop.presaleCost : drop.publicCost };
608
+ }
602
609
  async function readDrop(ctx, config) {
603
610
  validateTlStacksConfig(config);
604
611
  throwIfAborted(ctx);
@@ -616,9 +623,7 @@ async function readDrop(ctx, config) {
616
623
  if (drop.currencyAddress !== zeroAddress2) {
617
624
  bad("nftContract", `is sold for an ERC-20 (${drop.currencyAddress}). Dropkit supports drops priced in the native token only.`);
618
625
  }
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;
626
+ const { presalePrice, unitPrice } = priceFor(drop, phase);
622
627
  const startTime = seconds(drop.startTime, "startTime");
623
628
  const presaleEnd = seconds(drop.startTime + drop.presaleDuration, "presaleDuration");
624
629
  const soldOut = drop.supply === 0n;
@@ -815,6 +820,20 @@ function decodeTlRevert(e) {
815
820
  }
816
821
  async function simulate(ctx, attempt, plan) {
817
822
  throwIfAborted(ctx);
823
+ const { config } = attempt;
824
+ const nft = getAddress3(config.nftContract);
825
+ const [drop, phaseRaw, fee] = await Promise.all([
826
+ readStacks(ctx, config, "getDrop", [nft]),
827
+ readStacks(ctx, config, "getDropPhase", [nft]),
828
+ readStacks(ctx, config, "protocolFee")
829
+ ]);
830
+ if (drop.currencyAddress !== zeroAddress2) {
831
+ 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" });
832
+ }
833
+ const current = BigInt(attempt.quantity) * (priceFor(drop, Number(phaseRaw)).unitPrice + fee);
834
+ if (current !== plan.mint.value) {
835
+ throw new MintError("SIMULATION_REVERTED", TL_MESSAGES.InsufficientFunds, { domain: "tl-stacks" });
836
+ }
818
837
  try {
819
838
  await io(ctx, () => ctx.client.call({ account: attempt.payer, to: plan.mint.to, data: plan.mint.data, value: plan.mint.value }));
820
839
  } catch (e) {
@@ -1395,6 +1414,8 @@ var contractAdapter = { readDrop: readDrop2, readWallet: readWallet2, buildPlan:
1395
1414
  // src/react/useMint.ts
1396
1415
  var REFRESH_MS = 3e4;
1397
1416
  var TICK_MS = 1e3;
1417
+ var BOUNDARY_RETRY_MS = 3e3;
1418
+ var BOUNDARY_RETRY_MAX = 10;
1398
1419
  var ASYNC_STATES = ["loading", "connecting", "switching-chain", "approving", "minting", "confirming"];
1399
1420
  function isAsyncState(name) {
1400
1421
  return ASYNC_STATES.includes(name);
@@ -1496,6 +1517,7 @@ function useMint(options) {
1496
1517
  const accountKeyRef = useRef(null);
1497
1518
  const connectingRef = useRef(false);
1498
1519
  const pendingRefreshRef = useRef(false);
1520
+ const boundaryRetryRef = useRef(null);
1499
1521
  const pendingQuantityRef = useRef(null);
1500
1522
  const widgetFailRef = useRef(null);
1501
1523
  const widgetLoadRef = useRef(null);
@@ -1707,6 +1729,7 @@ function useMint(options) {
1707
1729
  assertPayer();
1708
1730
  dispatch({ type: "MINT_PROMPTED", attemptId: attempt.attemptId });
1709
1731
  const hash = await submit(plan.mint);
1732
+ if (cfg.type === "manifold-claim") void recordClaimMint({ instanceId: cfg.instanceId, hash });
1710
1733
  assertActive();
1711
1734
  dispatch({ type: "TX_SUBMITTED", attemptId: attempt.attemptId });
1712
1735
  emit("tx-submitted", { state: "confirming", reason: null, txHash: hash, quantity: attempt.quantity, chainId: attempt.chainId });
@@ -1753,6 +1776,7 @@ function useMint(options) {
1753
1776
  throw new MintError("BRIDGE_FAILED", `Relay could not complete the mint paid on ${where}${why}.${noRefund}`);
1754
1777
  }
1755
1778
  const fillHash = status.txHashes[0] ?? null;
1779
+ if (fillHash && cfg.type === "manifold-claim") void recordClaimMint({ instanceId: cfg.instanceId, hash: fillHash });
1756
1780
  let tokens = [];
1757
1781
  if (fillHash) {
1758
1782
  try {
@@ -1967,6 +1991,8 @@ function useMint(options) {
1967
1991
  mounted.current = true;
1968
1992
  return () => {
1969
1993
  mounted.current = false;
1994
+ if (boundaryRetryRef.current) clearTimeout(boundaryRetryRef.current);
1995
+ boundaryRetryRef.current = null;
1970
1996
  lifeRef.current?.controller.abort();
1971
1997
  lifeRef.current = null;
1972
1998
  };
@@ -2168,6 +2194,22 @@ function useMint(options) {
2168
2194
  document.removeEventListener("visibilitychange", onVisible);
2169
2195
  };
2170
2196
  }, [refreshNow]);
2197
+ const retryWhileStale = useCallback(
2198
+ (staleKey, life) => {
2199
+ if (staleKey === void 0) return;
2200
+ const step = (tries) => {
2201
+ if (tries >= BOUNDARY_RETRY_MAX || !mounted.current || lifeRef.current !== life || stateRef.current.drop?.walletKey !== staleKey) return;
2202
+ if (boundaryRetryRef.current) clearTimeout(boundaryRetryRef.current);
2203
+ boundaryRetryRef.current = setTimeout(() => {
2204
+ boundaryRetryRef.current = null;
2205
+ if (!mounted.current || lifeRef.current !== life) return;
2206
+ void refreshNow().then(() => step(tries + 1));
2207
+ }, BOUNDARY_RETRY_MS);
2208
+ };
2209
+ step(0);
2210
+ },
2211
+ [refreshNow]
2212
+ );
2171
2213
  const boundary = machine.drop ? [machine.drop.startTime, machine.drop.endTime, machine.drop.phaseEndsAt ?? null].some((t) => t !== null && t > machine.now) : false;
2172
2214
  useEffect(() => {
2173
2215
  if (!boundary) return;
@@ -2176,10 +2218,13 @@ function useMint(options) {
2176
2218
  const now = nowSec();
2177
2219
  const crossed = s.drop && [s.drop.startTime, s.drop.endTime, s.drop.phaseEndsAt ?? null].some((t) => t !== null && t > s.now && t <= now);
2178
2220
  dispatch({ type: "TICK", now });
2179
- if (crossed) void refreshNow();
2221
+ if (crossed) {
2222
+ const life = lifeRef.current;
2223
+ void refreshNow().then(() => life && retryWhileStale(s.drop?.walletKey, life));
2224
+ }
2180
2225
  }, TICK_MS);
2181
2226
  return () => clearInterval(timer);
2182
- }, [boundary, dispatch, refreshNow]);
2227
+ }, [boundary, dispatch, refreshNow, retryWhileStale]);
2183
2228
  const prevName = useRef(null);
2184
2229
  useEffect(() => {
2185
2230
  const name = widgetFail ? isUnsupported(widgetFail.reason) ? "unsupported" : "error" : machine.name;
@@ -2433,7 +2478,7 @@ function MintButton(props) {
2433
2478
  }
2434
2479
 
2435
2480
  // src/index.ts
2436
- var VERSION = "0.4.0";
2481
+ var VERSION = "0.5.0";
2437
2482
  export {
2438
2483
  CLICKABLE_STATES,
2439
2484
  MAX_QUANTITY,