@unifold/connect-react 0.1.44 → 0.1.46

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.mts CHANGED
@@ -141,15 +141,11 @@ interface WithdrawConfig {
141
141
  */
142
142
  senderAddress: string;
143
143
  /**
144
- * Callback invoked with transaction details when user confirms withdrawal.
145
- * The platform must implement the actual transaction signing/sending since
146
- * we don't have the private key.
147
- *
148
- * Optional — if omitted, the user must have a matching connected browser wallet
149
- * to execute the withdrawal. If neither `withdraw` nor a connected wallet is available,
150
- * the modal will show an error.
144
+ * Callback invoked with transaction details when the user confirms withdrawal.
145
+ * The host app is responsible for signing and submitting the transaction the
146
+ * SDK does not have access to the user's private key.
151
147
  */
152
- withdraw?: (txInfo: WithdrawTransactionInfo) => void | Promise<void>;
148
+ withdraw: (txInfo: WithdrawTransactionInfo) => void | Promise<void>;
153
149
  onSuccess?: (data: WithdrawResult) => void;
154
150
  onError?: (error: WithdrawError) => void;
155
151
  onClose?: () => void;
package/dist/index.d.ts CHANGED
@@ -141,15 +141,11 @@ interface WithdrawConfig {
141
141
  */
142
142
  senderAddress: string;
143
143
  /**
144
- * Callback invoked with transaction details when user confirms withdrawal.
145
- * The platform must implement the actual transaction signing/sending since
146
- * we don't have the private key.
147
- *
148
- * Optional — if omitted, the user must have a matching connected browser wallet
149
- * to execute the withdrawal. If neither `withdraw` nor a connected wallet is available,
150
- * the modal will show an error.
144
+ * Callback invoked with transaction details when the user confirms withdrawal.
145
+ * The host app is responsible for signing and submitting the transaction the
146
+ * SDK does not have access to the user's private key.
151
147
  */
152
- withdraw?: (txInfo: WithdrawTransactionInfo) => void | Promise<void>;
148
+ withdraw: (txInfo: WithdrawTransactionInfo) => void | Promise<void>;
153
149
  onSuccess?: (data: WithdrawResult) => void;
154
150
  onError?: (error: WithdrawError) => void;
155
151
  onClose?: () => void;
package/dist/index.js CHANGED
@@ -6715,52 +6715,6 @@ async function getDepositQuote(request, publishableKey) {
6715
6715
  const json = await response.json();
6716
6716
  return json.data;
6717
6717
  }
6718
- async function buildHypercoreTransaction(request, publishableKey) {
6719
- const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6720
- validatePublishableKey(pk);
6721
- const response = await fetch(
6722
- `${API_BASE_URL}/v1/public/transactions/hypercore/build`,
6723
- {
6724
- method: "POST",
6725
- headers: {
6726
- accept: "application/json",
6727
- "x-publishable-key": pk,
6728
- "Content-Type": "application/json"
6729
- },
6730
- body: JSON.stringify(request)
6731
- }
6732
- );
6733
- if (!response.ok) {
6734
- const error = await response.json().catch(() => ({ message: response.statusText }));
6735
- throw new Error(
6736
- `Failed to build HyperCore transaction: ${error.message || response.statusText}`
6737
- );
6738
- }
6739
- return response.json();
6740
- }
6741
- async function sendHypercoreTransaction(request, publishableKey) {
6742
- const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6743
- validatePublishableKey(pk);
6744
- const response = await fetch(
6745
- `${API_BASE_URL}/v1/public/transactions/hypercore/send`,
6746
- {
6747
- method: "POST",
6748
- headers: {
6749
- accept: "application/json",
6750
- "x-publishable-key": pk,
6751
- "Content-Type": "application/json"
6752
- },
6753
- body: JSON.stringify(request)
6754
- }
6755
- );
6756
- if (!response.ok) {
6757
- const error = await response.json().catch(() => ({ message: response.statusText }));
6758
- throw new Error(
6759
- `Failed to send HyperCore transaction: ${error.message || response.statusText}`
6760
- );
6761
- }
6762
- return response.json();
6763
- }
6764
6718
  function useUserIp() {
6765
6719
  const {
6766
6720
  data: userIpInfo,
@@ -21248,10 +21202,11 @@ function BrowserWalletModal({
21248
21202
  const chainType = depositWallet.chain_type;
21249
21203
  const recipientAddress = depositWallet.address;
21250
21204
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
21251
- const { executions: depositExecutions, isPolling } = useDepositPolling({
21205
+ const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
21252
21206
  userId,
21253
21207
  publishableKey,
21254
21208
  clientSecret,
21209
+ depositWalletId: depositWallet.id,
21255
21210
  enabled: open && hasSignedTransaction,
21256
21211
  onDepositSuccess,
21257
21212
  onDepositError
@@ -21502,6 +21457,7 @@ function BrowserWalletModal({
21502
21457
  }
21503
21458
  setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
21504
21459
  setHasSignedTransaction(true);
21460
+ handleIveDeposited();
21505
21461
  setIsConfirming(false);
21506
21462
  setStep("confirming");
21507
21463
  onSuccess?.(txHash);
@@ -24233,249 +24189,10 @@ function useVerifyRecipientAddress(params) {
24233
24189
  refetchOnWindowFocus: false
24234
24190
  });
24235
24191
  }
24236
- async function sendEvmWithdraw(params) {
24237
- const {
24238
- provider,
24239
- fromAddress,
24240
- depositWalletAddress,
24241
- sourceTokenAddress,
24242
- sourceChainId,
24243
- amountBaseUnit
24244
- } = params;
24245
- const currentChainIdHex = await provider.request({
24246
- method: "eth_chainId",
24247
- params: []
24248
- });
24249
- const currentChainId = parseInt(currentChainIdHex, 16).toString();
24250
- if (currentChainId !== sourceChainId) {
24251
- const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
24252
- try {
24253
- await provider.request({
24254
- method: "wallet_switchEthereumChain",
24255
- params: [{ chainId: requiredHex }]
24256
- });
24257
- const newHex = await provider.request({ method: "eth_chainId", params: [] });
24258
- if (parseInt(newHex, 16).toString() !== sourceChainId) {
24259
- throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
24260
- }
24261
- } catch (err) {
24262
- if (err && typeof err === "object" && "code" in err) {
24263
- const e = err;
24264
- if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
24265
- if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
24266
- }
24267
- throw err;
24268
- }
24269
- }
24270
- const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
24271
- const amountBig = BigInt(amountBaseUnit);
24272
- const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
24273
- from: fromAddress,
24274
- to: sourceTokenAddress,
24275
- data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
24276
- };
24277
- let gasEstimate;
24278
- try {
24279
- const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
24280
- gasEstimate = BigInt(hex);
24281
- } catch {
24282
- gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
24283
- }
24284
- const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
24285
- const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
24286
- const gasCost = gasWithBuffer * gasPrice;
24287
- const ethBalance = BigInt(
24288
- await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
24289
- );
24290
- const totalRequired = isNative ? gasCost + amountBig : gasCost;
24291
- if (ethBalance < totalRequired) {
24292
- const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
24293
- if (isNative) {
24294
- throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
24295
- }
24296
- throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
24297
- }
24298
- const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
24299
- return txHash;
24300
- }
24301
- async function sendSolanaWithdraw(params) {
24302
- const {
24303
- provider,
24304
- fromAddress,
24305
- depositWalletAddress,
24306
- sourceTokenAddress,
24307
- amountBaseUnit,
24308
- publishableKey
24309
- } = params;
24310
- if (!provider.publicKey) {
24311
- await provider.connect();
24312
- }
24313
- const buildResponse = await buildSolanaTransaction(
24314
- {
24315
- chain_id: "mainnet",
24316
- token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
24317
- source_address: fromAddress,
24318
- destination_address: depositWalletAddress,
24319
- amount: amountBaseUnit
24320
- },
24321
- publishableKey
24322
- );
24323
- const { VersionedTransaction } = await import(
24324
- /* @vite-ignore */
24325
- "@solana/web3.js"
24326
- );
24327
- const binaryString = atob(buildResponse.transaction);
24328
- const bytes = new Uint8Array(binaryString.length);
24329
- for (let i = 0; i < binaryString.length; i++) {
24330
- bytes[i] = binaryString.charCodeAt(i);
24331
- }
24332
- const transaction = VersionedTransaction.deserialize(bytes);
24333
- const signedTransaction = await provider.signTransaction(transaction);
24334
- const serialized = signedTransaction.serialize();
24335
- let binaryStr = "";
24336
- for (let i = 0; i < serialized.length; i++) {
24337
- binaryStr += String.fromCharCode(serialized[i]);
24338
- }
24339
- const sendResponse = await sendSolanaTransaction(
24340
- { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
24341
- publishableKey
24342
- );
24343
- return sendResponse.signature;
24344
- }
24345
24192
  var HYPERCORE_CHAIN_ID = "1337";
24346
- var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
24347
24193
  function isHypercoreChain(chainId) {
24348
24194
  return chainId === HYPERCORE_CHAIN_ID;
24349
24195
  }
24350
- async function sendHypercoreWithdraw(params) {
24351
- const {
24352
- provider,
24353
- fromAddress,
24354
- depositWalletAddress,
24355
- sourceTokenAddress,
24356
- amount,
24357
- tokenSymbol,
24358
- publishableKey
24359
- } = params;
24360
- const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
24361
- const currentChainHex = await provider.request({
24362
- method: "eth_chainId",
24363
- params: []
24364
- });
24365
- const activeChainId = String(parseInt(currentChainHex, 16));
24366
- const buildResult = await buildHypercoreTransaction(
24367
- {
24368
- action_type: isSpot ? "spot_send" : "usd_send",
24369
- signature_chain_type: "ethereum",
24370
- signature_chain_id: activeChainId,
24371
- recipient_address: depositWalletAddress,
24372
- token_address: sourceTokenAddress,
24373
- token_symbol: tokenSymbol || void 0,
24374
- amount
24375
- },
24376
- publishableKey
24377
- );
24378
- const signature = await provider.request({
24379
- method: "eth_signTypedData_v4",
24380
- params: [fromAddress, JSON.stringify(buildResult.typed_data)]
24381
- });
24382
- await sendHypercoreTransaction(
24383
- {
24384
- action_payload: buildResult.action_payload,
24385
- signature,
24386
- nonce: buildResult.nonce
24387
- },
24388
- publishableKey
24389
- );
24390
- }
24391
- async function detectBrowserWallet(chainType, senderAddress) {
24392
- const win = typeof window !== "undefined" ? window : null;
24393
- if (!win || !senderAddress) return null;
24394
- if (getUserDisconnectedWallet()) return null;
24395
- const anyWin = win;
24396
- if (chainType === "solana") {
24397
- const solProviders = [];
24398
- if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
24399
- if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
24400
- if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
24401
- if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
24402
- for (const { provider, name } of solProviders) {
24403
- if (!provider) continue;
24404
- try {
24405
- let addr;
24406
- if (provider.isConnected && provider.publicKey) {
24407
- addr = provider.publicKey.toString();
24408
- } else {
24409
- const resp = await provider.connect({ onlyIfTrusted: true });
24410
- if (resp?.publicKey) addr = resp.publicKey.toString();
24411
- }
24412
- if (addr && addr === senderAddress) {
24413
- return { chainFamily: "solana", provider, name, address: addr };
24414
- }
24415
- } catch {
24416
- }
24417
- }
24418
- }
24419
- if (chainType === "ethereum") {
24420
- const evmProviders = [];
24421
- const seen = /* @__PURE__ */ new Set();
24422
- const add = (p, name) => {
24423
- if (p && typeof p.request === "function" && !seen.has(p)) {
24424
- seen.add(p);
24425
- evmProviders.push({ provider: p, name });
24426
- }
24427
- };
24428
- if (!anyWin.__eip6963Providers) {
24429
- anyWin.__eip6963Providers = [];
24430
- }
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
- }
24466
- }
24467
- for (const { provider, name } of evmProviders) {
24468
- try {
24469
- const accounts = await provider.request({ method: "eth_accounts" });
24470
- if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
24471
- return { chainFamily: "evm", provider, name, address: accounts[0] };
24472
- }
24473
- } catch {
24474
- }
24475
- }
24476
- }
24477
- return null;
24478
- }
24479
24196
  var t8 = i18n2.withdrawModal;
24480
24197
  var tCrypto = i18n2.transferCrypto;
24481
24198
  function formatProcessingTime2(seconds) {
@@ -24646,6 +24363,9 @@ function WithdrawForm({
24646
24363
  setIsSubmitting(true);
24647
24364
  setSubmitError(null);
24648
24365
  try {
24366
+ if (!onWithdraw) {
24367
+ throw new Error("No withdrawal method available. Please provide an onWithdraw handler.");
24368
+ }
24649
24369
  const depositWallet = await onDepositWalletCreation({
24650
24370
  destinationChainType: selectedChain.chain_type,
24651
24371
  destinationChainId: selectedChain.chain_id,
@@ -24703,63 +24423,16 @@ function WithdrawForm({
24703
24423
  withdrawIntentAddress: depositWallet.address,
24704
24424
  recipientAddress: trimmedAddress
24705
24425
  };
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,
24743
- amount: humanAmount,
24744
- amountBaseUnit,
24745
- depositWallet: depositWallet.address
24746
- });
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, {
24754
- sourceChainId,
24755
- amount: humanAmount,
24756
- amountBaseUnit,
24757
- depositWallet: depositWallet.address
24758
- });
24759
- throw callbackErr;
24760
- }
24761
- } else {
24762
- throw new Error("No withdrawal method available. Please connect a wallet.");
24426
+ try {
24427
+ await onWithdraw(txInfo);
24428
+ } catch (callbackErr) {
24429
+ console.error("[Unifold] onWithdraw callback failed:", callbackErr, {
24430
+ sourceChainId,
24431
+ amount: humanAmount,
24432
+ amountBaseUnit,
24433
+ depositWallet: depositWallet.address
24434
+ });
24435
+ throw callbackErr;
24763
24436
  }
24764
24437
  onWithdrawSubmitted?.(txInfo);
24765
24438
  } catch (err) {
package/dist/index.mjs CHANGED
@@ -6693,52 +6693,6 @@ async function getDepositQuote(request, publishableKey) {
6693
6693
  const json = await response.json();
6694
6694
  return json.data;
6695
6695
  }
6696
- async function buildHypercoreTransaction(request, publishableKey) {
6697
- const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6698
- validatePublishableKey(pk);
6699
- const response = await fetch(
6700
- `${API_BASE_URL}/v1/public/transactions/hypercore/build`,
6701
- {
6702
- method: "POST",
6703
- headers: {
6704
- accept: "application/json",
6705
- "x-publishable-key": pk,
6706
- "Content-Type": "application/json"
6707
- },
6708
- body: JSON.stringify(request)
6709
- }
6710
- );
6711
- if (!response.ok) {
6712
- const error = await response.json().catch(() => ({ message: response.statusText }));
6713
- throw new Error(
6714
- `Failed to build HyperCore transaction: ${error.message || response.statusText}`
6715
- );
6716
- }
6717
- return response.json();
6718
- }
6719
- async function sendHypercoreTransaction(request, publishableKey) {
6720
- const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6721
- validatePublishableKey(pk);
6722
- const response = await fetch(
6723
- `${API_BASE_URL}/v1/public/transactions/hypercore/send`,
6724
- {
6725
- method: "POST",
6726
- headers: {
6727
- accept: "application/json",
6728
- "x-publishable-key": pk,
6729
- "Content-Type": "application/json"
6730
- },
6731
- body: JSON.stringify(request)
6732
- }
6733
- );
6734
- if (!response.ok) {
6735
- const error = await response.json().catch(() => ({ message: response.statusText }));
6736
- throw new Error(
6737
- `Failed to send HyperCore transaction: ${error.message || response.statusText}`
6738
- );
6739
- }
6740
- return response.json();
6741
- }
6742
6696
  function useUserIp() {
6743
6697
  const {
6744
6698
  data: userIpInfo,
@@ -21239,10 +21193,11 @@ function BrowserWalletModal({
21239
21193
  const chainType = depositWallet.chain_type;
21240
21194
  const recipientAddress = depositWallet.address;
21241
21195
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
21242
- const { executions: depositExecutions, isPolling } = useDepositPolling({
21196
+ const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
21243
21197
  userId,
21244
21198
  publishableKey,
21245
21199
  clientSecret,
21200
+ depositWalletId: depositWallet.id,
21246
21201
  enabled: open && hasSignedTransaction,
21247
21202
  onDepositSuccess,
21248
21203
  onDepositError
@@ -21493,6 +21448,7 @@ function BrowserWalletModal({
21493
21448
  }
21494
21449
  setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
21495
21450
  setHasSignedTransaction(true);
21451
+ handleIveDeposited();
21496
21452
  setIsConfirming(false);
21497
21453
  setStep("confirming");
21498
21454
  onSuccess?.(txHash);
@@ -24224,249 +24180,10 @@ function useVerifyRecipientAddress(params) {
24224
24180
  refetchOnWindowFocus: false
24225
24181
  });
24226
24182
  }
24227
- async function sendEvmWithdraw(params) {
24228
- const {
24229
- provider,
24230
- fromAddress,
24231
- depositWalletAddress,
24232
- sourceTokenAddress,
24233
- sourceChainId,
24234
- amountBaseUnit
24235
- } = params;
24236
- const currentChainIdHex = await provider.request({
24237
- method: "eth_chainId",
24238
- params: []
24239
- });
24240
- const currentChainId = parseInt(currentChainIdHex, 16).toString();
24241
- if (currentChainId !== sourceChainId) {
24242
- const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
24243
- try {
24244
- await provider.request({
24245
- method: "wallet_switchEthereumChain",
24246
- params: [{ chainId: requiredHex }]
24247
- });
24248
- const newHex = await provider.request({ method: "eth_chainId", params: [] });
24249
- if (parseInt(newHex, 16).toString() !== sourceChainId) {
24250
- throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
24251
- }
24252
- } catch (err) {
24253
- if (err && typeof err === "object" && "code" in err) {
24254
- const e = err;
24255
- if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
24256
- if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
24257
- }
24258
- throw err;
24259
- }
24260
- }
24261
- const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
24262
- const amountBig = BigInt(amountBaseUnit);
24263
- const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
24264
- from: fromAddress,
24265
- to: sourceTokenAddress,
24266
- data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
24267
- };
24268
- let gasEstimate;
24269
- try {
24270
- const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
24271
- gasEstimate = BigInt(hex);
24272
- } catch {
24273
- gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
24274
- }
24275
- const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
24276
- const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
24277
- const gasCost = gasWithBuffer * gasPrice;
24278
- const ethBalance = BigInt(
24279
- await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
24280
- );
24281
- const totalRequired = isNative ? gasCost + amountBig : gasCost;
24282
- if (ethBalance < totalRequired) {
24283
- const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
24284
- if (isNative) {
24285
- throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
24286
- }
24287
- throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
24288
- }
24289
- const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
24290
- return txHash;
24291
- }
24292
- async function sendSolanaWithdraw(params) {
24293
- const {
24294
- provider,
24295
- fromAddress,
24296
- depositWalletAddress,
24297
- sourceTokenAddress,
24298
- amountBaseUnit,
24299
- publishableKey
24300
- } = params;
24301
- if (!provider.publicKey) {
24302
- await provider.connect();
24303
- }
24304
- const buildResponse = await buildSolanaTransaction(
24305
- {
24306
- chain_id: "mainnet",
24307
- token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
24308
- source_address: fromAddress,
24309
- destination_address: depositWalletAddress,
24310
- amount: amountBaseUnit
24311
- },
24312
- publishableKey
24313
- );
24314
- const { VersionedTransaction } = await import(
24315
- /* @vite-ignore */
24316
- "@solana/web3.js"
24317
- );
24318
- const binaryString = atob(buildResponse.transaction);
24319
- const bytes = new Uint8Array(binaryString.length);
24320
- for (let i = 0; i < binaryString.length; i++) {
24321
- bytes[i] = binaryString.charCodeAt(i);
24322
- }
24323
- const transaction = VersionedTransaction.deserialize(bytes);
24324
- const signedTransaction = await provider.signTransaction(transaction);
24325
- const serialized = signedTransaction.serialize();
24326
- let binaryStr = "";
24327
- for (let i = 0; i < serialized.length; i++) {
24328
- binaryStr += String.fromCharCode(serialized[i]);
24329
- }
24330
- const sendResponse = await sendSolanaTransaction(
24331
- { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
24332
- publishableKey
24333
- );
24334
- return sendResponse.signature;
24335
- }
24336
24183
  var HYPERCORE_CHAIN_ID = "1337";
24337
- var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
24338
24184
  function isHypercoreChain(chainId) {
24339
24185
  return chainId === HYPERCORE_CHAIN_ID;
24340
24186
  }
24341
- async function sendHypercoreWithdraw(params) {
24342
- const {
24343
- provider,
24344
- fromAddress,
24345
- depositWalletAddress,
24346
- sourceTokenAddress,
24347
- amount,
24348
- tokenSymbol,
24349
- publishableKey
24350
- } = params;
24351
- const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
24352
- const currentChainHex = await provider.request({
24353
- method: "eth_chainId",
24354
- params: []
24355
- });
24356
- const activeChainId = String(parseInt(currentChainHex, 16));
24357
- const buildResult = await buildHypercoreTransaction(
24358
- {
24359
- action_type: isSpot ? "spot_send" : "usd_send",
24360
- signature_chain_type: "ethereum",
24361
- signature_chain_id: activeChainId,
24362
- recipient_address: depositWalletAddress,
24363
- token_address: sourceTokenAddress,
24364
- token_symbol: tokenSymbol || void 0,
24365
- amount
24366
- },
24367
- publishableKey
24368
- );
24369
- const signature = await provider.request({
24370
- method: "eth_signTypedData_v4",
24371
- params: [fromAddress, JSON.stringify(buildResult.typed_data)]
24372
- });
24373
- await sendHypercoreTransaction(
24374
- {
24375
- action_payload: buildResult.action_payload,
24376
- signature,
24377
- nonce: buildResult.nonce
24378
- },
24379
- publishableKey
24380
- );
24381
- }
24382
- async function detectBrowserWallet(chainType, senderAddress) {
24383
- const win = typeof window !== "undefined" ? window : null;
24384
- if (!win || !senderAddress) return null;
24385
- if (getUserDisconnectedWallet()) return null;
24386
- const anyWin = win;
24387
- if (chainType === "solana") {
24388
- const solProviders = [];
24389
- if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
24390
- if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
24391
- if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
24392
- if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
24393
- for (const { provider, name } of solProviders) {
24394
- if (!provider) continue;
24395
- try {
24396
- let addr;
24397
- if (provider.isConnected && provider.publicKey) {
24398
- addr = provider.publicKey.toString();
24399
- } else {
24400
- const resp = await provider.connect({ onlyIfTrusted: true });
24401
- if (resp?.publicKey) addr = resp.publicKey.toString();
24402
- }
24403
- if (addr && addr === senderAddress) {
24404
- return { chainFamily: "solana", provider, name, address: addr };
24405
- }
24406
- } catch {
24407
- }
24408
- }
24409
- }
24410
- if (chainType === "ethereum") {
24411
- const evmProviders = [];
24412
- const seen = /* @__PURE__ */ new Set();
24413
- const add = (p, name) => {
24414
- if (p && typeof p.request === "function" && !seen.has(p)) {
24415
- seen.add(p);
24416
- evmProviders.push({ provider: p, name });
24417
- }
24418
- };
24419
- if (!anyWin.__eip6963Providers) {
24420
- anyWin.__eip6963Providers = [];
24421
- }
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
- }
24457
- }
24458
- for (const { provider, name } of evmProviders) {
24459
- try {
24460
- const accounts = await provider.request({ method: "eth_accounts" });
24461
- if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
24462
- return { chainFamily: "evm", provider, name, address: accounts[0] };
24463
- }
24464
- } catch {
24465
- }
24466
- }
24467
- }
24468
- return null;
24469
- }
24470
24187
  var t8 = i18n2.withdrawModal;
24471
24188
  var tCrypto = i18n2.transferCrypto;
24472
24189
  function formatProcessingTime2(seconds) {
@@ -24637,6 +24354,9 @@ function WithdrawForm({
24637
24354
  setIsSubmitting(true);
24638
24355
  setSubmitError(null);
24639
24356
  try {
24357
+ if (!onWithdraw) {
24358
+ throw new Error("No withdrawal method available. Please provide an onWithdraw handler.");
24359
+ }
24640
24360
  const depositWallet = await onDepositWalletCreation({
24641
24361
  destinationChainType: selectedChain.chain_type,
24642
24362
  destinationChainId: selectedChain.chain_id,
@@ -24694,63 +24414,16 @@ function WithdrawForm({
24694
24414
  withdrawIntentAddress: depositWallet.address,
24695
24415
  recipientAddress: trimmedAddress
24696
24416
  };
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,
24734
- amount: humanAmount,
24735
- amountBaseUnit,
24736
- depositWallet: depositWallet.address
24737
- });
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, {
24745
- sourceChainId,
24746
- amount: humanAmount,
24747
- amountBaseUnit,
24748
- depositWallet: depositWallet.address
24749
- });
24750
- throw callbackErr;
24751
- }
24752
- } else {
24753
- throw new Error("No withdrawal method available. Please connect a wallet.");
24417
+ try {
24418
+ await onWithdraw(txInfo);
24419
+ } catch (callbackErr) {
24420
+ console.error("[Unifold] onWithdraw callback failed:", callbackErr, {
24421
+ sourceChainId,
24422
+ amount: humanAmount,
24423
+ amountBaseUnit,
24424
+ depositWallet: depositWallet.address
24425
+ });
24426
+ throw callbackErr;
24754
24427
  }
24755
24428
  onWithdrawSubmitted?.(txInfo);
24756
24429
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/connect-react",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
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.44",
35
- "@unifold/react-provider": "0.1.44",
36
- "@unifold/ui-react": "0.1.44"
34
+ "@unifold/core": "0.1.46",
35
+ "@unifold/react-provider": "0.1.46",
36
+ "@unifold/ui-react": "0.1.46"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/react": "^19.0.0",