@rhinestone/deposit-modal 0.1.51 → 0.1.53

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,6 +6,7 @@ import {
6
6
  getExplorerTxUrl,
7
7
  getTokenAddress,
8
8
  getTokenDecimalsByAddress,
9
+ getTokenIcon,
9
10
  getTokenSymbol
10
11
  } from "./chunk-ZJQZEIHA.mjs";
11
12
 
@@ -1223,7 +1224,7 @@ function accountFromPrivateKey(privateKey) {
1223
1224
  }
1224
1225
 
1225
1226
  // src/components/steps/ProcessingStep.tsx
1226
- import { useState, useEffect as useEffect2, useRef as useRef2 } from "react";
1227
+ import { useEffect as useEffect2, useRef as useRef2, useState } from "react";
1227
1228
  import { formatUnits } from "viem";
1228
1229
 
1229
1230
  // src/components/ui/PoweredBy.tsx
@@ -1345,11 +1346,42 @@ function txRefsMatch(a, b) {
1345
1346
  }
1346
1347
 
1347
1348
  // src/components/steps/ProcessingStep.tsx
1348
- import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1349
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1349
1350
  var INITIAL_POLL_INTERVAL = 3e3;
1350
1351
  var MAX_POLL_INTERVAL = 3e4;
1351
1352
  var BACKOFF_MULTIPLIER = 1.5;
1352
- var PROCESS_TIMEOUT_MS = 10 * 60 * 1e3;
1353
+ var ESCALATED_DELAY_MS = 10 * 60 * 1e3;
1354
+ var SOFT_DELAY_MS = {
1355
+ confirming: 90 * 1e3,
1356
+ received: 90 * 1e3,
1357
+ bridging: 4 * 60 * 1e3
1358
+ };
1359
+ var PHASE_TIMINGS_PREFIX = "rhinestone:phase-timings";
1360
+ function loadPhaseTimings(txHash) {
1361
+ if (typeof window === "undefined") return null;
1362
+ try {
1363
+ const raw = window.localStorage.getItem(`${PHASE_TIMINGS_PREFIX}:${txHash}`);
1364
+ if (!raw) return null;
1365
+ const parsed = JSON.parse(raw);
1366
+ if (typeof parsed.startedAt !== "number") return null;
1367
+ return parsed;
1368
+ } catch {
1369
+ return null;
1370
+ }
1371
+ }
1372
+ function savePhaseTimings(txHash, timings) {
1373
+ if (typeof window === "undefined") return;
1374
+ try {
1375
+ window.localStorage.setItem(
1376
+ `${PHASE_TIMINGS_PREFIX}:${txHash}`,
1377
+ JSON.stringify(timings)
1378
+ );
1379
+ } catch {
1380
+ }
1381
+ }
1382
+ function truncateHash(hash) {
1383
+ return `${hash.slice(0, 10)}...${hash.slice(-8)}`;
1384
+ }
1353
1385
  function isEventForTx(event, txHash) {
1354
1386
  const eventTxHash = getEventTxHash(event);
1355
1387
  if (!eventTxHash) return false;
@@ -1387,6 +1419,57 @@ function formatBridgeFailedMessage(event) {
1387
1419
  }
1388
1420
  return { message: "Bridge failed" };
1389
1421
  }
