@rhinestone/deposit-modal 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/bridge-transcript.json +14 -0
- package/dist/ClaimModal-GFDBVCN5.cjs +11 -0
- package/dist/ClaimModal-VQS3AKEL.mjs +11 -0
- package/dist/{DepositModalReown-Q2JMLT47.mjs → DepositModalReown-KOJ7VEY7.mjs} +30 -29
- package/dist/{DepositModalReown-46LPVFB6.cjs → DepositModalReown-R37SSHUF.cjs} +79 -78
- package/dist/WithdrawModal-QVXHMH43.mjs +12 -0
- package/dist/WithdrawModal-RY2NMFLE.cjs +12 -0
- package/dist/{caip-D8aRWdEY.d.cts → caip-BMi-9t09.d.cts} +27 -3
- package/dist/{caip-D8aRWdEY.d.ts → caip-BMi-9t09.d.ts} +27 -3
- package/dist/{chunk-V2OBGLJD.cjs → chunk-3OOY67VJ.cjs} +1103 -253
- package/dist/{chunk-6KG642KH.cjs → chunk-5P2PVLS4.cjs} +1 -1
- package/dist/{chunk-IN77XSWO.mjs → chunk-5VONFVQN.mjs} +976 -126
- package/dist/chunk-6HUHVXCY.cjs +704 -0
- package/dist/{chunk-PKML3XVS.mjs → chunk-7UQ6OUEE.mjs} +166 -45
- package/dist/{chunk-K4H6TGBE.mjs → chunk-CXBMIZUF.mjs} +1 -1
- package/dist/{chunk-MTFJSE52.cjs → chunk-DTVZUBHI.cjs} +236 -115
- package/dist/{chunk-VUATPOWJ.mjs → chunk-EAGMY3QE.mjs} +74 -17
- package/dist/{chunk-RN5VKWI6.mjs → chunk-FTWKAJGN.mjs} +1 -1
- package/dist/{chunk-KTUVSKR4.mjs → chunk-IKUYZA7A.mjs} +265 -523
- package/dist/{chunk-DW2EQA2U.cjs → chunk-LVCD6RHF.cjs} +2 -2
- package/dist/{chunk-4KCSH4T3.cjs → chunk-OY5N3E6L.cjs} +86 -29
- package/dist/chunk-QJ7RCCU7.mjs +704 -0
- package/dist/chunk-UCBUCX2W.mjs +3169 -0
- package/dist/{chunk-YCQZJQO6.cjs → chunk-VPDCGD2D.cjs} +622 -880
- package/dist/{chunk-7ICSHJFE.cjs → chunk-X4D52IZK.cjs} +1501 -176
- package/dist/claim.cjs +5 -7
- package/dist/claim.d.cts +3 -3
- package/dist/claim.d.ts +3 -3
- package/dist/claim.mjs +4 -6
- package/dist/{constants-DBrWhJWE.d.cts → constants-BT4ctuHo.d.cts} +7 -6
- package/dist/{constants-DBrWhJWE.d.ts → constants-D21ZdNOP.d.ts} +7 -6
- package/dist/constants.cjs +3 -3
- package/dist/constants.d.cts +3 -3
- package/dist/constants.d.ts +3 -3
- package/dist/constants.mjs +2 -2
- package/dist/deposit.cjs +7 -8
- package/dist/deposit.d.cts +3 -3
- package/dist/deposit.d.ts +3 -3
- package/dist/deposit.mjs +6 -7
- package/dist/embed.cjs +135 -44
- package/dist/embed.d.cts +2 -2
- package/dist/embed.d.ts +2 -2
- package/dist/embed.mjs +116 -25
- package/dist/index.cjs +13 -11
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +12 -10
- package/dist/polymarket.cjs +6 -6
- package/dist/polymarket.mjs +2 -2
- package/dist/styles.css +132 -100
- package/dist/{types-Bho4OA03.d.ts → types-CQ0NHqCy.d.ts} +146 -11
- package/dist/{types-DP_3KwlD.d.cts → types-CxiLX5sv.d.cts} +146 -11
- package/dist/withdraw.cjs +6 -6
- package/dist/withdraw.d.cts +4 -4
- package/dist/withdraw.d.ts +4 -4
- package/dist/withdraw.mjs +5 -5
- package/package.json +7 -6
- package/dist/ClaimModal-IKTJU43Y.cjs +0 -13
- package/dist/ClaimModal-SEKNWRMA.mjs +0 -13
- package/dist/WithdrawModal-5ICGD4HJ.mjs +0 -12
- package/dist/WithdrawModal-VP6PMIRO.cjs +0 -12
- package/dist/chunk-7SR7ENVJ.mjs +0 -1844
- package/dist/chunk-CFKC77SV.mjs +0 -1062
- package/dist/chunk-LZFRL2AL.cjs +0 -81
- package/dist/chunk-WUJIKCFU.mjs +0 -81
- package/dist/chunk-X2IPAPXU.cjs +0 -163
- package/dist/chunk-YWMWI7PZ.cjs +0 -1062
- package/dist/chunk-ZEO6ADM3.mjs +0 -163
package/dist/chunk-7SR7ENVJ.mjs
DELETED
|
@@ -1,1844 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BodyHeader,
|
|
3
|
-
Button,
|
|
4
|
-
Callout,
|
|
5
|
-
CdnIcon,
|
|
6
|
-
CheckIcon,
|
|
7
|
-
ChevronDownIcon,
|
|
8
|
-
ExternalLinkIcon,
|
|
9
|
-
InfoIcon,
|
|
10
|
-
PoweredBy,
|
|
11
|
-
TokenIcon,
|
|
12
|
-
WalletIcon,
|
|
13
|
-
debugError,
|
|
14
|
-
debugLog,
|
|
15
|
-
estimateReceiveAmount,
|
|
16
|
-
formatFeeUsd,
|
|
17
|
-
formatQuotedReceive,
|
|
18
|
-
formatRawTokenAmount,
|
|
19
|
-
formatTokenAmount,
|
|
20
|
-
isRecognizedToken,
|
|
21
|
-
quoteFeeGroups,
|
|
22
|
-
quoteFeeRow,
|
|
23
|
-
resolveTokenDisplay,
|
|
24
|
-
tokenAmountToNumber,
|
|
25
|
-
useExplorerTxUrl,
|
|
26
|
-
useLatestRef
|
|
27
|
-
} from "./chunk-IN77XSWO.mjs";
|
|
28
|
-
import {
|
|
29
|
-
NATIVE_TOKEN_ADDRESS,
|
|
30
|
-
SOLANA_MAINNET_CAIP2,
|
|
31
|
-
cdnIconUrl,
|
|
32
|
-
getChainIcon,
|
|
33
|
-
getChainName,
|
|
34
|
-
targetChainToCaip2,
|
|
35
|
-
targetChainToChainId,
|
|
36
|
-
toEvmCaip2
|
|
37
|
-
} from "./chunk-VUATPOWJ.mjs";
|
|
38
|
-
|
|
39
|
-
// src/core/removed-props.ts
|
|
40
|
-
var MANAGED_ACCOUNT_REMOVALS = {
|
|
41
|
-
signerAddress: "removed \u2014 accounts are service-managed, so there is no session signer. See MIGRATION.md.",
|
|
42
|
-
sessionChainIds: "removed \u2014 accounts are service-managed, so there is no smart session. See MIGRATION.md.",
|
|
43
|
-
dappAddress: "removed \u2014 the modal reads the address off `walletClient.account` instead, which cannot disagree with the wallet your app has connected.",
|
|
44
|
-
dappWalletClient: "renamed to `walletClient`.",
|
|
45
|
-
dappPublicClient: "renamed to `publicClient`.",
|
|
46
|
-
allowedRoutes: "removed \u2014 which chains and tokens you accept is the project's `depositWhitelist`, enforced by the processor. Offering a subset means a separate API key.",
|
|
47
|
-
rhinestoneApiKey: "removed \u2014 it was never read. The API key belongs on your backend proxy, which attaches it to the upstream request; the modal runs in the browser."
|
|
48
|
-
};
|
|
49
|
-
var REMOVED_PROPS = {
|
|
50
|
-
DepositModal: {
|
|
51
|
-
...MANAGED_ACCOUNT_REMOVALS,
|
|
52
|
-
dappImports: "renamed to `assetMigrations`.",
|
|
53
|
-
initialDappImport: "renamed to `initialAssetMigration`.",
|
|
54
|
-
fiatOnrampMethods: "replaced by `fiatMethods`, a boolean map keyed by Swapped payment group (`creditcard`, `bank-transfer`, `apple-pay`). Omit it to offer all of them.",
|
|
55
|
-
enableSolana: "removed \u2014 Solana sources follow the project's `depositWhitelist`."
|
|
56
|
-
},
|
|
57
|
-
WithdrawModal: {
|
|
58
|
-
...MANAGED_ACCOUNT_REMOVALS,
|
|
59
|
-
safeAddress: "renamed to `accountAddress`, and it need not be a Safe.",
|
|
60
|
-
onSignTransaction: "replaced by `onSendTransaction`, which performs one transfer and returns its hash. The modal no longer submits the transaction itself.",
|
|
61
|
-
reownAppId: "removed \u2014 WithdrawModal never connects a wallet; your app performs the transfer via `onSendTransaction`.",
|
|
62
|
-
onRequestConnect: "removed \u2014 WithdrawModal never connects a wallet."
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
var REMOVED_UI_CONFIG_KEYS = {
|
|
66
|
-
checkLiquidity: "removed \u2014 the modal no longer surfaces a liquidity cap. Route capacity is enforced when the deposit is processed.",
|
|
67
|
-
showHistoryButton: "removed \u2014 deposit history is always offered, from the modal's home screen. There is no way to hide it."
|
|
68
|
-
};
|
|
69
|
-
var warned = /* @__PURE__ */ new Set();
|
|
70
|
-
function warnOnce(component, key, replacement) {
|
|
71
|
-
const id = `${component}.${key}`;
|
|
72
|
-
if (warned.has(id)) return;
|
|
73
|
-
warned.add(id);
|
|
74
|
-
console.error(
|
|
75
|
-
`[rhinestone] <${component}> was passed \`${key}\`, which no longer exists: ${replacement}`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
function warnRemovedProps(component, props) {
|
|
79
|
-
const table = REMOVED_PROPS[component];
|
|
80
|
-
if (!table) return;
|
|
81
|
-
for (const key of Object.keys(table)) {
|
|
82
|
-
if (Object.prototype.hasOwnProperty.call(props, key)) {
|
|
83
|
-
warnOnce(component, key, table[key]);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const uiConfig = props.uiConfig;
|
|
87
|
-
if (uiConfig && typeof uiConfig === "object") {
|
|
88
|
-
for (const key of Object.keys(REMOVED_UI_CONFIG_KEYS)) {
|
|
89
|
-
if (Object.prototype.hasOwnProperty.call(uiConfig, key)) {
|
|
90
|
-
warnOnce(
|
|
91
|
-
component,
|
|
92
|
-
`uiConfig.${key}`,
|
|
93
|
-
REMOVED_UI_CONFIG_KEYS[key]
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// src/core/analytics-target.ts
|
|
101
|
-
var HEX_TOKEN = /^0x(?:[0-9a-f]{32}|[0-9a-f]{40})$/i;
|
|
102
|
-
var BASE58_TOKEN = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
103
|
-
function analyticsTargetProperties(input) {
|
|
104
|
-
const properties = {};
|
|
105
|
-
const chain = resolveChain(input.targetChain);
|
|
106
|
-
const token = resolveToken(input.targetToken);
|
|
107
|
-
if (chain) properties.target_chain = chain;
|
|
108
|
-
if (token) properties.target_token = token;
|
|
109
|
-
return properties;
|
|
110
|
-
}
|
|
111
|
-
function resolveChain(targetChain) {
|
|
112
|
-
if (targetChain === void 0) return void 0;
|
|
113
|
-
if (typeof targetChain === "number" && !(targetChain > 0 && Number.isInteger(targetChain))) {
|
|
114
|
-
return void 0;
|
|
115
|
-
}
|
|
116
|
-
return targetChainToCaip2(targetChain);
|
|
117
|
-
}
|
|
118
|
-
function resolveToken(targetToken) {
|
|
119
|
-
const raw = targetToken?.trim();
|
|
120
|
-
if (!raw) return void 0;
|
|
121
|
-
if (HEX_TOKEN.test(raw)) return raw.toLowerCase();
|
|
122
|
-
if (BASE58_TOKEN.test(raw)) return raw;
|
|
123
|
-
return raw.toLowerCase() === "native" ? "native" : void 0;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/core/submission-uncertainty.ts
|
|
127
|
-
var MARKER = "__rhinestoneSubmissionUncertain";
|
|
128
|
-
function markSubmissionUncertain(error) {
|
|
129
|
-
Object.defineProperty(error, MARKER, {
|
|
130
|
-
value: true,
|
|
131
|
-
enumerable: false
|
|
132
|
-
});
|
|
133
|
-
return error;
|
|
134
|
-
}
|
|
135
|
-
function isSubmissionUncertain(error) {
|
|
136
|
-
let current = error;
|
|
137
|
-
for (let depth = 0; depth < 10; depth += 1) {
|
|
138
|
-
if (typeof current !== "object" || current === null) return false;
|
|
139
|
-
if (current[MARKER] === true) return true;
|
|
140
|
-
current = current.cause;
|
|
141
|
-
}
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// src/components/steps/ProcessingStep.tsx
|
|
146
|
-
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
147
|
-
|
|
148
|
-
// src/components/ui/Tooltip.tsx
|
|
149
|
-
import {
|
|
150
|
-
useState,
|
|
151
|
-
useRef,
|
|
152
|
-
useEffect,
|
|
153
|
-
useCallback
|
|
154
|
-
} from "react";
|
|
155
|
-
import { createPortal } from "react-dom";
|
|
156
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
157
|
-
function Tooltip({ content, children, className }) {
|
|
158
|
-
const [open, setOpen] = useState(false);
|
|
159
|
-
const [position, setPosition] = useState(null);
|
|
160
|
-
const triggerRef = useRef(null);
|
|
161
|
-
const bubbleRef = useRef(null);
|
|
162
|
-
const updatePosition = useCallback(() => {
|
|
163
|
-
const trigger = triggerRef.current;
|
|
164
|
-
if (!trigger) return;
|
|
165
|
-
const rect = trigger.getBoundingClientRect();
|
|
166
|
-
setPosition({
|
|
167
|
-
top: rect.top,
|
|
168
|
-
left: rect.left + rect.width / 2
|
|
169
|
-
});
|
|
170
|
-
}, []);
|
|
171
|
-
useEffect(() => {
|
|
172
|
-
if (!open) return;
|
|
173
|
-
updatePosition();
|
|
174
|
-
function handleOutside(event) {
|
|
175
|
-
const target = event.target;
|
|
176
|
-
if (!target) return;
|
|
177
|
-
if (triggerRef.current?.contains(target)) return;
|
|
178
|
-
if (bubbleRef.current?.contains(target)) return;
|
|
179
|
-
setOpen(false);
|
|
180
|
-
}
|
|
181
|
-
function handleKey(event) {
|
|
182
|
-
if (event.key === "Escape") setOpen(false);
|
|
183
|
-
}
|
|
184
|
-
document.addEventListener("mousedown", handleOutside);
|
|
185
|
-
document.addEventListener("touchstart", handleOutside, { passive: true });
|
|
186
|
-
document.addEventListener("keydown", handleKey);
|
|
187
|
-
window.addEventListener("scroll", updatePosition, true);
|
|
188
|
-
window.addEventListener("resize", updatePosition);
|
|
189
|
-
return () => {
|
|
190
|
-
document.removeEventListener("mousedown", handleOutside);
|
|
191
|
-
document.removeEventListener("touchstart", handleOutside);
|
|
192
|
-
document.removeEventListener("keydown", handleKey);
|
|
193
|
-
window.removeEventListener("scroll", updatePosition, true);
|
|
194
|
-
window.removeEventListener("resize", updatePosition);
|
|
195
|
-
};
|
|
196
|
-
}, [open, updatePosition]);
|
|
197
|
-
return /* @__PURE__ */ jsxs(
|
|
198
|
-
"span",
|
|
199
|
-
{
|
|
200
|
-
ref: triggerRef,
|
|
201
|
-
className: `rs-tooltip ${className ?? ""}`,
|
|
202
|
-
onMouseEnter: () => setOpen(true),
|
|
203
|
-
onMouseLeave: () => setOpen(false),
|
|
204
|
-
children: [
|
|
205
|
-
/* @__PURE__ */ jsx(
|
|
206
|
-
"span",
|
|
207
|
-
{
|
|
208
|
-
className: "rs-tooltip-trigger",
|
|
209
|
-
role: "button",
|
|
210
|
-
tabIndex: 0,
|
|
211
|
-
"aria-label": content,
|
|
212
|
-
onClick: (event) => {
|
|
213
|
-
event.stopPropagation();
|
|
214
|
-
event.preventDefault();
|
|
215
|
-
setOpen((value) => !value);
|
|
216
|
-
},
|
|
217
|
-
onKeyDown: (event) => {
|
|
218
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
219
|
-
event.preventDefault();
|
|
220
|
-
setOpen((value) => !value);
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
children
|
|
224
|
-
}
|
|
225
|
-
),
|
|
226
|
-
open && position && typeof document !== "undefined" && createPortal(
|
|
227
|
-
/* @__PURE__ */ jsx(
|
|
228
|
-
"span",
|
|
229
|
-
{
|
|
230
|
-
ref: bubbleRef,
|
|
231
|
-
className: "rs-tooltip-bubble",
|
|
232
|
-
role: "tooltip",
|
|
233
|
-
style: { top: position.top, left: position.left },
|
|
234
|
-
children: content
|
|
235
|
-
}
|
|
236
|
-
),
|
|
237
|
-
document.body
|
|
238
|
-
)
|
|
239
|
-
]
|
|
240
|
-
}
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
Tooltip.displayName = "Tooltip";
|
|
244
|
-
|
|
245
|
-
// src/components/ui/FeesAccordion.tsx
|
|
246
|
-
import { useState as useState2 } from "react";
|
|
247
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
248
|
-
function FeesAccordion({ total, rows, tooltip }) {
|
|
249
|
-
const [open, setOpen] = useState2(false);
|
|
250
|
-
const expandable = rows.length > 0;
|
|
251
|
-
return /* @__PURE__ */ jsxs2("div", { className: "rs-fees-accordion", children: [
|
|
252
|
-
/* @__PURE__ */ jsxs2("div", { className: "rs-fees-accordion-summary", children: [
|
|
253
|
-
/* @__PURE__ */ jsxs2("span", { className: "rs-fees-accordion-label", children: [
|
|
254
|
-
/* @__PURE__ */ jsx2("span", { children: "Fees" }),
|
|
255
|
-
tooltip && /* @__PURE__ */ jsx2(Tooltip, { content: tooltip, children: /* @__PURE__ */ jsx2("span", { className: "rs-review-detail-info", "aria-label": "Fees info", children: /* @__PURE__ */ jsx2(InfoIcon, {}) }) })
|
|
256
|
-
] }),
|
|
257
|
-
/* @__PURE__ */ jsxs2(
|
|
258
|
-
"button",
|
|
259
|
-
{
|
|
260
|
-
type: "button",
|
|
261
|
-
className: "rs-fees-accordion-toggle",
|
|
262
|
-
"aria-label": "Fees",
|
|
263
|
-
"aria-expanded": expandable ? open : void 0,
|
|
264
|
-
disabled: !expandable,
|
|
265
|
-
onClick: () => expandable && setOpen((o) => !o),
|
|
266
|
-
children: [
|
|
267
|
-
/* @__PURE__ */ jsx2("span", { children: total }),
|
|
268
|
-
expandable && /* @__PURE__ */ jsx2(
|
|
269
|
-
"span",
|
|
270
|
-
{
|
|
271
|
-
className: `rs-fees-accordion-chevron${open ? " rs-fees-accordion-chevron--open" : ""}`,
|
|
272
|
-
"aria-hidden": "true",
|
|
273
|
-
children: /* @__PURE__ */ jsx2(ChevronDownIcon, {})
|
|
274
|
-
}
|
|
275
|
-
)
|
|
276
|
-
]
|
|
277
|
-
}
|
|
278
|
-
)
|
|
279
|
-
] }),
|
|
280
|
-
expandable && open && /* @__PURE__ */ jsx2("div", { className: "rs-fees-accordion-rows", children: rows.map((row, i) => /* @__PURE__ */ jsxs2("div", { className: "rs-fees-accordion-row", children: [
|
|
281
|
-
/* @__PURE__ */ jsx2("span", { children: row.label }),
|
|
282
|
-
/* @__PURE__ */ jsxs2("span", { className: "rs-review-detail-value", children: [
|
|
283
|
-
/* @__PURE__ */ jsx2(
|
|
284
|
-
"span",
|
|
285
|
-
{
|
|
286
|
-
className: row.strike ? "rs-review-detail-value--strike" : void 0,
|
|
287
|
-
children: row.value
|
|
288
|
-
}
|
|
289
|
-
),
|
|
290
|
-
row.tooltip && /* @__PURE__ */ jsx2(Tooltip, { content: row.tooltip, children: /* @__PURE__ */ jsx2(
|
|
291
|
-
"span",
|
|
292
|
-
{
|
|
293
|
-
className: "rs-review-detail-info",
|
|
294
|
-
"aria-label": `${row.label} info`,
|
|
295
|
-
children: /* @__PURE__ */ jsx2(InfoIcon, {})
|
|
296
|
-
}
|
|
297
|
-
) })
|
|
298
|
-
] })
|
|
299
|
-
] }, `${row.label}-${i}`)) })
|
|
300
|
-
] });
|
|
301
|
-
}
|
|
302
|
-
FeesAccordion.displayName = "FeesAccordion";
|
|
303
|
-
|
|
304
|
-
// src/components/steps/SwappedReceipt.tsx
|
|
305
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
306
|
-
function SwappedReceipt({
|
|
307
|
-
onrampMethod,
|
|
308
|
-
onrampMethodIcon,
|
|
309
|
-
amountPaid,
|
|
310
|
-
depositedAmount,
|
|
311
|
-
depositedSymbol,
|
|
312
|
-
feesTotal,
|
|
313
|
-
feeRows,
|
|
314
|
-
feesTooltip,
|
|
315
|
-
newLabel,
|
|
316
|
-
onNewDeposit,
|
|
317
|
-
onClose
|
|
318
|
-
}) {
|
|
319
|
-
return /* @__PURE__ */ jsxs3("div", { className: "rs-screen", children: [
|
|
320
|
-
/* @__PURE__ */ jsxs3("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
|
|
321
|
-
/* @__PURE__ */ jsx3(BodyHeader, { icon: /* @__PURE__ */ jsx3(CheckIcon, {}), title: "Deposit successful" }),
|
|
322
|
-
/* @__PURE__ */ jsxs3("div", { className: "rs-review-details", children: [
|
|
323
|
-
onrampMethod && /* @__PURE__ */ jsxs3("div", { className: "rs-review-detail-row", children: [
|
|
324
|
-
/* @__PURE__ */ jsx3("span", { children: "Onramp method" }),
|
|
325
|
-
/* @__PURE__ */ jsxs3("span", { className: "rs-review-detail-value", children: [
|
|
326
|
-
/* @__PURE__ */ jsx3("span", { children: onrampMethod }),
|
|
327
|
-
onrampMethodIcon && /* @__PURE__ */ jsx3("span", { className: "rs-review-detail-icon rs-review-detail-icon--square", children: /* @__PURE__ */ jsx3(CdnIcon, { src: onrampMethodIcon }) })
|
|
328
|
-
] })
|
|
329
|
-
] }),
|
|
330
|
-
amountPaid && /* @__PURE__ */ jsxs3("div", { className: "rs-review-detail-row", children: [
|
|
331
|
-
/* @__PURE__ */ jsx3("span", { children: "Amount paid" }),
|
|
332
|
-
/* @__PURE__ */ jsx3("span", { className: "rs-review-detail-value", children: amountPaid })
|
|
333
|
-
] }),
|
|
334
|
-
/* @__PURE__ */ jsxs3("div", { className: "rs-review-detail-row", children: [
|
|
335
|
-
/* @__PURE__ */ jsx3("span", { children: "Deposited amount" }),
|
|
336
|
-
/* @__PURE__ */ jsxs3("span", { className: "rs-review-detail-value", children: [
|
|
337
|
-
/* @__PURE__ */ jsx3("span", { children: depositedAmount }),
|
|
338
|
-
depositedSymbol && /* @__PURE__ */ jsx3("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx3(TokenIcon, { symbol: depositedSymbol }) })
|
|
339
|
-
] })
|
|
340
|
-
] }),
|
|
341
|
-
feesTotal != null && /* @__PURE__ */ jsx3(
|
|
342
|
-
FeesAccordion,
|
|
343
|
-
{
|
|
344
|
-
total: feesTotal,
|
|
345
|
-
rows: feeRows ?? [],
|
|
346
|
-
tooltip: feesTooltip ?? void 0
|
|
347
|
-
}
|
|
348
|
-
)
|
|
349
|
-
] }),
|
|
350
|
-
/* @__PURE__ */ jsxs3("div", { className: "rs-screen-button-row", children: [
|
|
351
|
-
onNewDeposit && /* @__PURE__ */ jsx3(Button, { variant: "outline", onClick: onNewDeposit, fullWidth: true, children: newLabel }),
|
|
352
|
-
onClose && /* @__PURE__ */ jsx3(Button, { onClick: onClose, fullWidth: true, children: "Done" })
|
|
353
|
-
] })
|
|
354
|
-
] }),
|
|
355
|
-
/* @__PURE__ */ jsx3(PoweredBy, {})
|
|
356
|
-
] });
|
|
357
|
-
}
|
|
358
|
-
SwappedReceipt.displayName = "SwappedReceipt";
|
|
359
|
-
|
|
360
|
-
// src/components/ui/ExchangeLogos.tsx
|
|
361
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
362
|
-
var EXCHANGE_SLUGS = [
|
|
363
|
-
"binance",
|
|
364
|
-
"bitfinex",
|
|
365
|
-
"btcturk",
|
|
366
|
-
"bybit",
|
|
367
|
-
"coinbase",
|
|
368
|
-
"gateio",
|
|
369
|
-
"htx",
|
|
370
|
-
"kraken",
|
|
371
|
-
"kucoin"
|
|
372
|
-
];
|
|
373
|
-
var EXCHANGE_LOGO_SOURCES = Object.fromEntries(
|
|
374
|
-
EXCHANGE_SLUGS.map((slug) => [slug, cdnIconUrl("exchanges", slug)])
|
|
375
|
-
);
|
|
376
|
-
var EXCHANGE_LOGO_ALIASES = {
|
|
377
|
-
gate: "gateio"
|
|
378
|
-
};
|
|
379
|
-
function normalize(value) {
|
|
380
|
-
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
381
|
-
}
|
|
382
|
-
function getLogoSource(value) {
|
|
383
|
-
const key = normalize(value);
|
|
384
|
-
return EXCHANGE_LOGO_SOURCES[EXCHANGE_LOGO_ALIASES[key] ?? key] ?? null;
|
|
385
|
-
}
|
|
386
|
-
function getExchangeLogoSrc(name, connection) {
|
|
387
|
-
return getLogoSource(name) ?? getLogoSource(connection ?? "");
|
|
388
|
-
}
|
|
389
|
-
function getExchangeLogo(name, connection) {
|
|
390
|
-
const src = getExchangeLogoSrc(name, connection);
|
|
391
|
-
return src ? /* @__PURE__ */ jsx4(CdnIcon, { src }) : null;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// src/core/webhook.ts
|
|
395
|
-
function isRecord(value) {
|
|
396
|
-
return typeof value === "object" && value !== null;
|
|
397
|
-
}
|
|
398
|
-
function asString(value) {
|
|
399
|
-
return typeof value === "string" ? value : void 0;
|
|
400
|
-
}
|
|
401
|
-
function asNumber(value) {
|
|
402
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
403
|
-
if (typeof value !== "string") return void 0;
|
|
404
|
-
const trimmed = value.trim();
|
|
405
|
-
if (!trimmed) return void 0;
|
|
406
|
-
const caipMatch = trimmed.match(/^eip155:(\d+)$/);
|
|
407
|
-
if (caipMatch?.[1]) {
|
|
408
|
-
const parsed2 = Number(caipMatch[1]);
|
|
409
|
-
return Number.isFinite(parsed2) ? parsed2 : void 0;
|
|
410
|
-
}
|
|
411
|
-
const parsed = Number(trimmed);
|
|
412
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
413
|
-
}
|
|
414
|
-
function asAmount(value) {
|
|
415
|
-
if (typeof value === "string") return value;
|
|
416
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
417
|
-
return value.toString();
|
|
418
|
-
}
|
|
419
|
-
return void 0;
|
|
420
|
-
}
|
|
421
|
-
function asAddress(value) {
|
|
422
|
-
if (typeof value !== "string") return void 0;
|
|
423
|
-
return /^0x[a-fA-F0-9]{40}$/.test(value) ? value : void 0;
|
|
424
|
-
}
|
|
425
|
-
function getEventTxHash(event) {
|
|
426
|
-
if (!event?.type) return void 0;
|
|
427
|
-
if (event.type === "deposit-received") {
|
|
428
|
-
return asString(event.data?.transactionHash);
|
|
429
|
-
}
|
|
430
|
-
if (event.type === "bridge-started" || event.type === "bridge-complete") {
|
|
431
|
-
const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
|
|
432
|
-
const source = isRecord(event.data?.source) ? event.data.source : void 0;
|
|
433
|
-
return asString(deposit?.transactionHash) ?? asString(source?.transactionHash);
|
|
434
|
-
}
|
|
435
|
-
if (event.type === "bridge-failed" || event.type === "error") {
|
|
436
|
-
const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
|
|
437
|
-
const source = isRecord(event.data?.source) ? event.data.source : void 0;
|
|
438
|
-
return asString(deposit?.transactionHash) ?? asString(source?.transactionHash);
|
|
439
|
-
}
|
|
440
|
-
return void 0;
|
|
441
|
-
}
|
|
442
|
-
function getEventSourceDetails(event) {
|
|
443
|
-
if (!event?.type || !isRecord(event.data)) return {};
|
|
444
|
-
if (event.type === "deposit-received") {
|
|
445
|
-
return {
|
|
446
|
-
chainId: asNumber(event.data.chain),
|
|
447
|
-
amount: asAmount(event.data.amount),
|
|
448
|
-
token: asAddress(event.data.token)
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
const source = isRecord(event.data.source) ? event.data.source : void 0;
|
|
452
|
-
const deposit = isRecord(event.data.deposit) ? event.data.deposit : void 0;
|
|
453
|
-
if (event.type === "bridge-started" || event.type === "bridge-complete" || event.type === "bridge-failed" || event.type === "error") {
|
|
454
|
-
return {
|
|
455
|
-
chainId: asNumber(source?.chain) ?? asNumber(deposit?.chain),
|
|
456
|
-
amount: asAmount(source?.amount) ?? asAmount(deposit?.amount),
|
|
457
|
-
token: asAddress(source?.asset) ?? asAddress(deposit?.asset) ?? asAddress(deposit?.token)
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
return {};
|
|
461
|
-
}
|
|
462
|
-
function asChain(value) {
|
|
463
|
-
if (typeof value === "string") {
|
|
464
|
-
const trimmed = value.trim();
|
|
465
|
-
if (trimmed.startsWith("solana")) return "solana";
|
|
466
|
-
if (trimmed.startsWith("hypercore")) return "hypercore";
|
|
467
|
-
}
|
|
468
|
-
return asNumber(value);
|
|
469
|
-
}
|
|
470
|
-
function getEventDestinationDetails(event) {
|
|
471
|
-
if (!event?.type || !isRecord(event.data)) return {};
|
|
472
|
-
if (event.type !== "bridge-started" && event.type !== "bridge-complete") {
|
|
473
|
-
return {};
|
|
474
|
-
}
|
|
475
|
-
const destination = isRecord(event.data.destination) ? event.data.destination : void 0;
|
|
476
|
-
if (!destination) return {};
|
|
477
|
-
const token = asString(destination.asset);
|
|
478
|
-
return {
|
|
479
|
-
chainId: asChain(destination.chain),
|
|
480
|
-
amount: asAmount(destination.amount),
|
|
481
|
-
token: token?.trim() || void 0
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
function isDepositEvent(event) {
|
|
485
|
-
return event?.type === "deposit-received" || event?.type === "bridge-started" || event?.type === "bridge-complete" || event?.type === "bridge-failed" || event?.type === "error";
|
|
486
|
-
}
|
|
487
|
-
function isFailedEvent(event) {
|
|
488
|
-
return event?.type === "bridge-failed" || event?.type === "error";
|
|
489
|
-
}
|
|
490
|
-
function isHexString(value) {
|
|
491
|
-
return value.startsWith("0x") || value.startsWith("0X");
|
|
492
|
-
}
|
|
493
|
-
function txRefsMatch(a, b) {
|
|
494
|
-
if (isHexString(a) && isHexString(b)) {
|
|
495
|
-
return a.toLowerCase() === b.toLowerCase();
|
|
496
|
-
}
|
|
497
|
-
return a === b;
|
|
498
|
-
}
|
|
499
|
-
function formatBridgeFailedMessage(event) {
|
|
500
|
-
const eventData = event?.data ?? {};
|
|
501
|
-
const code = typeof eventData.errorCode === "string" ? eventData.errorCode : void 0;
|
|
502
|
-
const backendMessage = typeof eventData.message === "string" ? eventData.message.trim() : "";
|
|
503
|
-
function toUserFacingFailure(raw) {
|
|
504
|
-
const lower = raw.toLowerCase();
|
|
505
|
-
if (lower.includes("insufficient funds")) {
|
|
506
|
-
return "Deposit was received, but processing could not continue due to insufficient funds. Please retry.";
|
|
507
|
-
}
|
|
508
|
-
if (lower.includes("no valid quote available")) {
|
|
509
|
-
return "No bridge route is currently available for this transfer. Please try again shortly.";
|
|
510
|
-
}
|
|
511
|
-
if (lower.includes("simulation failed")) {
|
|
512
|
-
return "Transfer processing failed during simulation. Please retry.";
|
|
513
|
-
}
|
|
514
|
-
if (raw.length > 220) {
|
|
515
|
-
return "Transfer processing failed. Please retry.";
|
|
516
|
-
}
|
|
517
|
-
return raw;
|
|
518
|
-
}
|
|
519
|
-
if (backendMessage.length > 0) {
|
|
520
|
-
return { message: toUserFacingFailure(backendMessage), code };
|
|
521
|
-
}
|
|
522
|
-
if (code) {
|
|
523
|
-
return { message: `Bridge failed (${code})`, code };
|
|
524
|
-
}
|
|
525
|
-
return { message: "Bridge failed" };
|
|
526
|
-
}
|
|
527
|
-
function failureMessageForEvent(event) {
|
|
528
|
-
if (event?.type === "error") {
|
|
529
|
-
const message = isRecord(event.data) ? asString(event.data.message) : void 0;
|
|
530
|
-
return message ?? "Unknown error";
|
|
531
|
-
}
|
|
532
|
-
return formatBridgeFailedMessage(event).message;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// src/core/useTokenPrices.ts
|
|
536
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
537
|
-
var PRICE_SERVICE_NATIVE = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
538
|
-
var WRAPPED_SOL_MINT = "So11111111111111111111111111111111111111112";
|
|
539
|
-
var SOL_SYSTEM_PROGRAM = "11111111111111111111111111111111";
|
|
540
|
-
function isSolanaNativeAddress(address) {
|
|
541
|
-
if (!address) return true;
|
|
542
|
-
const lower = address.toLowerCase();
|
|
543
|
-
return lower === "native" || lower === SOL_SYSTEM_PROGRAM;
|
|
544
|
-
}
|
|
545
|
-
function isNativeAddress(address) {
|
|
546
|
-
if (!address) return true;
|
|
547
|
-
return address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
548
|
-
}
|
|
549
|
-
function caip2For(token) {
|
|
550
|
-
if (token.chainId === "solana") {
|
|
551
|
-
const mint = isSolanaNativeAddress(token.address) ? WRAPPED_SOL_MINT : token.address;
|
|
552
|
-
return mint ? `${SOLANA_MAINNET_CAIP2}:${mint}` : void 0;
|
|
553
|
-
}
|
|
554
|
-
if (typeof token.chainId !== "number") return void 0;
|
|
555
|
-
const address = isNativeAddress(token.address) ? PRICE_SERVICE_NATIVE : token.address;
|
|
556
|
-
return `${toEvmCaip2(token.chainId)}:${address.toLowerCase()}`;
|
|
557
|
-
}
|
|
558
|
-
async function fetchTokenPriceUsd(service, token) {
|
|
559
|
-
const caip2 = caip2For(token);
|
|
560
|
-
if (!caip2) return null;
|
|
561
|
-
const prices = await service.fetchPricesByAddress([caip2]);
|
|
562
|
-
const price = prices[caip2];
|
|
563
|
-
return typeof price === "number" && price > 0 ? price : null;
|
|
564
|
-
}
|
|
565
|
-
function useTokenPrices(service, tokens) {
|
|
566
|
-
const [prices, setPrices] = useState3({});
|
|
567
|
-
const defined = tokens.filter((t) => Boolean(t?.symbol));
|
|
568
|
-
const entries = [
|
|
569
|
-
...new Map(
|
|
570
|
-
defined.flatMap((token) => {
|
|
571
|
-
const caip2 = caip2For(token);
|
|
572
|
-
return caip2 ? [{ symbol: token.symbol.toUpperCase(), caip2 }] : [];
|
|
573
|
-
}).map((entry) => [entry.caip2, entry])
|
|
574
|
-
).values()
|
|
575
|
-
].sort((a, b) => a.caip2.localeCompare(b.caip2));
|
|
576
|
-
const key = JSON.stringify(entries);
|
|
577
|
-
useEffect2(() => {
|
|
578
|
-
if (key === "[]") return;
|
|
579
|
-
let cancelled = false;
|
|
580
|
-
const parsed = JSON.parse(key);
|
|
581
|
-
const caip2Ids = [...new Set(parsed.map((e) => e.caip2))];
|
|
582
|
-
service.fetchPricesByAddress(caip2Ids).then((byAddress) => {
|
|
583
|
-
if (cancelled) return;
|
|
584
|
-
const merged = {};
|
|
585
|
-
for (const entry of parsed) {
|
|
586
|
-
const price = byAddress[entry.caip2];
|
|
587
|
-
if (typeof price === "number") merged[entry.symbol] = price;
|
|
588
|
-
}
|
|
589
|
-
setPrices(merged);
|
|
590
|
-
}).catch(() => {
|
|
591
|
-
});
|
|
592
|
-
return () => {
|
|
593
|
-
cancelled = true;
|
|
594
|
-
};
|
|
595
|
-
}, [service, key]);
|
|
596
|
-
return prices;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// src/components/steps/ProcessingStep.tsx
|
|
600
|
-
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
601
|
-
function SuccessBadge() {
|
|
602
|
-
return /* @__PURE__ */ jsxs4(
|
|
603
|
-
"svg",
|
|
604
|
-
{
|
|
605
|
-
width: "40",
|
|
606
|
-
height: "40",
|
|
607
|
-
viewBox: "0 0 40 40",
|
|
608
|
-
fill: "none",
|
|
609
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
610
|
-
"aria-hidden": "true",
|
|
611
|
-
children: [
|
|
612
|
-
/* @__PURE__ */ jsx5(
|
|
613
|
-
"rect",
|
|
614
|
-
{
|
|
615
|
-
width: "40",
|
|
616
|
-
height: "40",
|
|
617
|
-
rx: "8",
|
|
618
|
-
fill: "var(--rs-icon-wrapper-bg)"
|
|
619
|
-
}
|
|
620
|
-
),
|
|
621
|
-
/* @__PURE__ */ jsx5(
|
|
622
|
-
"path",
|
|
623
|
-
{
|
|
624
|
-
d: "M28 14L17 25L12 20",
|
|
625
|
-
stroke: "var(--rs-icon-wrapper-icon)",
|
|
626
|
-
strokeWidth: "2",
|
|
627
|
-
strokeLinecap: "round",
|
|
628
|
-
strokeLinejoin: "round"
|
|
629
|
-
}
|
|
630
|
-
)
|
|
631
|
-
]
|
|
632
|
-
}
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
function FailedBadge() {
|
|
636
|
-
return /* @__PURE__ */ jsxs4(
|
|
637
|
-
"svg",
|
|
638
|
-
{
|
|
639
|
-
width: "40",
|
|
640
|
-
height: "40",
|
|
641
|
-
viewBox: "0 0 40 40",
|
|
642
|
-
fill: "none",
|
|
643
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
644
|
-
"aria-hidden": "true",
|
|
645
|
-
children: [
|
|
646
|
-
/* @__PURE__ */ jsx5("rect", { width: "40", height: "40", rx: "8", fill: "#FB2C36" }),
|
|
647
|
-
/* @__PURE__ */ jsx5(
|
|
648
|
-
"path",
|
|
649
|
-
{
|
|
650
|
-
d: "M26 14L14 26M14 14L26 26",
|
|
651
|
-
stroke: "white",
|
|
652
|
-
strokeWidth: "2",
|
|
653
|
-
strokeLinecap: "round",
|
|
654
|
-
strokeLinejoin: "round"
|
|
655
|
-
}
|
|
656
|
-
)
|
|
657
|
-
]
|
|
658
|
-
}
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
|
-
var INITIAL_POLL_INTERVAL = 3e3;
|
|
662
|
-
var MAX_POLL_INTERVAL = 3e4;
|
|
663
|
-
var BACKOFF_MULTIPLIER = 1.5;
|
|
664
|
-
var SWAPPED_RECEIPT_STATUS_RETRY_INTERVAL_MS = 1e3;
|
|
665
|
-
var SWAPPED_FIAT_STATUS_MAX_ATTEMPTS = 12;
|
|
666
|
-
var ESCALATED_DELAY_MS = 10 * 60 * 1e3;
|
|
667
|
-
var SOFT_DELAY_MS = {
|
|
668
|
-
confirming: 90 * 1e3,
|
|
669
|
-
received: 90 * 1e3,
|
|
670
|
-
bridging: 4 * 60 * 1e3
|
|
671
|
-
};
|
|
672
|
-
var PHASE_TIMINGS_PREFIX = "rhinestone:phase-timings";
|
|
673
|
-
var PAYMENT_METHOD_LABELS = {
|
|
674
|
-
creditcard: "Card",
|
|
675
|
-
debitcard: "Card",
|
|
676
|
-
card: "Card",
|
|
677
|
-
"apple-pay": "Apple Pay",
|
|
678
|
-
applepay: "Apple Pay",
|
|
679
|
-
"google-pay": "Google Pay",
|
|
680
|
-
googlepay: "Google Pay",
|
|
681
|
-
"bank-transfer": "Bank Transfer",
|
|
682
|
-
banktransfer: "Bank Transfer",
|
|
683
|
-
sepa: "SEPA",
|
|
684
|
-
"open-banking": "Open Banking",
|
|
685
|
-
"krak-pay": "Kraken Pay",
|
|
686
|
-
krakpay: "Kraken Pay",
|
|
687
|
-
kraken: "Kraken",
|
|
688
|
-
coinbase: "Coinbase",
|
|
689
|
-
binance: "Binance"
|
|
690
|
-
};
|
|
691
|
-
function formatPaymentMethod(method) {
|
|
692
|
-
const key = method.trim().toLowerCase();
|
|
693
|
-
if (PAYMENT_METHOD_LABELS[key]) return PAYMENT_METHOD_LABELS[key];
|
|
694
|
-
return key.replace(/[-_]+/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
695
|
-
}
|
|
696
|
-
function buildQuoteFeeRows(breakdown, sponsoredTooltip) {
|
|
697
|
-
if (!breakdown) return { rows: [], chargeableUsd: 0 };
|
|
698
|
-
const rows = [];
|
|
699
|
-
let chargeableUsd = 0;
|
|
700
|
-
for (const group of quoteFeeGroups(breakdown)) {
|
|
701
|
-
if (group.chargedUsd > 0) {
|
|
702
|
-
chargeableUsd += group.chargedUsd;
|
|
703
|
-
rows.push({ label: group.label, value: formatFeeUsd(group.chargedUsd) });
|
|
704
|
-
} else if (group.sponsoredUsd > 0) {
|
|
705
|
-
rows.push({
|
|
706
|
-
label: group.label,
|
|
707
|
-
value: formatFeeUsd(group.sponsoredUsd),
|
|
708
|
-
strike: true,
|
|
709
|
-
tooltip: sponsoredTooltip
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
return { rows, chargeableUsd };
|
|
714
|
-
}
|
|
715
|
-
function toSwappedFiatContext(status) {
|
|
716
|
-
return {
|
|
717
|
-
orderCrypto: status.orderCrypto,
|
|
718
|
-
orderCryptoAmount: status.orderCryptoAmount,
|
|
719
|
-
paidAmountUsd: status.paidAmountUsd,
|
|
720
|
-
paidAmountEur: status.paidAmountEur,
|
|
721
|
-
onrampFeeUsd: status.onrampFeeUsd,
|
|
722
|
-
paymentMethod: status.paymentMethod
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
function hasFiatReceiptPricing(status) {
|
|
726
|
-
return status.paidAmountUsd != null && status.onrampFeeUsd != null;
|
|
727
|
-
}
|
|
728
|
-
function loadPhaseTimings(txHash) {
|
|
729
|
-
if (typeof window === "undefined") return null;
|
|
730
|
-
try {
|
|
731
|
-
const raw = window.localStorage.getItem(`${PHASE_TIMINGS_PREFIX}:${txHash}`);
|
|
732
|
-
if (!raw) return null;
|
|
733
|
-
const parsed = JSON.parse(raw);
|
|
734
|
-
if (typeof parsed.startedAt !== "number") return null;
|
|
735
|
-
return parsed;
|
|
736
|
-
} catch {
|
|
737
|
-
return null;
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
function savePhaseTimings(txHash, timings) {
|
|
741
|
-
if (typeof window === "undefined") return;
|
|
742
|
-
try {
|
|
743
|
-
window.localStorage.setItem(
|
|
744
|
-
`${PHASE_TIMINGS_PREFIX}:${txHash}`,
|
|
745
|
-
JSON.stringify(timings)
|
|
746
|
-
);
|
|
747
|
-
} catch {
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
function isEventForTx(event, txHash) {
|
|
751
|
-
const eventTxHash = getEventTxHash(event);
|
|
752
|
-
if (!eventTxHash) return false;
|
|
753
|
-
return txRefsMatch(eventTxHash, txHash);
|
|
754
|
-
}
|
|
755
|
-
function parseWebhookTimestamp(event) {
|
|
756
|
-
if (typeof event?.time !== "string") return void 0;
|
|
757
|
-
const timestamp = Date.parse(event.time);
|
|
758
|
-
return Number.isFinite(timestamp) ? timestamp : void 0;
|
|
759
|
-
}
|
|
760
|
-
function syncPhaseTimings(previous, event) {
|
|
761
|
-
if (!event?.type) return previous;
|
|
762
|
-
const timestamp = parseWebhookTimestamp(event) ?? Date.now();
|
|
763
|
-
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;
|
|
764
|
-
const setBridging = (event.type === "bridge-started" || event.type === "bridge-complete") && previous.bridgingAt === void 0;
|
|
765
|
-
const setCompleted = event.type === "bridge-complete" && previous.completedAt === void 0;
|
|
766
|
-
if (!setReceived && !setBridging && !setCompleted) return previous;
|
|
767
|
-
return {
|
|
768
|
-
...previous,
|
|
769
|
-
...setReceived && { receivedAt: timestamp },
|
|
770
|
-
...setBridging && { bridgingAt: timestamp },
|
|
771
|
-
...setCompleted && { completedAt: timestamp }
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
function formatTimer(seconds) {
|
|
775
|
-
const safe = Math.max(0, seconds);
|
|
776
|
-
const mins = Math.floor(safe / 60);
|
|
777
|
-
const secs = safe % 60;
|
|
778
|
-
return `${mins}:${String(secs).padStart(2, "0")}`;
|
|
779
|
-
}
|
|
780
|
-
function TickerChar({ value }) {
|
|
781
|
-
const [current, setCurrent] = useState4(value);
|
|
782
|
-
const [previous, setPrevious] = useState4(null);
|
|
783
|
-
const [animKey, setAnimKey] = useState4(0);
|
|
784
|
-
useEffect3(() => {
|
|
785
|
-
if (value === current) return;
|
|
786
|
-
setPrevious(current);
|
|
787
|
-
setCurrent(value);
|
|
788
|
-
setAnimKey((k) => k + 1);
|
|
789
|
-
const timeout = setTimeout(() => setPrevious(null), 360);
|
|
790
|
-
return () => clearTimeout(timeout);
|
|
791
|
-
}, [value, current]);
|
|
792
|
-
return /* @__PURE__ */ jsxs4("span", { className: "rs-ticker-slot", children: [
|
|
793
|
-
previous !== null && /* @__PURE__ */ jsx5("span", { className: "rs-ticker-out", children: previous }, `out-${animKey}`),
|
|
794
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-ticker-in", children: current }, `in-${animKey}`)
|
|
795
|
-
] });
|
|
796
|
-
}
|
|
797
|
-
function Ticker({ value }) {
|
|
798
|
-
return /* @__PURE__ */ jsx5("span", { className: "rs-ticker", "aria-label": value, children: value.split("").map((char, index) => (
|
|
799
|
-
// Position-stable key so each slot keeps its own animation state.
|
|
800
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
801
|
-
/* @__PURE__ */ jsx5(TickerChar, { value: char }, index)
|
|
802
|
-
)) });
|
|
803
|
-
}
|
|
804
|
-
function getPhaseStartTime(phaseId, phaseTimings) {
|
|
805
|
-
if (phaseId === "confirming") return phaseTimings.startedAt;
|
|
806
|
-
if (phaseId === "received") {
|
|
807
|
-
return phaseTimings.receivedAt ?? phaseTimings.startedAt;
|
|
808
|
-
}
|
|
809
|
-
return phaseTimings.bridgingAt ?? phaseTimings.receivedAt ?? phaseTimings.startedAt;
|
|
810
|
-
}
|
|
811
|
-
function getFailedPhaseId(phaseTimings) {
|
|
812
|
-
if (phaseTimings.bridgingAt !== void 0) return "bridging";
|
|
813
|
-
if (phaseTimings.receivedAt !== void 0) return "received";
|
|
814
|
-
return "confirming";
|
|
815
|
-
}
|
|
816
|
-
function getCurrentPhaseId(state, phaseTimings) {
|
|
817
|
-
if (state.type === "failed") {
|
|
818
|
-
return getFailedPhaseId(phaseTimings);
|
|
819
|
-
}
|
|
820
|
-
if (state.type === "complete") {
|
|
821
|
-
return void 0;
|
|
822
|
-
}
|
|
823
|
-
if (state.lastEvent?.type === "bridge-started" || state.lastEvent?.type === "bridge-complete")
|
|
824
|
-
return "bridging";
|
|
825
|
-
if (state.lastEvent?.type === "deposit-received") return "received";
|
|
826
|
-
return "confirming";
|
|
827
|
-
}
|
|
828
|
-
function getCompletionDestinationTxHash(event) {
|
|
829
|
-
const eventData = event?.data;
|
|
830
|
-
const swapTxHash = eventData?.swap?.transactionHash;
|
|
831
|
-
const destinationTxHash = eventData?.destination?.transactionHash;
|
|
832
|
-
return swapTxHash ?? destinationTxHash;
|
|
833
|
-
}
|
|
834
|
-
function getTerminalProcessingOutcome(event) {
|
|
835
|
-
if (event?.type === "post-bridge-swap-complete") {
|
|
836
|
-
return {
|
|
837
|
-
type: "complete",
|
|
838
|
-
destinationTxHash: getCompletionDestinationTxHash(event)
|
|
839
|
-
};
|
|
840
|
-
}
|
|
841
|
-
if (event?.type === "post-bridge-swap-failed") {
|
|
842
|
-
return {
|
|
843
|
-
type: "failed",
|
|
844
|
-
message: formatBridgeFailedMessage(event).message
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
if (event?.type === "bridge-complete") {
|
|
848
|
-
return {
|
|
849
|
-
type: "complete",
|
|
850
|
-
destinationTxHash: getCompletionDestinationTxHash(event)
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
if (event?.type === "bridge-failed") {
|
|
854
|
-
return {
|
|
855
|
-
type: "failed",
|
|
856
|
-
message: formatBridgeFailedMessage(event).message
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
|
-
if (event?.type === "error") {
|
|
860
|
-
return {
|
|
861
|
-
type: "failed",
|
|
862
|
-
message: event.data?.message ?? "Unknown error"
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
return null;
|
|
866
|
-
}
|
|
867
|
-
function getInitialProcessingState(event, txHash) {
|
|
868
|
-
if (!event || !isEventForTx(event, txHash)) return null;
|
|
869
|
-
const terminal = getTerminalProcessingOutcome(event);
|
|
870
|
-
if (terminal?.type === "complete") {
|
|
871
|
-
return { type: "complete", lastEvent: event };
|
|
872
|
-
}
|
|
873
|
-
if (terminal?.type === "failed") {
|
|
874
|
-
return { type: "failed", message: terminal.message, lastEvent: event };
|
|
875
|
-
}
|
|
876
|
-
if (isDepositEvent(event)) {
|
|
877
|
-
return { type: "processing", lastEvent: event };
|
|
878
|
-
}
|
|
879
|
-
return null;
|
|
880
|
-
}
|
|
881
|
-
function getSettledSourceTxHash(event, fallbackTxHash) {
|
|
882
|
-
return event?.data?.source?.transactionHash ?? fallbackTxHash;
|
|
883
|
-
}
|
|
884
|
-
function ProcessingStep({
|
|
885
|
-
smartAccount,
|
|
886
|
-
solanaDepositAddress,
|
|
887
|
-
txHash,
|
|
888
|
-
sourceChain,
|
|
889
|
-
sourceToken,
|
|
890
|
-
targetChain,
|
|
891
|
-
amount,
|
|
892
|
-
sourceSymbol: providedSourceSymbol,
|
|
893
|
-
sourceDecimals: providedSourceDecimals,
|
|
894
|
-
amountUsd,
|
|
895
|
-
service,
|
|
896
|
-
directTransfer,
|
|
897
|
-
sourceTxHashPending,
|
|
898
|
-
initialEvent,
|
|
899
|
-
flowLabel = "deposit",
|
|
900
|
-
debug,
|
|
901
|
-
targetToken,
|
|
902
|
-
uiConfig,
|
|
903
|
-
quotedFeeAmount,
|
|
904
|
-
quotedFeeSymbol,
|
|
905
|
-
quote,
|
|
906
|
-
balanceAfterUsd,
|
|
907
|
-
isSwappedOrder,
|
|
908
|
-
swappedContext,
|
|
909
|
-
onClose,
|
|
910
|
-
onNewDeposit,
|
|
911
|
-
onRetry,
|
|
912
|
-
onDepositComplete,
|
|
913
|
-
onDepositFailed,
|
|
914
|
-
onSourceTransactionObserved,
|
|
915
|
-
onError
|
|
916
|
-
}) {
|
|
917
|
-
const startTimeRef = useRef2(Date.now());
|
|
918
|
-
const pollIntervalRef = useRef2(INITIAL_POLL_INTERVAL);
|
|
919
|
-
const pollTimeoutRef = useRef2(null);
|
|
920
|
-
const escalatedDelayRef = useRef2(false);
|
|
921
|
-
const processingContextRef = useLatestRef({
|
|
922
|
-
amount,
|
|
923
|
-
sourceChain,
|
|
924
|
-
sourceToken,
|
|
925
|
-
sourceDecimals: providedSourceDecimals,
|
|
926
|
-
amountUsd,
|
|
927
|
-
targetChain,
|
|
928
|
-
targetToken
|
|
929
|
-
});
|
|
930
|
-
const onDepositCompleteRef = useLatestRef(onDepositComplete);
|
|
931
|
-
const onDepositFailedRef = useLatestRef(onDepositFailed);
|
|
932
|
-
const onErrorRef = useLatestRef(onError);
|
|
933
|
-
const explorerTxUrl = useExplorerTxUrl();
|
|
934
|
-
const initialTerminalEventRef = useRef2(null);
|
|
935
|
-
const [state, setState] = useState4(() => {
|
|
936
|
-
if (directTransfer) return { type: "complete" };
|
|
937
|
-
const initial = getInitialProcessingState(
|
|
938
|
-
initialEvent,
|
|
939
|
-
txHash
|
|
940
|
-
);
|
|
941
|
-
if (initial) {
|
|
942
|
-
if (initial.type !== "processing") {
|
|
943
|
-
initialTerminalEventRef.current = initial.lastEvent ?? null;
|
|
944
|
-
}
|
|
945
|
-
return initial;
|
|
946
|
-
}
|
|
947
|
-
return { type: "processing" };
|
|
948
|
-
});
|
|
949
|
-
const [elapsedSeconds, setElapsedSeconds] = useState4(0);
|
|
950
|
-
const [phaseTimings, setPhaseTimings] = useState4(() => {
|
|
951
|
-
const saved = loadPhaseTimings(txHash);
|
|
952
|
-
if (saved) {
|
|
953
|
-
startTimeRef.current = saved.startedAt;
|
|
954
|
-
return saved;
|
|
955
|
-
}
|
|
956
|
-
return { startedAt: startTimeRef.current };
|
|
957
|
-
});
|
|
958
|
-
const [hasEscalatedDelay, setHasEscalatedDelay] = useState4(false);
|
|
959
|
-
const updatePhaseTimings = useCallback2(
|
|
960
|
-
(updater) => {
|
|
961
|
-
setPhaseTimings((previous) => {
|
|
962
|
-
const next = updater(previous);
|
|
963
|
-
savePhaseTimings(txHash, next);
|
|
964
|
-
return next;
|
|
965
|
-
});
|
|
966
|
-
},
|
|
967
|
-
[txHash]
|
|
968
|
-
);
|
|
969
|
-
useEffect3(() => {
|
|
970
|
-
if (!directTransfer) return;
|
|
971
|
-
const completedAt = Date.now();
|
|
972
|
-
updatePhaseTimings(() => ({
|
|
973
|
-
startedAt: startTimeRef.current,
|
|
974
|
-
completedAt,
|
|
975
|
-
endedAt: completedAt
|
|
976
|
-
}));
|
|
977
|
-
debugLog(debug, "processing", "direct-transfer:complete", {
|
|
978
|
-
txHash,
|
|
979
|
-
flowLabel
|
|
980
|
-
});
|
|
981
|
-
const context = processingContextRef.current;
|
|
982
|
-
onDepositCompleteRef.current?.(txHash, void 0, {
|
|
983
|
-
amount: context.amount,
|
|
984
|
-
sourceChain: context.sourceChain,
|
|
985
|
-
sourceToken: context.sourceToken,
|
|
986
|
-
sourceDecimals: context.sourceDecimals,
|
|
987
|
-
amountUsd: context.amountUsd,
|
|
988
|
-
targetChain: context.targetChain,
|
|
989
|
-
targetToken: context.targetToken
|
|
990
|
-
});
|
|
991
|
-
}, [
|
|
992
|
-
debug,
|
|
993
|
-
directTransfer,
|
|
994
|
-
flowLabel,
|
|
995
|
-
onDepositCompleteRef,
|
|
996
|
-
processingContextRef,
|
|
997
|
-
txHash,
|
|
998
|
-
updatePhaseTimings
|
|
999
|
-
]);
|
|
1000
|
-
useEffect3(() => {
|
|
1001
|
-
const event = initialTerminalEventRef.current;
|
|
1002
|
-
if (!event) return;
|
|
1003
|
-
initialTerminalEventRef.current = null;
|
|
1004
|
-
const outcome = getTerminalProcessingOutcome(event);
|
|
1005
|
-
if (!outcome) return;
|
|
1006
|
-
if (outcome.type === "complete") {
|
|
1007
|
-
const context = processingContextRef.current;
|
|
1008
|
-
const sourceTxHash2 = getSettledSourceTxHash(event, txHash);
|
|
1009
|
-
debugLog(debug, "processing", "initial-event:complete", {
|
|
1010
|
-
txHash,
|
|
1011
|
-
sourceTxHash: sourceTxHash2,
|
|
1012
|
-
destinationTxHash: outcome.destinationTxHash,
|
|
1013
|
-
event: event.type
|
|
1014
|
-
});
|
|
1015
|
-
onDepositCompleteRef.current?.(
|
|
1016
|
-
sourceTxHash2,
|
|
1017
|
-
outcome.destinationTxHash,
|
|
1018
|
-
{
|
|
1019
|
-
amount: context.amount,
|
|
1020
|
-
sourceChain: context.sourceChain,
|
|
1021
|
-
sourceToken: context.sourceToken,
|
|
1022
|
-
sourceDecimals: context.sourceDecimals,
|
|
1023
|
-
amountUsd: context.amountUsd,
|
|
1024
|
-
targetChain: context.targetChain,
|
|
1025
|
-
targetToken: context.targetToken
|
|
1026
|
-
}
|
|
1027
|
-
);
|
|
1028
|
-
return;
|
|
1029
|
-
}
|
|
1030
|
-
debugLog(debug, "processing", "initial-event:failed", {
|
|
1031
|
-
txHash,
|
|
1032
|
-
message: outcome.message,
|
|
1033
|
-
event: event.type
|
|
1034
|
-
});
|
|
1035
|
-
onDepositFailedRef.current?.(txHash, outcome.message);
|
|
1036
|
-
}, [
|
|
1037
|
-
debug,
|
|
1038
|
-
onDepositCompleteRef,
|
|
1039
|
-
onDepositFailedRef,
|
|
1040
|
-
processingContextRef,
|
|
1041
|
-
txHash
|
|
1042
|
-
]);
|
|
1043
|
-
useEffect3(() => {
|
|
1044
|
-
if (directTransfer || state.type !== "processing") return;
|
|
1045
|
-
const updateElapsed = () => {
|
|
1046
|
-
setElapsedSeconds(
|
|
1047
|
-
Math.floor((Date.now() - startTimeRef.current) / 1e3)
|
|
1048
|
-
);
|
|
1049
|
-
};
|
|
1050
|
-
updateElapsed();
|
|
1051
|
-
const intervalId = setInterval(updateElapsed, 1e3);
|
|
1052
|
-
return () => clearInterval(intervalId);
|
|
1053
|
-
}, [directTransfer, state.type]);
|
|
1054
|
-
useEffect3(() => {
|
|
1055
|
-
if (state.type === "processing") return;
|
|
1056
|
-
const endedAt = state.type === "complete" ? phaseTimings.completedAt ?? Date.now() : Date.now();
|
|
1057
|
-
setElapsedSeconds(Math.floor((endedAt - startTimeRef.current) / 1e3));
|
|
1058
|
-
updatePhaseTimings(
|
|
1059
|
-
(previous) => previous.endedAt !== void 0 ? previous : { ...previous, endedAt }
|
|
1060
|
-
);
|
|
1061
|
-
}, [phaseTimings.completedAt, state.type, updatePhaseTimings]);
|
|
1062
|
-
useEffect3(() => {
|
|
1063
|
-
if (!state.lastEvent) return;
|
|
1064
|
-
updatePhaseTimings(
|
|
1065
|
-
(previous) => syncPhaseTimings(previous, state.lastEvent)
|
|
1066
|
-
);
|
|
1067
|
-
}, [state.lastEvent?.time, state.lastEvent?.type, updatePhaseTimings]);
|
|
1068
|
-
const [swappedFiatContext, setSwappedFiatContext] = useState4(null);
|
|
1069
|
-
useEffect3(() => {
|
|
1070
|
-
let cancelled = false;
|
|
1071
|
-
let timeoutId;
|
|
1072
|
-
const isFiatSwappedOrder = isSwappedOrder && swappedContext?.variant === "fiat";
|
|
1073
|
-
const expectedOrderUuid = swappedContext?.expectedOrderUuid ?? null;
|
|
1074
|
-
setSwappedFiatContext(null);
|
|
1075
|
-
if (isFiatSwappedOrder && !expectedOrderUuid) {
|
|
1076
|
-
return () => {
|
|
1077
|
-
cancelled = true;
|
|
1078
|
-
};
|
|
1079
|
-
}
|
|
1080
|
-
let attempts = 0;
|
|
1081
|
-
const matchesCurrentDeposit = (res) => {
|
|
1082
|
-
if (isFiatSwappedOrder) {
|
|
1083
|
-
return res.orderId === expectedOrderUuid;
|
|
1084
|
-
}
|
|
1085
|
-
return res.transactionId != null && res.transactionId.toLowerCase() === txHash.toLowerCase();
|
|
1086
|
-
};
|
|
1087
|
-
const scheduleRetry = () => {
|
|
1088
|
-
if (cancelled || !isFiatSwappedOrder || attempts >= SWAPPED_FIAT_STATUS_MAX_ATTEMPTS) {
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
timeoutId = setTimeout(
|
|
1092
|
-
fetchContext,
|
|
1093
|
-
SWAPPED_RECEIPT_STATUS_RETRY_INTERVAL_MS
|
|
1094
|
-
);
|
|
1095
|
-
};
|
|
1096
|
-
async function fetchContext() {
|
|
1097
|
-
attempts += 1;
|
|
1098
|
-
try {
|
|
1099
|
-
const res = await service.fetchSwappedOrderStatus(smartAccount);
|
|
1100
|
-
if (cancelled) return;
|
|
1101
|
-
if (!res || !matchesCurrentDeposit(res)) {
|
|
1102
|
-
scheduleRetry();
|
|
1103
|
-
return;
|
|
1104
|
-
}
|
|
1105
|
-
setSwappedFiatContext(toSwappedFiatContext(res));
|
|
1106
|
-
if (isFiatSwappedOrder && !hasFiatReceiptPricing(res)) {
|
|
1107
|
-
scheduleRetry();
|
|
1108
|
-
}
|
|
1109
|
-
} catch {
|
|
1110
|
-
scheduleRetry();
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
fetchContext();
|
|
1114
|
-
return () => {
|
|
1115
|
-
cancelled = true;
|
|
1116
|
-
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
1117
|
-
};
|
|
1118
|
-
}, [
|
|
1119
|
-
service,
|
|
1120
|
-
smartAccount,
|
|
1121
|
-
txHash,
|
|
1122
|
-
isSwappedOrder,
|
|
1123
|
-
swappedContext?.variant,
|
|
1124
|
-
swappedContext?.expectedOrderUuid
|
|
1125
|
-
]);
|
|
1126
|
-
useEffect3(() => {
|
|
1127
|
-
if (directTransfer) return;
|
|
1128
|
-
if (state.type !== "processing") {
|
|
1129
|
-
pollIntervalRef.current = INITIAL_POLL_INTERVAL;
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
let isMounted = true;
|
|
1133
|
-
async function pollStatus() {
|
|
1134
|
-
try {
|
|
1135
|
-
const account = sourceChain === "solana" && solanaDepositAddress ? solanaDepositAddress : smartAccount;
|
|
1136
|
-
debugLog(debug, "processing", "poll:request", {
|
|
1137
|
-
account,
|
|
1138
|
-
txHash,
|
|
1139
|
-
intervalMs: pollIntervalRef.current
|
|
1140
|
-
});
|
|
1141
|
-
const data = await service.fetchStatus(account, txHash);
|
|
1142
|
-
const lastEvent2 = data.lastEvent;
|
|
1143
|
-
const eventMatchesTx = isEventForTx(lastEvent2, txHash);
|
|
1144
|
-
const eventForCurrentTx = eventMatchesTx ? lastEvent2 : void 0;
|
|
1145
|
-
if (lastEvent2) {
|
|
1146
|
-
const eventData = lastEvent2.data;
|
|
1147
|
-
debugLog(debug, "processing", "poll:event", {
|
|
1148
|
-
type: lastEvent2.type,
|
|
1149
|
-
matchesTx: eventMatchesTx,
|
|
1150
|
-
intentId: eventData?.intentId
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
if (!isMounted) return;
|
|
1154
|
-
if (eventForCurrentTx?.type === "bridge-complete") {
|
|
1155
|
-
setState({ type: "complete", lastEvent: eventForCurrentTx });
|
|
1156
|
-
const sourceTxHash2 = getSettledSourceTxHash(
|
|
1157
|
-
eventForCurrentTx,
|
|
1158
|
-
txHash
|
|
1159
|
-
);
|
|
1160
|
-
const destinationTxHash2 = eventForCurrentTx.data?.destination?.transactionHash;
|
|
1161
|
-
debugLog(debug, "processing", "state:complete", {
|
|
1162
|
-
txHash,
|
|
1163
|
-
sourceTxHash: sourceTxHash2,
|
|
1164
|
-
destinationTxHash: destinationTxHash2,
|
|
1165
|
-
event: eventForCurrentTx.type
|
|
1166
|
-
});
|
|
1167
|
-
const context = processingContextRef.current;
|
|
1168
|
-
onDepositCompleteRef.current?.(sourceTxHash2, destinationTxHash2, {
|
|
1169
|
-
amount: context.amount,
|
|
1170
|
-
sourceChain: context.sourceChain,
|
|
1171
|
-
sourceToken: context.sourceToken,
|
|
1172
|
-
sourceDecimals: context.sourceDecimals,
|
|
1173
|
-
amountUsd: context.amountUsd,
|
|
1174
|
-
targetChain: context.targetChain,
|
|
1175
|
-
targetToken: context.targetToken
|
|
1176
|
-
});
|
|
1177
|
-
return;
|
|
1178
|
-
}
|
|
1179
|
-
if (eventForCurrentTx?.type === "bridge-failed") {
|
|
1180
|
-
const formatted = formatBridgeFailedMessage(eventForCurrentTx);
|
|
1181
|
-
setState({
|
|
1182
|
-
type: "failed",
|
|
1183
|
-
message: formatted.message,
|
|
1184
|
-
lastEvent: eventForCurrentTx
|
|
1185
|
-
});
|
|
1186
|
-
debugLog(debug, "processing", "state:failed", {
|
|
1187
|
-
txHash,
|
|
1188
|
-
message: formatted.message,
|
|
1189
|
-
code: formatted.code
|
|
1190
|
-
});
|
|
1191
|
-
onDepositFailedRef.current?.(txHash, formatted.message);
|
|
1192
|
-
return;
|
|
1193
|
-
}
|
|
1194
|
-
if (eventForCurrentTx?.type === "error") {
|
|
1195
|
-
const errorMessage = eventForCurrentTx.data?.message ?? "Unknown error";
|
|
1196
|
-
setState({
|
|
1197
|
-
type: "failed",
|
|
1198
|
-
message: errorMessage,
|
|
1199
|
-
lastEvent: eventForCurrentTx
|
|
1200
|
-
});
|
|
1201
|
-
debugLog(debug, "processing", "state:error-event", {
|
|
1202
|
-
txHash,
|
|
1203
|
-
message: errorMessage
|
|
1204
|
-
});
|
|
1205
|
-
onDepositFailedRef.current?.(txHash, errorMessage);
|
|
1206
|
-
return;
|
|
1207
|
-
}
|
|
1208
|
-
setState((previous) => ({
|
|
1209
|
-
type: "processing",
|
|
1210
|
-
lastEvent: eventForCurrentTx ?? previous.lastEvent
|
|
1211
|
-
}));
|
|
1212
|
-
scheduleNextPoll();
|
|
1213
|
-
} catch (error) {
|
|
1214
|
-
debugError(debug, "processing", "poll:failure", error, {
|
|
1215
|
-
smartAccount,
|
|
1216
|
-
txHash,
|
|
1217
|
-
intervalMs: pollIntervalRef.current
|
|
1218
|
-
});
|
|
1219
|
-
scheduleNextPoll();
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
function scheduleNextPoll() {
|
|
1223
|
-
if (!isMounted) return;
|
|
1224
|
-
pollTimeoutRef.current = setTimeout(() => {
|
|
1225
|
-
pollIntervalRef.current = Math.min(
|
|
1226
|
-
pollIntervalRef.current * BACKOFF_MULTIPLIER,
|
|
1227
|
-
MAX_POLL_INTERVAL
|
|
1228
|
-
);
|
|
1229
|
-
debugLog(debug, "processing", "poll:scheduled", {
|
|
1230
|
-
nextIntervalMs: pollIntervalRef.current
|
|
1231
|
-
});
|
|
1232
|
-
pollStatus();
|
|
1233
|
-
}, pollIntervalRef.current);
|
|
1234
|
-
}
|
|
1235
|
-
pollStatus();
|
|
1236
|
-
return () => {
|
|
1237
|
-
isMounted = false;
|
|
1238
|
-
if (pollTimeoutRef.current) {
|
|
1239
|
-
clearTimeout(pollTimeoutRef.current);
|
|
1240
|
-
}
|
|
1241
|
-
};
|
|
1242
|
-
}, [
|
|
1243
|
-
debug,
|
|
1244
|
-
directTransfer,
|
|
1245
|
-
onDepositCompleteRef,
|
|
1246
|
-
onDepositFailedRef,
|
|
1247
|
-
processingContextRef,
|
|
1248
|
-
service,
|
|
1249
|
-
smartAccount,
|
|
1250
|
-
solanaDepositAddress,
|
|
1251
|
-
sourceChain,
|
|
1252
|
-
state.type,
|
|
1253
|
-
txHash
|
|
1254
|
-
]);
|
|
1255
|
-
useEffect3(() => {
|
|
1256
|
-
if (directTransfer || state.type !== "processing") return;
|
|
1257
|
-
const timeoutId = setTimeout(() => {
|
|
1258
|
-
if (escalatedDelayRef.current) return;
|
|
1259
|
-
escalatedDelayRef.current = true;
|
|
1260
|
-
setHasEscalatedDelay(true);
|
|
1261
|
-
const message = "Transfer is taking longer than expected. Your funds are safe and processing will continue automatically.";
|
|
1262
|
-
debugLog(debug, "processing", "state:delay-escalated", {
|
|
1263
|
-
txHash,
|
|
1264
|
-
timeoutMs: ESCALATED_DELAY_MS
|
|
1265
|
-
});
|
|
1266
|
-
onErrorRef.current?.(message, "PROCESS_TIMEOUT");
|
|
1267
|
-
}, ESCALATED_DELAY_MS);
|
|
1268
|
-
return () => clearTimeout(timeoutId);
|
|
1269
|
-
}, [debug, directTransfer, onErrorRef, state.type, txHash]);
|
|
1270
|
-
const isComplete = state.type === "complete";
|
|
1271
|
-
const isFailed = state.type === "failed";
|
|
1272
|
-
const isProcessing = state.type === "processing";
|
|
1273
|
-
const lastEvent = state.lastEvent;
|
|
1274
|
-
const failureMessage = state.type === "failed" ? state.message : void 0;
|
|
1275
|
-
const timelineNowMs = phaseTimings.endedAt ?? Date.now();
|
|
1276
|
-
const flowNoun = flowLabel === "withdraw" ? "withdrawal" : "deposit";
|
|
1277
|
-
const flowCapitalized = flowLabel === "withdraw" ? "Withdrawal" : "Deposit";
|
|
1278
|
-
const destinationTxHash = lastEvent?.data?.destination?.transactionHash || null;
|
|
1279
|
-
const sourceTxHash = getSettledSourceTxHash(lastEvent, txHash);
|
|
1280
|
-
const sourceDetails = getEventSourceDetails(lastEvent);
|
|
1281
|
-
const displaySourceChain = sourceDetails.chainId ?? sourceChain;
|
|
1282
|
-
const displaySourceToken = sourceDetails.token ?? sourceToken;
|
|
1283
|
-
const displayAmount = sourceDetails.amount ?? amount;
|
|
1284
|
-
const targetChainId = targetChainToChainId(targetChain);
|
|
1285
|
-
const settledSourceTxHash = lastEvent?.data?.source?.transactionHash;
|
|
1286
|
-
const sourceExplorerHash = settledSourceTxHash ?? (sourceTxHashPending ? null : sourceTxHash);
|
|
1287
|
-
useEffect3(() => {
|
|
1288
|
-
if (sourceTxHashPending && settledSourceTxHash) {
|
|
1289
|
-
onSourceTransactionObserved?.(settledSourceTxHash);
|
|
1290
|
-
}
|
|
1291
|
-
}, [onSourceTransactionObserved, settledSourceTxHash, sourceTxHashPending]);
|
|
1292
|
-
const sourceExplorerUrl = sourceExplorerHash ? explorerTxUrl(displaySourceChain, sourceExplorerHash) : null;
|
|
1293
|
-
const destExplorerUrl = destinationTxHash ? explorerTxUrl(targetChainId, destinationTxHash) : null;
|
|
1294
|
-
const sourceDisplay = (() => {
|
|
1295
|
-
const resolved = resolveTokenDisplay(displaySourceToken, displaySourceChain, {
|
|
1296
|
-
symbol: providedSourceSymbol ?? (displaySourceChain === "solana" ? "SOL" : "Token"),
|
|
1297
|
-
decimals: providedSourceDecimals
|
|
1298
|
-
});
|
|
1299
|
-
return {
|
|
1300
|
-
symbol: resolved.symbol,
|
|
1301
|
-
decimals: resolved.decimals ?? (displaySourceChain === "solana" ? 9 : 18)
|
|
1302
|
-
};
|
|
1303
|
-
})();
|
|
1304
|
-
const sourceSymbol = sourceDisplay.symbol;
|
|
1305
|
-
const formattedSentAmount = formatRawTokenAmount(displayAmount, sourceDisplay) ?? // Not raw base units (e.g. a decimal string) — render the number as-is.
|
|
1306
|
-
formatTokenAmount(Number(displayAmount), sourceDisplay.symbol) ?? displayAmount;
|
|
1307
|
-
const eventDestination = getEventDestinationDetails(lastEvent);
|
|
1308
|
-
const targetDisplay = resolveTokenDisplay(
|
|
1309
|
-
eventDestination.token ?? targetToken,
|
|
1310
|
-
eventDestination.chainId ?? targetChainId,
|
|
1311
|
-
// Dapp deposits default to USDC targets; mirror the source symbol last so
|
|
1312
|
-
// unresolvable same-token routes still label sensibly.
|
|
1313
|
-
{ symbol: providedSourceSymbol ?? "USDC" }
|
|
1314
|
-
);
|
|
1315
|
-
const targetSymbol = targetDisplay.symbol;
|
|
1316
|
-
const formattedDestinationAmount = eventDestination.amount !== void 0 ? formatRawTokenAmount(eventDestination.amount, targetDisplay) : void 0;
|
|
1317
|
-
const amountUsdNumber = amountUsd !== void 0 && Number(amountUsd) > 0 ? Number(amountUsd) : void 0;
|
|
1318
|
-
const prices = useTokenPrices(service, [
|
|
1319
|
-
{
|
|
1320
|
-
chainId: displaySourceChain,
|
|
1321
|
-
address: displaySourceToken,
|
|
1322
|
-
symbol: sourceDisplay.symbol
|
|
1323
|
-
},
|
|
1324
|
-
{
|
|
1325
|
-
chainId: eventDestination.chainId ?? targetChainId,
|
|
1326
|
-
address: eventDestination.token ?? targetToken,
|
|
1327
|
-
symbol: targetDisplay.symbol
|
|
1328
|
-
}
|
|
1329
|
-
]);
|
|
1330
|
-
const estimatedReceiveAmount = (() => {
|
|
1331
|
-
const estimate = estimateReceiveAmount({
|
|
1332
|
-
sourceAmount: tokenAmountToNumber(displayAmount, sourceDisplay.decimals),
|
|
1333
|
-
sourceSymbol: sourceDisplay.symbol,
|
|
1334
|
-
targetSymbol: targetDisplay.symbol,
|
|
1335
|
-
sourceAmountUsd: amountUsdNumber,
|
|
1336
|
-
sourceTrusted: isRecognizedToken(displaySourceToken, displaySourceChain),
|
|
1337
|
-
prices
|
|
1338
|
-
});
|
|
1339
|
-
return estimate !== void 0 ? formatTokenAmount(estimate, targetDisplay.symbol) : void 0;
|
|
1340
|
-
})();
|
|
1341
|
-
const quotedReceive = quote ? formatQuotedReceive(quote.output, targetSymbol) : void 0;
|
|
1342
|
-
const receiveDisplay = formattedDestinationAmount ? (
|
|
1343
|
-
// The delivered amount, once the bridge reports it — actual, not an
|
|
1344
|
-
// estimate, so it wins over the quote and carries no "~".
|
|
1345
|
-
`${formattedDestinationAmount} ${targetSymbol}`
|
|
1346
|
-
) : quotedReceive ?? (estimatedReceiveAmount !== void 0 ? `~${estimatedReceiveAmount} ${targetSymbol}` : amountUsdNumber !== void 0 ? `~$${amountUsdNumber.toFixed(2)}` : (
|
|
1347
|
-
// Cross-token with no price and no USD context (rare QR case):
|
|
1348
|
-
// an honest dash beats a wrong number.
|
|
1349
|
-
"\u2014"
|
|
1350
|
-
));
|
|
1351
|
-
const formattedBridgingCost = (() => {
|
|
1352
|
-
if (sourceSymbol.toUpperCase() !== targetSymbol.toUpperCase()) {
|
|
1353
|
-
return void 0;
|
|
1354
|
-
}
|
|
1355
|
-
const sentValue = tokenAmountToNumber(displayAmount, sourceDisplay.decimals);
|
|
1356
|
-
const receivedValue = eventDestination.amount !== void 0 ? tokenAmountToNumber(eventDestination.amount, targetDisplay.decimals) : void 0;
|
|
1357
|
-
if (sentValue === void 0 || receivedValue === void 0 || sentValue <= receivedValue) {
|
|
1358
|
-
return void 0;
|
|
1359
|
-
}
|
|
1360
|
-
const formatted = formatTokenAmount(sentValue - receivedValue, sourceSymbol);
|
|
1361
|
-
if (formatted === void 0 || Number(formatted.replace(/,/g, "")) === 0) {
|
|
1362
|
-
return void 0;
|
|
1363
|
-
}
|
|
1364
|
-
return formatted;
|
|
1365
|
-
})();
|
|
1366
|
-
const currentPhaseId = getCurrentPhaseId(state, phaseTimings);
|
|
1367
|
-
const activePhaseStartedAt = currentPhaseId ? getPhaseStartTime(currentPhaseId, phaseTimings) : void 0;
|
|
1368
|
-
const activePhaseElapsedMs = isProcessing && activePhaseStartedAt !== void 0 ? timelineNowMs - activePhaseStartedAt : 0;
|
|
1369
|
-
const delayPhaseId = isProcessing && currentPhaseId && activePhaseElapsedMs >= SOFT_DELAY_MS[currentPhaseId] ? currentPhaseId : void 0;
|
|
1370
|
-
void delayPhaseId;
|
|
1371
|
-
void hasEscalatedDelay;
|
|
1372
|
-
const sourceChainIcon = getChainIcon(displaySourceChain);
|
|
1373
|
-
const targetChainIcon = getChainIcon(targetChainId);
|
|
1374
|
-
const sourceChainName = getChainName(displaySourceChain);
|
|
1375
|
-
const targetChainName = getChainName(targetChainId);
|
|
1376
|
-
const timerText = formatTimer(elapsedSeconds);
|
|
1377
|
-
const feeSponsored = uiConfig?.feeSponsored ?? false;
|
|
1378
|
-
const feeTooltip = uiConfig?.feeTooltip ?? (feeSponsored ? "Network fees are sponsored for this deposit." : "Network fees apply.");
|
|
1379
|
-
const stateTitle = isComplete ? `${flowCapitalized} successful` : isFailed ? `${flowCapitalized} failed` : "Processing...";
|
|
1380
|
-
const handleRetry = onRetry ?? onNewDeposit;
|
|
1381
|
-
const headerContent = isComplete ? /* @__PURE__ */ jsxs4("div", { className: "rs-body-header", children: [
|
|
1382
|
-
/* @__PURE__ */ jsx5(SuccessBadge, {}),
|
|
1383
|
-
/* @__PURE__ */ jsx5("div", { className: "rs-body-header-text", children: /* @__PURE__ */ jsx5("h2", { className: "rs-body-header-title", children: stateTitle }) })
|
|
1384
|
-
] }) : isFailed ? /* @__PURE__ */ jsxs4("div", { className: "rs-body-header", children: [
|
|
1385
|
-
/* @__PURE__ */ jsx5(FailedBadge, {}),
|
|
1386
|
-
/* @__PURE__ */ jsx5("div", { className: "rs-body-header-text", children: /* @__PURE__ */ jsx5("h2", { className: "rs-body-header-title", children: stateTitle }) })
|
|
1387
|
-
] }) : /* @__PURE__ */ jsx5(BodyHeader, { icon: /* @__PURE__ */ jsx5(WalletIcon, {}), title: stateTitle });
|
|
1388
|
-
if (isComplete && isSwappedOrder) {
|
|
1389
|
-
const effectivePaymentMethod = swappedContext?.method ?? swappedFiatContext?.paymentMethod ?? null;
|
|
1390
|
-
const onrampMethod = effectivePaymentMethod ? formatPaymentMethod(effectivePaymentMethod) : null;
|
|
1391
|
-
const onrampMethodIcon = swappedContext?.variant === "connect" && effectivePaymentMethod ? getExchangeLogoSrc(
|
|
1392
|
-
onrampMethod ?? effectivePaymentMethod,
|
|
1393
|
-
effectivePaymentMethod
|
|
1394
|
-
) : null;
|
|
1395
|
-
const connectPaidAmount = swappedContext?.variant === "connect" ? `${formattedSentAmount} ${sourceSymbol}` : null;
|
|
1396
|
-
const amountPaid = connectPaidAmount ?? (swappedFiatContext?.paidAmountUsd != null ? `$${swappedFiatContext.paidAmountUsd.toFixed(2)}` : null);
|
|
1397
|
-
const depositedAmount = receiveDisplay;
|
|
1398
|
-
const onrampFeeUsd = swappedFiatContext?.onrampFeeUsd ?? null;
|
|
1399
|
-
const sponsoredFeeTooltip = "This fee is sponsored for this deposit.";
|
|
1400
|
-
const feesTooltip = feeSponsored ? "On-ramp fees are charged by the payment provider. Market and network fees are sponsored for this deposit." : "Fees include on-ramp, market, and network costs for this deposit.";
|
|
1401
|
-
const { rows: quoteFeeRows, chargeableUsd } = buildQuoteFeeRows(
|
|
1402
|
-
quote?.fees.breakdown,
|
|
1403
|
-
sponsoredFeeTooltip
|
|
1404
|
-
);
|
|
1405
|
-
const feeRows = [];
|
|
1406
|
-
if (onrampFeeUsd != null) {
|
|
1407
|
-
feeRows.push({
|
|
1408
|
-
label: "On-ramp fee",
|
|
1409
|
-
value: formatFeeUsd(onrampFeeUsd)
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
const hasFallbackFee = quoteFeeRows.length === 0 && quotedFeeAmount !== void 0 && Number.isFinite(Number(quotedFeeAmount));
|
|
1413
|
-
if (quoteFeeRows.length > 0) {
|
|
1414
|
-
feeRows.push(...quoteFeeRows);
|
|
1415
|
-
} else if (hasFallbackFee) {
|
|
1416
|
-
feeRows.push({
|
|
1417
|
-
label: "Network fee",
|
|
1418
|
-
value: formatFeeUsd(Number(quotedFeeAmount)),
|
|
1419
|
-
strike: feeSponsored,
|
|
1420
|
-
tooltip: feeSponsored ? sponsoredFeeTooltip : void 0
|
|
1421
|
-
});
|
|
1422
|
-
}
|
|
1423
|
-
const fallbackChargeableUsd = hasFallbackFee && !feeSponsored ? Number(quotedFeeAmount) : 0;
|
|
1424
|
-
const feesTotal = feeRows.length > 0 ? formatFeeUsd(
|
|
1425
|
-
(onrampFeeUsd ?? 0) + chargeableUsd + fallbackChargeableUsd
|
|
1426
|
-
) : null;
|
|
1427
|
-
return /* @__PURE__ */ jsx5(
|
|
1428
|
-
SwappedReceipt,
|
|
1429
|
-
{
|
|
1430
|
-
onrampMethod,
|
|
1431
|
-
onrampMethodIcon,
|
|
1432
|
-
amountPaid,
|
|
1433
|
-
depositedAmount,
|
|
1434
|
-
depositedSymbol: targetSymbol,
|
|
1435
|
-
feesTotal,
|
|
1436
|
-
feeRows,
|
|
1437
|
-
feesTooltip,
|
|
1438
|
-
newLabel: `New ${flowNoun}`,
|
|
1439
|
-
onNewDeposit,
|
|
1440
|
-
onClose: onClose ? () => onClose("success_done") : void 0
|
|
1441
|
-
}
|
|
1442
|
-
);
|
|
1443
|
-
}
|
|
1444
|
-
return /* @__PURE__ */ jsxs4("div", { className: "rs-screen", children: [
|
|
1445
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
|
|
1446
|
-
headerContent,
|
|
1447
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-review-details", children: [
|
|
1448
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1449
|
-
/* @__PURE__ */ jsx5("span", { children: "Source chain" }),
|
|
1450
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1451
|
-
/* @__PURE__ */ jsx5("span", { children: sourceChainName }),
|
|
1452
|
-
sourceChainIcon && /* @__PURE__ */ jsx5("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx5(CdnIcon, { src: sourceChainIcon }) }),
|
|
1453
|
-
sourceExplorerUrl && /* @__PURE__ */ jsx5(
|
|
1454
|
-
"a",
|
|
1455
|
-
{
|
|
1456
|
-
href: sourceExplorerUrl,
|
|
1457
|
-
target: "_blank",
|
|
1458
|
-
rel: "noopener noreferrer",
|
|
1459
|
-
className: "rs-review-detail-link",
|
|
1460
|
-
"aria-label": "View source transaction",
|
|
1461
|
-
children: /* @__PURE__ */ jsx5(ExternalLinkIcon, {})
|
|
1462
|
-
}
|
|
1463
|
-
)
|
|
1464
|
-
] })
|
|
1465
|
-
] }),
|
|
1466
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1467
|
-
/* @__PURE__ */ jsx5("span", { children: "Destination chain" }),
|
|
1468
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1469
|
-
/* @__PURE__ */ jsx5("span", { children: targetChainName }),
|
|
1470
|
-
targetChainIcon && /* @__PURE__ */ jsx5("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx5(CdnIcon, { src: targetChainIcon }) }),
|
|
1471
|
-
destExplorerUrl && /* @__PURE__ */ jsx5(
|
|
1472
|
-
"a",
|
|
1473
|
-
{
|
|
1474
|
-
href: destExplorerUrl,
|
|
1475
|
-
target: "_blank",
|
|
1476
|
-
rel: "noopener noreferrer",
|
|
1477
|
-
className: "rs-review-detail-link",
|
|
1478
|
-
"aria-label": "View destination transaction",
|
|
1479
|
-
children: /* @__PURE__ */ jsx5(ExternalLinkIcon, {})
|
|
1480
|
-
}
|
|
1481
|
-
)
|
|
1482
|
-
] })
|
|
1483
|
-
] }),
|
|
1484
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1485
|
-
/* @__PURE__ */ jsx5("span", { children: isProcessing ? "Time elapsed" : "Total time" }),
|
|
1486
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-value", children: /* @__PURE__ */ jsx5(Ticker, { value: timerText }) })
|
|
1487
|
-
] }),
|
|
1488
|
-
isSwappedOrder ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1489
|
-
swappedFiatContext?.paidAmountUsd != null && /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1490
|
-
/* @__PURE__ */ jsx5("span", { children: "You pay" }),
|
|
1491
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1492
|
-
"$",
|
|
1493
|
-
swappedFiatContext.paidAmountUsd.toFixed(2),
|
|
1494
|
-
swappedFiatContext.paymentMethod && /* @__PURE__ */ jsxs4("span", { style: { color: "#71717b", marginLeft: 6 }, children: [
|
|
1495
|
-
"via",
|
|
1496
|
-
" ",
|
|
1497
|
-
formatPaymentMethod(swappedFiatContext.paymentMethod)
|
|
1498
|
-
] })
|
|
1499
|
-
] })
|
|
1500
|
-
] }),
|
|
1501
|
-
swappedFiatContext?.onrampFeeUsd != null && /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1502
|
-
/* @__PURE__ */ jsx5("span", { children: "On-ramp fee" }),
|
|
1503
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1504
|
-
"$",
|
|
1505
|
-
swappedFiatContext.onrampFeeUsd.toFixed(2)
|
|
1506
|
-
] })
|
|
1507
|
-
] }),
|
|
1508
|
-
formattedBridgingCost && /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1509
|
-
/* @__PURE__ */ jsx5("span", { children: "Bridging cost" }),
|
|
1510
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1511
|
-
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1512
|
-
formattedBridgingCost,
|
|
1513
|
-
" ",
|
|
1514
|
-
sourceSymbol
|
|
1515
|
-
] }),
|
|
1516
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx5(TokenIcon, { symbol: sourceSymbol }) })
|
|
1517
|
-
] })
|
|
1518
|
-
] })
|
|
1519
|
-
] }) : /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1520
|
-
/* @__PURE__ */ jsx5("span", { children: isProcessing ? "You send" : "You sent" }),
|
|
1521
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1522
|
-
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1523
|
-
formattedSentAmount,
|
|
1524
|
-
" ",
|
|
1525
|
-
sourceSymbol
|
|
1526
|
-
] }),
|
|
1527
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx5(TokenIcon, { symbol: sourceSymbol }) })
|
|
1528
|
-
] })
|
|
1529
|
-
] }),
|
|
1530
|
-
/* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1531
|
-
/* @__PURE__ */ jsx5("span", { children: isProcessing ? "Receive" : "Received" }),
|
|
1532
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1533
|
-
/* @__PURE__ */ jsx5("span", { children: receiveDisplay }),
|
|
1534
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx5(TokenIcon, { symbol: targetSymbol }) })
|
|
1535
|
-
] })
|
|
1536
|
-
] }),
|
|
1537
|
-
isFailed && balanceAfterUsd !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1538
|
-
/* @__PURE__ */ jsx5("span", { children: "Balance" }),
|
|
1539
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1540
|
-
"$",
|
|
1541
|
-
balanceAfterUsd.toFixed(2)
|
|
1542
|
-
] })
|
|
1543
|
-
] }),
|
|
1544
|
-
isSwappedOrder ? quotedFeeAmount !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1545
|
-
/* @__PURE__ */ jsx5("span", { children: "Fees" }),
|
|
1546
|
-
/* @__PURE__ */ jsxs4("span", { className: "rs-review-detail-value", children: [
|
|
1547
|
-
/* @__PURE__ */ jsxs4(
|
|
1548
|
-
"span",
|
|
1549
|
-
{
|
|
1550
|
-
style: feeSponsored ? { textDecoration: "line-through" } : void 0,
|
|
1551
|
-
children: [
|
|
1552
|
-
quotedFeeAmount,
|
|
1553
|
-
" ",
|
|
1554
|
-
quotedFeeSymbol ?? sourceSymbol
|
|
1555
|
-
]
|
|
1556
|
-
}
|
|
1557
|
-
),
|
|
1558
|
-
/* @__PURE__ */ jsx5(Tooltip, { content: feeTooltip, children: /* @__PURE__ */ jsx5(
|
|
1559
|
-
"span",
|
|
1560
|
-
{
|
|
1561
|
-
className: "rs-review-detail-info",
|
|
1562
|
-
"aria-label": "Fee info",
|
|
1563
|
-
children: /* @__PURE__ */ jsx5(InfoIcon, {})
|
|
1564
|
-
}
|
|
1565
|
-
) })
|
|
1566
|
-
] })
|
|
1567
|
-
] }) : (() => {
|
|
1568
|
-
const { display, struck } = quoteFeeRow(quote?.fees);
|
|
1569
|
-
if (display !== null) {
|
|
1570
|
-
return /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1571
|
-
/* @__PURE__ */ jsx5("span", { children: "Fees" }),
|
|
1572
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-value", children: /* @__PURE__ */ jsx5(
|
|
1573
|
-
"span",
|
|
1574
|
-
{
|
|
1575
|
-
style: struck ? { textDecoration: "line-through" } : void 0,
|
|
1576
|
-
children: display
|
|
1577
|
-
}
|
|
1578
|
-
) })
|
|
1579
|
-
] });
|
|
1580
|
-
}
|
|
1581
|
-
const feeValue = quotedFeeAmount ?? formattedBridgingCost;
|
|
1582
|
-
if (feeValue === void 0) return null;
|
|
1583
|
-
return /* @__PURE__ */ jsxs4("div", { className: "rs-review-detail-row", children: [
|
|
1584
|
-
/* @__PURE__ */ jsx5("span", { children: "Fees" }),
|
|
1585
|
-
/* @__PURE__ */ jsx5("span", { className: "rs-review-detail-value", children: /* @__PURE__ */ jsxs4(
|
|
1586
|
-
"span",
|
|
1587
|
-
{
|
|
1588
|
-
style: feeSponsored ? { textDecoration: "line-through" } : void 0,
|
|
1589
|
-
children: [
|
|
1590
|
-
feeValue,
|
|
1591
|
-
" ",
|
|
1592
|
-
quotedFeeSymbol ?? sourceSymbol
|
|
1593
|
-
]
|
|
1594
|
-
}
|
|
1595
|
-
) })
|
|
1596
|
-
] });
|
|
1597
|
-
})()
|
|
1598
|
-
] }),
|
|
1599
|
-
isFailed && failureMessage && /* @__PURE__ */ jsx5(Callout, { variant: "error", children: failureMessage }),
|
|
1600
|
-
isProcessing && /* @__PURE__ */ jsx5(
|
|
1601
|
-
Button,
|
|
1602
|
-
{
|
|
1603
|
-
fullWidth: true,
|
|
1604
|
-
disabled: true,
|
|
1605
|
-
loading: true,
|
|
1606
|
-
loadingText: "Submitting transaction\u2026",
|
|
1607
|
-
children: "Submitting transaction\u2026"
|
|
1608
|
-
}
|
|
1609
|
-
),
|
|
1610
|
-
isComplete && /* @__PURE__ */ jsxs4("div", { className: "rs-screen-button-row", children: [
|
|
1611
|
-
onNewDeposit && /* @__PURE__ */ jsxs4(Button, { variant: "outline", onClick: onNewDeposit, fullWidth: true, children: [
|
|
1612
|
-
"New ",
|
|
1613
|
-
flowNoun
|
|
1614
|
-
] }),
|
|
1615
|
-
onClose && /* @__PURE__ */ jsx5(Button, { onClick: () => onClose("success_done"), fullWidth: true, children: "Done" })
|
|
1616
|
-
] }),
|
|
1617
|
-
isFailed && /* @__PURE__ */ jsxs4("div", { className: "rs-screen-button-row", children: [
|
|
1618
|
-
onClose && /* @__PURE__ */ jsx5(
|
|
1619
|
-
Button,
|
|
1620
|
-
{
|
|
1621
|
-
variant: "outline",
|
|
1622
|
-
onClick: () => onClose("failure_cancel"),
|
|
1623
|
-
fullWidth: true,
|
|
1624
|
-
children: "Cancel"
|
|
1625
|
-
}
|
|
1626
|
-
),
|
|
1627
|
-
handleRetry && /* @__PURE__ */ jsx5(Button, { onClick: handleRetry, fullWidth: true, children: "Try again" })
|
|
1628
|
-
] })
|
|
1629
|
-
] }),
|
|
1630
|
-
/* @__PURE__ */ jsx5(PoweredBy, {})
|
|
1631
|
-
] });
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
// src/core/account-setup.ts
|
|
1635
|
-
import { concat, isAddress, keccak256, toHex } from "viem";
|
|
1636
|
-
var SetupError = class extends Error {
|
|
1637
|
-
constructor(message, category) {
|
|
1638
|
-
super(message);
|
|
1639
|
-
this.category = category;
|
|
1640
|
-
this.name = "SetupError";
|
|
1641
|
-
}
|
|
1642
|
-
};
|
|
1643
|
-
function stableStringify(value) {
|
|
1644
|
-
if (value === null || typeof value !== "object") {
|
|
1645
|
-
return JSON.stringify(value);
|
|
1646
|
-
}
|
|
1647
|
-
if (Array.isArray(value)) {
|
|
1648
|
-
return `[${value.map(stableStringify).join(",")}]`;
|
|
1649
|
-
}
|
|
1650
|
-
const obj = value;
|
|
1651
|
-
const keys = Object.keys(obj).sort();
|
|
1652
|
-
const entries = keys.filter((k) => obj[k] !== void 0).map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
|
|
1653
|
-
return `{${entries.join(",")}}`;
|
|
1654
|
-
}
|
|
1655
|
-
function normalizeKeyToken(value) {
|
|
1656
|
-
if (value === void 0) return void 0;
|
|
1657
|
-
return value.startsWith("0x") ? value.toLowerCase() : value;
|
|
1658
|
-
}
|
|
1659
|
-
var SOLANA_ADDRESS_PATTERN = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
1660
|
-
function recipientMatchesTarget(recipient, targetChain) {
|
|
1661
|
-
return targetChainToCaip2(targetChain).startsWith("solana:") ? SOLANA_ADDRESS_PATTERN.test(recipient) : isAddress(recipient);
|
|
1662
|
-
}
|
|
1663
|
-
function deriveAccountSalt(input) {
|
|
1664
|
-
return keccak256(
|
|
1665
|
-
concat([
|
|
1666
|
-
keccak256(toHex(normalizeKeyToken(input.recipient) ?? "")),
|
|
1667
|
-
keccak256(toHex(targetChainToCaip2(input.targetChain))),
|
|
1668
|
-
keccak256(toHex(normalizeKeyToken(input.targetToken) ?? ""))
|
|
1669
|
-
])
|
|
1670
|
-
);
|
|
1671
|
-
}
|
|
1672
|
-
function computeRequestKey(input) {
|
|
1673
|
-
return stableStringify({
|
|
1674
|
-
targetChain: input.targetChain,
|
|
1675
|
-
targetToken: normalizeKeyToken(input.targetToken),
|
|
1676
|
-
recipient: normalizeKeyToken(input.recipient),
|
|
1677
|
-
outputTokenRules: input.outputTokenRules ?? null,
|
|
1678
|
-
rejectUnmapped: input.rejectUnmapped ?? null,
|
|
1679
|
-
forceRegister: input.forceRegister ?? false
|
|
1680
|
-
});
|
|
1681
|
-
}
|
|
1682
|
-
function computeCacheKey(input) {
|
|
1683
|
-
return stableStringify({
|
|
1684
|
-
targetChain: input.targetChain,
|
|
1685
|
-
targetToken: normalizeKeyToken(input.targetToken),
|
|
1686
|
-
recipient: normalizeKeyToken(input.recipient),
|
|
1687
|
-
outputTokenRules: input.outputTokenRules ?? null,
|
|
1688
|
-
rejectUnmapped: input.rejectUnmapped ?? null
|
|
1689
|
-
});
|
|
1690
|
-
}
|
|
1691
|
-
function computeIsCacheable(input) {
|
|
1692
|
-
return !input.forceRegister;
|
|
1693
|
-
}
|
|
1694
|
-
var SETUP_REQUEST_DEDUPE_TTL_MS = 3e4;
|
|
1695
|
-
var setupRequestDedupe = /* @__PURE__ */ new Map();
|
|
1696
|
-
function readDedupedAccountSetupResult(requestKey) {
|
|
1697
|
-
const now = Date.now();
|
|
1698
|
-
const existing = setupRequestDedupe.get(requestKey);
|
|
1699
|
-
if (existing?.settled && existing.expiresAt > now && existing.result) {
|
|
1700
|
-
return existing.result;
|
|
1701
|
-
}
|
|
1702
|
-
return null;
|
|
1703
|
-
}
|
|
1704
|
-
async function runAccountSetup(input, deps) {
|
|
1705
|
-
const { service, debug } = deps;
|
|
1706
|
-
const cacheKey = computeCacheKey(input);
|
|
1707
|
-
if (!input.recipient) {
|
|
1708
|
-
throw new SetupError(
|
|
1709
|
-
"A recipient is required to open a deposit account.",
|
|
1710
|
-
"client"
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
if (!recipientMatchesTarget(input.recipient, input.targetChain)) {
|
|
1714
|
-
throw new SetupError(
|
|
1715
|
-
input.targetChain === "solana" ? "A Solana destination needs a base58 recipient address." : "An EVM destination needs a 0x recipient address.",
|
|
1716
|
-
"client"
|
|
1717
|
-
);
|
|
1718
|
-
}
|
|
1719
|
-
try {
|
|
1720
|
-
const salt = deriveAccountSalt(input);
|
|
1721
|
-
debugLog(debug, "account-setup", "setup:start", {
|
|
1722
|
-
salt,
|
|
1723
|
-
recipient: input.recipient,
|
|
1724
|
-
targetChain: input.targetChain,
|
|
1725
|
-
forceRegister: input.forceRegister ?? false
|
|
1726
|
-
});
|
|
1727
|
-
const result = await service.registerManagedAccount({
|
|
1728
|
-
salt,
|
|
1729
|
-
target: {
|
|
1730
|
-
chain: targetChainToCaip2(input.targetChain),
|
|
1731
|
-
token: input.targetToken,
|
|
1732
|
-
recipient: input.recipient,
|
|
1733
|
-
...input.outputTokenRules?.length && {
|
|
1734
|
-
outputTokenRules: input.outputTokenRules
|
|
1735
|
-
},
|
|
1736
|
-
...input.rejectUnmapped != null && {
|
|
1737
|
-
rejectUnmapped: input.rejectUnmapped
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
});
|
|
1741
|
-
return {
|
|
1742
|
-
smartAccount: result.evmDepositAddress,
|
|
1743
|
-
solanaDepositAddress: result.solanaDepositAddress,
|
|
1744
|
-
cacheKey
|
|
1745
|
-
};
|
|
1746
|
-
} catch (error) {
|
|
1747
|
-
debugError(debug, "account-setup", "setup:failed", error, {
|
|
1748
|
-
recipient: input.recipient
|
|
1749
|
-
});
|
|
1750
|
-
if (error instanceof SetupError) throw error;
|
|
1751
|
-
throw mapError(error);
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
function runAccountSetupDeduped(input, deps, requestKey) {
|
|
1755
|
-
const now = Date.now();
|
|
1756
|
-
const existing = setupRequestDedupe.get(requestKey);
|
|
1757
|
-
if (existing && (!existing.settled || existing.expiresAt > now)) {
|
|
1758
|
-
debugLog(deps.debug, "account-setup", "setup:dedupe-hit", {
|
|
1759
|
-
recipient: input.recipient,
|
|
1760
|
-
forceRegister: input.forceRegister ?? false
|
|
1761
|
-
});
|
|
1762
|
-
return existing.promise;
|
|
1763
|
-
}
|
|
1764
|
-
const entry = {
|
|
1765
|
-
promise: runAccountSetup(input, deps),
|
|
1766
|
-
settled: false,
|
|
1767
|
-
expiresAt: Number.POSITIVE_INFINITY,
|
|
1768
|
-
result: null
|
|
1769
|
-
};
|
|
1770
|
-
setupRequestDedupe.set(requestKey, entry);
|
|
1771
|
-
entry.promise.then((result) => {
|
|
1772
|
-
entry.settled = true;
|
|
1773
|
-
entry.result = result;
|
|
1774
|
-
entry.expiresAt = Date.now() + SETUP_REQUEST_DEDUPE_TTL_MS;
|
|
1775
|
-
const cleanupTimer = setTimeout(() => {
|
|
1776
|
-
if (setupRequestDedupe.get(requestKey) === entry) {
|
|
1777
|
-
setupRequestDedupe.delete(requestKey);
|
|
1778
|
-
}
|
|
1779
|
-
}, SETUP_REQUEST_DEDUPE_TTL_MS);
|
|
1780
|
-
if (typeof cleanupTimer === "object" && cleanupTimer && "unref" in cleanupTimer && typeof cleanupTimer.unref === "function") {
|
|
1781
|
-
cleanupTimer.unref();
|
|
1782
|
-
}
|
|
1783
|
-
}).catch(() => {
|
|
1784
|
-
if (setupRequestDedupe.get(requestKey) === entry) {
|
|
1785
|
-
setupRequestDedupe.delete(requestKey);
|
|
1786
|
-
}
|
|
1787
|
-
});
|
|
1788
|
-
return entry.promise;
|
|
1789
|
-
}
|
|
1790
|
-
function mapError(error) {
|
|
1791
|
-
if (error instanceof TypeError) {
|
|
1792
|
-
return new SetupError(
|
|
1793
|
-
"Couldn't reach the deposit service. Please check your connection.",
|
|
1794
|
-
"network"
|
|
1795
|
-
);
|
|
1796
|
-
}
|
|
1797
|
-
if (error instanceof Error) {
|
|
1798
|
-
const statusMatch = error.message.match(/\b(4\d{2}|5\d{2})\b/);
|
|
1799
|
-
if (statusMatch) {
|
|
1800
|
-
const status = Number(statusMatch[1]);
|
|
1801
|
-
if (status >= 500) {
|
|
1802
|
-
return new SetupError(
|
|
1803
|
-
"Deposit service is temporarily unavailable. Please try again shortly.",
|
|
1804
|
-
"server"
|
|
1805
|
-
);
|
|
1806
|
-
}
|
|
1807
|
-
return new SetupError(error.message, "client");
|
|
1808
|
-
}
|
|
1809
|
-
return new SetupError(
|
|
1810
|
-
"Deposit service is temporarily unavailable. Please try again shortly.",
|
|
1811
|
-
"unknown"
|
|
1812
|
-
);
|
|
1813
|
-
}
|
|
1814
|
-
return new SetupError(
|
|
1815
|
-
"Deposit service is temporarily unavailable. Please try again shortly.",
|
|
1816
|
-
"unknown"
|
|
1817
|
-
);
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
export {
|
|
1821
|
-
getExchangeLogoSrc,
|
|
1822
|
-
getExchangeLogo,
|
|
1823
|
-
Tooltip,
|
|
1824
|
-
markSubmissionUncertain,
|
|
1825
|
-
isSubmissionUncertain,
|
|
1826
|
-
getEventTxHash,
|
|
1827
|
-
getEventSourceDetails,
|
|
1828
|
-
isDepositEvent,
|
|
1829
|
-
isFailedEvent,
|
|
1830
|
-
txRefsMatch,
|
|
1831
|
-
failureMessageForEvent,
|
|
1832
|
-
fetchTokenPriceUsd,
|
|
1833
|
-
useTokenPrices,
|
|
1834
|
-
ProcessingStep,
|
|
1835
|
-
SetupError,
|
|
1836
|
-
deriveAccountSalt,
|
|
1837
|
-
computeRequestKey,
|
|
1838
|
-
computeCacheKey,
|
|
1839
|
-
computeIsCacheable,
|
|
1840
|
-
readDedupedAccountSetupResult,
|
|
1841
|
-
runAccountSetupDeduped,
|
|
1842
|
-
warnRemovedProps,
|
|
1843
|
-
analyticsTargetProperties
|
|
1844
|
-
};
|