coinley-pay 0.61.0 → 0.63.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.
@@ -6,7 +6,7 @@ import { useState, useRef, useEffect, useCallback, useMemo } from "react";
6
6
  import ReactDOM, { createPortal } from "react-dom";
7
7
  import { useConnect, useAccount, useSwitchChain, useSendTransaction, useWaitForTransactionReceipt, WagmiProvider, useDisconnect } from "wagmi";
8
8
  import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
9
- import { s as sdkAnalytics, c as clarityAnalytics, d as dist, a as Buffer2, B as Buffer$1, g as getCurrencyInfo, p as prefetchRates, i as isSupportedCurrency, b as convertToUSD, f as formatCurrency } from "./index-Dssajde4.js";
9
+ import { s as sdkAnalytics, c as clarityAnalytics, d as dist, a as Buffer2, B as Buffer$1, g as getCurrencyInfo, p as prefetchRates, i as isSupportedCurrency, b as convertToUSD, f as formatCurrency } from "./index-BFlZCZrz.js";
10
10
  import { createConfig, fallback, http, getAccount as getAccount$1, getWalletClient, simulateContract, writeContract, readContract, waitForTransactionReceipt, estimateFeesPerGas as estimateFeesPerGas$1 } from "@wagmi/core";
11
11
  import { injected, metaMask, coinbaseWallet, walletConnect } from "@wagmi/connectors";
12
12
  import { defineChain as defineChain$1, erc20Abi, http as http$1, createPublicClient, fallback as fallback$1 } from "viem";