1422
+ function parseWebhookTimestamp(event) {
1423
+ if (typeof event?.time !== "string") return void 0;
1424
+ const timestamp = Date.parse(event.time);
1425
+ return Number.isFinite(timestamp) ? timestamp : void 0;
1426
+ }
1427
+ function syncPhaseTimings(previous, event) {
1428
+ if (!event?.type) return previous;
1429
+ const timestamp = parseWebhookTimestamp(event) ?? Date.now();
1430
+ const setReceived = (event.type === "deposit-received" || event.type === "bridge-started" || event.type === "bridge-complete" || event.type === "bridge-failed" || event.type === "error") && previous.receivedAt === void 0;
1431
+ const setBridging = (event.type === "bridge-started" || event.type === "bridge-complete") && previous.bridgingAt === void 0;
1432
+ const setCompleted = event.type === "bridge-complete" && previous.completedAt === void 0;
1433
+ if (!setReceived && !setBridging && !setCompleted) return previous;
1434
+ return {
1435
+ ...previous,
1436
+ ...setReceived && { receivedAt: timestamp },
1437
+ ...setBridging && { bridgingAt: timestamp },
1438
+ ...setCompleted && { completedAt: timestamp }
1439
+ };
1440
+ }
1441
+ function formatElapsedTime(seconds) {
1442
+ if (seconds < 60) return `${seconds} second${seconds !== 1 ? "s" : ""}`;
1443
+ const mins = Math.floor(seconds / 60);
1444
+ const secs = seconds % 60;
1445
+ return `${mins}m ${secs}s`;
1446
+ }
1447
+ function getPhaseStartTime(phaseId, phaseTimings) {
1448
+ if (phaseId === "confirming") return phaseTimings.startedAt;
1449
+ if (phaseId === "received") {
1450
+ return phaseTimings.receivedAt ?? phaseTimings.startedAt;
1451
+ }
1452
+ return phaseTimings.bridgingAt ?? phaseTimings.receivedAt ?? phaseTimings.startedAt;
1453
+ }
1454
+ function getFailedPhaseId(phaseTimings) {
1455
+ if (phaseTimings.bridgingAt !== void 0) return "bridging";
1456
+ if (phaseTimings.receivedAt !== void 0) return "received";
1457
+ return "confirming";
1458
+ }
1459
+ function getCurrentPhaseId(state, phaseTimings, isEarlyComplete) {
1460
+ if (state.type === "failed") {
1461
+ return getFailedPhaseId(phaseTimings);
1462
+ }
1463
+ if (isEarlyComplete) {
1464
+ return "bridging";
1465
+ }
1466
+ if (state.type === "complete") {
1467
+ return void 0;
1468
+ }
1469
+ if (state.lastEvent?.type === "bridge-started") return "bridging";
1470
+ if (state.lastEvent?.type === "deposit-received") return "received";
1471
+ return "confirming";
1472
+ }
1390
1473
  function ProcessingStep({
1391
1474
  smartAccount,
1392
1475
  txHash,
@@ -1408,43 +1491,80 @@ function ProcessingStep({
1408
1491
  onDepositFailed,
1409
1492
  onError
1410
1493
  }) {
1494
+ const startTimeRef = useRef2(Date.now());
1495
+ const pollIntervalRef = useRef2(INITIAL_POLL_INTERVAL);
1496
+ const pollTimeoutRef = useRef2(null);
1497
+ const escalatedDelayRef = useRef2(false);
1411
1498
  const [state, setState] = useState(
1412
1499
  directTransfer ? { type: "complete" } : { type: "processing" }
1413
1500
  );
1414
1501
  const [elapsedSeconds, setElapsedSeconds] = useState(0);
1415
- const startTimeRef = useRef2(Date.now());
1416
- const intervalRef = useRef2(null);
1417
- useEffect2(() => {
1418
- if (directTransfer) {
1419
- debugLog(debug, "processing", "direct-transfer:complete", {
1420
- txHash,
1421
- flowLabel
1422
- });
1423
- onDepositComplete?.(txHash, void 0, { amount, sourceChain, sourceToken, targetChain, targetToken });
1424
- return;
1502
+ const [phaseTimings, setPhaseTimings] = useState(() => {
1503
+ const saved = loadPhaseTimings(txHash);
1504
+ if (saved) {
1505
+ startTimeRef.current = saved.startedAt;
1506
+ return saved;
1425
1507
  }
1426
- }, [debug, directTransfer, flowLabel, txHash, onDepositComplete, amount, sourceChain, sourceToken, targetChain, targetToken]);
1508
+ return { startedAt: startTimeRef.current };
1509
+ });
1510
+ const [hasEscalatedDelay, setHasEscalatedDelay] = useState(false);
1427
1511
  useEffect2(() => {
1428
- if (directTransfer) return;
1429
- startTimeRef.current = Date.now();
1430
- intervalRef.current = setInterval(() => {
1431
- setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
1432
- }, 1e3);
1433
- return () => {
1434
- if (intervalRef.current) clearInterval(intervalRef.current);
1512
+ if (!directTransfer) return;
1513
+ const completedAt = Date.now();
1514
+ setPhaseTimings({
1515
+ startedAt: startTimeRef.current,
1516
+ completedAt,
1517
+ endedAt: completedAt
1518
+ });
1519
+ debugLog(debug, "processing", "direct-transfer:complete", {
1520
+ txHash,
1521
+ flowLabel
1522
+ });
1523
+ onDepositComplete?.(txHash, void 0, {
1524
+ amount,
1525
+ sourceChain,
1526
+ sourceToken,
1527
+ targetChain,
1528
+ targetToken
1529
+ });
1530
+ }, [
1531
+ amount,
1532
+ debug,
1533
+ directTransfer,
1534
+ flowLabel,
1535
+ onDepositComplete,
1536
+ sourceChain,
1537
+ sourceToken,
1538
+ targetChain,
1539
+ targetToken,
1540
+ txHash
1541
+ ]);
1542
+ useEffect2(() => {
1543
+ if (directTransfer || state.type !== "processing") return;
1544
+ const updateElapsed = () => {
1545
+ setElapsedSeconds(
1546
+ Math.floor((Date.now() - startTimeRef.current) / 1e3)
1547
+ );
1435
1548
  };
1436
- }, [directTransfer]);
1549
+ updateElapsed();
1550
+ const intervalId = setInterval(updateElapsed, 1e3);
1551
+ return () => clearInterval(intervalId);
1552
+ }, [directTransfer, state.type]);
1437
1553
  useEffect2(() => {
1438
- if (state.type === "complete" || state.type === "failed" || state.type === "error") {
1439
- if (intervalRef.current) {
1440
- clearInterval(intervalRef.current);
1441
- intervalRef.current = null;
1442
- }
1443
- }
1444
- }, [state.type]);
1445
- const pollIntervalRef = useRef2(INITIAL_POLL_INTERVAL);
1446
- const pollTimeoutRef = useRef2(null);
1447
- const processTimeoutRef = useRef2(null);
1554
+ if (state.type === "processing") return;
1555
+ const endedAt = state.type === "complete" ? phaseTimings.completedAt ?? Date.now() : Date.now();
1556
+ setElapsedSeconds(Math.floor((endedAt - startTimeRef.current) / 1e3));
1557
+ setPhaseTimings(
1558
+ (previous) => previous.endedAt !== void 0 ? previous : { ...previous, endedAt }
1559
+ );
1560
+ }, [phaseTimings.completedAt, state.type]);
1561
+ useEffect2(() => {
1562
+ if (!state.lastEvent) return;
1563
+ setPhaseTimings((previous) => syncPhaseTimings(previous, state.lastEvent));
1564
+ }, [state.lastEvent?.time, state.lastEvent?.type]);
1565
+ useEffect2(() => {
1566
+ savePhaseTimings(txHash, phaseTimings);
1567
+ }, [txHash, phaseTimings]);
1448
1568
  useEffect2(() => {
1449
1569
  if (directTransfer) return;
1450
1570
  if (state.type !== "processing") {
@@ -1480,7 +1600,13 @@ function ProcessingStep({
1480
1600
  destinationTxHash: destinationTxHash2,
1481
1601
  event: eventForCurrentTx.type
1482
1602
  });
1483
- onDepositComplete?.(txHash, destinationTxHash2, { amount, sourceChain, sourceToken, targetChain, targetToken });
1603
+ onDepositComplete?.(txHash, destinationTxHash2, {
1604
+ amount,
1605
+ sourceChain,
1606
+ sourceToken,
1607
+ targetChain,
1608
+ targetToken
1609
+ });
1484
1610
  return;
1485
1611
  }
1486
1612
  if (!waitForFinalTx && eventForCurrentTx?.type === "bridge-started") {
@@ -1489,7 +1615,13 @@ function ProcessingStep({
1489
1615
  txHash,
1490
1616
  event: eventForCurrentTx.type
1491
1617
  });
1492
- onDepositComplete?.(txHash, void 0, { amount, sourceChain, sourceToken, targetChain, targetToken });
1618
+ onDepositComplete?.(txHash, void 0, {
1619
+ amount,
1620
+ sourceChain,
1621
+ sourceToken,
1622
+ targetChain,
1623
+ targetToken
1624
+ });
1493
1625
  return;
1494
1626
  }
1495
1627
  if (eventForCurrentTx?.type === "bridge-failed") {
@@ -1521,7 +1653,10 @@ function ProcessingStep({
1521
1653
  onDepositFailed?.(txHash, errorMessage);
1522
1654
  return;
1523
1655
  }
1524
- setState({ type: "processing", lastEvent: eventForCurrentTx });
1656
+ setState((previous) => ({
1657
+ type: "processing",
1658
+ lastEvent: eventForCurrentTx ?? previous.lastEvent
1659
+ }));
1525
1660
  scheduleNextPoll();
1526
1661
  } catch (error) {
1527
1662
  debugError(debug, "processing", "poll:failure", error, {
@@ -1553,46 +1688,43 @@ function ProcessingStep({
1553
1688
  }
1554
1689
  };
1555
1690
  }, [
1691
+ amount,
1556
1692
  debug,
1557
1693
  directTransfer,
1558
- state.type,
1694
+ onDepositComplete,
1695
+ onDepositFailed,
1696
+ service,
1559
1697
  smartAccount,
1698
+ sourceChain,
1699
+ sourceToken,
1700
+ state.type,
1701
+ targetChain,
1702
+ targetToken,
1560
1703
  txHash,
1561
- service,
1562
- waitForFinalTx,
1563
- onDepositComplete,
1564
- onDepositFailed
1704
+ waitForFinalTx
1565
1705
  ]);
1566
1706
  useEffect2(() => {
1567
- if (directTransfer) return;
1568
- if (state.type !== "processing") {
1569
- if (processTimeoutRef.current) {
1570
- clearTimeout(processTimeoutRef.current);
1571
- processTimeoutRef.current = null;
1572
- }
1573
- return;
1574
- }
1575
- processTimeoutRef.current = setTimeout(() => {
1576
- const message = "Transfer is taking longer than expected. Your funds are safe and our team has been notified.";
1577
- debugLog(debug, "processing", "state:timeout", {
1707
+ if (directTransfer || state.type !== "processing") return;
1708
+ const timeoutId = setTimeout(() => {
1709
+ if (escalatedDelayRef.current) return;
1710
+ escalatedDelayRef.current = true;
1711
+ setHasEscalatedDelay(true);
1712
+ const message = "Transfer is taking longer than expected. Your funds are safe and processing will continue automatically.";
1713
+ debugLog(debug, "processing", "state:delay-escalated", {
1578
1714
  txHash,
1579
- timeoutMs: PROCESS_TIMEOUT_MS
1715
+ timeoutMs: ESCALATED_DELAY_MS
1580
1716
  });
1581
- setState({ type: "error", message });
1582
1717
  onError?.(message, "PROCESS_TIMEOUT");
1583
- }, PROCESS_TIMEOUT_MS);
1584
- return () => {
1585
- if (processTimeoutRef.current) {
1586
- clearTimeout(processTimeoutRef.current);
1587
- processTimeoutRef.current = null;
1588
- }
1589
- };
1590
- }, [debug, directTransfer, state.type, txHash, onError]);
1591
- const isDelayed = state.type === "error" || state.type === "failed";
1718
+ }, ESCALATED_DELAY_MS);
1719
+ return () => clearTimeout(timeoutId);
1720
+ }, [debug, directTransfer, onError, state.type, txHash]);
1592
1721
  const isComplete = state.type === "complete";
1722
+ const isFailed = state.type === "failed";
1593
1723
  const isProcessing = state.type === "processing";
1594
- const lastEvent = state.type === "processing" || state.type === "complete" || state.type === "failed" ? state.lastEvent : void 0;
1724
+ const lastEvent = state.lastEvent;
1725
+ const failureMessage = state.type === "failed" ? state.message : void 0;
1595
1726
  const isEarlyComplete = !waitForFinalTx && lastEvent?.type === "bridge-started";
1727
+ const timelineNowMs = phaseTimings.endedAt ?? Date.now();
1596
1728
  const flowNoun = flowLabel === "withdraw" ? "withdrawal" : "deposit";
1597
1729
  const flowCapitalized = flowLabel === "withdraw" ? "Withdrawal" : "Deposit";
1598
1730
  const destinationTxHash = lastEvent?.data?.destination?.transactionHash || null;
@@ -1602,16 +1734,12 @@ function ProcessingStep({
1602
1734
  const displayAmount = sourceDetails.amount ?? amount;
1603
1735
  const sourceExplorerUrl = getExplorerTxUrl(displaySourceChain, txHash);
1604
1736
  const destExplorerUrl = destinationTxHash ? getExplorerTxUrl(targetChain, destinationTxHash) : null;
1605
- const truncateHash = (hash) => `${hash.slice(0, 10)}...${hash.slice(-8)}`;
1606
- const formatElapsedTime = (seconds) => {
1607
- if (seconds < 60) return `${seconds} second${seconds !== 1 ? "s" : ""}`;
1608
- const mins = Math.floor(seconds / 60);
1609
- const secs = seconds % 60;
1610
- return `${mins}m ${secs}s`;
1611
- };
1612
1737
  const isEvmSourceToken = /^0x[a-fA-F0-9]{40}$/.test(displaySourceToken);
1613
1738
  const sourceSymbol = displaySourceChain === "solana" ? providedSourceSymbol ?? "SOL" : isEvmSourceToken ? getTokenSymbol(displaySourceToken, displaySourceChain) : providedSourceSymbol ?? "Token";
1614
- const sourceDecimals = displaySourceChain === "solana" ? providedSourceDecimals ?? 9 : isEvmSourceToken ? getTokenDecimalsByAddress(displaySourceToken, displaySourceChain) : providedSourceDecimals ?? 18;
1739
+ const sourceDecimals = displaySourceChain === "solana" ? providedSourceDecimals ?? 9 : isEvmSourceToken ? getTokenDecimalsByAddress(
1740
+ displaySourceToken,
1741
+ displaySourceChain
1742
+ ) : providedSourceDecimals ?? 18;
1615
1743
  const formattedReceivedAmount = (() => {
1616
1744
  try {
1617
1745
  const raw = formatUnits(BigInt(displayAmount), sourceDecimals);
@@ -1624,299 +1752,112 @@ function ProcessingStep({
1624
1752
  });
1625
1753
  }
1626
1754
  })();
1627
- if (isComplete) {
1628
- return /* @__PURE__ */ jsxs6("div", { className: "rs-step", children: [
1629
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-body rs-space-y-3", children: [
1630
- /* @__PURE__ */ jsxs6("div", { className: "rs-success-state", children: [
1631
- /* @__PURE__ */ jsx7("div", { className: "rs-success-checkmark", children: /* @__PURE__ */ jsx7(
1632
- "svg",
1633
- {
1634
- viewBox: "0 0 24 24",
1635
- fill: "none",
1636
- stroke: "currentColor",
1637
- strokeWidth: "2.5",
1638
- children: /* @__PURE__ */ jsx7(
1639
- "path",
1640
- {
1641
- strokeLinecap: "round",
1642
- strokeLinejoin: "round",
1643
- d: "M5 12l5 5L20 7"
1644
- }
1645
- )
1646
- }
1647
- ) }),
1648
- /* @__PURE__ */ jsx7("div", { className: "rs-success-title", children: isEarlyComplete ? `${flowCapitalized} confirmed` : `${flowCapitalized} successful` }),
1649
- /* @__PURE__ */ jsx7("div", { className: "rs-success-subtitle", children: directTransfer ? "Your transfer is complete." : isEarlyComplete ? "Your transfer has been confirmed and funds will arrive shortly." : "Your funds have been successfully bridged." })
1650
- ] }),
1651
- /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1652
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1653
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Status" }),
1654
- /* @__PURE__ */ jsx7(
1655
- "span",
1656
- {
1657
- className: "rs-card-value",
1658
- style: { color: "var(--rs-success)" },
1659
- children: isEarlyComplete ? "Confirmed" : "Successful"
1660
- }
1661
- )
1662
- ] }),
1663
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1664
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Total time" }),
1665
- /* @__PURE__ */ jsx7("span", { className: "rs-card-value", children: formatElapsedTime(elapsedSeconds) })
1666
- ] }),
1667
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1668
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "You sent" }),
1669
- /* @__PURE__ */ jsxs6("span", { className: "rs-card-value", children: [
1670
- formattedReceivedAmount,
1671
- " ",
1672
- sourceSymbol
1673
- ] })
1674
- ] })
1675
- ] }),
1676
- /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1677
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1678
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Source" }),
1679
- /* @__PURE__ */ jsxs6(
1680
- "span",
1681
- {
1682
- className: "rs-card-value",
1683
- style: { display: "flex", alignItems: "center", gap: 6 },
1684
- children: [
1685
- getChainIcon(displaySourceChain) && /* @__PURE__ */ jsx7(
1686
- "img",
1687
- {
1688
- src: getChainIcon(displaySourceChain),
1689
- alt: "",
1690
- style: { width: 14, height: 14, borderRadius: "50%" }
1691
- }
1692
- ),
1693
- getChainName(displaySourceChain)
1694
- ]
1695
- }
1696
- )
1697
- ] }),
1698
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1699
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Destination" }),
1700
- /* @__PURE__ */ jsxs6(
1701
- "span",
1702
- {
1703
- className: "rs-card-value",
1704
- style: { display: "flex", alignItems: "center", gap: 6 },
1705
- children: [
1706
- getChainIcon(targetChain) && /* @__PURE__ */ jsx7(
1707
- "img",
1708
- {
1709
- src: getChainIcon(targetChain),
1710
- alt: "",
1711
- style: { width: 14, height: 14, borderRadius: "50%" }
1712
- }
1713
- ),
1714
- getChainName(targetChain)
1715
- ]
1716
- }
1717
- )
1718
- ] }),
1719
- sourceExplorerUrl && /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1720
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Transaction" }),
1721
- /* @__PURE__ */ jsxs6(
1722
- "a",
1723
- {
1724
- href: sourceExplorerUrl,
1725
- target: "_blank",
1726
- rel: "noopener noreferrer",
1727
- className: "rs-link rs-link-external rs-font-mono rs-text-xs",
1728
- children: [
1729
- truncateHash(txHash),
1730
- /* @__PURE__ */ jsx7(
1731
- "svg",
1732
- {
1733
- viewBox: "0 0 24 24",
1734
- fill: "none",
1735
- stroke: "currentColor",
1736
- strokeWidth: "2.5",
1737
- style: { width: 12, height: 12 },
1738
- children: /* @__PURE__ */ jsx7(
1739
- "path",
1740
- {
1741
- strokeLinecap: "round",
1742
- strokeLinejoin: "round",
1743
- d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
1744
- }
1745
- )
1746
- }
1747
- )
1748
- ]
1749
- }
1750
- )
1751
- ] }),
1752
- destinationTxHash && destExplorerUrl && /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1753
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Destination tx" }),
1754
- /* @__PURE__ */ jsxs6(
1755
- "a",
1756
- {
1757
- href: destExplorerUrl,
1758
- target: "_blank",
1759
- rel: "noopener noreferrer",
1760
- className: "rs-link rs-link-external rs-font-mono rs-text-xs",
1761
- children: [
1762
- truncateHash(destinationTxHash),
1763
- /* @__PURE__ */ jsx7(
1764
- "svg",
1765
- {
1766
- viewBox: "0 0 24 24",
1767
- fill: "none",
1768
- stroke: "currentColor",
1769
- strokeWidth: "2.5",
1770
- style: { width: 12, height: 12 },
1771
- children: /* @__PURE__ */ jsx7(
1772
- "path",
1773
- {
1774
- strokeLinecap: "round",
1775
- strokeLinejoin: "round",
1776
- d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
1777
- }
1778
- )
1779
- }
1780
- )
1781
- ]
1782
- }
1783
- )
1784
- ] })
1785
- ] })
1786
- ] }),
1787
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-footer", style: { gap: 8, display: "flex" }, children: [
1788
- /* @__PURE__ */ jsx7(Button, { variant: "outline", onClick: onClose, fullWidth: true, children: "Close" }),
1789
- /* @__PURE__ */ jsxs6(Button, { onClick: onNewDeposit, fullWidth: true, children: [
1790
- "New ",
1791
- flowNoun
1792
- ] })
1793
- ] }),
1794
- /* @__PURE__ */ jsx7(PoweredBy, {})
1795
- ] });
1796
- }
1755
+ const currentPhaseId = getCurrentPhaseId(state, phaseTimings, isEarlyComplete);
1756
+ const activePhaseStartedAt = currentPhaseId ? getPhaseStartTime(currentPhaseId, phaseTimings) : void 0;
1757
+ const activePhaseElapsedMs = isProcessing && activePhaseStartedAt !== void 0 ? timelineNowMs - activePhaseStartedAt : 0;
1758
+ const delayPhaseId = isProcessing && currentPhaseId && activePhaseElapsedMs >= SOFT_DELAY_MS[currentPhaseId] ? currentPhaseId : void 0;
1759
+ const headerTitle = isFailed ? `${flowCapitalized} could not be completed` : isComplete ? isEarlyComplete ? `${flowCapitalized} confirmed` : `${flowCapitalized} successful` : delayPhaseId === "received" ? "Bridge pending" : delayPhaseId === "bridging" ? "Bridge delayed" : delayPhaseId === "confirming" ? `Confirming ${flowNoun}` : `Submitting transaction...`;
1760
+ const headerDescription = isFailed ? failureMessage ?? "The transfer could not be completed." : isComplete ? directTransfer ? "Your transfer is complete." : isEarlyComplete ? "The bridge has started. Funds will arrive shortly." : "Your funds were successfully deposited." : delayPhaseId === "received" ? "Funds are in. We are still waiting for the bridge transaction to begin." : delayPhaseId === "bridging" ? "The bridge has started but settlement is taking longer than expected." : delayPhaseId === "confirming" ? "The source transaction has not been picked up yet, but we are still polling automatically." : state.lastEvent?.type === "deposit-received" ? "Transfer received. Preparing bridge execution." : state.lastEvent?.type === "bridge-started" ? `Bridge started. Sending funds to ${getChainName(targetChain)}.` : "Filling your transaction on the blockchain.";
1761
+ const showAlert = !isFailed && (delayPhaseId !== void 0 || hasEscalatedDelay);
1762
+ const alertMessage = hasEscalatedDelay ? "Taking longer than expected. You can close this window \u2014 processing continues in the background." : "This step is slower than usual but still processing.";
1763
+ const fillStatus = isComplete ? "Successful" : isFailed ? "Failed" : "Processing";
1764
+ const fillStatusClass = isComplete ? "rs-card-value--success" : isFailed ? "rs-card-value--error" : "";
1765
+ const [detailsExpanded, setDetailsExpanded] = useState(false);
1766
+ const txLinkIcon = /* @__PURE__ */ jsx7("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: /* @__PURE__ */ jsx7(
1767
+ "path",
1768
+ {
1769
+ strokeLinecap: "round",
1770
+ strokeLinejoin: "round",
1771
+ d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
1772
+ }
1773
+ ) });
1797
1774
  return /* @__PURE__ */ jsxs6("div", { className: "rs-step", children: [
1798
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-header", children: [
1799
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-header-row", children: [
1800
- /* @__PURE__ */ jsx7(
1801
- "div",
1802
- {
1803
- className: `rs-step-icon ${isDelayed ? "rs-step-icon--warning" : "rs-step-icon--accent"}`,
1804
- children: isDelayed ? /* @__PURE__ */ jsx7(
1805
- "svg",
1775
+ /* @__PURE__ */ jsxs6("div", { className: "rs-step-header--centered", children: [
1776
+ isFailed ? /* @__PURE__ */ jsx7("div", { className: "rs-failed-badge", children: /* @__PURE__ */ jsxs6(
1777
+ "svg",
1778
+ {
1779
+ viewBox: "0 0 24 24",
1780
+ fill: "none",
1781
+ stroke: "currentColor",
1782
+ strokeWidth: "2",
1783
+ children: [
1784
+ /* @__PURE__ */ jsx7(
1785
+ "path",
1806
1786
  {
1807
- viewBox: "0 0 24 24",
1808
- fill: "none",
1809
- stroke: "currentColor",
1810
- strokeWidth: "2",
1811
- children: /* @__PURE__ */ jsx7(
1812
- "path",
1813
- {
1814
- strokeLinecap: "round",
1815
- strokeLinejoin: "round",
1816
- d: "M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z"
1817
- }
1818
- )
1787
+ strokeLinecap: "round",
1788
+ strokeLinejoin: "round",
1789
+ d: "M12 9v3.75m0 3.75h.008v.008H12v-.008z"
1819
1790
  }
1820
- ) : /* @__PURE__ */ jsx7(Spinner, {})
1821
- }
1822
- ),
1823
- /* @__PURE__ */ jsx7("div", { className: "rs-step-title", children: isDelayed ? `${flowCapitalized} taking longer than expected` : `Bridging ${flowCapitalized}` })
1824
- ] }),
1825
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-description rs-text-secondary", children: [
1826
- state.type === "processing" && (lastEvent?.type === "deposit-received" ? "Transfer received. Preparing bridge..." : lastEvent?.type === "bridge-started" ? "Transfer confirmed. Funds arriving shortly..." : `Bridging your ${flowNoun} to ${getChainName(targetChain)}.`),
1827
- (state.type === "failed" || state.type === "error") && "Your funds are safe. Our team has been notified and is working to complete your transfer."
1828
- ] })
1829
- ] }),
1830
- /* @__PURE__ */ jsxs6("div", { className: "rs-step-body rs-space-y-3", children: [
1831
- isProcessing && /* @__PURE__ */ jsxs6(Fragment, { children: [
1832
- /* @__PURE__ */ jsx7("div", { className: "rs-progress-bar", children: /* @__PURE__ */ jsx7("div", { className: "rs-progress-bar-fill rs-progress-bar-fill--indeterminate" }) }),
1833
- /* @__PURE__ */ jsxs6("div", { className: "rs-alert rs-alert--info", children: [
1834
- /* @__PURE__ */ jsx7(
1835
- "svg",
1836
- {
1837
- className: "rs-alert-icon",
1838
- viewBox: "0 0 24 24",
1839
- fill: "none",
1840
- stroke: "currentColor",
1841
- strokeWidth: "2",
1842
- children: /* @__PURE__ */ jsx7(
1843
- "path",
1844
- {
1845
- strokeLinecap: "round",
1846
- strokeLinejoin: "round",
1847
- d: "M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
1848
- }
1849
- )
1850
- }
1851
- ),
1852
- /* @__PURE__ */ jsxs6("p", { className: "rs-alert-text", children: [
1853
- "You can safely close this window. Your ",
1854
- flowNoun,
1855
- " will complete in the background."
1856
- ] })
1857
- ] }),
1858
- /* @__PURE__ */ jsxs6(
1859
- "div",
1860
- {
1861
- className: "rs-text-sm rs-text-tertiary",
1862
- style: { textAlign: "center" },
1863
- children: [
1864
- "Elapsed: ",
1865
- formatElapsedTime(elapsedSeconds)
1866
- ]
1867
- }
1868
- )
1869
- ] }),
1870
- isDelayed && /* @__PURE__ */ jsxs6("div", { className: "rs-alert rs-alert--info", children: [
1871
- /* @__PURE__ */ jsx7(
1872
- "svg",
1873
- {
1874
- className: "rs-alert-icon",
1875
- viewBox: "0 0 24 24",
1876
- fill: "none",
1877
- stroke: "currentColor",
1878
- strokeWidth: "2",
1879
- children: /* @__PURE__ */ jsx7(
1791
+ ),
1792
+ /* @__PURE__ */ jsx7(
1880
1793
  "path",
1881
1794
  {
1882
1795
  strokeLinecap: "round",
1883
1796
  strokeLinejoin: "round",
1884
- d: "M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
1797
+ d: "M10.29 3.86L1.82 18a2.25 2.25 0 001.93 3.37h16.5A2.25 2.25 0 0022.18 18L13.71 3.86a2.25 2.25 0 00-3.42 0z"
1885
1798
  }
1886
1799
  )
1887
- }
1888
- ),
1889
- /* @__PURE__ */ jsx7("p", { className: "rs-alert-text", children: "You can safely close this window. Your funds are secure and the transfer will be completed automatically." })
1890
- ] }),
1891
- /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1892
- /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1893
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Status" }),
1894
- /* @__PURE__ */ jsx7(
1895
- "span",
1800
+ ]
1801
+ }
1802
+ ) }) : isComplete ? /* @__PURE__ */ jsx7("div", { className: "rs-success-badge", children: /* @__PURE__ */ jsx7(
1803
+ "svg",
1804
+ {
1805
+ viewBox: "0 0 24 24",
1806
+ fill: "none",
1807
+ stroke: "currentColor",
1808
+ strokeWidth: "2.5",
1809
+ children: /* @__PURE__ */ jsx7(
1810
+ "path",
1896
1811
  {
1897
- className: "rs-card-value",
1898
- style: { color: isDelayed ? "var(--color-amber8, #e2a336)" : void 0 },
1899
- children: isDelayed ? "Processing" : "In progress"
1812
+ strokeLinecap: "round",
1813
+ strokeLinejoin: "round",
1814
+ d: "M5 12l5 5L20 7"
1900
1815
  }
1901
1816
  )
1817
+ }
1818
+ ) }) : /* @__PURE__ */ jsx7("div", { className: "rs-processing-badge", children: /* @__PURE__ */ jsx7(Spinner, {}) }),
1819
+ /* @__PURE__ */ jsx7("div", { className: "rs-step-title", children: headerTitle }),
1820
+ /* @__PURE__ */ jsx7("div", { className: "rs-step-description rs-text-secondary", children: headerDescription })
1821
+ ] }),
1822
+ /* @__PURE__ */ jsxs6("div", { className: "rs-step-body rs-space-y-3", children: [
1823
+ /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1824
+ /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1825
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Fill status" }),
1826
+ /* @__PURE__ */ jsx7("span", { className: `rs-card-value ${fillStatusClass}`, children: fillStatus })
1902
1827
  ] }),
