@orderly.network/onramper-plugin 0.0.2-alpha.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.
Files changed (81) hide show
  1. package/README.md +113 -0
  2. package/dist/chunk-QKQ47GQZ.js +11 -0
  3. package/dist/chunk-QKQ47GQZ.js.map +1 -0
  4. package/dist/chunk-XNMUIY72.mjs +9 -0
  5. package/dist/chunk-XNMUIY72.mjs.map +1 -0
  6. package/dist/de-GYR62SPI.js +36 -0
  7. package/dist/de-GYR62SPI.js.map +1 -0
  8. package/dist/de-XNITMI2B.mjs +34 -0
  9. package/dist/de-XNITMI2B.mjs.map +1 -0
  10. package/dist/en-IAAY2CDT.js +36 -0
  11. package/dist/en-IAAY2CDT.js.map +1 -0
  12. package/dist/en-UCLS4WAV.mjs +34 -0
  13. package/dist/en-UCLS4WAV.mjs.map +1 -0
  14. package/dist/es-76I5JYOI.mjs +34 -0
  15. package/dist/es-76I5JYOI.mjs.map +1 -0
  16. package/dist/es-B7VYU5TQ.js +36 -0
  17. package/dist/es-B7VYU5TQ.js.map +1 -0
  18. package/dist/fr-5G5K3WZB.js +36 -0
  19. package/dist/fr-5G5K3WZB.js.map +1 -0
  20. package/dist/fr-YBDFJ5YI.mjs +34 -0
  21. package/dist/fr-YBDFJ5YI.mjs.map +1 -0
  22. package/dist/id-RPSFROFO.js +36 -0
  23. package/dist/id-RPSFROFO.js.map +1 -0
  24. package/dist/id-TWEEXYGV.mjs +34 -0
  25. package/dist/id-TWEEXYGV.mjs.map +1 -0
  26. package/dist/index.d.mts +158 -0
  27. package/dist/index.d.ts +158 -0
  28. package/dist/index.js +1863 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/index.mjs +1851 -0
  31. package/dist/index.mjs.map +1 -0
  32. package/dist/it-64LYBKQP.js +36 -0
  33. package/dist/it-64LYBKQP.js.map +1 -0
  34. package/dist/it-ESHQ6ZEW.mjs +34 -0
  35. package/dist/it-ESHQ6ZEW.mjs.map +1 -0
  36. package/dist/ja-AMRP6CIA.js +36 -0
  37. package/dist/ja-AMRP6CIA.js.map +1 -0
  38. package/dist/ja-TTBR7X25.mjs +34 -0
  39. package/dist/ja-TTBR7X25.mjs.map +1 -0
  40. package/dist/ko-BTMZAQ7J.js +36 -0
  41. package/dist/ko-BTMZAQ7J.js.map +1 -0
  42. package/dist/ko-PUJOVSVE.mjs +34 -0
  43. package/dist/ko-PUJOVSVE.mjs.map +1 -0
  44. package/dist/nl-BZB2BRQ7.js +36 -0
  45. package/dist/nl-BZB2BRQ7.js.map +1 -0
  46. package/dist/nl-SENDBWKK.mjs +34 -0
  47. package/dist/nl-SENDBWKK.mjs.map +1 -0
  48. package/dist/pl-GGYFSVAJ.mjs +34 -0
  49. package/dist/pl-GGYFSVAJ.mjs.map +1 -0
  50. package/dist/pl-ORAYIBD7.js +36 -0
  51. package/dist/pl-ORAYIBD7.js.map +1 -0
  52. package/dist/pt-RWI3GBG6.js +36 -0
  53. package/dist/pt-RWI3GBG6.js.map +1 -0
  54. package/dist/pt-S4FOVI3A.mjs +34 -0
  55. package/dist/pt-S4FOVI3A.mjs.map +1 -0
  56. package/dist/ru-AP7GWUPY.js +36 -0
  57. package/dist/ru-AP7GWUPY.js.map +1 -0
  58. package/dist/ru-ZF4FQ3S2.mjs +34 -0
  59. package/dist/ru-ZF4FQ3S2.mjs.map +1 -0
  60. package/dist/styles.css +1 -0
  61. package/dist/tc-RZ4GC2Z6.js +36 -0
  62. package/dist/tc-RZ4GC2Z6.js.map +1 -0
  63. package/dist/tc-TQ4TWJLG.mjs +34 -0
  64. package/dist/tc-TQ4TWJLG.mjs.map +1 -0
  65. package/dist/tr-E6HTGNQA.js +36 -0
  66. package/dist/tr-E6HTGNQA.js.map +1 -0
  67. package/dist/tr-RM566BKR.mjs +34 -0
  68. package/dist/tr-RM566BKR.mjs.map +1 -0
  69. package/dist/uk-6FVT4QXK.js +36 -0
  70. package/dist/uk-6FVT4QXK.js.map +1 -0
  71. package/dist/uk-K25BMMM3.mjs +34 -0
  72. package/dist/uk-K25BMMM3.mjs.map +1 -0
  73. package/dist/vi-KGVGSDIB.js +36 -0
  74. package/dist/vi-KGVGSDIB.js.map +1 -0
  75. package/dist/vi-MTEYJND7.mjs +34 -0
  76. package/dist/vi-MTEYJND7.mjs.map +1 -0
  77. package/dist/zh-A3GFFBKX.js +36 -0
  78. package/dist/zh-A3GFFBKX.js.map +1 -0
  79. package/dist/zh-JDOWM3XW.mjs +34 -0
  80. package/dist/zh-JDOWM3XW.mjs.map +1 -0
  81. package/package.json +47 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,1851 @@