@@ -21126,7 +21126,7 @@ const WalletSelector = ({
21126
21126
  try {
21127
21127
  setAppKitError(null);
21128
21128
  setWalletConnectAddress(solanaAccountState.address);
21129
- const { createWalletConnectAdapter } = await import("./appKitSolana-C_InTqyc.js");
21129
+ const { createWalletConnectAdapter } = await import("./appKitSolana-Dyj8Yus-.js");
21130
21130
  const adapter = createWalletConnectAdapter(solanaAccountState.address);
21131
21131
  await solanaWallet.connectWalletConnect(adapter, solanaAccountState.address);
21132
21132
  console.log("✅ WalletConnect synced with SDK");
@@ -21231,7 +21231,7 @@ const WalletSelector = ({
21231
21231
  setAppKitLoading(true);
21232
21232
  setAppKitError(null);
21233
21233
  try {
21234
- const { initializeAppKitEVM, openAppKitModal } = await import("./appKitEVM-BzMDYdux.js");
21234
+ const { initializeAppKitEVM, openAppKitModal } = await import("./appKitEVM-f4GTnd8I.js");
21235
21235
  await initializeAppKitEVM(wagmiConfig);
21236
21236
  await openAppKitModal();
21237
21237
  } catch (error) {
@@ -21251,7 +21251,7 @@ const WalletSelector = ({
21251
21251
  setAppKitError(null);
21252
21252
  try {
21253
21253
  console.log("📦 Loading AppKit Solana module...");
21254
- const { initializeAppKitSolana } = await import("./appKitSolana-C_InTqyc.js");
21254
+ const { initializeAppKitSolana } = await import("./appKitSolana-Dyj8Yus-.js");
21255
21255
  console.log("✅ Module loaded, initializing...");
21256
21256
  const modal = await initializeAppKitSolana(solanaWallet);
21257
21257
  console.log("✅ AppKit Solana initialized successfully");
@@ -23128,6 +23128,29 @@ const injectCoinleyFonts = () => {
23128
23128
  `;
23129
23129
  document.head.appendChild(style);
23130
23130
  };
23131
+ const FIVE_MINUTES_MS = 5 * 60 * 1e3;
23132
+ const TEN_MINUTES_MS = 10 * 60 * 1e3;
23133
+ const getRefundPendingGuidance = (elapsedMs = 0) => {
23134
+ if (elapsedMs >= TEN_MINUTES_MS) {
23135
+ return {
23136
+ title: "Refund is taking longer than expected",
23137
+ description: "Your refund is still being processed. You can safely close this window while we continue in the background.",
23138
+ eta: "Most refunds arrive within 15 minutes. If yours does not, check again later or contact support with your payment ID."
23139
+ };
23140
+ }
23141
+ if (elapsedMs >= FIVE_MINUTES_MS) {
23142
+ return {
23143
+ title: "Refund is still being processed",
23144
+ description: "Your refund request has been accepted and is still processing. You do not need to keep this window open.",
23145
+ eta: "Most refunds at this stage arrive within about 10 minutes."
23146
+ };
23147
+ }
23148
+ return {
23149
+ title: "Refund request received",
23150
+ description: "Your refund is being processed automatically. You can safely close this window.",
23151
+ eta: "Most refunds arrive within about 5 minutes."
23152
+ };
23153
+ };
23131
23154
  const CHECKOUT_BUILD = "checkout-2026-04-22b-route-destination-trials";
23132
23155
  const UNDERPAYMENT_RECOVERY_STORAGE_PREFIX = "coinley_underpayment_recovery:";
23133
23156
  const UNDERPAYMENT_RECOVERY_TTL_MS = 2 * 60 * 60 * 1e3;
@@ -23356,11 +23379,13 @@ const CoinleyPaymentInternal = ({
23356
23379
  const [refundRequestMessage, setRefundRequestMessage] = useState("");
23357
23380
  const [offsetSuccessDetails, setOffsetSuccessDetails] = useState(null);
23358
23381
  const [refundSuccessDetails, setRefundSuccessDetails] = useState(null);
23382
+ const [overpaymentInfo, setOverpaymentInfo] = useState(null);
23359
23383
  const [recoveryLoadingAction, setRecoveryLoadingAction] = useState(null);
23360
23384
  const [recoveryLoadingStatus, setRecoveryLoadingStatus] = useState(null);
23361
23385
  const manualCheckTimeout = useRef(null);
23362
23386
  const recoveryLoadingStartedAt = useRef(0);
23363
23387
  const recoveryLoadingTimeout = useRef(null);
23388
+ const refundPendingStartedAt = useRef(0);
23364
23389
  const [copiedField, setCopiedField] = useState(null);
23365
23390
  const [expirationTime, setExpirationTime] = useState(null);
23366
23391
  const STANDARD_PAYMENT_TIMEOUT_MS = 15 * 60 * 1e3;
@@ -24291,11 +24316,13 @@ const CoinleyPaymentInternal = ({
24291
24316
  const txHash = resolvePaymentTransactionHash(statusResult.payment);
24292
24317
  if ((status === "completed" || status === "swept") && txHash) {
24293
24318
  clearInterval(pollInterval);
24294
- captureOffsetSuccessDetails(statusResult.payment, txHash);
24295
24319
  clearUnderpaymentRecovery(paymentData.id);
24296
24320
  setProcessingStatusMessage("");
24297
24321
  persistSuccessfulPaymentHash(statusResult.payment, txHash);
24298
- setCurrentStep(PAYMENT_STEPS.SUCCESS);
24322
+ const rawPmt = statusResult.payment;
24323
+ const rcvd = parseFloat(rawPmt.amountReceived || 0);
24324
+ const expd = parseFloat(rawPmt.amount || 0);
24325
+ const isOverpaid = rawPmt.refundReason === "overpaid_excess" || rawPmt.excessOwed != null || rcvd > 0 && expd > 0 && rcvd > expd;
24299
24326
  sdkAnalytics.trackPaymentSuccess(
24300
24327
  paymentData.id,
24301
24328
  config == null ? void 0 : config.amount,
@@ -24314,12 +24341,29 @@ const CoinleyPaymentInternal = ({
24314
24341
  onSuccess({
24315
24342
  paymentId: paymentData.id,
24316
24343
  transactionHash: txHash,
24317
- depositAddress: statusResult.payment.depositAddress,
24344
+ depositAddress: rawPmt.depositAddress,
24318
24345
  network: selectedNetwork == null ? void 0 : selectedNetwork.shortName,
24319
24346
  currency: selectedToken == null ? void 0 : selectedToken.symbol,
24320
- paymentDetails: statusResult.payment
24347
+ paymentDetails: rawPmt
24348
+ });
24349
+ }
24350
+ if (isOverpaid) {
24351
+ const excessStr = rawPmt.excessOwed != null ? rawPmt.excessOwed : rcvd > 0 && expd > 0 ? String((rcvd - expd).toFixed(6)) : null;
24352
+ setOverpaymentInfo({
24353
+ paymentId: paymentData.id,
24354
+ excessOwed: excessStr,
24355
+ tokenSymbol: rawPmt.currency || (selectedToken == null ? void 0 : selectedToken.symbol) || "tokens",
24356
+ networkLabel: (selectedNetwork == null ? void 0 : selectedNetwork.displayName) || (selectedNetwork == null ? void 0 : selectedNetwork.name) || (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "the deposit network"
24321
24357
  });
24358
+ setRefundAddress("");
24359
+ setRefundRequestStatus(null);
24360
+ setRefundRequestSubmitted(false);
24361
+ setRefundRequestMessage("");
24362
+ refundPendingStartedAt.current = 0;
24363
+ } else {
24364
+ captureOffsetSuccessDetails(rawPmt, txHash);
24322
24365
  }
24366
+ setCurrentStep(PAYMENT_STEPS.SUCCESS);
24323
24367
  return;
24324
24368
  }
24325
24369
  if (activateUnderpaymentFlow(statusResult.payment)) {
@@ -24354,6 +24398,25 @@ const CoinleyPaymentInternal = ({
24354
24398
  }, 5e3);
24355
24399
  return () => clearInterval(pollInterval);
24356
24400
  }, [currentStep, paymentData == null ? void 0 : paymentData.id, paymentData == null ? void 0 : paymentData.depositAddress, selectedNetwork, selectedToken, onSuccess, activateUnderpaymentFlow, captureOffsetSuccessDetails, clearUnderpaymentRecovery, resolvePaymentTransactionHash, persistSuccessfulPaymentHash]);
24401
+ useEffect(() => {
24402
+ if (currentStep !== PAYMENT_STEPS.SUCCESS || !(overpaymentInfo == null ? void 0 : overpaymentInfo.paymentId) || !refundRequestSubmitted || refundRequestStatus !== "pending") {
24403
+ return;
24404
+ }
24405
+ const pollInterval = setInterval(async () => {
24406
+ var _a2;
24407
+ try {
24408
+ const statusResult = await paymentFlow.api.getDepositStatus(overpaymentInfo.paymentId);
24409
+ if (statusResult.success && ((_a2 = statusResult.payment) == null ? void 0 : _a2.refundStatus) === "refunded") {
24410
+ clearInterval(pollInterval);
24411
+ refundPendingStartedAt.current = 0;
24412
+ setRefundRequestStatus("refunded");
24413
+ }
24414
+ } catch (e) {
24415
+ console.warn("[OverpaymentRefundPoll] Error:", e.message);
24416
+ }
24417
+ }, 5e3);
24418
+ return () => clearInterval(pollInterval);
24419
+ }, [currentStep, overpaymentInfo, refundRequestSubmitted, refundRequestStatus, paymentFlow.api]);
24357
24420
  useEffect(() => {
24358
24421
  const shouldPoll = (paymentData == null ? void 0 : paymentData.id) && (activeTab === PAYMENT_TABS.QR || activeTab === PAYMENT_TABS.TRANSFER) && currentStep === PAYMENT_STEPS.CONFIRM && !verifyingPayment && paymentType !== PAYMENT_TYPES.DEPOSIT && !(paymentData == null ? void 0 : paymentData.isDepositPayment) && !(paymentData == null ? void 0 : paymentData.depositAddress);
24359
24422
  if (!shouldPoll) {
@@ -24453,6 +24516,7 @@ const CoinleyPaymentInternal = ({
24453
24516
  setRecoveryLoadingAction(null);
24454
24517
  setRecoveryLoadingStatus(null);
24455
24518
  setCcSuccessDetails(null);
24519
+ setOverpaymentInfo(null);
24456
24520
  if (recoveryLoadingTimeout.current) {
24457
24521
  clearTimeout(recoveryLoadingTimeout.current);
24458
24522
  recoveryLoadingTimeout.current = null;
@@ -25377,6 +25441,7 @@ const CoinleyPaymentInternal = ({
25377
25441
  setRecoveryLoadingStatus({ action, ...status });
25378
25442
  });
25379
25443
  }, [runAfterRecoveryMinimum]);
25444
+ const getRefundPendingElapsedMs = useCallback(() => refundPendingStartedAt.current ? Math.max(Date.now() - refundPendingStartedAt.current, 0) : 0, []);
25380
25445
  const getOffsetWaitingStatus = useCallback((overrides = {}) => {
25381
25446
  const shortfallLabel = underpaymentInfo ? `${formatAmount(underpaymentInfo.shortfallAmount || underpaymentInfo.amountRemaining || 0)} ${underpaymentInfo.tokenSymbol || (selectedToken == null ? void 0 : selectedToken.symbol) || ""}`.trim() : "the remaining amount";
25382
25447
  const networkLabel = (underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel) || (selectedNetwork == null ? void 0 : selectedNetwork.name) || (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "the selected network";
@@ -25387,24 +25452,27 @@ const CoinleyPaymentInternal = ({
25387
25452
  ...overrides
25388
25453
  };
25389
25454
  }, [selectedNetwork == null ? void 0 : selectedNetwork.name, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, underpaymentInfo]);
25390
- const getRefundPendingStatus = useCallback(() => ({
25391
- title: "Refund request received",
25392
- description: "We will process it automatically.",
25393
- detail: `Refunding the received ${(underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol) || (selectedToken == null ? void 0 : selectedToken.symbol) || "tokens"} on ${(underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel) || (selectedNetwork == null ? void 0 : selectedNetwork.name) || (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "the selected network"}.`
25394
- }), [selectedNetwork == null ? void 0 : selectedNetwork.name, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel, underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol]);
25455
+ const getRefundPendingStatus = useCallback(() => {
25456
+ const guidance = getRefundPendingGuidance(getRefundPendingElapsedMs());
25457
+ return {
25458
+ ...guidance,
25459
+ detail: `${guidance.eta} Refunding the received ${(underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol) || (selectedToken == null ? void 0 : selectedToken.symbol) || "tokens"} on ${(underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel) || (selectedNetwork == null ? void 0 : selectedNetwork.name) || (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "the selected network"}.`
25460
+ };
25461
+ }, [getRefundPendingElapsedMs, selectedNetwork == null ? void 0 : selectedNetwork.name, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel, underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol]);
25395
25462
  const getCrossChainRefundPendingStatus = useCallback((status = ccRefundPendingInfo) => {
25396
25463
  var _a2, _b, _c, _d;
25397
25464
  const details = (status == null ? void 0 : status.refundPendingDetails) || {};
25398
25465
  const tokenSymbol = ((_a2 = status == null ? void 0 : status.underpayment) == null ? void 0 : _a2.tokenSymbol) || ((_b = status == null ? void 0 : status.underpayment) == null ? void 0 : _b.currency) || (underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol) || (ccOriginToken == null ? void 0 : ccOriginToken.symbol) || (selectedToken == null ? void 0 : selectedToken.symbol) || "tokens";
25399
25466
  const networkLabel = ((_c = status == null ? void 0 : status.underpayment) == null ? void 0 : _c.refundNetworkLabel) || (underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel) || ccChainName(((_d = status == null ? void 0 : status.relay) == null ? void 0 : _d.originChainId) || (ccResult == null ? void 0 : ccResult.originChainId) || ccOriginChainId);
25400
25467
  const refundAddressLabel = (status == null ? void 0 : status.refundRecipient) || refundAddress.trim();
25468
+ const guidance = getRefundPendingGuidance(getRefundPendingElapsedMs());
25401
25469
  const available = details.available && details.available !== "0.0" ? ` Relay has returned ${details.available} ${tokenSymbol}.` : "";
25402
25470
  return {
25403
- title: "Waiting for Relay refund",
25404
- description: "Relay is returning the underpaid funds before Coinley can send your refund.",
25405
- detail: `We will keep checking automatically and refund ${tokenSymbol} on ${networkLabel}${refundAddressLabel ? ` to ${truncateAddress(refundAddressLabel)}` : ""}.${available}`
25471
+ title: guidance.title,
25472
+ description: guidance.description,
25473
+ detail: `${guidance.eta} Refund will be sent as ${tokenSymbol} on ${networkLabel}${refundAddressLabel ? ` to ${truncateAddress(refundAddressLabel)}` : ""}.${available}`
25406
25474
  };
25407
- }, [ccOriginChainId, ccOriginToken == null ? void 0 : ccOriginToken.symbol, ccRefundPendingInfo, ccResult == null ? void 0 : ccResult.originChainId, refundAddress, selectedToken == null ? void 0 : selectedToken.symbol, underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel, underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol]);
25475
+ }, [ccOriginChainId, ccOriginToken == null ? void 0 : ccOriginToken.symbol, ccRefundPendingInfo, ccResult == null ? void 0 : ccResult.originChainId, getRefundPendingElapsedMs, refundAddress, selectedToken == null ? void 0 : selectedToken.symbol, underpaymentInfo == null ? void 0 : underpaymentInfo.refundNetworkLabel, underpaymentInfo == null ? void 0 : underpaymentInfo.tokenSymbol]);
25408
25476
  useEffect(() => () => {
25409
25477
  if (recoveryLoadingTimeout.current) {
25410
25478
  clearTimeout(recoveryLoadingTimeout.current);
@@ -25419,6 +25487,7 @@ const CoinleyPaymentInternal = ({
25419
25487
  const status = await paymentFlow.api.getCrossChainStatus(ccResult.id);
25420
25488
  setCcPhase(status.phase);
25421
25489
  if (status.refundStatus === "refunded") {
25490
+ refundPendingStartedAt.current = 0;
25422
25491
  finishRecoveryLoading(() => {
25423
25492
  setCcRefundPendingInfo(null);
25424
25493
  ccSucceeded.current = true;
@@ -25429,6 +25498,7 @@ const CoinleyPaymentInternal = ({
25429
25498
  setCurrentStep(PAYMENT_STEPS.SUCCESS);
25430
25499
  });
25431
25500
  } else if (status.refundStatus === "pending") {
25501
+ refundPendingStartedAt.current = refundPendingStartedAt.current || Date.now();
25432
25502
  activateUnderpaymentFromCrossChainStatus(status);
25433
25503
  setCcRefundPendingInfo(status);
25434
25504
  setRefundRequestSubmitted(true);
@@ -25498,6 +25568,7 @@ const CoinleyPaymentInternal = ({
25498
25568
  if (cancelled) return;
25499
25569
  setCcPhase(s.phase);
25500
25570
  if (s.refundStatus === "refunded") {
25571
+ refundPendingStartedAt.current = 0;
25501
25572
  ccSucceeded.current = true;
25502
25573
  setCcRefundPendingInfo(null);
25503
25574
  setRefundRequestStatus("refunded");
@@ -25506,6 +25577,7 @@ const CoinleyPaymentInternal = ({
25506
25577
  clearUnderpaymentRecovery(s.paymentId || ccResult.id);
25507
25578
  setCurrentStep(PAYMENT_STEPS.SUCCESS);
25508
25579
  } else if (s.refundStatus === "pending") {
25580
+ refundPendingStartedAt.current = refundPendingStartedAt.current || Date.now();
25509
25581
  activateUnderpaymentFromCrossChainStatus(s);
25510
25582
  setCcRefundPendingInfo(s);
25511
25583
  setRefundRequestSubmitted(true);
@@ -26357,6 +26429,7 @@ const CoinleyPaymentInternal = ({
26357
26429
  setUnderpaymentChoice(recoveryState.choice);
26358
26430
  setUnderpaymentView(recoveryState.view === "refund" ? "refund" : "offset");
26359
26431
  setManualCheckStatus(null);
26432
+ refundPendingStartedAt.current = 0;
26360
26433
  setRefundRequestSubmitted(false);
26361
26434
  setRefundRequestStatus(null);
26362
26435
  setRefundRequestMessage("");
@@ -26366,6 +26439,7 @@ const CoinleyPaymentInternal = ({
26366
26439
  setUnderpaymentChoice(null);
26367
26440
  setUnderpaymentView("choice");
26368
26441
  setRefundAddress("");
26442
+ refundPendingStartedAt.current = 0;
26369
26443
  setRefundRequestSubmitted(false);
26370
26444
  setRefundRequestStatus(null);
26371
26445
  setRefundRequestMessage("");
@@ -26381,6 +26455,7 @@ const CoinleyPaymentInternal = ({
26381
26455
  const trimmedAddress = refundAddress.trim();
26382
26456
  if (!trimmedAddress || !activeTransferPaymentId || refundRequestStatus === "submitting") return;
26383
26457
  startRecoveryLoading("refund");
26458
+ refundPendingStartedAt.current = Date.now();
26384
26459
  setRefundRequestStatus("submitting");
26385
26460
  setRefundRequestMessage("");
26386
26461
  setManualCheckStatus(null);
@@ -26413,6 +26488,7 @@ const CoinleyPaymentInternal = ({
26413
26488
  setRefundRequestSubmitted(true);
26414
26489
  setRefundRequestStatus(refundStatus === "refunded" ? "refunded" : "pending");
26415
26490
  if (refundStatus === "refunded") {
26491
+ refundPendingStartedAt.current = 0;
26416
26492
  finishRecoveryLoading(() => {
26417
26493
  var _a3;
26418
26494
  setRefundRequestMessage("");
@@ -26421,6 +26497,7 @@ const CoinleyPaymentInternal = ({
26421
26497
  setCurrentStep(PAYMENT_STEPS.SUCCESS);
26422
26498
  });
26423
26499
  } else {
26500
+ refundPendingStartedAt.current = refundPendingStartedAt.current || Date.now();
26424
26501
  setRefundRequestMessage("");
26425
26502
  if (ccResult) {
26426
26503
  const pendingStatus = {
@@ -26438,6 +26515,7 @@ const CoinleyPaymentInternal = ({
26438
26515
  }
26439
26516
  }
26440
26517
  } catch (error2) {
26518
+ refundPendingStartedAt.current = 0;
26441
26519
  console.warn("[RefundRequest] Error:", error2.message);
26442
26520
  finishRecoveryLoading(() => {
26443
26521
  setRefundRequestSubmitted(false);
@@ -26446,6 +26524,31 @@ const CoinleyPaymentInternal = ({
26446
26524
  });
26447
26525
  }
26448
26526
  }, [activeTransferPaymentId, captureRefundSuccessDetails, ccOriginChainId, ccOriginToken == null ? void 0 : ccOriginToken.symbol, ccResult, clearUnderpaymentRecovery, config, finishRecoveryLoading, getCrossChainRefundPendingStatus, getRefundPendingStatus, holdRecoveryLoading, refundAddress, refundRequestStatus, paymentFlow.api, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, startRecoveryLoading, underpaymentInfo]);
26527
+ const handleOverpaymentRefundSubmit = useCallback(async () => {
26528
+ var _a2;
26529
+ const trimmedAddress = refundAddress.trim();
26530
+ if (!trimmedAddress || !(overpaymentInfo == null ? void 0 : overpaymentInfo.paymentId) || refundRequestStatus === "submitting") return;
26531
+ setRefundRequestStatus("submitting");
26532
+ setRefundRequestMessage("");
26533
+ refundPendingStartedAt.current = Date.now();
26534
+ try {
26535
+ const result = await paymentFlow.api.requestDepositRefund(overpaymentInfo.paymentId, trimmedAddress);
26536
+ const refundSt = ((_a2 = result == null ? void 0 : result.payment) == null ? void 0 : _a2.refundStatus) || (result == null ? void 0 : result.status) || "pending";
26537
+ setRefundRequestSubmitted(true);
26538
+ if (refundSt === "refunded") {
26539
+ refundPendingStartedAt.current = 0;
26540
+ setRefundRequestStatus("refunded");
26541
+ } else {
26542
+ refundPendingStartedAt.current = refundPendingStartedAt.current || Date.now();
26543
+ setRefundRequestStatus("pending");
26544
+ }
26545
+ setRefundRequestMessage("");
26546
+ } catch (error2) {
26547
+ refundPendingStartedAt.current = 0;
26548
+ setRefundRequestStatus("error");
26549
+ setRefundRequestMessage(error2.message || "Failed to submit refund request. Please try again.");
26550
+ }
26551
+ }, [overpaymentInfo, refundAddress, refundRequestStatus, paymentFlow.api]);
26449
26552
  const handleDepositManualCheck = useCallback(async () => {
26450
26553
  if (manualCheckStatus === "checking" || !(paymentData == null ? void 0 : paymentData.id)) return;
26451
26554
  const isOffsetRecovery = Boolean(underpaymentInfo && underpaymentView === "offset");
@@ -26458,22 +26561,41 @@ const CoinleyPaymentInternal = ({
26458
26561
  if ((status === "completed" || status === "swept") && txHash) {
26459
26562
  finishRecoveryLoading(() => {
26460
26563
  setManualCheckStatus(null);
26461
- captureOffsetSuccessDetails(statusResult.payment, txHash);
26462
26564
  clearUnderpaymentRecovery(paymentData.id);
26463
26565
  persistSuccessfulPaymentHash(statusResult.payment, txHash);
26464
- setCurrentStep(PAYMENT_STEPS.SUCCESS);
26566
+ const rawPmt = statusResult.payment;
26567
+ const rcvd = parseFloat(rawPmt.amountReceived || 0);
26568
+ const expd = parseFloat(rawPmt.amount || 0);
26569
+ const isOverpaid = rawPmt.refundReason === "overpaid_excess" || rawPmt.excessOwed != null || rcvd > 0 && expd > 0 && rcvd > expd;
26465
26570
  sdkAnalytics.trackPaymentSuccess(paymentData.id, config == null ? void 0 : config.amount, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, txHash);
26466
26571
  clarityAnalytics.trackPaymentSuccess(paymentData.id, config == null ? void 0 : config.amount, selectedNetwork == null ? void 0 : selectedNetwork.shortName, selectedToken == null ? void 0 : selectedToken.symbol, txHash);
26467
26572
  if (onSuccess) {
26468
26573
  onSuccess({
26469
26574
  paymentId: paymentData.id,
26470
26575
  transactionHash: txHash,
26471
- depositAddress: statusResult.payment.depositAddress,
26576
+ depositAddress: rawPmt.depositAddress,
26472
26577
  network: selectedNetwork == null ? void 0 : selectedNetwork.shortName,
26473
26578
  currency: selectedToken == null ? void 0 : selectedToken.symbol,
26474
- paymentDetails: statusResult.payment
26579
+ paymentDetails: rawPmt
26580
+ });
26581
+ }
26582
+ if (isOverpaid) {
26583
+ const excessStr = rawPmt.excessOwed != null ? rawPmt.excessOwed : rcvd > 0 && expd > 0 ? String((rcvd - expd).toFixed(6)) : null;
26584
+ setOverpaymentInfo({
26585
+ paymentId: paymentData.id,
26586
+ excessOwed: excessStr,
26587
+ tokenSymbol: rawPmt.currency || (selectedToken == null ? void 0 : selectedToken.symbol) || "tokens",
26588
+ networkLabel: (selectedNetwork == null ? void 0 : selectedNetwork.displayName) || (selectedNetwork == null ? void 0 : selectedNetwork.name) || (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "the deposit network"
26475
26589
  });
26590
+ setRefundAddress("");
26591
+ setRefundRequestStatus(null);
26592
+ setRefundRequestSubmitted(false);
26593
+ setRefundRequestMessage("");
26594
+ refundPendingStartedAt.current = 0;
26595
+ } else {
26596
+ captureOffsetSuccessDetails(rawPmt, txHash);
26476
26597
  }
26598
+ setCurrentStep(PAYMENT_STEPS.SUCCESS);
26477
26599
  });
26478
26600
  return;
26479
26601
  }
@@ -26582,6 +26704,92 @@ const CoinleyPaymentInternal = ({
26582
26704
  );
26583
26705
  }
26584
26706
  if (currentStep === PAYMENT_STEPS.SUCCESS) {
26707
+ if (overpaymentInfo) {
26708
+ const opElapsedMs = refundPendingStartedAt.current ? Math.max(Date.now() - refundPendingStartedAt.current, 0) : 0;
26709
+ const opGuidance = refundRequestSubmitted && refundRequestStatus === "pending" ? getRefundPendingGuidance(opElapsedMs) : null;
26710
+ return renderInPortal(
26711
+ /* @__PURE__ */ jsxs("div", { id: SDK_ROOT_ID, className: `${SDK_ROOT_CLASS} fixed inset-0 z-50`, style: { fontFamily: FONT_FAMILY }, children: [
26712
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50", onClick: onClose }),
26713
+ /* @__PURE__ */ jsx("div", { className: isMobile ? "fixed inset-0 flex items-end" : "fixed inset-0 flex items-center justify-center p-4", style: { zIndex: 51 }, children: /* @__PURE__ */ jsxs("div", { className: isMobile ? "coinley-mobile-sheet relative flex w-full max-h-[92dvh] flex-col overflow-hidden rounded-t-[24px] bg-white px-4 pb-5 pt-7 shadow-2xl animate-slide-up-sheet" : "relative flex h-auto min-h-[520px] w-[430px] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-[28px] bg-white px-4 pb-5 pt-7 shadow-2xl", children: [
26714
+ /* @__PURE__ */ jsx(
26715
+ "button",
26716
+ {
26717
+ type: "button",
26718
+ onClick: onClose,
26719
+ className: "absolute right-4 top-5 flex h-8 w-8 items-center justify-center rounded-full text-[#111827] transition-colors hover:bg-gray-100",
26720
+ "aria-label": "Close payment modal",
26721
+ children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
26722
+ }
26723
+ ),
26724
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-y-auto pt-2", children: [
26725
+ /* @__PURE__ */ jsxs("div", { className: "mb-5 text-center", children: [
26726
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mb-3 flex h-16 w-16 items-center justify-center rounded-full bg-[#D9F8E6]", children: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-full bg-[#08C65A] text-white", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M5 13l4 4L19 7" }) }) }) }),
26727
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-lg font-semibold text-black", children: "Payment Received" }),
26728
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-[#6B7280]", children: overpaymentInfo.excessOwed ? `You sent ${formatAmount(overpaymentInfo.excessOwed)} ${overpaymentInfo.tokenSymbol} more than required. We will refund the excess to you.` : `You sent more than the required amount. We will refund the excess to you.` })
26729
+ ] }),
26730
+ /* @__PURE__ */ jsx("div", { className: "mb-5 rounded-lg border border-[#F5E5B8] bg-[#FFF9E8] px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
26731
+ /* @__PURE__ */ jsx("svg", { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-[#B54708]", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v4m0 4h.01M12 3a9 9 0 110 18 9 9 0 010-18z" }) }),
26732
+ /* @__PURE__ */ jsxs("p", { className: "text-xs leading-5 text-[#B54708]", children: [
26733
+ overpaymentInfo.excessOwed ? `We are holding ${formatAmount(overpaymentInfo.excessOwed)} ${overpaymentInfo.tokenSymbol} for you.` : `We are holding your excess ${overpaymentInfo.tokenSymbol} for you.`,
26734
+ " ",
26735
+ "Provide a wallet address below. You can safely close this window after submitting — the refund processes automatically."
26736
+ ] })
26737
+ ] }) }),
26738
+ refundRequestStatus === "refunded" ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-[#D1FAE5] bg-[#ECFDF5] px-3 py-3 text-center", children: [
26739
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-[#065F46]", children: "Excess refunded" }),
26740
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs leading-5 text-[#047857]", children: [
26741
+ "Your excess ",
26742
+ overpaymentInfo.tokenSymbol,
26743
+ " has been sent to your wallet."
26744
+ ] })
26745
+ ] }) : opGuidance ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-[#EEF0F4] bg-[#FAFAFB] px-3 py-3", children: [
26746
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-[#111827]", children: opGuidance.title }),
26747
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-5 text-[#535865]", children: opGuidance.description }),
26748
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs leading-5 text-[#8B8E98]", children: opGuidance.eta })
26749
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
26750
+ /* @__PURE__ */ jsxs("label", { className: "mb-2 block text-xs font-medium text-[#111827]", children: [
26751
+ "Your ",
26752
+ overpaymentInfo.tokenSymbol,
26753
+ " (",
26754
+ overpaymentInfo.networkLabel,
26755
+ ") wallet address for refund"
26756
+ ] }),
26757
+ /* @__PURE__ */ jsx(
26758
+ "input",
26759
+ {
26760
+ type: "text",
26761
+ value: refundAddress,
26762
+ onChange: (e) => setRefundAddress(e.target.value),
26763
+ placeholder: "Paste your wallet address here",
26764
+ className: "mb-4 h-11 w-full rounded-xl border border-[#E4E6EB] bg-white px-3 text-sm text-[#1F2430] outline-none transition-colors placeholder:text-[#8B8E98] focus:border-[#B49AF0]"
26765
+ }
26766
+ ),
26767
+ refundRequestMessage && /* @__PURE__ */ jsx("p", { className: `mb-3 text-xs leading-5 ${refundRequestStatus === "error" ? "text-red-600" : "text-[#8B8E98]"}`, children: refundRequestMessage }),
26768
+ /* @__PURE__ */ jsx(
26769
+ "button",
26770
+ {
26771
+ type: "button",
26772
+ onClick: handleOverpaymentRefundSubmit,
26773
+ disabled: !refundAddress.trim() || refundRequestStatus === "submitting",
26774
+ className: "h-12 w-full rounded-xl bg-[#7042D2] px-4 text-sm font-semibold text-white transition-colors hover:bg-[#5b34b1] disabled:opacity-50 disabled:cursor-not-allowed",
26775
+ children: refundRequestStatus === "submitting" ? "Submitting..." : "Submit Refund Address"
26776
+ }
26777
+ )
26778
+ ] })
26779
+ ] }),
26780
+ (refundRequestStatus === "refunded" || opGuidance) && /* @__PURE__ */ jsx(
26781
+ "button",
26782
+ {
26783
+ type: "button",
26784
+ onClick: onClose,
26785
+ className: "mt-4 h-12 w-full rounded-lg border border-[#E4E6EB] px-4 text-sm font-semibold text-[#374151] transition-colors hover:bg-gray-50",
26786
+ children: "Close"
26787
+ }
26788
+ )
26789
+ ] }) })
26790
+ ] })
26791
+ );
26792
+ }
26585
26793
  if (offsetSuccessDetails) {
26586
26794
  return renderInPortal(
26587
26795
  /* @__PURE__ */ jsxs("div", { id: SDK_ROOT_ID, className: `${SDK_ROOT_CLASS} fixed inset-0 z-50`, style: { fontFamily: FONT_FAMILY }, children: [
@@ -26835,7 +27043,7 @@ const CoinleyPaymentInternal = ({
26835
27043
  /* @__PURE__ */ jsx("div", { className: "flex overflow-hidden rounded-xl bg-[#F6F6F7] p-1", children: [
26836
27044
  { tab: PAYMENT_TABS.TRANSFER, label: "Transfer to address", mobileLabel: "Transfer" },
26837
27045
  { tab: PAYMENT_TABS.QR, label: "QR Code", mobileLabel: "QR Code" },
26838
- { tab: PAYMENT_TABS.WALLET, label: "Wallet Extension", mobileLabel: "Wallet" }
27046
+ { tab: PAYMENT_TABS.WALLET, label: "Wallet Extension", mobileLabel: "Wallet Extension" }
26839
27047
  ].map((method) => /* @__PURE__ */ jsx(
26840
27048
  "button",
26841
27049
  {
@@ -27525,6 +27733,7 @@ const CoinleyPaymentInternal = ({
27525
27733
  );
27526
27734
  const handleUnderpaymentChoiceContinue = () => {
27527
27735
  if (!underpaymentChoice) return;
27736
+ refundPendingStartedAt.current = 0;
27528
27737
  setRefundRequestSubmitted(false);
27529
27738
  const nextView = underpaymentChoice === "refund" ? "refund" : "offset";
27530
27739
  writeUnderpaymentRecovery(underpaymentChoice, nextView, underpaymentInfo);
@@ -28135,6 +28344,7 @@ const CoinleyPaymentInternal = ({
28135
28344
  setUnderpaymentChoice(null);
28136
28345
  setUnderpaymentView("choice");
28137
28346
  setRefundAddress("");
28347
+ refundPendingStartedAt.current = 0;
28138
28348
  setRefundRequestSubmitted(false);
28139
28349
  setRefundRequestStatus(null);
28140
28350
  setRefundRequestMessage("");
@@ -28238,4 +28448,4 @@ export {
28238
28448
  chainTransports as c,
28239
28449
  isFeatureEnabled as i
28240
28450
  };
28241
- //# sourceMappingURL=CoinleyPayment-BofSrJBx.js.map
28451
+ //# sourceMappingURL=CoinleyPayment-DcxnhCxE.js.map
@@ -1,4 +1,4 @@
1
- import { i as isFeatureEnabled, F as FEATURES, c as chainTransports, W as WALLETCONNECT_PROJECT_ID } from "./CoinleyPayment-BofSrJBx.js";
1
+ import { i as isFeatureEnabled, F as FEATURES, c as chainTransports, W as WALLETCONNECT_PROJECT_ID } from "./CoinleyPayment-DcxnhCxE.js";
2
2
  const logo = "https://coinley.io/logo.png";
3
3
  let appKitInstance = null;
4
4
  let isInitializing = false;
@@ -113,4 +113,4 @@ export {
113
113
  initializeAppKitEVM,
114
114
  openAppKitModal
115
115
  };
116
- //# sourceMappingURL=appKitEVM-BzMDYdux.js.map
116
+ //# sourceMappingURL=appKitEVM-f4GTnd8I.js.map
@@ -1,4 +1,4 @@
1
- import { F as FEATURES, W as WALLETCONNECT_PROJECT_ID } from "./CoinleyPayment-BofSrJBx.js";
1
+ import { F as FEATURES, W as WALLETCONNECT_PROJECT_ID } from "./CoinleyPayment-DcxnhCxE.js";
2
2
  const logo = "https://coinley.io/logo.png";
3
3
  let appKitInstance = null;
4
4
  let isInitializing = false;
@@ -243,4 +243,4 @@ export {
243
243
  disconnectWalletConnect,
244
244
  initializeAppKitSolana
245
245
  };
246
- //# sourceMappingURL=appKitSolana-C_InTqyc.js.map
246
+ //# sourceMappingURL=appKitSolana-Dyj8Yus-.js.map