1828
+ /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1829
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Total time" }),
1830
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-value", children: formatElapsedTime(elapsedSeconds) })
1831
+ ] })
1832
+ ] }),
1833
+ /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1903
1834
  /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1904
1835
  /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Source" }),
1905
1836
  /* @__PURE__ */ jsxs6(
1906
1837
  "span",
1907
1838
  {
1908
1839
  className: "rs-card-value",
1909
- style: { display: "flex", alignItems: "center", gap: 8 },
1840
+ style: { display: "flex", alignItems: "center", gap: 6 },
1910
1841
  children: [
1911
1842
  getChainIcon(displaySourceChain) && /* @__PURE__ */ jsx7(
1912
1843
  "img",
1913
1844
  {
1914
1845
  src: getChainIcon(displaySourceChain),
1915
1846
  alt: "",
1916
- style: { width: 16, height: 16, borderRadius: "50%" }
1847
+ style: { width: 16, height: 16, borderRadius: 3 }
1917
1848
  }
1918
1849
  ),
1919
- getChainName(displaySourceChain)
1850
+ getChainName(displaySourceChain),
1851
+ sourceExplorerUrl && /* @__PURE__ */ jsx7(
1852
+ "a",
1853
+ {
1854
+ href: sourceExplorerUrl,
1855
+ target: "_blank",
1856
+ rel: "noopener noreferrer",
1857
+ className: "rs-card-external-link",
1858
+ children: txLinkIcon
1859
+ }
1860
+ )
1920
1861
  ]
1921
1862
  }
1922
1863
  )
