@unifold/connect-react 0.1.43 → 0.1.44

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.
Files changed (3) hide show
  1. package/dist/index.js +151 -111
  2. package/dist/index.mjs +151 -111
  3. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -6542,6 +6542,28 @@ async function verifyRecipientAddress(request, publishableKey) {
6542
6542
  }
6543
6543
  return response.json();
6544
6544
  }
6545
+ async function checkHypercoreActivation(request, publishableKey) {
6546
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6547
+ validatePublishableKey(pk);
6548
+ const response = await fetch(
6549
+ `${API_BASE_URL}/v1/public/addresses/hypercore/activation`,
6550
+ {
6551
+ method: "POST",
6552
+ headers: {
6553
+ accept: "application/json",
6554
+ "x-publishable-key": pk,
6555
+ "Content-Type": "application/json"
6556
+ },
6557
+ body: JSON.stringify(request)
6558
+ }
6559
+ );
6560
+ if (!response.ok) {
6561
+ throw new Error(
6562
+ `HyperCore activation check failed: ${response.statusText}`
6563
+ );
6564
+ }
6565
+ return response.json();
6566
+ }
6545
6567
  async function getExchanges(query, publishableKey) {
6546
6568
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6547
6569
  validatePublishableKey(pk);
@@ -24369,6 +24391,7 @@ async function sendHypercoreWithdraw(params) {
24369
24391
  async function detectBrowserWallet(chainType, senderAddress) {
24370
24392
  const win = typeof window !== "undefined" ? window : null;
24371
24393
  if (!win || !senderAddress) return null;
24394
+ if (getUserDisconnectedWallet()) return null;
24372
24395
  const anyWin = win;
24373
24396
  if (chainType === "solana") {
24374
24397
  const solProviders = [];
@@ -24402,28 +24425,44 @@ async function detectBrowserWallet(chainType, senderAddress) {
24402
24425
  evmProviders.push({ provider: p, name });
24403
24426
  }
24404
24427
  };
24405
- add(anyWin.phantom?.ethereum, "Phantom");
24406
- add(anyWin.coinbaseWalletExtension, "Coinbase");
24407
- add(anyWin.trustwallet?.ethereum, "Trust Wallet");
24408
- add(anyWin.okxwallet, "OKX Wallet");
24409
- if (anyWin.__eip6963Providers) {
24410
- for (const detail of anyWin.__eip6963Providers) {
24411
- const rdns = detail.info?.rdns || "";
24412
- let name = detail.info?.name || "Wallet";
24413
- if (rdns.includes("metamask")) name = "MetaMask";
24414
- else if (rdns.includes("rabby")) name = "Rabby";
24415
- else if (rdns.includes("rainbow")) name = "Rainbow";
24416
- add(detail.provider, name);
24417
- }
24428
+ if (!anyWin.__eip6963Providers) {
24429
+ anyWin.__eip6963Providers = [];
24418
24430
  }
24419
- if (win.ethereum) {
24420
- const eth = win.ethereum;
24421
- let name = "Wallet";
24422
- if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
24423
- else if (eth.isRabby) name = "Rabby";
24424
- else if (eth.isRainbow) name = "Rainbow";
24425
- else if (eth.isCoinbaseWallet) name = "Coinbase";
24426
- add(eth, name);
24431
+ const handleAnnouncement = (event) => {
24432
+ const { detail } = event;
24433
+ if (!detail?.info || !detail?.provider) return;
24434
+ const exists = anyWin.__eip6963Providers.some((p) => p.info.uuid === detail.info.uuid);
24435
+ if (!exists) anyWin.__eip6963Providers.push(detail);
24436
+ };
24437
+ win.addEventListener("eip6963:announceProvider", handleAnnouncement);
24438
+ win.dispatchEvent(new Event("eip6963:requestProvider"));
24439
+ win.removeEventListener("eip6963:announceProvider", handleAnnouncement);
24440
+ for (const detail of anyWin.__eip6963Providers) {
24441
+ const rdns = detail.info?.rdns || "";
24442
+ let name = detail.info?.name || "Wallet";
24443
+ if (rdns.includes("metamask")) name = "MetaMask";
24444
+ else if (rdns.includes("phantom")) name = "Phantom";
24445
+ else if (rdns.includes("coinbase")) name = "Coinbase";
24446
+ else if (rdns.includes("rabby")) name = "Rabby";
24447
+ else if (rdns.includes("rainbow")) name = "Rainbow";
24448
+ else if (rdns.includes("okx")) name = "OKX Wallet";
24449
+ else if (rdns.includes("trust")) name = "Trust Wallet";
24450
+ add(detail.provider, name);
24451
+ }
24452
+ if (evmProviders.length === 0) {
24453
+ add(anyWin.phantom?.ethereum, "Phantom");
24454
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
24455
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
24456
+ add(anyWin.okxwallet, "OKX Wallet");
24457
+ if (evmProviders.length === 0 && win.ethereum) {
24458
+ const eth = win.ethereum;
24459
+ let name = "Wallet";
24460
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
24461
+ else if (eth.isRabby) name = "Rabby";
24462
+ else if (eth.isRainbow) name = "Rainbow";
24463
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
24464
+ add(eth, name);
24465
+ }
24427
24466
  }
24428
24467
  for (const { provider, name } of evmProviders) {
24429
24468
  try {
@@ -24476,12 +24515,9 @@ function WithdrawForm({
24476
24515
  estimatedProcessingTime,
24477
24516
  maxSlippagePercent,
24478
24517
  priceImpactPercent,
24479
- detectedWallet,
24518
+ senderAddress,
24480
24519
  sourceChainId,
24481
24520
  sourceTokenAddress,
24482
- isWalletMatch,
24483
- connectedWalletName,
24484
- canWithdraw,
24485
24521
  onWithdraw,
24486
24522
  onWithdrawError,
24487
24523
  onDepositWalletCreation,
@@ -24616,12 +24652,43 @@ function WithdrawForm({
24616
24652
  destinationTokenAddress: selectedChain.token_address,
24617
24653
  recipientAddress: trimmedAddress
24618
24654
  });
24619
- const amountBaseUnit = computeBaseUnit(
24655
+ let amountBaseUnit = computeBaseUnit(
24620
24656
  balanceData.balanceBaseUnit,
24621
24657
  parseFloat(amount),
24622
24658
  inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
24623
24659
  );
24624
- const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
24660
+ let humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
24661
+ if (isHypercoreChain(sourceChainId)) {
24662
+ try {
24663
+ const check = await checkHypercoreActivation(
24664
+ {
24665
+ source_address: senderAddress,
24666
+ recipient_address: depositWallet.address
24667
+ },
24668
+ publishableKey
24669
+ );
24670
+ if (!check.user_exists) {
24671
+ const fee = check.activation_fee;
24672
+ const maxSendable = balanceCrypto - fee;
24673
+ if (maxSendable <= 0) {
24674
+ throw new Error(
24675
+ `Insufficient balance. A ${fee} USDC activation fee is required for the first transfer to this address.`
24676
+ );
24677
+ }
24678
+ const requestedAmount = parseFloat(humanAmount);
24679
+ if (requestedAmount > maxSendable) {
24680
+ humanAmount = toSafeDecimalString(maxSendable, sourceDecimals);
24681
+ amountBaseUnit = computeBaseUnit(
24682
+ balanceData.balanceBaseUnit,
24683
+ maxSendable,
24684
+ balanceCrypto
24685
+ );
24686
+ }
24687
+ }
24688
+ } catch (e) {
24689
+ if (e instanceof Error && e.message.includes("activation fee")) throw e;
24690
+ }
24691
+ }
24625
24692
  const txInfo = {
24626
24693
  sourceChainType,
24627
24694
  sourceChainId,
@@ -24636,43 +24703,67 @@ function WithdrawForm({
24636
24703
  withdrawIntentAddress: depositWallet.address,
24637
24704
  recipientAddress: trimmedAddress
24638
24705
  };
24639
- if (detectedWallet) {
24640
- if (detectedWallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
24641
- await sendHypercoreWithdraw({
24642
- provider: detectedWallet.provider,
24643
- fromAddress: detectedWallet.address,
24644
- depositWalletAddress: depositWallet.address,
24645
- sourceTokenAddress,
24706
+ const wallet = await detectBrowserWallet(sourceChainType, senderAddress);
24707
+ console.log("browser wallet", wallet);
24708
+ if (wallet) {
24709
+ try {
24710
+ if (wallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
24711
+ await sendHypercoreWithdraw({
24712
+ provider: wallet.provider,
24713
+ fromAddress: wallet.address,
24714
+ depositWalletAddress: depositWallet.address,
24715
+ sourceTokenAddress,
24716
+ amount: humanAmount,
24717
+ tokenSymbol,
24718
+ publishableKey
24719
+ });
24720
+ } else if (wallet.chainFamily === "evm") {
24721
+ await sendEvmWithdraw({
24722
+ provider: wallet.provider,
24723
+ fromAddress: wallet.address,
24724
+ depositWalletAddress: depositWallet.address,
24725
+ sourceTokenAddress,
24726
+ sourceChainId,
24727
+ amountBaseUnit
24728
+ });
24729
+ } else if (wallet.chainFamily === "solana") {
24730
+ await sendSolanaWithdraw({
24731
+ provider: wallet.provider,
24732
+ fromAddress: wallet.address,
24733
+ depositWalletAddress: depositWallet.address,
24734
+ sourceTokenAddress,
24735
+ amountBaseUnit,
24736
+ publishableKey
24737
+ });
24738
+ }
24739
+ } catch (walletErr) {
24740
+ console.error("[Unifold] Browser wallet send failed:", walletErr, {
24741
+ wallet: `${wallet.name} (${wallet.chainFamily})`,
24742
+ sourceChainId,
24646
24743
  amount: humanAmount,
24647
- tokenSymbol,
24648
- publishableKey
24744
+ amountBaseUnit,
24745
+ depositWallet: depositWallet.address
24649
24746
  });
24650
- } else if (detectedWallet.chainFamily === "evm") {
24651
- await sendEvmWithdraw({
24652
- provider: detectedWallet.provider,
24653
- fromAddress: detectedWallet.address,
24654
- depositWalletAddress: depositWallet.address,
24655
- sourceTokenAddress,
24747
+ throw walletErr;
24748
+ }
24749
+ } else if (onWithdraw) {
24750
+ try {
24751
+ await onWithdraw(txInfo);
24752
+ } catch (callbackErr) {
24753
+ console.error("[Unifold] onWithdraw callback failed:", callbackErr, {
24656
24754
  sourceChainId,
24657
- amountBaseUnit
24658
- });
24659
- } else if (detectedWallet.chainFamily === "solana") {
24660
- await sendSolanaWithdraw({
24661
- provider: detectedWallet.provider,
24662
- fromAddress: detectedWallet.address,
24663
- depositWalletAddress: depositWallet.address,
24664
- sourceTokenAddress,
24755
+ amount: humanAmount,
24665
24756
  amountBaseUnit,
24666
- publishableKey
24757
+ depositWallet: depositWallet.address
24667
24758
  });
24759
+ throw callbackErr;
24668
24760
  }
24669
- } else if (onWithdraw) {
24670
- await onWithdraw(txInfo);
24671
24761
  } else {
24672
24762
  throw new Error("No withdrawal method available. Please connect a wallet.");
24673
24763
  }
24674
24764
  onWithdrawSubmitted?.(txInfo);
24675
24765
  } catch (err) {
24766
+ console.error("[Unifold] Withdrawal failed:", err);
24676
24767
  const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
24677
24768
  setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
24678
24769
  onWithdrawError?.({
@@ -24683,7 +24774,7 @@ function WithdrawForm({
24683
24774
  } finally {
24684
24775
  setIsSubmitting(false);
24685
24776
  }
24686
- }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
24777
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, sourceChainType, senderAddress, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
24687
24778
  return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
24688
24779
  /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { children: [
24689
24780
  /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
@@ -24894,23 +24985,12 @@ function WithdrawForm({
24894
24985
  ] })
24895
24986
  ] })
24896
24987
  ] }),
24897
- !canWithdraw && !submitError && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
24898
- "div",
24899
- {
24900
- className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
24901
- style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
24902
- children: [
24903
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(Wallet, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
24904
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("div", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No connected wallet detected. Please connect a wallet that matches your account to withdraw." })
24905
- ]
24906
- }
24907
- ),
24908
- isWalletMatch && connectedWalletName ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
24988
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
24909
24989
  "button",
24910
24990
  {
24911
24991
  type: "button",
24912
24992
  onClick: handleWithdraw,
24913
- disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
24993
+ disabled: !isFormValid || isSubmitting || !selectedToken || !selectedChain,
24914
24994
  className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
24915
24995
  style: {
24916
24996
  backgroundColor: colors2.primary,
@@ -24924,29 +25004,9 @@ function WithdrawForm({
24924
25004
  "Processing..."
24925
25005
  ] }) : isOverBalance ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(import_jsx_runtime71.Fragment, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(import_jsx_runtime71.Fragment, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(import_jsx_runtime71.Fragment, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
24926
25006
  /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(Wallet, { className: "uf-w-4 uf-h-4" }),
24927
- "Withdraw from ",
24928
- connectedWalletName
25007
+ t8.withdraw
24929
25008
  ] })
24930
25009
  }
24931
- ) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
24932
- "button",
24933
- {
24934
- type: "button",
24935
- onClick: handleWithdraw,
24936
- disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
24937
- className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
24938
- style: {
24939
- backgroundColor: colors2.primary,
24940
- color: colors2.primaryForeground,
24941
- fontFamily: fonts.medium,
24942
- borderRadius: components.button.borderRadius,
24943
- border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
24944
- },
24945
- children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
24946
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
24947
- "Processing..."
24948
- ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
24949
- }
24950
25010
  ),
24951
25011
  /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
24952
25012
  /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("div", { children: footerLeft }),
@@ -25325,22 +25385,6 @@ function WithdrawModal({
25325
25385
  });
25326
25386
  const [selectedToken, setSelectedToken] = (0, import_react27.useState)(null);
25327
25387
  const [selectedChain, setSelectedChain] = (0, import_react27.useState)(null);
25328
- const [detectedWallet, setDetectedWallet] = (0, import_react27.useState)(null);
25329
- const connectedWalletName = detectedWallet?.name ?? null;
25330
- const isWalletMatch = !!detectedWallet;
25331
- (0, import_react27.useEffect)(() => {
25332
- if (!senderAddress || !open) {
25333
- setDetectedWallet(null);
25334
- return;
25335
- }
25336
- let cancelled = false;
25337
- detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
25338
- if (!cancelled) setDetectedWallet(wallet);
25339
- });
25340
- return () => {
25341
- cancelled = true;
25342
- };
25343
- }, [senderAddress, sourceChainType, open]);
25344
25388
  const [view, setView] = (0, import_react27.useState)("form");
25345
25389
  const [withdrawDepositWalletId, setWithdrawDepositWalletId] = (0, import_react27.useState)();
25346
25390
  const [selectedExecution, setSelectedExecution] = (0, import_react27.useState)(null);
@@ -25433,7 +25477,6 @@ function WithdrawModal({
25433
25477
  if (chain) setSelectedChain(chain);
25434
25478
  }, [selectedToken]);
25435
25479
  const isSourceSupported = sourceValidation?.isSupported ?? null;
25436
- const canWithdraw = !!onWithdraw || isWalletMatch;
25437
25480
  const isAnyLoading = tokensLoading || isCheckingSourceToken;
25438
25481
  const withdrawPoweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
25439
25482
  return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(Dialog2, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
@@ -25464,7 +25507,7 @@ function WithdrawModal({
25464
25507
  /* ---------- Tracker view: execution list ---------- */
25465
25508
  /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(import_jsx_runtime74.Fragment, { children: [
25466
25509
  /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
25467
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
25510
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-h-[460px] uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-flex uf-flex-col uf-gap-2", children: allWithdrawals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
25468
25511
  WithdrawExecutionItem,
25469
25512
  {
25470
25513
  execution: ex,
@@ -25474,7 +25517,7 @@ function WithdrawModal({
25474
25517
  }
25475
25518
  },
25476
25519
  ex.id
25477
- )) }),
25520
+ )) }) }),
25478
25521
  withdrawPoweredByFooter
25479
25522
  ] })
25480
25523
  ) : (
@@ -25514,12 +25557,9 @@ function WithdrawModal({
25514
25557
  estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
25515
25558
  maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
25516
25559
  priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
25517
- detectedWallet,
25560
+ senderAddress,
25518
25561
  sourceChainId,
25519
25562
  sourceTokenAddress,
25520
- isWalletMatch,
25521
- connectedWalletName,
25522
- canWithdraw,
25523
25563
  onWithdraw,
25524
25564
  onWithdrawError,
25525
25565
  onDepositWalletCreation: handleDepositWalletCreation,
package/dist/index.mjs CHANGED
@@ -6520,6 +6520,28 @@ async function verifyRecipientAddress(request, publishableKey) {
6520
6520
  }
6521
6521
  return response.json();
6522
6522
  }
6523
+ async function checkHypercoreActivation(request, publishableKey) {
6524
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6525
+ validatePublishableKey(pk);
6526
+ const response = await fetch(
6527
+ `${API_BASE_URL}/v1/public/addresses/hypercore/activation`,
6528
+ {
6529
+ method: "POST",
6530
+ headers: {
6531
+ accept: "application/json",
6532
+ "x-publishable-key": pk,
6533
+ "Content-Type": "application/json"
6534
+ },
6535
+ body: JSON.stringify(request)
6536
+ }
6537
+ );
6538
+ if (!response.ok) {
6539
+ throw new Error(
6540
+ `HyperCore activation check failed: ${response.statusText}`
6541
+ );
6542
+ }
6543
+ return response.json();
6544
+ }
6523
6545
  async function getExchanges(query, publishableKey) {
6524
6546
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6525
6547
  validatePublishableKey(pk);
@@ -24360,6 +24382,7 @@ async function sendHypercoreWithdraw(params) {
24360
24382
  async function detectBrowserWallet(chainType, senderAddress) {
24361
24383
  const win = typeof window !== "undefined" ? window : null;
24362
24384
  if (!win || !senderAddress) return null;
24385
+ if (getUserDisconnectedWallet()) return null;
24363
24386
  const anyWin = win;
24364
24387
  if (chainType === "solana") {
24365
24388
  const solProviders = [];
@@ -24393,28 +24416,44 @@ async function detectBrowserWallet(chainType, senderAddress) {
24393
24416
  evmProviders.push({ provider: p, name });
24394
24417
  }
24395
24418
  };
24396
- add(anyWin.phantom?.ethereum, "Phantom");
24397
- add(anyWin.coinbaseWalletExtension, "Coinbase");
24398
- add(anyWin.trustwallet?.ethereum, "Trust Wallet");
24399
- add(anyWin.okxwallet, "OKX Wallet");
24400
- if (anyWin.__eip6963Providers) {
24401
- for (const detail of anyWin.__eip6963Providers) {
24402
- const rdns = detail.info?.rdns || "";
24403
- let name = detail.info?.name || "Wallet";
24404
- if (rdns.includes("metamask")) name = "MetaMask";
24405
- else if (rdns.includes("rabby")) name = "Rabby";
24406
- else if (rdns.includes("rainbow")) name = "Rainbow";
24407
- add(detail.provider, name);
24408
- }
24419
+ if (!anyWin.__eip6963Providers) {
24420
+ anyWin.__eip6963Providers = [];
24409
24421
  }
24410
- if (win.ethereum) {
24411
- const eth = win.ethereum;
24412
- let name = "Wallet";
24413
- if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
24414
- else if (eth.isRabby) name = "Rabby";
24415
- else if (eth.isRainbow) name = "Rainbow";
24416
- else if (eth.isCoinbaseWallet) name = "Coinbase";
24417
- add(eth, name);
24422
+ const handleAnnouncement = (event) => {
24423
+ const { detail } = event;
24424
+ if (!detail?.info || !detail?.provider) return;
24425
+ const exists = anyWin.__eip6963Providers.some((p) => p.info.uuid === detail.info.uuid);
24426
+ if (!exists) anyWin.__eip6963Providers.push(detail);
24427
+ };
24428
+ win.addEventListener("eip6963:announceProvider", handleAnnouncement);
24429
+ win.dispatchEvent(new Event("eip6963:requestProvider"));
24430
+ win.removeEventListener("eip6963:announceProvider", handleAnnouncement);
24431
+ for (const detail of anyWin.__eip6963Providers) {
24432
+ const rdns = detail.info?.rdns || "";
24433
+ let name = detail.info?.name || "Wallet";
24434
+ if (rdns.includes("metamask")) name = "MetaMask";
24435
+ else if (rdns.includes("phantom")) name = "Phantom";
24436
+ else if (rdns.includes("coinbase")) name = "Coinbase";
24437
+ else if (rdns.includes("rabby")) name = "Rabby";
24438
+ else if (rdns.includes("rainbow")) name = "Rainbow";
24439
+ else if (rdns.includes("okx")) name = "OKX Wallet";
24440
+ else if (rdns.includes("trust")) name = "Trust Wallet";
24441
+ add(detail.provider, name);
24442
+ }
24443
+ if (evmProviders.length === 0) {
24444
+ add(anyWin.phantom?.ethereum, "Phantom");
24445
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
24446
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
24447
+ add(anyWin.okxwallet, "OKX Wallet");
24448
+ if (evmProviders.length === 0 && win.ethereum) {
24449
+ const eth = win.ethereum;
24450
+ let name = "Wallet";
24451
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
24452
+ else if (eth.isRabby) name = "Rabby";
24453
+ else if (eth.isRainbow) name = "Rainbow";
24454
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
24455
+ add(eth, name);
24456
+ }
24418
24457
  }
24419
24458
  for (const { provider, name } of evmProviders) {
24420
24459
  try {
@@ -24467,12 +24506,9 @@ function WithdrawForm({
24467
24506
  estimatedProcessingTime,
24468
24507
  maxSlippagePercent,
24469
24508
  priceImpactPercent,
24470
- detectedWallet,
24509
+ senderAddress,
24471
24510
  sourceChainId,
24472
24511
  sourceTokenAddress,
24473
- isWalletMatch,
24474
- connectedWalletName,
24475
- canWithdraw,
24476
24512
  onWithdraw,
24477
24513
  onWithdrawError,
24478
24514
  onDepositWalletCreation,
@@ -24607,12 +24643,43 @@ function WithdrawForm({
24607
24643
  destinationTokenAddress: selectedChain.token_address,
24608
24644
  recipientAddress: trimmedAddress
24609
24645
  });
24610
- const amountBaseUnit = computeBaseUnit(
24646
+ let amountBaseUnit = computeBaseUnit(
24611
24647
  balanceData.balanceBaseUnit,
24612
24648
  parseFloat(amount),
24613
24649
  inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
24614
24650
  );
24615
- const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
24651
+ let humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
24652
+ if (isHypercoreChain(sourceChainId)) {
24653
+ try {
24654
+ const check = await checkHypercoreActivation(
24655
+ {
24656
+ source_address: senderAddress,
24657
+ recipient_address: depositWallet.address
24658
+ },
24659
+ publishableKey
24660
+ );
24661
+ if (!check.user_exists) {
24662
+ const fee = check.activation_fee;
24663
+ const maxSendable = balanceCrypto - fee;
24664
+ if (maxSendable <= 0) {
24665
+ throw new Error(
24666
+ `Insufficient balance. A ${fee} USDC activation fee is required for the first transfer to this address.`
24667
+ );
24668
+ }
24669
+ const requestedAmount = parseFloat(humanAmount);
24670
+ if (requestedAmount > maxSendable) {
24671
+ humanAmount = toSafeDecimalString(maxSendable, sourceDecimals);
24672
+ amountBaseUnit = computeBaseUnit(
24673
+ balanceData.balanceBaseUnit,
24674
+ maxSendable,
24675
+ balanceCrypto
24676
+ );
24677
+ }
24678
+ }
24679
+ } catch (e) {
24680
+ if (e instanceof Error && e.message.includes("activation fee")) throw e;
24681
+ }
24682
+ }
24616
24683
  const txInfo = {
24617
24684
  sourceChainType,
24618
24685
  sourceChainId,
@@ -24627,43 +24694,67 @@ function WithdrawForm({
24627
24694
  withdrawIntentAddress: depositWallet.address,
24628
24695
  recipientAddress: trimmedAddress
24629
24696
  };
24630
- if (detectedWallet) {
24631
- if (detectedWallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
24632
- await sendHypercoreWithdraw({
24633
- provider: detectedWallet.provider,
24634
- fromAddress: detectedWallet.address,
24635
- depositWalletAddress: depositWallet.address,
24636
- sourceTokenAddress,
24697
+ const wallet = await detectBrowserWallet(sourceChainType, senderAddress);
24698
+ console.log("browser wallet", wallet);
24699
+ if (wallet) {
24700
+ try {
24701
+ if (wallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
24702
+ await sendHypercoreWithdraw({
24703
+ provider: wallet.provider,
24704
+ fromAddress: wallet.address,
24705
+ depositWalletAddress: depositWallet.address,
24706
+ sourceTokenAddress,
24707
+ amount: humanAmount,
24708
+ tokenSymbol,
24709
+ publishableKey
24710
+ });
24711
+ } else if (wallet.chainFamily === "evm") {
24712
+ await sendEvmWithdraw({
24713
+ provider: wallet.provider,
24714
+ fromAddress: wallet.address,
24715
+ depositWalletAddress: depositWallet.address,
24716
+ sourceTokenAddress,
24717
+ sourceChainId,
24718
+ amountBaseUnit
24719
+ });
24720
+ } else if (wallet.chainFamily === "solana") {
24721
+ await sendSolanaWithdraw({
24722
+ provider: wallet.provider,
24723
+ fromAddress: wallet.address,
24724
+ depositWalletAddress: depositWallet.address,
24725
+ sourceTokenAddress,
24726
+ amountBaseUnit,
24727
+ publishableKey
24728
+ });
24729
+ }
24730
+ } catch (walletErr) {
24731
+ console.error("[Unifold] Browser wallet send failed:", walletErr, {
24732
+ wallet: `${wallet.name} (${wallet.chainFamily})`,
24733
+ sourceChainId,
24637
24734
  amount: humanAmount,
24638
- tokenSymbol,
24639
- publishableKey
24735
+ amountBaseUnit,
24736
+ depositWallet: depositWallet.address
24640
24737
  });
24641
- } else if (detectedWallet.chainFamily === "evm") {
24642
- await sendEvmWithdraw({
24643
- provider: detectedWallet.provider,
24644
- fromAddress: detectedWallet.address,
24645
- depositWalletAddress: depositWallet.address,
24646
- sourceTokenAddress,
24738
+ throw walletErr;
24739
+ }
24740
+ } else if (onWithdraw) {
24741
+ try {
24742
+ await onWithdraw(txInfo);
24743
+ } catch (callbackErr) {
24744
+ console.error("[Unifold] onWithdraw callback failed:", callbackErr, {
24647
24745
  sourceChainId,
24648
- amountBaseUnit
24649
- });
24650
- } else if (detectedWallet.chainFamily === "solana") {
24651
- await sendSolanaWithdraw({
24652
- provider: detectedWallet.provider,
24653
- fromAddress: detectedWallet.address,
24654
- depositWalletAddress: depositWallet.address,
24655
- sourceTokenAddress,
24746
+ amount: humanAmount,
24656
24747
  amountBaseUnit,
24657
- publishableKey
24748
+ depositWallet: depositWallet.address
24658
24749
  });
24750
+ throw callbackErr;
24659
24751
  }
24660
- } else if (onWithdraw) {
24661
- await onWithdraw(txInfo);
24662
24752
  } else {
24663
24753
  throw new Error("No withdrawal method available. Please connect a wallet.");
24664
24754
  }
24665
24755
  onWithdrawSubmitted?.(txInfo);
24666
24756
  } catch (err) {
24757
+ console.error("[Unifold] Withdrawal failed:", err);
24667
24758
  const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
24668
24759
  setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
24669
24760
  onWithdrawError?.({
@@ -24674,7 +24765,7 @@ function WithdrawForm({
24674
24765
  } finally {
24675
24766
  setIsSubmitting(false);
24676
24767
  }
24677
- }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
24768
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, sourceChainType, senderAddress, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
24678
24769
  return /* @__PURE__ */ jsxs47(Fragment11, { children: [
24679
24770
  /* @__PURE__ */ jsxs47("div", { children: [
24680
24771
  /* @__PURE__ */ jsx54(
@@ -24885,23 +24976,12 @@ function WithdrawForm({
24885
24976
  ] })
24886
24977
  ] })
24887
24978
  ] }),
24888
- !canWithdraw && !submitError && /* @__PURE__ */ jsxs47(
24889
- "div",
24890
- {
24891
- className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
24892
- style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
24893
- children: [
24894
- /* @__PURE__ */ jsx54(Wallet, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
24895
- /* @__PURE__ */ jsx54("div", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No connected wallet detected. Please connect a wallet that matches your account to withdraw." })
24896
- ]
24897
- }
24898
- ),
24899
- isWalletMatch && connectedWalletName ? /* @__PURE__ */ jsx54(
24979
+ /* @__PURE__ */ jsx54(
24900
24980
  "button",
24901
24981
  {
24902
24982
  type: "button",
24903
24983
  onClick: handleWithdraw,
24904
- disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
24984
+ disabled: !isFormValid || isSubmitting || !selectedToken || !selectedChain,
24905
24985
  className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
24906
24986
  style: {
24907
24987
  backgroundColor: colors2.primary,
@@ -24915,29 +24995,9 @@ function WithdrawForm({
24915
24995
  "Processing..."
24916
24996
  ] }) : isOverBalance ? /* @__PURE__ */ jsx54(Fragment11, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ jsx54(Fragment11, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ jsx54(Fragment11, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ jsxs47(Fragment11, { children: [
24917
24997
  /* @__PURE__ */ jsx54(Wallet, { className: "uf-w-4 uf-h-4" }),
24918
- "Withdraw from ",
24919
- connectedWalletName
24998
+ t8.withdraw
24920
24999
  ] })
24921
25000
  }
24922
- ) : /* @__PURE__ */ jsx54(
24923
- "button",
24924
- {
24925
- type: "button",
24926
- onClick: handleWithdraw,
24927
- disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
24928
- className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
24929
- style: {
24930
- backgroundColor: colors2.primary,
24931
- color: colors2.primaryForeground,
24932
- fontFamily: fonts.medium,
24933
- borderRadius: components.button.borderRadius,
24934
- border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
24935
- },
24936
- children: isSubmitting ? /* @__PURE__ */ jsxs47("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
24937
- /* @__PURE__ */ jsx54(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
24938
- "Processing..."
24939
- ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
24940
- }
24941
25001
  ),
24942
25002
  /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
24943
25003
  /* @__PURE__ */ jsx54("div", { children: footerLeft }),
@@ -25316,22 +25376,6 @@ function WithdrawModal({
25316
25376
  });
25317
25377
  const [selectedToken, setSelectedToken] = useState32(null);
25318
25378
  const [selectedChain, setSelectedChain] = useState32(null);
25319
- const [detectedWallet, setDetectedWallet] = useState32(null);
25320
- const connectedWalletName = detectedWallet?.name ?? null;
25321
- const isWalletMatch = !!detectedWallet;
25322
- useEffect272(() => {
25323
- if (!senderAddress || !open) {
25324
- setDetectedWallet(null);
25325
- return;
25326
- }
25327
- let cancelled = false;
25328
- detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
25329
- if (!cancelled) setDetectedWallet(wallet);
25330
- });
25331
- return () => {
25332
- cancelled = true;
25333
- };
25334
- }, [senderAddress, sourceChainType, open]);
25335
25379
  const [view, setView] = useState32("form");
25336
25380
  const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState32();
25337
25381
  const [selectedExecution, setSelectedExecution] = useState32(null);
@@ -25424,7 +25468,6 @@ function WithdrawModal({
25424
25468
  if (chain) setSelectedChain(chain);
25425
25469
  }, [selectedToken]);
25426
25470
  const isSourceSupported = sourceValidation?.isSupported ?? null;
25427
- const canWithdraw = !!onWithdraw || isWalletMatch;
25428
25471
  const isAnyLoading = tokensLoading || isCheckingSourceToken;
25429
25472
  const withdrawPoweredByFooter = /* @__PURE__ */ jsx57("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx57(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
25430
25473
  return /* @__PURE__ */ jsx57(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx57(Dialog2, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ jsx57(
@@ -25455,7 +25498,7 @@ function WithdrawModal({
25455
25498
  /* ---------- Tracker view: execution list ---------- */
25456
25499
  /* @__PURE__ */ jsxs50(Fragment13, { children: [
25457
25500
  /* @__PURE__ */ jsx57(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
25458
- /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx57("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ jsx57(
25501
+ /* @__PURE__ */ jsx57("div", { className: "uf-h-[460px] uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-flex-col uf-gap-2", children: allWithdrawals.length === 0 ? /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx57("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ jsx57(
25459
25502
  WithdrawExecutionItem,
25460
25503
  {
25461
25504
  execution: ex,
@@ -25465,7 +25508,7 @@ function WithdrawModal({
25465
25508
  }
25466
25509
  },
25467
25510
  ex.id
25468
- )) }),
25511
+ )) }) }),
25469
25512
  withdrawPoweredByFooter
25470
25513
  ] })
25471
25514
  ) : (
@@ -25505,12 +25548,9 @@ function WithdrawModal({
25505
25548
  estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
25506
25549
  maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
25507
25550
  priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
25508
- detectedWallet,
25551
+ senderAddress,
25509
25552
  sourceChainId,
25510
25553
  sourceTokenAddress,
25511
- isWalletMatch,
25512
- connectedWalletName,
25513
- canWithdraw,
25514
25554
  onWithdraw,
25515
25555
  onWithdrawError,
25516
25556
  onDepositWalletCreation: handleDepositWalletCreation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/connect-react",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "Unifold Connect React - Complete React SDK with UI components for crypto deposits",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -31,9 +31,9 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@tanstack/react-query": "^5.90.11",
34
- "@unifold/core": "0.1.43",
35
- "@unifold/ui-react": "0.1.43",
36
- "@unifold/react-provider": "0.1.43"
34
+ "@unifold/core": "0.1.44",
35
+ "@unifold/react-provider": "0.1.44",
36
+ "@unifold/ui-react": "0.1.44"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/react": "^19.0.0",