1
+ import { __glob } from './chunk-XNMUIY72.mjs';
2
+ import { createContext, useRef, useMemo, useState, useCallback, useSyncExternalStore, useEffect, useContext } from 'react';
3
+ import { preloadDefaultResource, useTranslation, i18n, ExternalLocaleProvider } from '@orderly.network/i18n';
4
+ import { Box, Flex, Text, cn, WalletIcon, Spinner, Button, DialogPortal, textVariants, DropdownMenuRoot, DropdownMenuTrigger, CaretDownIcon, DropdownMenuPortal, DropdownMenuContent, DropdownMenuItem, ScrollArea, Input, inputFormatter, ChainIcon, Badge, TokenIcon, toast } from '@orderly.network/ui';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import { computeHmac } from 'ethers';
7
+ import { useSWR, useConfig, useLocalStorage, useWalletConnector, useChains, useAccount } from '@orderly.network/hooks';
8
+ import { ABSTRACT_CHAIN_ID_MAP } from '@orderly.network/types';
9
+ import { praseChainIdToNumber, int2hex } from '@orderly.network/utils';
10
+ import { createInterceptor } from '@orderly.network/plugin-core';
11
+
12
+ // src/constants.ts
13
+ var FIAT_CURRENCIES = [
14
+ "USD",
15
+ "EUR",
16
+ "CNY",
17
+ "HKD",
18
+ "TWD",
19
+ "KRW",
20
+ "JPY"
21
+ ];
22
+ var PRESET_AMOUNTS = {
23
+ USD: [100, 500, 1e3, 5e3],
24
+ EUR: [100, 500, 1e3, 5e3],
25
+ CNY: [1e3, 5e3, 1e4, 5e4],
26
+ HKD: [1e3, 5e3, 1e4, 5e4],
27
+ TWD: [5e3, 2e4, 5e4, 2e5],
28
+ KRW: [2e5, 5e5, 1e6, 5e6],
29
+ JPY: [2e4, 5e4, 1e5, 5e5]
30
+ };
31
+ var ONRAMPER_WIDGET_BASE = "https://buy.onramper.com";
32
+ function formatCompact(n) {
33
+ const suffixes = [
34
+ [1e9, "B"],
35
+ [1e6, "M"],
36
+ [1e3, "K"]
37
+ ];
38
+ for (const [threshold, suffix] of suffixes) {
39
+ if (n >= threshold) {
40
+ const val = n / threshold;
41
+ return (val % 1 === 0 ? val.toString() : val.toFixed(1)) + suffix;
42
+ }
43
+ }
44
+ return n.toLocaleString();
45
+ }
46
+ var ExchangeIcon = (props) => /* @__PURE__ */ jsx(
47
+ "svg",
48
+ {
49
+ width: "12",
50
+ height: "12",
51
+ viewBox: "0 0 12 12",
52
+ fill: "currentColor",
53
+ xmlns: "http://www.w3.org/2000/svg",
54
+ ...props,
55
+ children: /* @__PURE__ */ jsx("path", { d: "M10.997 8.004a.5.5 0 0 0-.14-.36l-1.86-1.843-.703.703.984 1h-7.28a.5.5 0 0 0 0 1h7.28l-.984 1 .703.703 1.86-1.844a.5.5 0 0 0 .14-.36m-.5-4a.5.5 0 0 0-.5-.5H2.716l.984-1-.703-.703-1.859 1.843a.515.515 0 0 0 0 .719l1.86 1.844.702-.703-.984-1h7.281a.5.5 0 0 0 .5-.5" })
56
+ }
57
+ );
58
+ var ArrowDownIcon = (props) => /* @__PURE__ */ jsx(
59
+ "svg",
60
+ {
61
+ width: "20",
62
+ height: "21",
63
+ viewBox: "0 0 20 21",
64
+ fill: "currentColor",
65
+ xmlns: "http://www.w3.org/2000/svg",
66
+ ...props,
67
+ children: /* @__PURE__ */ jsx("path", { d: "M9.994 5.51a.83.83 0 0 0-.832.833v6.295l-2.498-2.471-1.17 1.17 3.902 3.929a.84.84 0 0 0 .599.244.84.84 0 0 0 .597-.244l3.903-3.928-1.171-1.171-2.498 2.471V6.343a.83.83 0 0 0-.832-.833" })
68
+ }
69
+ );
70
+ var BuyCryptoIcon = (props) => /* @__PURE__ */ jsx(
71
+ "svg",
72
+ {
73
+ width: "11",
74
+ height: "11",
75
+ viewBox: "0 0 11 11",
76
+ fill: "none",
77
+ xmlns: "http://www.w3.org/2000/svg",
78
+ ...props,
79
+ children: /* @__PURE__ */ jsx(
80
+ "path",
81
+ {
82
+ fillRule: "evenodd",
83
+ clipRule: "evenodd",
84
+ d: "M0 2.33333C0 1.04475 1.04475 0 2.33333 0H8.16667C9.45525 0 10.5 1.04475 10.5 2.33333V8.16667C10.5 9.45525 9.45525 10.5 8.16667 10.5H2.33333C1.04475 10.5 0 9.45525 0 8.16667V2.33333ZM7 5.83333H5.83333V7C5.83333 7.322 5.572 7.58333 5.25 7.58333C4.928 7.58333 4.66667 7.322 4.66667 7V5.83333H3.5C3.178 5.83333 2.91667 5.572 2.91667 5.25C2.91667 4.928 3.178 4.66667 3.5 4.66667H4.66667V3.5C4.66667 3.178 4.928 2.91667 5.25 2.91667C5.572 2.91667 5.83333 3.178 5.83333 3.5V4.66667H7C7.322 4.66667 7.58333 4.928 7.58333 5.25C7.58333 5.572 7.322 5.83333 7 5.83333Z",
85
+ fill: "currentColor"
86
+ }
87
+ )
88
+ }
89
+ );
90
+ var ChainSelect = (props) => {
91
+ const { chains, value, wrongNetwork, loading, disabled } = props;
92
+ const [open, setOpen] = useState(false);
93
+ const { t } = useTranslation();
94
+ const selectable = wrongNetwork || chains?.length > 1;
95
+ const chainIcon = wrongNetwork ? /* @__PURE__ */ jsx(
96
+ Flex,
97
+ {
98
+ width: 18,
99
+ height: 18,
100
+ intensity: 100,
101
+ r: "full",
102
+ justify: "center",
103
+ itemAlign: "center",
104
+ children: /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 80, children: "U" })
105
+ }
106
+ ) : /* @__PURE__ */ jsx(ChainIcon, { className: "oui-size-[18px]", chainId: value?.id });
107
+ const chainName = wrongNetwork ? t("onramp.unknownNetwork") : value?.info?.network_infos?.name;
108
+ const currentChain = chains.find((chain) => chain.chain_id === value?.id);
109
+ const extendedCurrentChain = currentChain;
110
+ const isCurrentChainSupported = !currentChain || extendedCurrentChain?.isSupported !== false;
111
+ const renderRightIcon = () => {
112
+ if (loading) {
113
+ return /* @__PURE__ */ jsx(Spinner, { size: "sm" });
114
+ }
115
+ if (selectable) {
116
+ return /* @__PURE__ */ jsx(ExchangeIcon, { className: "oui-text-base-contrast-54" });
117
+ }
118
+ };
119
+ const trigger = /* @__PURE__ */ jsxs(
120
+ Flex,
121
+ {
122
+ intensity: 500,
123
+ className: cn(
124
+ "oui-rounded-b-sm oui-rounded-t-xl oui-border oui-border-line",
125
+ disabled ? "oui-cursor-not-allowed" : selectable ? "oui-cursor-pointer" : "oui-cursor-auto",
126
+ props.className
127
+ ),
128
+ height: 54,
129
+ px: 3,
130
+ justify: "between",
131
+ itemAlign: "center",
132
+ children: [
133
+ /* @__PURE__ */ jsxs(
134
+ Flex,
135
+ {
136
+ direction: "column",
137
+ itemAlign: "start",
138
+ justify: "center",
139
+ className: "oui-gap-0",
140
+ children: [
141
+ /* @__PURE__ */ jsx(Flex, { className: "oui-h-[16px] oui-items-center", children: /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, children: t("transfer.network") }) }),
142
+ /* @__PURE__ */ jsxs(Flex, { gapX: 1, itemAlign: "center", className: "oui-mt-0.5 oui-h-[20px]", children: [
143
+ chainIcon,
144
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 80, className: "oui-leading-none", children: chainName }),
145
+ !isCurrentChainSupported && /* @__PURE__ */ jsx(Badge, { color: "danger", size: "xs", children: t("common.notSupported") })
146
+ ] })
147
+ ]
148
+ }
149
+ ),
150
+ renderRightIcon()
151
+ ]
152
+ }
153
+ );
154
+ const content = chains.map((chain, index) => {
155
+ const extendedChain = chain;
156
+ const isActive = chain.chain_id === value?.id;
157
+ const isSupported = extendedChain.isSupported !== false;
158
+ return /* @__PURE__ */ jsxs(
159
+ Flex,
160
+ {
161
+ px: 2,
162
+ r: "base",
163
+ justify: "between",
164
+ itemAlign: "center",
165
+ className: cn(
166
+ "oui-deposit-network-select-item",
167
+ "oui-h-[30px]",
168
+ isSupported ? "oui-cursor-pointer hover:oui-bg-base-5" : "oui-cursor-not-allowed",
169
+ isActive && "oui-bg-base-5",
170
+ index !== 0 && "oui-mt-[2px]"
171
+ ),
172
+ onClick: async () => {
173
+ if (!isSupported) return;
174
+ setOpen(false);
175
+ await props.onValueChange(chain);
176
+ },
177
+ children: [
178
+ /* @__PURE__ */ jsxs(Flex, { gapX: 1, itemAlign: "center", children: [
179
+ /* @__PURE__ */ jsx(
180
+ ChainIcon,
181
+ {
182
+ className: cn("oui-size-[18px]", !isSupported && "oui-opacity-50"),
183
+ chainId: chain.chain_id
184
+ }
185
+ ),
186
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: isSupported ? 54 : 36, children: chain.name }),
187
+ !isSupported && /* @__PURE__ */ jsx(Badge, { color: "danger", size: "xs", children: t("common.notSupported") })
188
+ ] }),
189
+ isActive && /* @__PURE__ */ jsx(
190
+ Box,
191
+ {
192
+ width: 4,
193
+ height: 4,
194
+ r: "full",
195
+ className: "oui-deposit-network-select-active-dot oui-bg-[linear-gradient(270deg,#59B0FE_0%,#26FEFE_100%)]"
196
+ }
197
+ )
198
+ ]
199
+ },
200
+ chain.chain_id
201
+ );
202
+ });
203
+ return /* @__PURE__ */ jsxs(DropdownMenuRoot, { open: selectable ? open : false, onOpenChange: setOpen, children: [
204
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { disabled, asChild: true, children: trigger }),
205
+ /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsx(
206
+ DropdownMenuContent,
207
+ {
208
+ onCloseAutoFocus: (e) => e.preventDefault(),
209
+ align: "start",
210
+ sideOffset: 2,
211
+ className: cn(
212
+ "oui-deposit-token-select-dropdown-menu-content",
213
+ "oui-bg-base-8 oui-p-1",
214
+ "oui-w-[var(--radix-dropdown-menu-trigger-width)]",
215
+ "oui-select-none oui-rounded-md"
216
+ ),
217
+ children: /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "oui-max-h-[110px]", children: content }) })
218
+ }
219
+ ) })
220
+ ] });
221
+ };
222
+ var ExchangeDivider = ({ icon }) => {
223
+ return /* @__PURE__ */ jsxs(Flex, { height: 40, gapX: 3, className: "oui-w-full", children: [
224
+ /* @__PURE__ */ jsx(Flex, { height: 1, className: "oui-flex-1 oui-bg-base-contrast-12" }),
225
+ icon || /* @__PURE__ */ jsx(ArrowDownIcon, { className: "oui-text-primary-light" }),
226
+ /* @__PURE__ */ jsx(Flex, { height: 1, className: "oui-flex-1 oui-bg-base-contrast-12" })
227
+ ] });
228
+ };
229
+ var HistoryDropdown = ({
230
+ transactions,
231
+ pendingTransactions,
232
+ containerRef
233
+ }) => {
234
+ const { t } = useTranslation();
235
+ if (transactions.length === 0) {
236
+ return /* @__PURE__ */ jsx(Flex, { justify: "between", itemAlign: "center", className: "oui-w-full", children: /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 98, weight: "semibold", children: t("onramp.youSpend") }) });
237
+ }
238
+ return /* @__PURE__ */ jsxs(DropdownMenuRoot, { children: [
239
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", itemAlign: "center", className: "oui-w-full", children: [
240
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 98, children: t("onramp.youSpend") }),
241
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
242
+ Flex,
243
+ {
244
+ gap: 1,
245
+ itemAlign: "center",
246
+ className: "oui-group oui-cursor-pointer",
247
+ children: [
248
+ pendingTransactions.length > 0 ? /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", className: "oui-gap-1.5", children: [
249
+ /* @__PURE__ */ jsx(Spinner, { size: "sm", className: "oui-text-primaryLight" }),
250
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, children: pendingTransactions.length === 1 ? t("onramp.pendingPurchase", {
251
+ count: pendingTransactions.length
252
+ }) : t("onramp.pendingPurchases", {
253
+ count: pendingTransactions.length
254
+ }) })
255
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", intensity: 54, children: t("onramp.history") }),
256
+ /* @__PURE__ */ jsx(
257
+ CaretDownIcon,
258
+ {
259
+ size: 10,
260
+ className: "oui-text-base-contrast-54 oui-transition-transform group-data-[state=open]:oui-rotate-180",
261
+ opacity: 1
262
+ }
263
+ )
264
+ ]
265
+ }
266
+ ) })
267
+ ] }),
268
+ /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsx(
269
+ DropdownMenuContent,
270
+ {
271
+ align: "end",
272
+ className: "oui-text-semibold oui-custom-scrollbar oui-z-50 oui-max-h-[105px] oui-overflow-y-auto oui-rounded-lg oui-border oui-border-line-12 oui-bg-base-8 oui-p-1 oui-shadow-lg",
273
+ style: containerRef?.current ? { width: containerRef.current.offsetWidth } : void 0,
274
+ children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 1, children: transactions.map((tx) => /* @__PURE__ */ jsx(
275
+ DropdownMenuItem,
276
+ {
277
+ className: "oui-flex oui-w-full oui-cursor-default oui-items-start oui-justify-between oui-rounded-md oui-px-2 oui-py-0.5 oui-outline-none focus:oui-bg-base-6 data-[disabled]:oui-pointer-events-none data-[disabled]:oui-opacity-50",
278
+ children: /* @__PURE__ */ jsxs("div", { className: "oui-grid oui-w-full oui-grid-cols-[0.5fr_1fr_1fr_1.2fr_minmax(auto,max-content)] oui-items-center oui-gap-1", children: [
279
+ /* @__PURE__ */ jsx(
280
+ Text,
281
+ {
282
+ size: "xs",
283
+ weight: "semibold",
284
+ className: "oui-truncate oui-whitespace-nowrap oui-uppercase oui-text-base-contrast-80",
285
+ children: tx.sourceCurrency
286
+ }
287
+ ),
288
+ /* @__PURE__ */ jsx(
289
+ Text,
290
+ {
291
+ size: "xs",
292
+ weight: "semibold",
293
+ className: "oui-truncate oui-whitespace-nowrap",
294
+ children: tx.inAmount
295
+ }
296
+ ),
297
+ /* @__PURE__ */ jsx(
298
+ Text,
299
+ {
300
+ size: "xs",
301
+ intensity: 54,
302
+ className: "oui-truncate oui-whitespace-nowrap oui-capitalize",
303
+ children: tx.onramp
304
+ }
305
+ ),
306
+ /* @__PURE__ */ jsx(
307
+ Text,
308
+ {
309
+ size: "xs",
310
+ weight: "semibold",
311
+ className: cn(
312
+ "oui-truncate oui-whitespace-nowrap oui-capitalize",
313
+ tx.status === "failed" || tx.status === "canceled" ? "oui-text-danger" : tx.status === "pending" || tx.status === "new" ? "oui-text-warning" : "oui-text-success"
314
+ ),
315
+ children: tx.status === "paid" ? t("onramp.statusCompleted") : tx.status
316
+ }
317
+ ),
318
+ /* @__PURE__ */ jsx(
319
+ Text,
320
+ {
321
+ size: "xs",
322
+ intensity: 36,
323
+ className: "oui-whitespace-nowrap oui-text-right",
324
+ children: new Date(tx.statusDate).toLocaleString("en-US", {
325
+ month: "short",
326
+ day: "numeric",
327
+ hour: "2-digit",
328
+ minute: "2-digit"
329
+ })
330
+ }
331
+ )
332
+ ] })
333
+ },
334
+ tx.transactionId
335
+ )) })
336
+ }
337
+ ) })
338
+ ] });
339
+ };
340
+ var PartnerSelect = ({
341
+ partners,
342
+ value,
343
+ onValueChange,
344
+ containerRef
345
+ }) => {
346
+ const { t } = useTranslation();
347
+ const [open, setOpen] = useState(false);
348
+ const selectable = partners.length > 1;
349
+ const triggerRef = useRef(null);
350
+ const getAlignOffset = () => {
351
+ if (!containerRef?.current || !triggerRef.current) return 0;
352
+ const containerRect = containerRef.current.getBoundingClientRect();
353
+ const triggerRect = triggerRef.current.getBoundingClientRect();
354
+ return triggerRect.right - containerRect.right;
355
+ };
356
+ return /* @__PURE__ */ jsxs(DropdownMenuRoot, { open: selectable ? open : false, onOpenChange: setOpen, children: [
357
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { children: /* @__PURE__ */ jsxs(
358
+ Flex,
359
+ {
360
+ ref: triggerRef,
361
+ itemAlign: "center",
362
+ gap: 1,
363
+ className: "oui-cursor-pointer oui-select-none",
364
+ children: [
365
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, weight: "semibold", children: t("onramp.by") }),
366
+ /* @__PURE__ */ jsx(
367
+ "img",
368
+ {
369
+ alt: value.name,
370
+ src: `https://cdn.onramper.com/icons/onramps/${value.id.toLowerCase()}-colored.svg`,
371
+ className: "oui-size-4 oui-rounded-full oui-object-cover"
372
+ }
373
+ ),
374
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, weight: "semibold", children: value.name }),
375
+ selectable && /* @__PURE__ */ jsx(
376
+ CaretDownIcon,
377
+ {
378
+ size: 10,
379
+ className: "oui-text-base-contrast-54",
380
+ opacity: 1
381
+ }
382
+ )
383
+ ]
384
+ }
385
+ ) }),
386
+ /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsx(
387
+ DropdownMenuContent,
388
+ {
389
+ onCloseAutoFocus: (e) => e.preventDefault(),
390
+ align: "end",
391
+ sideOffset: 10,
392
+ alignOffset: getAlignOffset(),
393
+ className: cn(
394
+ "oui-z-50 oui-bg-base-8 oui-p-1",
395
+ "oui-min-w-[270px] oui-select-none oui-rounded-[6px]",
396
+ "oui-border oui-border-line-6"
397
+ ),
398
+ style: containerRef?.current ? { width: containerRef.current.offsetWidth } : void 0,
399
+ children: /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "oui-flex oui-max-h-[220px] oui-flex-col oui-gap-1", children: partners.map((partner) => {
400
+ const isActive = partner.id === value.id;
401
+ const diffPercentage = value.payout === 0 ? 0 : (partner.payout - value.payout) / value.payout * 100;
402
+ return /* @__PURE__ */ jsxs(
403
+ Flex,
404
+ {
405
+ p: 2,
406
+ justify: "between",
407
+ itemAlign: "center",
408
+ className: cn(
409
+ "oui-min-h-[56px] oui-cursor-pointer oui-rounded-[4px] oui-transition-colors hover:oui-bg-base-6",
410
+ isActive ? "oui-bg-base-5" : "oui-bg-transparent"
411
+ ),
412
+ onClick: () => {
413
+ onValueChange(partner);
414
+ setOpen(false);
415
+ },
416
+ children: [
417
+ /* @__PURE__ */ jsxs(
418
+ Flex,
419
+ {
420
+ direction: "column",
421
+ itemAlign: "start",
422
+ justify: "center",
423
+ gap: 1,
424
+ className: "oui-flex-[3]",
425
+ children: [
426
+ /* @__PURE__ */ jsxs(Flex, { gap: 1, itemAlign: "center", children: [
427
+ /* @__PURE__ */ jsx(
428
+ "img",
429
+ {
430
+ alt: partner.name,
431
+ src: `https://cdn.onramper.com/icons/onramps/${partner.id.toLowerCase()}-colored.svg`,
432
+ className: "oui-size-4 oui-rounded-full oui-object-cover",
433
+ onError: (e) => {
434
+ e.target.src = "https://cdn.onramper.com/icons/tokens/usdc.svg";
435
+ }
436
+ }
437
+ ),
438
+ /* @__PURE__ */ jsx(
439
+ Text,
440
+ {
441
+ size: "sm",
442
+ intensity: 54,
443
+ weight: "semibold",
444
+ className: "oui-leading-5 oui-tracking-[0.42px]",
445
+ children: partner.name
446
+ }
447
+ )
448
+ ] }),
449
+ partner.recommendations && partner.recommendations.length > 0 && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Flex, { className: "oui-flex-wrap oui-gap-1", children: partner.recommendations.map((rec, i) => /* @__PURE__ */ jsx(
450
+ Flex,
451
+ {
452
+ px: 1,
453
+ py: 1,
454
+ className: cn(
455
+ "oui-rounded-[4px] oui-bg-gradient-to-r",
456
+ "oui-from-[rgb(var(--oui-gradient-brand-start)_/_0.12)]",
457
+ "oui-to-[rgb(var(--oui-gradient-brand-end)_/_0.12)]"
458
+ ),
459
+ children: /* @__PURE__ */ jsx(
460
+ Text.gradient,
461
+ {
462
+ size: "3xs",
463
+ weight: "semibold",
464
+ color: "brand",
465
+ className: "oui-leading-[10px] oui-tracking-[0.3px]",
466
+ children: rec
467
+ }
468
+ )
469
+ },
470
+ i
471
+ )) }) })
472
+ ]
473
+ }
474
+ ),
475
+ /* @__PURE__ */ jsx(
476
+ Flex,
477
+ {
478
+ direction: "column",
479
+ itemAlign: "end",
480
+ justify: "center",
481
+ gap: 1,
482
+ className: "oui-flex-[2] oui-text-xs oui-font-semibold oui-tracking-[0.36px]",
483
+ children: isActive ? /* @__PURE__ */ jsxs(Fragment, { children: [
484
+ /* @__PURE__ */ jsx(
485
+ Text,
486
+ {
487
+ intensity: 36,
488
+ className: "oui-text-right oui-leading-[15px]",
489
+ children: t("onramp.youReceive")
490
+ }
491
+ ),
492
+ /* @__PURE__ */ jsxs(Text, { intensity: 98, className: "oui-leading-[15px]", children: [
493
+ partner.payout.toFixed(2),
494
+ " USDC"
495
+ ] })
496
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
497
+ /* @__PURE__ */ jsxs(Text, { intensity: 54, className: "oui-leading-[15px]", children: [
498
+ partner.payout.toFixed(2),
499
+ " USDC"
500
+ ] }),
501
+ /* @__PURE__ */ jsxs(
502
+ Text,
503
+ {
504
+ className: cn(
505
+ "oui-text-right oui-leading-[15px]",
506
+ diffPercentage < 0 ? "oui-text-danger" : diffPercentage > 0 ? "oui-text-success" : "oui-text-base-contrast-54"
507
+ ),
508
+ children: [
509
+ diffPercentage > 0 ? "+" : "",
510
+ diffPercentage.toFixed(2),
511
+ "%"
512
+ ]
513
+ }
514
+ )
515
+ ] })
516
+ }
517
+ )
518
+ ]
519
+ },
520
+ partner.id
521
+ );
522
+ }) }) })
523
+ }
524
+ ) })
525
+ ] });
526
+ };
527
+ var PaymentMethodSelect = (props) => {
528
+ const { t } = useTranslation();
529
+ const { methods, value, disabled, loading } = props;
530
+ const [open, setOpen] = useState(false);
531
+ const selectable = methods.length > 1;
532
+ const renderRightIcon = () => {
533
+ if (selectable) {
534
+ return /* @__PURE__ */ jsx(ExchangeIcon, { className: "oui-text-base-contrast-54" });
535
+ }
536
+ };
537
+ const trigger = /* @__PURE__ */ jsxs(
538
+ Flex,
539
+ {
540
+ intensity: 500,
541
+ className: cn(
542
+ "oui-rounded-[4px] oui-rounded-t-xl oui-border oui-border-line",
543
+ disabled ? "oui-cursor-not-allowed" : selectable ? "oui-cursor-pointer" : "oui-cursor-auto",
544
+ props.className
545
+ ),
546
+ height: 54,
547
+ px: 3,
548
+ justify: "between",
549
+ itemAlign: "center",
550
+ children: [
551
+ /* @__PURE__ */ jsxs("div", { children: [
552
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, children: t("onramp.payWith") }) }),
553
+ /* @__PURE__ */ jsx(Flex, { gapX: 1, itemAlign: "center", children: loading ? /* @__PURE__ */ jsx(Spinner, { size: "sm" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
554
+ value.icon && /* @__PURE__ */ jsx(
555
+ "img",
556
+ {
557
+ src: value.icon,
558
+ alt: value.name,
559
+ width: 16,
560
+ height: 16,
561
+ className: "oui-rounded-lg oui-bg-secondary oui-object-contain oui-p-px"
562
+ }
563
+ ),
564
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 80, children: value.name })
565
+ ] }) })
566
+ ] }),
567
+ renderRightIcon()
568
+ ]
569
+ }
570
+ );
571
+ const content = methods.map((method, index) => {
572
+ const isActive = method.id === value.id;
573
+ return /* @__PURE__ */ jsxs(
574
+ Flex,
575
+ {
576
+ px: 2,
577
+ r: "base",
578
+ justify: "between",
579
+ itemAlign: "center",
580
+ className: cn(
581
+ "oui-h-[30px] oui-cursor-pointer hover:oui-bg-base-5",
582
+ isActive && "oui-bg-base-5",
583
+ index !== 0 && "oui-mt-[2px]"
584
+ ),
585
+ onClick: () => {
586
+ setOpen(false);
587
+ props.onValueChange(method);
588
+ },
589
+ children: [
590
+ /* @__PURE__ */ jsxs(Flex, { gapX: 1, itemAlign: "center", children: [
591
+ method.icon && /* @__PURE__ */ jsx(
592
+ "img",
593
+ {
594
+ src: method.icon,
595
+ alt: method.name,
596
+ width: 14,
597
+ height: 14,
598
+ className: "oui-rounded-lg oui-bg-secondary oui-object-contain oui-p-px"
599
+ }
600
+ ),
601
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: isActive ? 80 : 54, children: method.name })
602
+ ] }),
603
+ isActive && /* @__PURE__ */ jsx(
604
+ Box,
605
+ {
606
+ width: 4,
607
+ height: 4,
608
+ r: "full",
609
+ className: "oui-bg-[linear-gradient(270deg,#59B0FE_0%,#26FEFE_100%)]"
610
+ }
611
+ )
612
+ ]
613
+ },
614
+ method.id
615
+ );
616
+ });
617
+ return /* @__PURE__ */ jsxs(DropdownMenuRoot, { open: selectable ? open : false, onOpenChange: setOpen, children: [
618
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { disabled, asChild: true, children: trigger }),
619
+ /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsx(
620
+ DropdownMenuContent,
621
+ {
622
+ onCloseAutoFocus: (e) => e.preventDefault(),
623
+ align: "start",
624
+ sideOffset: 2,
625
+ className: cn(
626
+ "oui-z-50 oui-bg-base-8 oui-p-1",
627
+ "oui-w-[var(--radix-dropdown-menu-trigger-width)]",
628
+ "oui-select-none oui-rounded-md"
629
+ ),
630
+ children: /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "oui-max-h-[145px]", children: content }) })
631
+ }
632
+ ) })
633
+ ] });
634
+ };
635
+ var QuantityInput = (props) => {
636
+ const { t } = useTranslation();
637
+ const {
638
+ classNames,
639
+ label,
640
+ value,
641
+ onValueChange,
642
+ loading,
643
+ placeholder,
644
+ suffix,
645
+ error,
646
+ ...rest
647
+ } = props;
648
+ const inputRef = useRef(null);
649
+ const hasError = !!error;
650
+ const prefix = /* @__PURE__ */ jsxs(Box, { children: [
651
+ /* @__PURE__ */ jsx(Box, { className: "oui-absolute oui-top-1.5", children: /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, children: label || t("onramp.quantity") }) }),
652
+ loading && /* @__PURE__ */ jsx(Box, { className: "oui-absolute oui-bottom-1", children: /* @__PURE__ */ jsx(Spinner, { size: "sm" }) })
653
+ ] });
654
+ const _placeholder = placeholder ?? (loading ? "" : "0");
655
+ return /* @__PURE__ */ jsxs(Box, { children: [
656
+ /* @__PURE__ */ jsx(
657
+ Input,
658
+ {
659
+ ref: inputRef,
660
+ autoComplete: "off",
661
+ placeholder: _placeholder,
662
+ color: hasError ? "danger" : "default",
663
+ prefix,
664
+ suffix,
665
+ value,
666
+ onValueChange: (value2) => {
667
+ onValueChange?.(value2);
668
+ },
669
+ formatters: [
670
+ inputFormatter.numberFormatter,
671
+ inputFormatter.dpFormatter(2),
672
+ inputFormatter.currencyFormatter
673
+ ],
674
+ ...rest,
675
+ classNames: {
676
+ ...classNames,
677
+ root: cn(
678
+ "oui-relative oui-h-[54px] oui-px-3",
679
+ "oui-rounded-lg oui-border oui-border-line",
680
+ props.readOnly ? "oui-border-none oui-bg-base-6 focus-within:oui-outline-0" : "oui-bg-base-5",
681
+ classNames?.root
682
+ ),
683
+ input: cn(
684
+ "oui-absolute oui-top-[25px] oui-h-[20px]",
685
+ classNames?.input
686
+ )
687
+ }
688
+ }
689
+ ),
690
+ hasError && /* @__PURE__ */ jsx(Text, { size: "2xs", className: "oui-mt-1 oui-px-1 oui-text-danger", children: error })
691
+ ] });
692
+ };
693
+ var CurrencySuffix = ({
694
+ currencies,
695
+ selected,
696
+ onSelect
697
+ }) => {
698
+ const [open, setOpen] = useState(false);
699
+ const selectable = currencies.length > 1;
700
+ const trigger = /* @__PURE__ */ jsxs(
701
+ Flex,
702
+ {
703
+ itemAlign: "center",
704
+ gap: 1,
705
+ className: cn(selectable && "oui-cursor-pointer"),
706
+ children: [
707
+ /* @__PURE__ */ jsx(
708
+ "img",
709
+ {
710
+ src: `https://cdn.onramper.com/icons/tokens/${selected.toLowerCase()}.svg`,
711
+ alt: selected,
712
+ className: "oui-size-4 oui-rounded-full"
713
+ }
714
+ ),
715
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 80, weight: "semibold", children: selected }),
716
+ selectable && /* @__PURE__ */ jsx(
717
+ CaretDownIcon,
718
+ {
719
+ size: 10,
720
+ className: "oui-text-base-contrast-54",
721
+ opacity: 1
722
+ }
723
+ )
724
+ ]
725
+ }
726
+ );
727
+ return /* @__PURE__ */ jsx("div", { className: "oui-absolute oui-right-3 oui-flex oui-h-[20px] oui-items-center", children: selectable ? /* @__PURE__ */ jsxs(DropdownMenuRoot, { open, onOpenChange: setOpen, children: [
728
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: trigger }),
729
+ /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsx(
730
+ DropdownMenuContent,
731
+ {
732
+ onCloseAutoFocus: (e) => e.preventDefault(),
733
+ align: "end",
734
+ sideOffset: 2,
735
+ className: cn(
736
+ "oui-z-50 oui-bg-base-8 oui-p-1",
737
+ "oui-min-w-[80px]",
738
+ "oui-select-none oui-rounded-md"
739
+ ),
740
+ children: /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "oui-max-h-[110px]", children: currencies.map((currency) => {
741
+ const isActive = currency === selected;
742
+ return /* @__PURE__ */ jsx(
743
+ Flex,
744
+ {
745
+ px: 2,
746
+ r: "base",
747
+ justify: "between",
748
+ itemAlign: "center",
749
+ className: cn(
750
+ "oui-h-[30px] oui-cursor-pointer hover:oui-bg-base-5",
751
+ isActive && "oui-bg-base-5",
752
+ "oui-mt-[2px]"
753
+ ),
754
+ onClick: () => {
755
+ setOpen(false);
756
+ onSelect(currency);
757
+ },
758
+ children: /* @__PURE__ */ jsxs(Flex, { gap: 2, itemAlign: "center", children: [
759
+ /* @__PURE__ */ jsx(
760
+ "img",
761
+ {
762
+ src: `https://cdn.onramper.com/icons/tokens/${currency.toLowerCase()}.svg`,
763
+ alt: currency,
764
+ className: "oui-size-4 oui-rounded-full"
765
+ }
766
+ ),
767
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: isActive ? 80 : 54, children: currency })
768
+ ] })
769
+ },
770
+ currency
771
+ );
772
+ }) }) })
773
+ }
774
+ ) })
775
+ ] }) : trigger });
776
+ };
777
+ var TokenSuffix = ({ symbol }) => {
778
+ return /* @__PURE__ */ jsx("div", { className: "oui-absolute oui-right-3 oui-flex oui-h-[20px] oui-items-center", children: /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", gap: 1, children: [
779
+ /* @__PURE__ */ jsx(TokenIcon, { name: symbol, size: "xs" }),
780
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 80, weight: "semibold", children: symbol })
781
+ ] }) });
782
+ };
783
+ var RADIUS = 6;
784
+ var TRACK_STROKE = 1.5;
785
+ var ARC_STROKE = 2;
786
+ var SIZE = (RADIUS + ARC_STROKE) * 2;
787
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
788
+ function createTickStore(duration) {
789
+ let elapsed = 0;
790
+ const listeners = /* @__PURE__ */ new Set();
791
+ let timer = null;
792
+ function start() {
793
+ stop();
794
+ elapsed = 0;
795
+ timer = setInterval(() => {
796
+ elapsed += 1;
797
+ if (elapsed >= duration) stop();
798
+ listeners.forEach((l) => l());
799
+ }, 1e3);
800
+ }
801
+ function stop() {
802
+ if (timer) {
803
+ clearInterval(timer);
804
+ timer = null;
805
+ }
806
+ }
807
+ return {
808
+ getSnapshot: () => elapsed,
809
+ subscribe: (cb) => {
810
+ listeners.add(cb);
811
+ if (listeners.size === 1) start();
812
+ return () => {
813
+ listeners.delete(cb);
814
+ if (listeners.size === 0) stop();
815
+ };
816
+ },
817
+ reset: () => start()
818
+ };
819
+ }
820
+ var store = createTickStore(30);
821
+ var QuoteCountdown = ({
822
+ duration = 30,
823
+ isValidating = false
824
+ }) => {
825
+ const prevValidatingRef = useRef(isValidating);
826
+ if (prevValidatingRef.current && !isValidating) {
827
+ store.reset();
828
+ }
829
+ prevValidatingRef.current = isValidating;
830
+ const subscribe = useCallback((cb) => store.subscribe(cb), []);
831
+ const getSnapshot = useCallback(() => store.getSnapshot(), []);
832
+ const elapsed = useSyncExternalStore(subscribe, getSnapshot);
833
+ const prevElapsedRef = useRef(elapsed);
834
+ const isResetting = elapsed < prevElapsedRef.current;
835
+ prevElapsedRef.current = elapsed;
836
+ const finished = elapsed >= duration;
837
+ const progress = finished ? 1 : elapsed / duration;
838
+ const dashOffset = CIRCUMFERENCE * (1 - progress);
839
+ const transitionDuration = isResetting ? "0.6s" : "0.2s";
840
+ return /* @__PURE__ */ jsxs(
841
+ "svg",
842
+ {
843
+ width: SIZE,
844
+ height: SIZE,
845
+ viewBox: `0 0 ${SIZE} ${SIZE}`,
846
+ className: "oui-shrink-0",
847
+ style: { transform: "rotate(-90deg)" },
848
+ children: [
849
+ /* @__PURE__ */ jsx(
850
+ "circle",
851
+ {
852
+ cx: SIZE / 2,
853
+ cy: SIZE / 2,
854
+ r: RADIUS,
855
+ fill: "none",
856
+ stroke: "rgba(255,255,255,0.1)",
857
+ strokeWidth: TRACK_STROKE
858
+ }
859
+ ),
860
+ /* @__PURE__ */ jsx(
861
+ "circle",
862
+ {
863
+ cx: SIZE / 2,
864
+ cy: SIZE / 2,
865
+ r: RADIUS,
866
+ fill: "none",
867
+ stroke: "rgb(var(--oui-color-primary-light))",
868
+ strokeWidth: ARC_STROKE,
869
+ strokeLinecap: "round",
870
+ strokeDasharray: CIRCUMFERENCE,
871
+ strokeDashoffset: dashOffset,
872
+ style: {
873
+ transition: `stroke-dashoffset ${transitionDuration} ease-in-out`
874
+ }
875
+ }
876
+ )
877
+ ]
878
+ }
879
+ );
880
+ };
881
+ var OnrampFormUI = (props) => {
882
+ const { t } = useTranslation();
883
+ const {
884
+ paymentMethods,
885
+ selectedPaymentMethod,
886
+ onPaymentMethodChange,
887
+ fiatCurrencies,
888
+ selectedCurrency,
889
+ onCurrencyChange,
890
+ spendAmount,
891
+ onSpendAmountChange,
892
+ presetAmounts,
893
+ chains,
894
+ selectedChain,
895
+ onChainChange,
896
+ wallet,
897
+ address,
898
+ receiveQuantity,
899
+ receiveQuantityPlaceholder,
900
+ partners,
901
+ selectedPartner,
902
+ onPartnerChange,
903
+ exchangeRateText,
904
+ isQuoteLoading,
905
+ onContinue,
906
+ isContinueDisabled,
907
+ iframeDialogOpen,
908
+ onramperIframeUrl,
909
+ quoteIsValidating,
910
+ spendAmountError,
911
+ transactions,
912
+ pendingTransactions
913
+ } = props;
914
+ const formRef = useRef(null);
915
+ return /* @__PURE__ */ jsxs(Box, { id: "oui-onramp-form", className: textVariants({ weight: "semibold" }), children: [
916
+ /* @__PURE__ */ jsxs(
917
+ Flex,
918
+ {
919
+ ref: formRef,
920
+ direction: "column",
921
+ className: "oui-w-full oui-tracking-[0.03em]",
922
+ children: [
923
+ /* @__PURE__ */ jsxs(
924
+ Flex,
925
+ {
926
+ direction: "column",
927
+ itemAlign: "start",
928
+ className: "oui-w-full",
929
+ gap: 3,
930
+ children: [
931
+ /* @__PURE__ */ jsx(
932
+ HistoryDropdown,
933
+ {
934
+ transactions,
935
+ pendingTransactions,
936
+ containerRef: formRef
937
+ }
938
+ ),
939
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", className: "oui-w-full", gap: 2, children: [
940
+ /* @__PURE__ */ jsxs(Box, { className: "oui-w-full", children: [
941
+ /* @__PURE__ */ jsx(
942
+ PaymentMethodSelect,
943
+ {
944
+ methods: selectedPaymentMethod ? paymentMethods : [],
945
+ value: selectedPaymentMethod ?? {
946
+ id: "_",
947
+ name: t("onramp.noPaymentMethod")
948
+ },
949
+ onValueChange: onPaymentMethodChange,
950
+ disabled: !selectedPaymentMethod,
951
+ loading: isQuoteLoading && !selectedPaymentMethod
952
+ }
953
+ ),
954
+ /* @__PURE__ */ jsx(
955
+ QuantityInput,
956
+ {
957
+ value: spendAmount,
958
+ onValueChange: onSpendAmountChange,
959
+ placeholder: presetAmounts[0].toString(),
960
+ error: spendAmountError,
961
+ suffix: /* @__PURE__ */ jsx(
962
+ CurrencySuffix,
963
+ {
964
+ currencies: fiatCurrencies,
965
+ selected: selectedCurrency,
966
+ onSelect: (c) => onCurrencyChange(c)
967
+ }
968
+ ),
969
+ classNames: {
970
+ root: "oui-mt-1 oui-rounded-t-[4px] oui-rounded-b-xl"
971
+ }
972
+ }
973
+ )
974
+ ] }),
975
+ /* @__PURE__ */ jsx(Flex, { gap: 3, className: "oui-w-full", children: presetAmounts.map((amount) => /* @__PURE__ */ jsx(
976
+ Flex,
977
+ {
978
+ justify: "center",
979
+ itemAlign: "center",
980
+ className: cn(
981
+ "oui-h-6 oui-flex-1 oui-cursor-pointer oui-rounded",
982
+ "oui-bg-base-6 oui-transition-colors hover:oui-bg-base-5"
983
+ ),
984
+ onClick: () => onSpendAmountChange(amount.toString()),
985
+ children: /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 36, weight: "semibold", children: formatCompact(amount) })
986
+ },
987
+ amount
988
+ )) })
989
+ ] })
990
+ ]
991
+ }
992
+ ),
993
+ /* @__PURE__ */ jsx(ExchangeDivider, {}),
994
+ /* @__PURE__ */ jsxs(
995
+ Flex,
996
+ {
997
+ direction: "column",
998
+ itemAlign: "start",
999
+ className: "oui-w-full",
1000
+ gap: 3,
1001
+ children: [
1002
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", className: "oui-w-full", children: [
1003
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 98, weight: "semibold", children: t("onramp.youReceive") }),
1004
+ /* @__PURE__ */ jsxs(Flex, { gapX: 1, children: [
1005
+ /* @__PURE__ */ jsx(WalletIcon, { size: "2xs", name: wallet?.label ?? "" }),
1006
+ /* @__PURE__ */ jsx(Text.formatted, { size: "sm", intensity: 54, rule: "address", children: address })
1007
+ ] })
1008
+ ] }),
1009
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", className: "oui-w-full", gap: 1, children: [
1010
+ /* @__PURE__ */ jsxs(Flex, { className: "oui-w-full", gap: 1, children: [
1011
+ /* @__PURE__ */ jsx(Box, { className: "oui-min-w-0 oui-flex-1", children: /* @__PURE__ */ jsx(
1012
+ ChainSelect,
1013
+ {
1014
+ chains,
1015
+ value: selectedChain,
1016
+ onValueChange: onChainChange,
1017
+ wrongNetwork: !selectedChain,
1018
+ className: "oui-w-full oui-rounded-[4px] oui-rounded-tl-xl"
1019
+ }
1020
+ ) }),
1021
+ /* @__PURE__ */ jsx(Box, { className: "oui-min-w-0 oui-flex-1", children: /* @__PURE__ */ jsx(
1022
+ QuantityInput,
1023
+ {
1024
+ readOnly: true,
1025
+ loading: isQuoteLoading,
1026
+ value: isQuoteLoading ? "" : receiveQuantity,
1027
+ placeholder: isQuoteLoading ? "" : receiveQuantityPlaceholder,
1028
+ suffix: /* @__PURE__ */ jsx(TokenSuffix, { symbol: "USDC" }),
1029
+ classNames: {
1030
+ root: cn(
1031
+ "oui-rounded-[4px] oui-rounded-b-sm oui-rounded-tr-xl",
1032
+ "oui-border-none oui-bg-base-6 focus-within:oui-outline-0"
1033
+ )
1034
+ }
1035
+ }
1036
+ ) })
1037
+ ] }),
1038
+ /* @__PURE__ */ jsxs(
1039
+ Flex,
1040
+ {
1041
+ justify: "between",
1042
+ itemAlign: "center",
1043
+ className: cn(
1044
+ "oui-w-full oui-rounded-b-xl oui-rounded-t-[4px]",
1045
+ "oui-bg-base-6 oui-px-3 oui-py-2"
1046
+ ),
1047
+ children: [
1048
+ /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", gap: 1, children: [
1049
+ exchangeRateText && /* @__PURE__ */ jsx(
1050
+ QuoteCountdown,
1051
+ {
1052
+ duration: 30,
1053
+ isValidating: quoteIsValidating
1054
+ }
1055
+ ),
1056
+ /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 54, weight: "semibold", children: exchangeRateText || "\u2014" })
1057
+ ] }),
1058
+ selectedPartner ? /* @__PURE__ */ jsx(
1059
+ PartnerSelect,
1060
+ {
1061
+ partners,
1062
+ value: selectedPartner,
1063
+ onValueChange: onPartnerChange,
1064
+ containerRef: formRef
1065
+ }
1066
+ ) : isQuoteLoading ? /* @__PURE__ */ jsx(Spinner, { size: "sm" }) : /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 36, children: t("onramp.noPartner") })
1067
+ ]
1068
+ }
1069
+ )
1070
+ ] })
1071
+ ]
1072
+ }
1073
+ ),
1074
+ /* @__PURE__ */ jsx(Flex, { justify: "center", className: "oui-w-full oui-pt-7", children: /* @__PURE__ */ jsx(Box, { className: "oui-w-full lg:oui-w-auto lg:oui-min-w-[184px]", children: /* @__PURE__ */ jsx(
1075
+ Button,
1076
+ {
1077
+ fullWidth: true,
1078
+ size: { initial: "md", lg: "lg" },
1079
+ onClick: onContinue,
1080
+ disabled: isContinueDisabled,
1081
+ children: t("onramp.continue")
1082
+ }
1083
+ ) }) })
1084
+ ]
1085
+ }
1086
+ ),
1087
+ iframeDialogOpen && /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsx("div", { className: "oui-fixed oui-inset-0 oui-z-50 oui-flex oui-flex-col oui-bg-black/80", children: /* @__PURE__ */ jsx(
1088
+ "iframe",
1089
+ {
1090
+ src: onramperIframeUrl,
1091
+ title: t("onramp.iframeTitle"),
1092
+ allow: "accelerometer; autoplay; camera; gyroscope; payment; microphone",
1093
+ className: "oui-w-full oui-flex-1 oui-border-none"
1094
+ }
1095
+ ) }) })
1096
+ ] });
1097
+ };
1098
+ var OnrampConfigContext = createContext(null);
1099
+ function OnrampConfigProvider({
1100
+ config,
1101
+ children
1102
+ }) {
1103
+ return /* @__PURE__ */ jsx(OnrampConfigContext.Provider, { value: config, children });
1104
+ }
1105
+ function useOnrampConfig() {
1106
+ const config = useContext(OnrampConfigContext);
1107
+ if (!config) {
1108
+ throw new Error("useOnrampConfig must be used within OnrampConfigProvider");
1109
+ }
1110
+ return config;
1111
+ }
1112
+ function arrangeStringAlphabetically(inputString) {
1113
+ const inputObject = {};
1114
+ inputString.split("&").forEach((pair) => {
1115
+ const [key, value] = pair.split("=");
1116
+ const nestedPairs = value.split(",");
1117
+ inputObject[key] = {};
1118
+ nestedPairs.forEach((nestedPair) => {
1119
+ const [nestedKey, nestedValue] = nestedPair.split(":");
1120
+ inputObject[key][nestedKey] = nestedValue;
1121
+ });
1122
+ });
1123
+ for (const key in inputObject) {
1124
+ inputObject[key] = Object.fromEntries(
1125
+ Object.entries(inputObject[key]).sort()
1126
+ );
1127
+ }
1128
+ const sortedKeys = Object.keys(inputObject).sort();
1129
+ const parts = [];
1130
+ for (const key of sortedKeys) {
1131
+ const nested = Object.entries(inputObject[key]).map(([k, v]) => `${k}:${v}`).join(",");
1132
+ parts.push(`${key}=${nested}`);
1133
+ }
1134
+ return parts.join("&");
1135
+ }
1136
+ function generateOnramperSignature(secretKey, data) {
1137
+ const encoder = new TextEncoder();
1138
+ const sig = computeHmac(
1139
+ "sha256",
1140
+ encoder.encode(secretKey),
1141
+ encoder.encode(data)
1142
+ );
1143
+ return sig.startsWith("0x") ? sig.slice(2) : sig;
1144
+ }
1145
+
1146
+ // src/utils/buildOnramperUrl.ts
1147
+ function buildOnramperIframeUrl({
1148
+ spendAmount,
1149
+ selectedCurrency,
1150
+ onramperToken,
1151
+ selectedPaymentMethod,
1152
+ selectedPartner,
1153
+ address,
1154
+ apiKey,
1155
+ secretKey
1156
+ }) {
1157
+ const params = new URLSearchParams();
1158
+ params.set("themeName", "dark");
1159
+ params.set("apiKey", apiKey);
1160
+ params.set("mode", "buy");
1161
+ params.set("skipTransactionScreen", "true");
1162
+ params.set("txnRedirect", "true");
1163
+ if (spendAmount) params.set("txnAmount", spendAmount);
1164
+ if (selectedCurrency) params.set("txnFiat", selectedCurrency.toLowerCase());
1165
+ if (onramperToken) params.set("txnCrypto", onramperToken);
1166
+ if (selectedPaymentMethod)
1167
+ params.set("txnPaymentMethod", selectedPaymentMethod.id);
1168
+ if (selectedPartner) params.set("txnOnramp", selectedPartner.id);
1169
+ if (address && onramperToken) {
1170
+ const walletsValue = `${onramperToken}:${address}`.toLowerCase();
1171
+ params.set("wallets", walletsValue);
1172
+ if (secretKey) {
1173
+ const signContent = arrangeStringAlphabetically(
1174
+ `wallets=${walletsValue}`
1175
+ );
1176
+ const signature = generateOnramperSignature(secretKey, signContent);
1177
+ params.set("signature", signature);
1178
+ }
1179
+ }
1180
+ return `${ONRAMPER_WIDGET_BASE}?${params.toString()}`;
1181
+ }
1182
+
1183
+ // src/hooks/useOnrampCheckout.ts
1184
+ function useOnrampCheckout({
1185
+ spendAmount,
1186
+ selectedCurrency,
1187
+ spendAmountError,
1188
+ onramperToken,
1189
+ selectedPartner,
1190
+ selectedPaymentMethod,
1191
+ address,
1192
+ isLoading
1193
+ }) {
1194
+ const { t } = useTranslation();
1195
+ const { apiKey, secretKey } = useOnrampConfig();
1196
+ const [iframeDialogOpen, setIframeDialogOpen] = useState(false);
1197
+ const onramperIframeUrl = useMemo(
1198
+ () => buildOnramperIframeUrl({
1199
+ spendAmount,
1200
+ selectedCurrency,
1201
+ onramperToken,
1202
+ selectedPaymentMethod,
1203
+ selectedPartner,
1204
+ address,
1205
+ apiKey,
1206
+ secretKey
1207
+ }),
1208
+ [
1209
+ spendAmount,
1210
+ selectedCurrency,
1211
+ onramperToken,
1212
+ selectedPaymentMethod,
1213
+ selectedPartner,
1214
+ address,
1215
+ apiKey,
1216
+ secretKey
1217
+ ]
1218
+ );
1219
+ const isContinueDisabled = useMemo(
1220
+ () => !spendAmount || isNaN(parseFloat(spendAmount)) || parseFloat(spendAmount) <= 0 || !selectedCurrency || !onramperToken || !selectedPartner || !selectedPaymentMethod || !address || isLoading || !!spendAmountError,
1221
+ [
1222
+ spendAmount,
1223
+ selectedCurrency,
1224
+ spendAmountError,
1225
+ onramperToken,
1226
+ selectedPartner,
1227
+ selectedPaymentMethod,
1228
+ address,
1229
+ isLoading
1230
+ ]
1231
+ );
1232
+ const onContinue = useCallback(() => {
1233
+ const missing = [];
1234
+ const num = parseFloat(spendAmount);
1235
+ if (!spendAmount || isNaN(num) || num <= 0)
1236
+ missing.push(t("onramp.missing.spendAmount"));
1237
+ if (!selectedCurrency)
1238
+ missing.push(t("onramp.missing.currency"));
1239
+ if (!onramperToken)
1240
+ missing.push(t("onramp.missing.network"));
1241
+ if (!selectedPartner)
1242
+ missing.push(t("onramp.missing.partner"));
1243
+ if (!selectedPaymentMethod)
1244
+ missing.push(t("onramp.missing.paymentMethod"));
1245
+ if (!address)
1246
+ missing.push(t("onramp.missing.address"));
1247
+ if (missing.length > 0) {
1248
+ const msg = t("onramp.missingRequiredInfo", {
1249
+ list: missing.join(", ")
1250
+ });
1251
+ toast.error(msg);
1252
+ return;
1253
+ }
1254
+ setIframeDialogOpen(true);
1255
+ }, [
1256
+ spendAmount,
1257
+ selectedCurrency,
1258
+ onramperToken,
1259
+ selectedPartner,
1260
+ selectedPaymentMethod,
1261
+ address,
1262
+ t
1263
+ ]);
1264
+ return {
1265
+ onramperIframeUrl,
1266
+ iframeDialogOpen,
1267
+ setIframeDialogOpen,
1268
+ isContinueDisabled,
1269
+ onContinue
1270
+ };
1271
+ }
1272
+ var ONRAMPER_BASE = "https://api.onramper.com/quotes";
1273
+ var CHAIN_TO_ONRAMPER_TOKEN = {
1274
+ 1: "usdc_ethereum",
1275
+ // Ethereum
1276
+ 10: "usdc_optimism",
1277
+ // Optimism
1278
+ 56: "usdc_bsc",
1279
+ // BNB Smart Chain
1280
+ 100: "usdc_gnosis",
1281
+ // Gnosis
1282
+ 137: "usdc_polygon",
1283
+ // Polygon
1284
+ 143: "usdc_monad",
1285
+ // Monad Mainnet
1286
+ 324: "usdc_zksync",
1287
+ // zkSync Era
1288
+ 2020: "usdc_ronin",
1289
+ // Ronin
1290
+ 8453: "usdc_base",
1291
+ // Base
1292
+ 42161: "usdc_arbitrum",
1293
+ // Arbitrum One
1294
+ 42220: "usdc_celo",
1295
+ // Celo
1296
+ 43114: "usdc_avaxc",
1297
+ // Avalanche C-Chain
1298
+ 57073: "usdc_ink",
1299
+ // Ink
1300
+ 59144: "usdc_linea",
1301
+ // Linea
1302
+ 900900900: "usdc_solana"
1303
+ // Solana Mainnet
1304
+ };
1305
+ var ONRAMP_SUPPORTED_CHAIN_IDS = new Set(
1306
+ Object.keys(CHAIN_TO_ONRAMPER_TOKEN).map(Number)
1307
+ );
1308
+ function getOnramperToken(chainId) {
1309
+ return CHAIN_TO_ONRAMPER_TOKEN[chainId];
1310
+ }
1311
+ var onrampFetcher = async (url, apiKey) => {
1312
+ const res = await fetch(url, {
1313
+ headers: {
1314
+ accept: "application/json",
1315
+ Authorization: apiKey
1316
+ }
1317
+ });
1318
+ if (!res.ok) {
1319
+ throw new Error(`Onramper API error: ${res.status}`);
1320
+ }
1321
+ return res.json();
1322
+ };
1323
+ var buildQuoteUrl = (currency, amount, onramperToken) => `${ONRAMPER_BASE}/${currency.toLowerCase()}/${onramperToken}?amount=${amount}`;
1324
+ function filterValidRamps(items) {
1325
+ return items.filter((item) => !item.errors);
1326
+ }
1327
+ function toPartners(items) {
1328
+ return items.map((item) => ({
1329
+ id: item.ramp,
1330
+ name: item.ramp.charAt(0).toUpperCase() + item.ramp.slice(1),
1331
+ rate: item.rate ?? 0,
1332
+ payout: item.payout ?? 0,
1333
+ recommendations: item.recommendations ?? []
1334
+ }));
1335
+ }
1336
+ function toPaymentMethods(items) {
1337
+ const seen = /* @__PURE__ */ new Set();
1338
+ const methods = [];
1339
+ for (const item of items) {
1340
+ if (!item.availablePaymentMethods) continue;
1341
+ for (const pm of item.availablePaymentMethods) {
1342
+ if (!seen.has(pm.paymentTypeId)) {
1343
+ seen.add(pm.paymentTypeId);
1344
+ methods.push({
1345
+ id: pm.paymentTypeId,
1346
+ name: pm.name,
1347
+ icon: pm.icon
1348
+ });
1349
+ }
1350
+ }
1351
+ }
1352
+ return methods;
1353
+ }
1354
+ function getPaymentMethodsForPartner(items, partnerId) {
1355
+ const item = items.find((i) => i.ramp === partnerId);
1356
+ if (!item?.availablePaymentMethods) return [];
1357
+ return item.availablePaymentMethods.map((pm) => ({
1358
+ id: pm.paymentTypeId,
1359
+ name: pm.name,
1360
+ icon: pm.icon
1361
+ }));
1362
+ }
1363
+ function extractAllLimits(items) {
1364
+ const result = {};
1365
+ for (const item of items) {
1366
+ if (!item.availablePaymentMethods) continue;
1367
+ for (const pm of item.availablePaymentMethods) {
1368
+ const agg = pm.details?.limits?.aggregatedLimit;
1369
+ if (agg && !result[pm.paymentTypeId]) {
1370
+ result[pm.paymentTypeId] = agg;
1371
+ }
1372
+ }
1373
+ }
1374
+ return result;
1375
+ }
1376
+ var DEFAULT_AMOUNT = 100;
1377
+ function useOnrampQuotes(currency, amount, onramperToken) {
1378
+ const { apiKey } = useOnrampConfig();
1379
+ const token = onramperToken || "";
1380
+ const num = amount ? parseFloat(amount) : NaN;
1381
+ const effectiveAmount = !isNaN(num) && num > 0 ? num : DEFAULT_AMOUNT;
1382
+ const url = buildQuoteUrl(currency, effectiveAmount, token);
1383
+ const { data, error, isLoading, isValidating } = useSWR(
1384
+ `onramp-quote-${currency.toLowerCase()}-${effectiveAmount}-${token}`,
1385
+ () => onrampFetcher(url, apiKey),
1386
+ {
1387
+ refreshInterval: 3e4,
1388
+ revalidateOnFocus: false,
1389
+ dedupingInterval: 1e3,
1390
+ keepPreviousData: true
1391
+ }
1392
+ );
1393
+ const validRamps = useMemo(
1394
+ () => data ? filterValidRamps(data) : [],
1395
+ [data]
1396
+ );
1397
+ const isAvailable = validRamps.length > 0 && !error;
1398
+ const partners = useMemo(() => toPartners(validRamps), [validRamps]);
1399
+ const paymentMethods = useMemo(
1400
+ () => toPaymentMethods(validRamps),
1401
+ [validRamps]
1402
+ );
1403
+ const latestLimits = useMemo(
1404
+ () => extractAllLimits(validRamps),
1405
+ [validRamps]
1406
+ );
1407
+ const [accumulatedLimits, setAccumulatedLimits] = useState({});
1408
+ useEffect(() => {
1409
+ if (Object.keys(latestLimits).length > 0) {
1410
+ setAccumulatedLimits((prev) => ({ ...prev, ...latestLimits }));
1411
+ }
1412
+ }, [latestLimits]);
1413
+ return {
1414
+ isAvailable,
1415
+ partners,
1416
+ paymentMethods,
1417
+ paymentMethodLimits: accumulatedLimits,
1418
+ isLoading,
1419
+ error,
1420
+ validRamps,
1421
+ isValidating,
1422
+ getPaymentMethodsForPartner: (partnerId) => getPaymentMethodsForPartner(validRamps, partnerId)
1423
+ };
1424
+ }
1425
+ function useOnrampAvailability(currency) {
1426
+ return useOnrampQuotes(currency);
1427
+ }
1428
+ var PENDING_STATUSES = /* @__PURE__ */ new Set(["pending", "new"]);
1429
+ function useOnrampTransactionStatus(walletAddress) {
1430
+ const { workerUrl } = useOnrampConfig();
1431
+ const { data, error } = useSWR(
1432
+ walletAddress && workerUrl ? `${workerUrl}?walletAddress=${walletAddress}` : null,
1433
+ async (url) => {
1434
+ const res = await fetch(url);
1435
+ if (!res.ok) {
1436
+ if (res.status === 404) return [];
1437
+ throw new Error("Failed to fetch transaction status");
1438
+ }
1439
+ return res.json();
1440
+ },
1441
+ {
1442
+ refreshInterval: (latestData) => {
1443
+ if (!walletAddress) return 0;
1444
+ if (latestData && latestData.some((tx) => PENDING_STATUSES.has(tx.status))) {
1445
+ return 1e4;
1446
+ }
1447
+ return 3e4;
1448
+ },
1449
+ revalidateOnFocus: true
1450
+ }
1451
+ );
1452
+ const transactions = useMemo(() => data || [], [data]);
1453
+ const pendingTransactions = useMemo(
1454
+ () => transactions.filter((tx) => PENDING_STATUSES.has(tx.status)),
1455
+ [transactions]
1456
+ );
1457
+ const historyTransactions = useMemo(
1458
+ () => transactions.filter((tx) => !PENDING_STATUSES.has(tx.status)),
1459
+ [transactions]
1460
+ );
1461
+ return {
1462
+ transactions,
1463
+ pendingTransactions,
1464
+ historyTransactions,
1465
+ error,
1466
+ isLoading: !data && !error && !!walletAddress
1467
+ };
1468
+ }
1469
+ function usePartnerPaymentSelection(partners, getPaymentMethodsForPartner2) {
1470
+ const [selectedPartnerId, setSelectedPartnerId] = useState(
1471
+ null
1472
+ );
1473
+ const [selectedPaymentMethodId, setSelectedPaymentMethodId] = useState(null);
1474
+ const selectedPartner = useMemo(() => {
1475
+ if (partners.length === 0) return null;
1476
+ if (selectedPartnerId) {
1477
+ const found = partners.find((p) => p.id === selectedPartnerId);
1478
+ if (found) return found;
1479
+ }
1480
+ return partners[0];
1481
+ }, [partners, selectedPartnerId]);
1482
+ const onPartnerChange = useCallback((partner) => {
1483
+ setSelectedPartnerId(partner.id);
1484
+ setSelectedPaymentMethodId(null);
1485
+ }, []);
1486
+ const paymentMethods = useMemo(() => {
1487
+ if (!selectedPartner) return [];
1488
+ return getPaymentMethodsForPartner2(selectedPartner.id);
1489
+ }, [selectedPartner, getPaymentMethodsForPartner2]);
1490
+ const selectedPaymentMethod = useMemo(() => {
1491
+ if (paymentMethods.length === 0) return null;
1492
+ if (selectedPaymentMethodId) {
1493
+ const found = paymentMethods.find(
1494
+ (m) => m.id === selectedPaymentMethodId
1495
+ );
1496
+ if (found) return found;
1497
+ }
1498
+ return paymentMethods[0];
1499
+ }, [paymentMethods, selectedPaymentMethodId]);
1500
+ const onPaymentMethodChange = useCallback((method) => {
1501
+ setSelectedPaymentMethodId(method.id);
1502
+ }, []);
1503
+ return {
1504
+ selectedPartner,
1505
+ onPartnerChange,
1506
+ paymentMethods,
1507
+ selectedPaymentMethod,
1508
+ onPaymentMethodChange
1509
+ };
1510
+ }
1511
+ function useReceiveDisplay({
1512
+ spendAmount,
1513
+ spendAmountError,
1514
+ selectedPartner,
1515
+ selectedCurrency,
1516
+ effectiveSpendAmountForQuote
1517
+ }) {
1518
+ const receiveQuantity = useMemo(() => {
1519
+ if (spendAmountError) return "";
1520
+ const num = parseFloat(spendAmount);
1521
+ if (isNaN(num) || num <= 0 || !selectedPartner) return "";
1522
+ if (selectedPartner.payout > 0) return selectedPartner.payout.toFixed(2);
1523
+ return "0";
1524
+ }, [spendAmount, spendAmountError, selectedPartner]);
1525
+ const receiveQuantityPlaceholder = useMemo(() => {
1526
+ if (!selectedPartner) return "";
1527
+ if (selectedPartner.payout > 0) return selectedPartner.payout.toFixed(2);
1528
+ if (!selectedPartner.rate) return "";
1529
+ const num = parseFloat(effectiveSpendAmountForQuote);
1530
+ if (!isNaN(num) && num > 0) return (num / selectedPartner.rate).toFixed(2);
1531
+ return "";
1532
+ }, [selectedPartner, effectiveSpendAmountForQuote]);
1533
+ const exchangeRateText = useMemo(() => {
1534
+ if (!selectedPartner?.rate) return "";
1535
+ return `1 USDC \u2248 ${selectedPartner.rate.toFixed(4)} ${selectedCurrency}`;
1536
+ }, [selectedPartner, selectedCurrency]);
1537
+ return { receiveQuantity, receiveQuantityPlaceholder, exchangeRateText };
1538
+ }
1539
+ function useSpendAmount() {
1540
+ const [selectedCurrency, setSelectedCurrency] = useState("USD");
1541
+ const [spendAmount, setSpendAmount] = useState("");
1542
+ const [debouncedSpendAmount, setDebouncedSpendAmount] = useState(
1543
+ PRESET_AMOUNTS["USD"][0].toString()
1544
+ );
1545
+ useEffect(() => {
1546
+ const handler = setTimeout(() => {
1547
+ setDebouncedSpendAmount(spendAmount);
1548
+ }, 500);
1549
+ return () => clearTimeout(handler);
1550
+ }, [spendAmount]);
1551
+ const effectiveSpendAmountForQuote = useMemo(() => {
1552
+ const num = parseFloat(debouncedSpendAmount);
1553
+ if (!isNaN(num) && num > 0) return debouncedSpendAmount;
1554
+ return PRESET_AMOUNTS[selectedCurrency][0].toString();
1555
+ }, [debouncedSpendAmount, selectedCurrency]);
1556
+ const onCurrencyChange = (currency) => {
1557
+ setSelectedCurrency(currency);
1558
+ setSpendAmount("");
1559
+ setDebouncedSpendAmount(PRESET_AMOUNTS[currency][0].toString());
1560
+ };
1561
+ return {
1562
+ fiatCurrencies: FIAT_CURRENCIES,
1563
+ selectedCurrency,
1564
+ onCurrencyChange,
1565
+ spendAmount,
1566
+ onSpendAmountChange: setSpendAmount,
1567
+ presetAmounts: PRESET_AMOUNTS[selectedCurrency],
1568
+ effectiveSpendAmountForQuote
1569
+ };
1570
+ }
1571
+ function useWalletAddress() {
1572
+ const { wallet, connectedChain } = useWalletConnector();
1573
+ const { state: accountState, account } = useAccount();
1574
+ const address = useMemo(() => {
1575
+ let addr = accountState.address;
1576
+ if (connectedChain?.id && ABSTRACT_CHAIN_ID_MAP.has(parseInt(connectedChain.id))) {
1577
+ addr = account.getAdditionalInfo()?.AGWAddress;
1578
+ }
1579
+ return addr;
1580
+ }, [accountState, account, connectedChain]);
1581
+ return { wallet, address };
1582
+ }
1583
+ function useChainSelect() {
1584
+ const { t } = useTranslation();
1585
+ const networkId = useConfig("networkId");
1586
+ const [linkDeviceStorage] = useLocalStorage("orderly_link_device", {});
1587
+ const { connectedChain, settingChain, setChain } = useWalletConnector();
1588
+ const [allChains, { findByChainId }] = useChains(networkId, {
1589
+ pick: "network_infos",
1590
+ filter: (chain) => chain.network_infos?.bridge_enable || chain.network_infos?.bridgeless
1591
+ });
1592
+ const chains = useMemo(
1593
+ () => allChains.filter((c) => ONRAMP_SUPPORTED_CHAIN_IDS.has(c.chain_id)),
1594
+ [allChains]
1595
+ );
1596
+ const currentChain = useMemo(() => {
1597
+ const chainId = connectedChain ? praseChainIdToNumber(connectedChain.id) : parseInt(linkDeviceStorage?.chainId);
1598
+ if (!chainId) return null;
1599
+ const chain = findByChainId(chainId);
1600
+ return {
1601
+ ...connectedChain,
1602
+ id: chainId,
1603
+ info: chain
1604
+ };
1605
+ }, [findByChainId, connectedChain, linkDeviceStorage]);
1606
+ const onChainChange = useCallback(
1607
+ async (chain) => {
1608
+ const chainInfo = findByChainId(chain.chain_id);
1609
+ if (!connectedChain) {
1610
+ return;
1611
+ }
1612
+ const currentChainId = praseChainIdToNumber(connectedChain.id);
1613
+ if (!chainInfo || chainInfo.network_infos?.chain_id === currentChainId) {
1614
+ return Promise.resolve();
1615
+ }
1616
+ return setChain({
1617
+ chainId: int2hex(Number(chainInfo.network_infos?.chain_id))
1618
+ }).then((switched) => {
1619
+ if (switched) {
1620
+ toast.success(t("connector.networkSwitched"));
1621
+ } else {
1622
+ toast.error(t("connector.switchChain.failed"));
1623
+ }
1624
+ }).catch((error) => {
1625
+ if (error && error.message) {
1626
+ toast.error(
1627
+ `${t("connector.switchChain.failed")}: ${error.message}`
1628
+ );
1629
+ }
1630
+ });
1631
+ },
1632
+ [connectedChain, setChain, findByChainId, t]
1633
+ );
1634
+ return {
1635
+ chains,
1636
+ currentChain,
1637
+ settingChain,
1638
+ onChainChange
1639
+ };
1640
+ }
1641
+
1642
+ // src/components/onrampForm/onrampForm.script.tsx
1643
+ var useOnrampFormScript = () => {
1644
+ const { t } = useTranslation();
1645
+ const spend = useSpendAmount();
1646
+ const { chains, currentChain, onChainChange } = useChainSelect();
1647
+ const onramperToken = useMemo(
1648
+ () => currentChain ? getOnramperToken(currentChain.id) : void 0,
1649
+ [currentChain]
1650
+ );
1651
+ const {
1652
+ isAvailable,
1653
+ partners,
1654
+ isLoading,
1655
+ getPaymentMethodsForPartner: getPaymentMethodsForPartner2,
1656
+ paymentMethodLimits,
1657
+ isValidating
1658
+ } = useOnrampQuotes(
1659
+ spend.selectedCurrency,
1660
+ spend.effectiveSpendAmountForQuote,
1661
+ onramperToken
1662
+ );
1663
+ const selection = usePartnerPaymentSelection(
1664
+ partners,
1665
+ getPaymentMethodsForPartner2
1666
+ );
1667
+ const spendAmountError = useMemo(() => {
1668
+ if (!spend.spendAmount || !selection.selectedPaymentMethod) return "";
1669
+ const num = parseFloat(spend.spendAmount);
1670
+ if (isNaN(num) || num <= 0) return "";
1671
+ const limits = paymentMethodLimits[selection.selectedPaymentMethod.id];
1672
+ if (!limits) return "";
1673
+ if (num < limits.min || num > limits.max) {
1674
+ return t("onramp.amountBetween", {
1675
+ currency: spend.selectedCurrency,
1676
+ min: limits.min,
1677
+ max: limits.max
1678
+ });
1679
+ }
1680
+ return "";
1681
+ }, [
1682
+ spend.spendAmount,
1683
+ spend.selectedCurrency,
1684
+ selection.selectedPaymentMethod,
1685
+ paymentMethodLimits,
1686
+ t
1687
+ ]);
1688
+ const { wallet, address } = useWalletAddress();
1689
+ const {
1690
+ transactions,
1691
+ pendingTransactions,
1692
+ historyTransactions,
1693
+ isLoading: isStatusLoading
1694
+ } = useOnrampTransactionStatus(address ?? null);
1695
+ const { receiveQuantity, receiveQuantityPlaceholder, exchangeRateText } = useReceiveDisplay({
1696
+ spendAmount: spend.spendAmount,
1697
+ spendAmountError,
1698
+ selectedPartner: selection.selectedPartner,
1699
+ selectedCurrency: spend.selectedCurrency,
1700
+ effectiveSpendAmountForQuote: spend.effectiveSpendAmountForQuote
1701
+ });
1702
+ const checkout = useOnrampCheckout({
1703
+ spendAmount: spend.spendAmount,
1704
+ selectedCurrency: spend.selectedCurrency,
1705
+ spendAmountError,
1706
+ onramperToken,
1707
+ selectedPartner: selection.selectedPartner,
1708
+ selectedPaymentMethod: selection.selectedPaymentMethod,
1709
+ address,
1710
+ isLoading
1711
+ });
1712
+ return {
1713
+ paymentMethods: selection.paymentMethods,
1714
+ selectedPaymentMethod: selection.selectedPaymentMethod,
1715
+ onPaymentMethodChange: selection.onPaymentMethodChange,
1716
+ fiatCurrencies: spend.fiatCurrencies,
1717
+ selectedCurrency: spend.selectedCurrency,
1718
+ onCurrencyChange: spend.onCurrencyChange,
1719
+ spendAmount: spend.spendAmount,
1720
+ onSpendAmountChange: spend.onSpendAmountChange,
1721
+ presetAmounts: spend.presetAmounts,
1722
+ chains,
1723
+ selectedChain: currentChain,
1724
+ onChainChange,
1725
+ wallet,
1726
+ address,
1727
+ receiveQuantity,
1728
+ receiveQuantityPlaceholder,
1729
+ partners,
1730
+ selectedPartner: selection.selectedPartner,
1731
+ onPartnerChange: selection.onPartnerChange,
1732
+ exchangeRateText,
1733
+ quoteIsValidating: isValidating,
1734
+ isAvailable,
1735
+ isQuoteLoading: isLoading,
1736
+ spendAmountError,
1737
+ ...checkout,
1738
+ statusData: pendingTransactions.length > 0 ? pendingTransactions[0] : historyTransactions.length > 0 ? historyTransactions[0] : null,
1739
+ transactions,
1740
+ pendingTransactions,
1741
+ historyTransactions,
1742
+ isStatusLoading
1743
+ };
1744
+ };
1745
+ var OnrampForm = (props) => {
1746
+ const state = useOnrampFormScript();
1747
+ return /* @__PURE__ */ jsx(OnrampFormUI, { ...state, ...props });
1748
+ };
1749
+
1750
+ // src/i18n/module.ts
1751
+ var OnrampLocales = {
1752
+ "onramp.pluginName": "Buy Crypto (Onramper)",
1753
+ "onramp.tabTitle": "Buy Crypto",
1754
+ "onramp.noPaymentMethod": "No available payment method",
1755
+ "onramp.youReceive": "You receive",
1756
+ "onramp.youSpend": "You spend",
1757
+ "onramp.noPartner": "No available partner",
1758
+ "onramp.continue": "Continue",
1759
+ "onramp.iframeTitle": "Onramper Widget",
1760
+ "onramp.amountBetween": "Amount should be in between {{currency}} {{min}} and {{currency}} {{max}}",
1761
+ "onramp.by": "by",
1762
+ "onramp.payWith": "Pay with",
1763
+ "onramp.history": "History",
1764
+ "onramp.pendingPurchase": "{{count}} pending purchase",
1765
+ "onramp.pendingPurchases": "{{count}} pending purchases",
1766
+ "onramp.statusCompleted": "completed",
1767
+ "onramp.quantity": "Quantity",
1768
+ "onramp.unknownNetwork": "Unknown",
1769
+ "onramp.missingRequiredInfo": "Missing required info: {{list}}",
1770
+ "onramp.missing.spendAmount": "spend amount",
1771
+ "onramp.missing.currency": "fiat currency",
1772
+ "onramp.missing.network": "network (chain)",
1773
+ "onramp.missing.partner": "partner",
1774
+ "onramp.missing.paymentMethod": "payment method",
1775
+ "onramp.missing.address": "wallet address"
1776
+ };
1777
+
1778
+ // import("./locales/**/*.json") in src/i18n/provider.tsx
1779
+ var globImport_locales_json = __glob({
1780
+ "./locales/de.json": () => import('./de-XNITMI2B.mjs'),
1781
+ "./locales/en.json": () => import('./en-UCLS4WAV.mjs'),
1782
+ "./locales/es.json": () => import('./es-76I5JYOI.mjs'),
1783
+ "./locales/fr.json": () => import('./fr-YBDFJ5YI.mjs'),
1784
+ "./locales/id.json": () => import('./id-TWEEXYGV.mjs'),
1785
+ "./locales/it.json": () => import('./it-ESHQ6ZEW.mjs'),
1786
+ "./locales/ja.json": () => import('./ja-TTBR7X25.mjs'),
1787
+ "./locales/ko.json": () => import('./ko-PUJOVSVE.mjs'),
1788
+ "./locales/nl.json": () => import('./nl-SENDBWKK.mjs'),
1789
+ "./locales/pl.json": () => import('./pl-GGYFSVAJ.mjs'),
1790
+ "./locales/pt.json": () => import('./pt-S4FOVI3A.mjs'),
1791
+ "./locales/ru.json": () => import('./ru-ZF4FQ3S2.mjs'),
1792
+ "./locales/tc.json": () => import('./tc-TQ4TWJLG.mjs'),
1793
+ "./locales/tr.json": () => import('./tr-RM566BKR.mjs'),
1794
+ "./locales/uk.json": () => import('./uk-K25BMMM3.mjs'),
1795
+ "./locales/vi.json": () => import('./vi-MTEYJND7.mjs'),
1796
+ "./locales/zh.json": () => import('./zh-JDOWM3XW.mjs')
1797
+ });
1798
+
1799
+ // src/i18n/provider.tsx
1800
+ preloadDefaultResource(OnrampLocales);
1801
+ var resources = (lang) => {
1802
+ return globImport_locales_json(`./locales/${lang}.json`).then(
1803
+ (res) => res.default
1804
+ );
1805
+ };
1806
+ var OnrampLocaleProvider = (props) => {
1807
+ return /* @__PURE__ */ jsx(ExternalLocaleProvider, { resources, children: props.children });
1808
+ };
1809
+ var defaultIcon = /* @__PURE__ */ jsx("div", { className: "oui-flex oui-items-center oui-justify-center", children: /* @__PURE__ */ jsx(BuyCryptoIcon, { width: 11, height: 11, className: "oui-mt-0.5 oui-ml-0.5" }) });
1810
+ function registerOnrampPlugin(options) {
1811
+ return (SDK) => {
1812
+ SDK.registerPlugin({
1813
+ id: "orderly-onramp",
1814
+ name: i18n.t("onramp.pluginName"),
1815
+ version: "1.0.0",
1816
+ interceptors: [
1817
+ createInterceptor("Transfer.DepositAndWithdraw", (Original, props) => {
1818
+ if (!options.apiKey || !options.secretKey) {
1819
+ return /* @__PURE__ */ jsx(Original, { ...props });
1820
+ }
1821
+ const onrampTab = {
1822
+ id: "onramp",
1823
+ title: options.title ?? i18n.t("onramp.tabTitle"),
1824
+ icon: options.icon ?? defaultIcon,
1825
+ component: (props2) => /* @__PURE__ */ jsx(
1826
+ OnrampConfigProvider,
1827
+ {
1828
+ config: {
1829
+ apiKey: options.apiKey,
1830
+ secretKey: options.secretKey,
1831
+ workerUrl: options.workerUrl
1832
+ },
1833
+ children: /* @__PURE__ */ jsx(OnrampForm, { ...props2 })
1834
+ }
1835
+ ),
1836
+ order: 30
1837
+ };
1838
+ const extraTabs = [
1839
+ ...Array.isArray(props.extraTabs) ? props.extraTabs : [],
1840
+ onrampTab
1841
+ ];
1842
+ return /* @__PURE__ */ jsx(OnrampLocaleProvider, { children: /* @__PURE__ */ jsx(Original, { ...props, extraTabs }) });
1843
+ })
1844
+ ]
1845
+ });
1846
+ };
1847
+ }
1848
+
1849
+ export { ArrowDownIcon, BuyCryptoIcon, ExchangeIcon, FIAT_CURRENCIES, OnrampForm, OnrampFormUI, PRESET_AMOUNTS, formatCompact, registerOnrampPlugin, useOnrampAvailability, useOnrampFormScript };
1850
+ //# sourceMappingURL=index.mjs.map
1851
+ //# sourceMappingURL=index.mjs.map