@@ -1927,56 +1868,148 @@ function ProcessingStep({
1927
1868
  "span",
1928
1869
  {
1929
1870
  className: "rs-card-value",
1930
- style: { display: "flex", alignItems: "center", gap: 8 },
1871
+ style: { display: "flex", alignItems: "center", gap: 6 },
1931
1872
  children: [
1932
1873
  getChainIcon(targetChain) && /* @__PURE__ */ jsx7(
1933
1874
  "img",
1934
1875
  {
1935
1876
  src: getChainIcon(targetChain),
1936
1877
  alt: "",
1937
- style: { width: 16, height: 16, borderRadius: "50%" }
1878
+ style: { width: 16, height: 16, borderRadius: 3 }
1938
1879
  }
1939
1880
  ),
1940
- getChainName(targetChain)
1881
+ getChainName(targetChain),
1882
+ destExplorerUrl && /* @__PURE__ */ jsx7(
1883
+ "a",
1884
+ {
1885
+ href: destExplorerUrl,
1886
+ target: "_blank",
1887
+ rel: "noopener noreferrer",
1888
+ className: "rs-card-external-link",
1889
+ children: txLinkIcon
1890
+ }
1891
+ )
1941
1892
  ]
1942
1893
  }
1943
1894
  )
1944
- ] }),
1895
+ ] })
1896
+ ] }),
1897
+ /* @__PURE__ */ jsx7("div", { className: "rs-card", children: /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1898
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "You receive" }),
1899
+ /* @__PURE__ */ jsxs6(
1900
+ "span",
1901
+ {
1902
+ className: "rs-card-value",
1903
+ style: { display: "flex", alignItems: "center", gap: 6 },
1904
+ children: [
1905
+ getTokenIcon(sourceSymbol) && /* @__PURE__ */ jsx7(
1906
+ "img",
1907
+ {
1908
+ src: getTokenIcon(sourceSymbol),
1909
+ alt: "",
1910
+ style: { width: 16, height: 16, borderRadius: "50%" }
1911
+ }
1912
+ ),
1913
+ formattedReceivedAmount,
1914
+ " ",
1915
+ sourceSymbol
1916
+ ]
1917
+ }
1918
+ )
1919
+ ] }) }),
1920
+ /* @__PURE__ */ jsxs6(
1921
+ "button",
1922
+ {
1923
+ type: "button",
1924
+ className: `rs-details-toggle ${detailsExpanded ? "rs-details-toggle--open" : ""}`,
1925
+ onClick: () => setDetailsExpanded(!detailsExpanded),
1926
+ children: [
1927
+ detailsExpanded ? "Less details" : "More details",
1928
+ /* @__PURE__ */ jsx7(
1929
+ "svg",
1930
+ {
1931
+ viewBox: "0 0 24 24",
1932
+ fill: "none",
1933
+ stroke: "currentColor",
1934
+ strokeWidth: "2",
1935
+ children: /* @__PURE__ */ jsx7(
1936
+ "path",
1937
+ {
1938
+ strokeLinecap: "round",
1939
+ strokeLinejoin: "round",
1940
+ d: "M19.5 8.25l-7.5 7.5-7.5-7.5"
1941
+ }
1942
+ )
1943
+ }
1944
+ )
1945
+ ]
1946
+ }
1947
+ ),
1948
+ detailsExpanded && /* @__PURE__ */ jsxs6("div", { className: "rs-card", children: [
1945
1949
  /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1946
- /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Transaction" }),
1947
- sourceExplorerUrl ? /* @__PURE__ */ jsxs6(
1950
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Source tx" }),
1951
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-value", children: sourceExplorerUrl ? /* @__PURE__ */ jsxs6(
1948
1952
  "a",
1949
1953
  {
1950
1954
  href: sourceExplorerUrl,
1951
1955
  target: "_blank",
1952
1956
  rel: "noopener noreferrer",
1953
- className: "rs-link rs-link-external rs-font-mono rs-text-xs",
1957
+ className: "rs-card-external-link",
1958
+ style: { gap: 4, fontFamily: "ui-monospace, SFMono-Regular, monospace", fontSize: 12 },
1954
1959
  children: [
1955
1960
  truncateHash(txHash),
1956
- /* @__PURE__ */ jsx7(
1957
- "svg",
1958
- {
1959
- viewBox: "0 0 24 24",
1960
- fill: "none",
1961
- stroke: "currentColor",
1962
- strokeWidth: "2.5",
1963
- children: /* @__PURE__ */ jsx7(
1964
- "path",
1965
- {
1966
- strokeLinecap: "round",
1967
- strokeLinejoin: "round",
1968
- d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
1969
- }
1970
- )
1971
- }
1972
- )
1961
+ txLinkIcon
1962
+ ]
1963
+ }
1964
+ ) : /* @__PURE__ */ jsx7("span", { style: { fontFamily: "ui-monospace, SFMono-Regular, monospace", fontSize: 12 }, children: truncateHash(txHash) }) })
1965
+ ] }),
1966
+ destinationTxHash && /* @__PURE__ */ jsxs6("div", { className: "rs-card-row", children: [
1967
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-label", children: "Destination tx" }),
1968
+ /* @__PURE__ */ jsx7("span", { className: "rs-card-value", children: destExplorerUrl ? /* @__PURE__ */ jsxs6(
1969
+ "a",
1970
+ {
1971
+ href: destExplorerUrl,
1972
+ target: "_blank",
1973
+ rel: "noopener noreferrer",
1974
+ className: "rs-card-external-link",
1975
+ style: { gap: 4, fontFamily: "ui-monospace, SFMono-Regular, monospace", fontSize: 12 },
1976
+ children: [
1977
+ truncateHash(destinationTxHash),
1978
+ txLinkIcon
1973
1979
  ]
1974
1980
  }
1975
- ) : /* @__PURE__ */ jsx7("span", { className: "rs-card-value rs-card-value--mono", children: truncateHash(txHash) })
1981
+ ) : /* @__PURE__ */ jsx7("span", { style: { fontFamily: "ui-monospace, SFMono-Regular, monospace", fontSize: 12 }, children: truncateHash(destinationTxHash) }) })
1976
1982
  ] })
1983
+ ] }),
1984
+ showAlert && /* @__PURE__ */ jsxs6("div", { className: "rs-alert rs-alert--warning", children: [
1985
+ /* @__PURE__ */ jsx7(
1986
+ "svg",
1987
+ {
1988
+ className: "rs-alert-icon",
1989
+ viewBox: "0 0 24 24",
1990
+ fill: "none",
1991
+ stroke: "currentColor",
1992
+ strokeWidth: "2",
1993
+ children: /* @__PURE__ */ jsx7(
1994
+ "path",
1995
+ {
1996
+ strokeLinecap: "round",
1997
+ strokeLinejoin: "round",
1998
+ d: "M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z"
1999
+ }
2000
+ )
2001
+ }
2002
+ ),
2003
+ /* @__PURE__ */ jsx7("p", { className: "rs-alert-text", children: alertMessage })
2004
+ ] })
2005
+ ] }),
2006
+ (isComplete || isFailed) && /* @__PURE__ */ jsxs6("div", { className: "rs-step-footer", style: { gap: 8, display: "flex" }, children: [
2007
+ /* @__PURE__ */ jsx7(Button, { variant: "outline", onClick: onClose, fullWidth: true, children: "Close" }),
2008
+ onNewDeposit && /* @__PURE__ */ jsxs6(Button, { onClick: onNewDeposit, fullWidth: true, children: [
2009
+ "New ",
2010
+ flowNoun
1977
2011
  ] })
1978
2012
  ] }),
1979
- isDelayed && /* @__PURE__ */ jsx7("div", { className: "rs-step-footer", children: /* @__PURE__ */ jsx7(Button, { onClick: onClose, fullWidth: true, children: "Close" }) }),
1980
2013
  /* @__PURE__ */ jsx7(PoweredBy, {})
1981
2014
  ] });
1982
2015
  }