@agg-build/hooks 4.26.1 → 4.27.3

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 (45) hide show
  1. package/dist/deposit.d.mts +142 -138
  2. package/dist/deposit.d.mts.map +1 -0
  3. package/dist/deposit.d.ts +142 -138
  4. package/dist/deposit.d.ts.map +1 -0
  5. package/dist/deposit.js +751 -2414
  6. package/dist/deposit.mjs +744 -727
  7. package/dist/deposit.mjs.map +1 -0
  8. package/dist/index-CbNR3EIA.d.mts +341 -0
  9. package/dist/index-CbNR3EIA.d.mts.map +1 -0
  10. package/dist/index-CsP1jRMD.d.ts +341 -0
  11. package/dist/index-CsP1jRMD.d.ts.map +1 -0
  12. package/dist/index-D0fXU85a.d.mts +743 -0
  13. package/dist/index-D0fXU85a.d.mts.map +1 -0
  14. package/dist/index-D0fXU85a.d.ts +743 -0
  15. package/dist/index-D0fXU85a.d.ts.map +1 -0
  16. package/dist/index.d.mts +6458 -7515
  17. package/dist/index.d.mts.map +1 -0
  18. package/dist/index.d.ts +6458 -7515
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +7451 -11417
  21. package/dist/index.mjs +7154 -5221
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/use-ramp-session-7RAG9tvY.js +30 -0
  24. package/dist/use-ramp-session-BFWHCtuc.mjs +21 -0
  25. package/dist/use-ramp-session-BFWHCtuc.mjs.map +1 -0
  26. package/dist/use-sync-balances-BkcqInJh.mjs +1779 -0
  27. package/dist/use-sync-balances-BkcqInJh.mjs.map +1 -0
  28. package/dist/{use-sync-balances-CeD8qZWP.d.ts → use-sync-balances-CVEg__2V.d.mts} +7 -8
  29. package/dist/use-sync-balances-CVEg__2V.d.mts.map +1 -0
  30. package/dist/{use-sync-balances-CeD8qZWP.d.mts → use-sync-balances-CVEg__2V.d.ts} +7 -8
  31. package/dist/use-sync-balances-CVEg__2V.d.ts.map +1 -0
  32. package/dist/use-sync-balances-HryB8Q7F.js +1974 -0
  33. package/dist/withdraw--f5kYKJA.mjs +1474 -0
  34. package/dist/withdraw--f5kYKJA.mjs.map +1 -0
  35. package/dist/withdraw-BXWZYmJa.js +1591 -0
  36. package/dist/withdraw.d.mts +3 -351
  37. package/dist/withdraw.d.ts +3 -351
  38. package/dist/withdraw.js +10 -2229
  39. package/dist/withdraw.mjs +3 -20
  40. package/package.json +7 -6
  41. package/dist/chunk-JFJNW2PD.mjs +0 -5649
  42. package/dist/chunk-LNIAMJTZ.mjs +0 -505
  43. package/dist/chunk-OZQ3K47U.mjs +0 -31
  44. package/dist/use-deposit-addresses-B9ICS-3U.d.mts +0 -236
  45. package/dist/use-deposit-addresses-B9ICS-3U.d.ts +0 -236
package/dist/deposit.js CHANGED
@@ -1,2437 +1,774 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __defProps = Object.defineProperties;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
- var __spreadValues = (a, b) => {
12
- for (var prop in b || (b = {}))
13
- if (__hasOwnProp.call(b, prop))
14
- __defNormalProp(a, prop, b[prop]);
15
- if (__getOwnPropSymbols)
16
- for (var prop of __getOwnPropSymbols(b)) {
17
- if (__propIsEnum.call(b, prop))
18
- __defNormalProp(a, prop, b[prop]);
19
- }
20
- return a;
21
- };
22
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
- var __export = (target, all) => {
24
- for (var name in all)
25
- __defProp(target, name, { get: all[name], enumerable: true });
26
- };
27
- var __copyProps = (to, from, except, desc) => {
28
- if (from && typeof from === "object" || typeof from === "function") {
29
- for (let key of __getOwnPropNames(from))
30
- if (!__hasOwnProp.call(to, key) && key !== except)
31
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
- }
33
- return to;
34
- };
35
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
- var __async = (__this, __arguments, generator) => {
37
- return new Promise((resolve, reject) => {
38
- var fulfilled = (value) => {
39
- try {
40
- step(generator.next(value));
41
- } catch (e) {
42
- reject(e);
43
- }
44
- };
45
- var rejected = (value) => {
46
- try {
47
- step(generator.throw(value));
48
- } catch (e) {
49
- reject(e);
50
- }
51
- };
52
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
53
- step((generator = generator.apply(__this, __arguments)).next());
54
- });
55
- };
56
-
57
- // src/deposit/index.ts
58
- var deposit_exports = {};
59
- __export(deposit_exports, {
60
- DEFAULT_SOLANA_RPC_ENDPOINT: () => DEFAULT_SOLANA_RPC_ENDPOINT,
61
- SVM_CHAIN_IDS: () => SVM_CHAIN_IDS,
62
- normalizeWalletError: () => normalizeWalletError,
63
- useDepositAddresses: () => useDepositAddresses,
64
- useDepositFlow: () => useDepositFlow,
65
- useSyncBalances: () => useSyncBalances,
66
- useWalletSendToken: () => useWalletSendToken,
67
- useWalletTokenBalance: () => useWalletTokenBalance,
68
- useWalletTransactionStatus: () => useWalletTransactionStatus
69
- });
70
- module.exports = __toCommonJS(deposit_exports);
71
-
72
- // src/deposit/normalize-wallet-error.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_use_sync_balances = require("./use-sync-balances-HryB8Q7F.js");
3
+ const require_use_ramp_session = require("./use-ramp-session-7RAG9tvY.js");
4
+ let _tanstack_react_query = require("@tanstack/react-query");
5
+ let react = require("react");
6
+ let _solana_web3_js = require("@solana/web3.js");
7
+ let viem = require("viem");
8
+ let wagmi = require("wagmi");
9
+ let _solana_wallet_adapter_react = require("@solana/wallet-adapter-react");
10
+ //#region src/deposit/normalize-wallet-error.ts
73
11
  function normalizeWalletError(error, supportedChains) {
74
- var _a, _b;
75
- const message = error instanceof Error ? error.message : String(error);
76
- const lower = message.toLowerCase();
77
- if (lower.includes("user rejected") || lower.includes("user denied") || lower.includes("rejected the request") || lower.includes("denied transaction signature")) {
78
- return { message: "Wallet request rejected.", tone: "error" };
79
- }
80
- const chainMismatch = message.includes("does not match the target chain") || message.includes("Expected Chain ID:");
81
- if (chainMismatch) {
82
- const match = message.match(/Expected Chain ID:\s*(\d+)/i);
83
- const targetChainId = match ? Number(match[1]) : void 0;
84
- const targetChainName = (_b = (_a = supportedChains == null ? void 0 : supportedChains.find((chain) => chain.chainId === targetChainId)) == null ? void 0 : _a.name) != null ? _b : targetChainId ? `chain ${targetChainId}` : "the selected chain";
85
- return {
86
- message: `Wallet chain does not match. Please switch your wallet to ${targetChainName}.`,
87
- tone: "warning"
88
- };
89
- }
90
- return { message, tone: "error" };
12
+ const message = error instanceof Error ? error.message : String(error);
13
+ const lower = message.toLowerCase();
14
+ if (lower.includes("user rejected") || lower.includes("user denied") || lower.includes("rejected the request") || lower.includes("denied transaction signature")) return {
15
+ message: "Wallet request rejected.",
16
+ tone: "error"
17
+ };
18
+ if (message.includes("does not match the target chain") || message.includes("Expected Chain ID:")) {
19
+ const match = message.match(/Expected Chain ID:\s*(\d+)/i);
20
+ const targetChainId = match ? Number(match[1]) : void 0;
21
+ return {
22
+ message: `Wallet chain does not match. Please switch your wallet to ${supportedChains?.find((chain) => chain.chainId === targetChainId)?.name ?? (targetChainId ? `chain ${targetChainId}` : "the selected chain")}.`,
23
+ tone: "warning"
24
+ };
25
+ }
26
+ return {
27
+ message,
28
+ tone: "error"
29
+ };
91
30
  }
92
-
93
- // src/deposit/use-wallet-token-balance.ts
94
- var import_web32 = require("@solana/web3.js");
95
- var import_react_query2 = require("@tanstack/react-query");
96
- var import_viem = require("viem");
97
- var import_wagmi = require("wagmi");
98
-
99
- // src/deposit/constants.ts
100
- var DEFAULT_SOLANA_RPC_ENDPOINTS = [
101
- "https://solana-mainnet.g.alchemy.com/v2",
102
- "https://solana-rpc.publicnode.com",
103
- "https://api.mainnet.solana.com",
104
- "https://rpc.ankr.com/solana"
31
+ //#endregion
32
+ //#region src/deposit/constants.ts
33
+ /**
34
+ * Priority-ordered list of Solana RPC endpoints the deposit hooks fall back
35
+ * through when the previous endpoint errors or times out. The partner-supplied
36
+ * `solanaRpcUrl` (when present) is prepended at runtime; these are the
37
+ * always-on safety net so a single provider outage never strands users on a
38
+ * "0 balance" screen.
39
+ */
40
+ const DEFAULT_SOLANA_RPC_ENDPOINTS = [
41
+ "https://solana-mainnet.g.alchemy.com/v2",
42
+ "https://solana-rpc.publicnode.com",
43
+ "https://api.mainnet.solana.com",
44
+ "https://rpc.ankr.com/solana"
105
45
  ];
106
- var DEFAULT_SOLANA_RPC_ENDPOINT = "https://solana-rpc.publicnode.com";
107
- var SVM_CHAIN_IDS = /* @__PURE__ */ new Set([792703809]);
108
- var MULTI_CHAIN_SOLANA_WALLET_NAMES = /* @__PURE__ */ new Set(["Phantom"]);
109
-
110
- // src/deposit/use-svm-address.ts
111
- var import_react = require("react");
112
- var import_wallet_adapter_react = require("@solana/wallet-adapter-react");
113
- function getPhantomProvider() {
114
- var _a, _b;
115
- if (typeof window === "undefined") return void 0;
116
- const w = window;
117
- return (_b = (_a = w.phantom) == null ? void 0 : _a.solana) != null ? _b : w.solana;
46
+ /**
47
+ * Back-compat alias for callers that still want a single default endpoint.
48
+ * New code should prefer the full list and the failover helper.
49
+ */
50
+ const DEFAULT_SOLANA_RPC_ENDPOINT = "https://solana-rpc.publicnode.com";
51
+ const SVM_CHAIN_IDS = /* @__PURE__ */ new Set([792703809]);
52
+ const MULTI_CHAIN_SOLANA_WALLET_NAMES = /* @__PURE__ */ new Set(["Phantom"]);
53
+ //#endregion
54
+ //#region src/deposit/use-svm-address.ts
55
+ function getPhantomProvider$1() {
56
+ if (typeof window === "undefined") return void 0;
57
+ const w = window;
58
+ return w.phantom?.solana ?? w.solana;
118
59
  }
119
60
  function useSvmAddress() {
120
- var _a;
121
- const { publicKey: adapterPublicKey } = (0, import_wallet_adapter_react.useWallet)();
122
- const [phantomAddress, setPhantomAddress] = (0, import_react.useState)(void 0);
123
- (0, import_react.useEffect)(() => {
124
- var _a2;
125
- const provider = getPhantomProvider();
126
- if (!provider) return;
127
- const existing = (_a2 = provider.publicKey) == null ? void 0 : _a2.toBase58();
128
- if (existing) {
129
- setPhantomAddress(existing);
130
- return;
131
- }
132
- provider.connect({ onlyIfTrusted: true }).then((res) => setPhantomAddress(res.publicKey.toString())).catch(() => {
133
- });
134
- }, []);
135
- return (_a = adapterPublicKey == null ? void 0 : adapterPublicKey.toBase58()) != null ? _a : phantomAddress;
61
+ const { publicKey: adapterPublicKey } = (0, _solana_wallet_adapter_react.useWallet)();
62
+ const [phantomAddress, setPhantomAddress] = (0, react.useState)(void 0);
63
+ (0, react.useEffect)(() => {
64
+ const provider = getPhantomProvider$1();
65
+ if (!provider) return;
66
+ const existing = provider.publicKey?.toBase58();
67
+ if (existing) {
68
+ setPhantomAddress(existing);
69
+ return;
70
+ }
71
+ provider.connect({ onlyIfTrusted: true }).then((res) => setPhantomAddress(res.publicKey.toString())).catch(() => {});
72
+ }, []);
73
+ return adapterPublicKey?.toBase58() ?? phantomAddress;
136
74
  }
137
-
138
- // src/deposit/svm-connections.ts
139
- var import_web3 = require("@solana/web3.js");
140
- var import_react4 = require("react");
141
- var import_react_query = require("@tanstack/react-query");
142
-
143
- // src/core/providers/contexts.ts
144
- var import_react2 = require("react");
145
-
146
- // src/core/ui-config/labels.ts
147
- var enUsLabels = {
148
- common: {
149
- close: "Close",
150
- loading: "Loading",
151
- retry: "Retry",
152
- errorPrefix: "Error",
153
- tabsAria: "Tabs",
154
- hiddenTabsAria: "Hidden tabs",
155
- scrollTabsLeft: "Scroll tabs left",
156
- scrollTabsRight: "Scroll tabs right",
157
- selectAria: "Select",
158
- lineChartAria: "Line chart",
159
- candlestickChartAria: "Candlestick chart",
160
- lineChartSeriesSwitchAria: "Chart series switch",
161
- chartSources: (historyVenue, liquidityVenue) => `History: ${historyVenue} \xB7 Resting liquidity: ${liquidityVenue != null ? liquidityVenue : "all venues"}`,
162
- chartBidLiquidity: (amount) => `Bid ${amount}`,
163
- chartAskLiquidity: (amount) => `Ask ${amount}`,
164
- chartEmpty: "No price history in this range",
165
- lineChartSeriesOptionAria: (seriesLabel) => `Show ${seriesLabel} series`,
166
- chartTypeSwitchAria: "Chart type switch",
167
- lineChartType: "Line",
168
- candlestickChartType: "Candlestick"
169
- },
170
- venues: {
171
- polymarket: "Polymarket",
172
- kalshi: "Kalshi",
173
- opinion: "Opinion",
174
- predict: "Predict",
175
- pred: "PRED",
176
- tiprun: "Tip Run",
177
- limitless: "Limitless",
178
- probable: "Probable",
179
- myriad: "Myriad",
180
- hyperliquid: "Hyperliquid",
181
- novig: "Novig",
182
- prophetx: "ProphetX",
183
- betdex: "BETDEX"
184
- },
185
- auth: {
186
- connect: (connectorName) => connectorName ? `Sign in with ${connectorName}` : "Sign in",
187
- signIn: "Sign in",
188
- signingIn: "Signing in...",
189
- signInStatement: "Sign in to AGG",
190
- emailAddress: "Email address",
191
- continue: "Continue",
192
- emailUnavailable: "Email sign-in is currently unavailable.",
193
- signInWithMethod: (methodLabel) => `Sign in with ${methodLabel}`,
194
- socialWalletNotice: "A wallet will automatically be created for you when signing up with a social account.",
195
- learnMore: "Learn more",
196
- dividerOr: "OR",
197
- connectWallet: "Connect wallet",
198
- terms: "Terms",
199
- privacyPolicy: "Privacy Policy",
200
- legalNoticePrefix: "By signing in, you agree to our",
201
- legalNoticeSeparator: "&",
202
- deposit: "Deposit",
203
- depositGeoBlocked: "Deposits are not available in your region.",
204
- balances: "Balances",
205
- viewAll: "View All",
206
- loadingBalances: "Loading balances...",
207
- myProfile: "My Profile",
208
- withdraw: "Withdraw",
209
- disconnect: "Disconnect",
210
- claimWinnings: "Claim Now",
211
- claimableWinningsBadge: (count) => `${count} claimable winning${count === 1 ? "" : "s"}`,
212
- claimableWinningsTooltip: (count) => `${count} position${count === 1 ? "" : "s"} ready to claim`,
213
- walletMenuFor: (profileLabel) => `Profile menu for ${profileLabel}`
214
- },
215
- balanceRefill: {
216
- tabLabel: "Balance management",
217
- title: "Automatic balance refill",
218
- description: "Keep a minimum USDC balance on one network by moving funds from another managed network.",
219
- networkLabel: "Network to maintain",
220
- minimumLabel: "Minimum balance",
221
- refillAmountLabel: "Refill by at least",
222
- dailyCapLabel: "Maximum per day",
223
- maximumFeeLabel: "Maximum fee per refill",
224
- activeLabel: "Automatic refill is active",
225
- pausedLabel: "Automatic refill is paused",
226
- enableAction: "Enable automatic refill",
227
- saveAction: "Save refill settings",
228
- pauseAction: "Pause automatic refill",
229
- resumeAction: "Resume automatic refill",
230
- loading: "Loading refill settings...",
231
- loadError: "Refill settings could not be loaded.",
232
- saveError: "Refill settings could not be saved.",
233
- saved: "Refill settings saved.",
234
- consent: "By enabling, you authorize AGG to move USDC between your managed wallets within these limits.",
235
- lastRefill: "Latest refill",
236
- manageTitle: "Manage balances",
237
- manageDescription: "Set a minimum balance and refill target for each venue. When a venue falls below your minimum, funds are automatically transferred from your balances on other venues to restore it to your refill target.",
238
- noAutoRefill: "No auto-refill",
239
- autoRefill: "Auto-refill",
240
- minimumShortLabel: "Min",
241
- refillToLabel: "Refill to",
242
- unitLabel: "USDC",
243
- resetAction: "Reset",
244
- cancelAction: "Cancel",
245
- saveChangesAction: "Save changes",
246
- modalLoading: "Loading balances...",
247
- modalEmptyTitle: "No supported networks",
248
- modalEmptyDescription: "There are no supported networks to manage yet.",
249
- modalLoadError: "Balances could not be loaded.",
250
- requiredError: "Enter an amount.",
251
- positiveError: "Enter an amount greater than 0.",
252
- precisionError: "Use no more than 6 decimal places.",
253
- relationshipError: "Refill to must be greater than or equal to Min.",
254
- maximumError: (maximum) => `Enter an amount no greater than ${maximum} USDC.`,
255
- createUnavailableError: "Auto-refill cannot be enabled for this network until refill limits are supported by the API.",
256
- expandNetwork: (network) => `Expand ${network} balance settings`,
257
- collapseNetwork: (network) => `Collapse ${network} balance settings`,
258
- statuses: {
259
- reserved: "Funds reserved",
260
- executing: "Refill in progress",
261
- completed: "Refill completed",
262
- failed: "Refill failed"
263
- }
264
- },
265
- deposit: {
266
- title: "Deposit",
267
- back: "Go back",
268
- balancePrefix: "Balance:",
269
- balanceLabel: "Balance",
270
- done: "Done",
271
- methods: {
272
- walletTitle: (walletLabel) => `Use your wallet (${walletLabel})`,
273
- walletDescription: "Deposit instantly from your connected wallet",
274
- cryptoTitle: "Send crypto",
275
- cryptoDescription: "Transfer from any wallet or exchange",
276
- cardTitle: "Deposit with card",
277
- cardDescription: "Buy crypto instantly with your card"
278
- },
279
- walletFlow: {
280
- title: "Use your wallet",
281
- tokenLabel: "Token",
282
- networkLabel: "Network",
283
- amountLabel: "Amount",
284
- max: "Max",
285
- feePrefix: "Fee ~",
286
- confirm: "Confirm Deposit"
287
- },
288
- sendCrypto: {
289
- title: "Send crypto",
290
- tokenLabel: "Supported token",
291
- networkLabel: "Supported network",
292
- depositAddressLabel: "Your deposit address",
293
- copy: "Copy",
294
- copied: "Copied!",
295
- minDepositPrefix: "Min deposit",
296
- warning: "Send only the selected token on the selected network. Wrong token or network may results in permanently lost funds.",
297
- qrPlaceholder: "QR code placeholder",
298
- addressLoadingTitle: "Preparing your deposit address...",
299
- addressLoadingDescription: "We're generating your address, this usually takes a few seconds."
300
- },
301
- cardFlow: {
302
- title: "Buy crypto",
303
- amountLabel: "Amount",
304
- currencyLabel: "Currency",
305
- tokenLabel: "Token",
306
- networkLabel: "Network",
307
- destinationWalletLabel: "Destination wallet",
308
- getQuotes: "Get Quotes",
309
- minRequired: (amount) => `Min required: ${amount}`,
310
- minAmountError: (amount) => `Enter at least ${amount} to continue`,
311
- selectProviderTitle: "Select provider",
312
- feeLabel: "Fee",
313
- providerBadges: {
314
- best: "BEST",
315
- lowKyc: "LOW KYC"
316
- },
317
- successTitle: "Purchase complete",
318
- successDescription: "Your USDC has been successfully added to your balance.",
319
- pendingTitle: (provider) => `Complete your payment on ${provider}`,
320
- pendingDescription: "Once your transaction is finished, your balance may take a few minutes to update. The deposit will appear in your activity once it's successful.",
321
- pendingWalletAddressHelp: "Some providers may ask for a wallet address during checkout, use this one to receive your deposit:",
322
- pendingCopyAddress: "Copy deposit address",
323
- viewActivity: "View Activity",
324
- chooseAnotherProvider: "Choose another provider",
325
- summary: {
326
- provider: "Provider",
327
- fees: "Fees"
328
- },
329
- loadingQuotes: "Finding the best rates...",
330
- errorLoadingQuotesTitle: "Failed to load quotes",
331
- errorLoadingQuotesDescription: "Please try again.",
332
- retry: "Retry",
333
- noQuotes: "No quotes available for this configuration.",
334
- widgetTitle: "Complete Purchase"
335
- },
336
- processingTitle: "Processing deposit",
337
- processingSteps: {
338
- submitting: "Waiting for wallet confirmation",
339
- submitted: "Wallet confirmed",
340
- confirming: "Processing transaction\u2026",
341
- updatingBalance: "Updating balance",
342
- fundsAvailable: "Funds available"
343
- },
344
- successTitle: "Deposit complete",
345
- successDescription: "Your USDC has been successfully added to your balance.",
346
- summary: {
347
- amountReceived: "Amount received",
348
- network: "Network",
349
- fromWallet: "From wallet",
350
- gasFee: "Gas fee"
351
- }
352
- },
353
- withdraw: {
354
- title: "Withdraw",
355
- back: "Go back",
356
- done: "Done",
357
- balancePrefix: "Balance:",
358
- methods: {
359
- walletTitle: "Withdraw to wallet",
360
- walletDescription: "Withdraw funds instantly to your crypto wallet",
361
- cardTitle: "Withdraw with card",
362
- cardDescription: "Withdraw funds to your card"
363
- },
364
- walletFlow: {
365
- title: "Withdraw to wallet",
366
- recipientAddressLabel: "Recipient address",
367
- amountLabel: "Amount",
368
- max: "Max",
369
- tokenLabel: "Receive token",
370
- networkLabel: "Receive network",
371
- estimatedFees: "Est. fees",
372
- networkReserve: "Network reserve",
373
- networkReserveTooltipAria: "Network reserve details",
374
- networkReserveTooltipLineOne: "This reserve helps cover network and bridge costs.",
375
- networkReserveTooltipLineTwo: "Any unused amount stays in your balance.",
376
- youReceive: "You'll receive",
377
- confirm: "Confirm withdrawal",
378
- calculatingFees: "Calculating fees\u2026",
379
- successTitle: "Withdrawal submitted",
380
- successDescription: (tokenSymbol) => `Your ${tokenSymbol} withdrawal is being processed and will arrive shortly.`,
381
- // Terminal-state copy. The success step swaps `successTitle` /
382
- // `successDescription` for these once the lifecycle has reached a
383
- // terminal status — otherwise a finished withdrawal would keep showing
384
- // "submitted / processing" forever and force the user to hard-refresh.
385
- successTitleCompleted: "Withdrawal complete",
386
- successDescriptionCompleted: (tokenSymbol) => `Your ${tokenSymbol} has been successfully sent to your wallet.`,
387
- successTitlePartial: "Withdrawal partially completed",
388
- successDescriptionPartial: () => "Part of your withdrawal was completed successfully, but the remaining funds failed to transfer and were returned to your balance.",
389
- successTitleFailed: "Withdrawal failed",
390
- successDescriptionFailed: () => "We couldn't complete your withdrawal. Your funds were returned to your balance.",
391
- retry: "Try Again",
392
- close: "Close",
393
- loadingDescription: "This may take a few minutes. You can safely close this window and check the status later in your activity.",
394
- summary: {
395
- requestedWithdrawal: "Requested withdrawal",
396
- // Calling this "Amount received" would imply receipt before the
397
- // lifecycle has confirmed. Keep it honest as the submitted amount.
398
- amountReceived: "Amount",
399
- network: "Network",
400
- toWallet: "To wallet",
401
- fees: "Fees"
402
- },
403
- lifecycle: {
404
- pending: "Submitted \u2014 preparing your withdrawal\u2026",
405
- bridging: "Bridging funds across chains\u2026",
406
- transferring: "Transferring to your wallet\u2026",
407
- completed: "Withdrawal complete.",
408
- partial: "Withdrawal partially completed \u2014 see details below.",
409
- failed: "Withdrawal failed.",
410
- loadingSteps: {
411
- preparing: "Preparing funds",
412
- bridging: "Bridging between networks",
413
- sending: "Sending to your wallet",
414
- confirming: "Waiting for network confirmation"
415
- },
416
- steps: {
417
- bridge: (sourceChainName, destChainName) => `Bridging from ${sourceChainName} to ${destChainName}`,
418
- transfer: (destChainName) => `Transferring on ${destChainName}`
419
- }
420
- }
421
- },
422
- cardFlow: {
423
- title: "Sell crypto",
424
- amountLabel: "Amount",
425
- currencyLabel: "Currency",
426
- tokenLabel: "Token",
427
- networkLabel: "Network",
428
- destinationWalletLabel: "Destination wallet",
429
- getQuotes: "Get Quotes",
430
- selectProviderTitle: "Select provider",
431
- feeLabel: "Fee",
432
- providerBadges: {
433
- best: "BEST",
434
- lowKyc: "LOW KYC"
435
- },
436
- successTitle: "Withdrawal complete",
437
- successDescription: "Your USDC has been successfully sent to your wallet.",
438
- summary: {
439
- provider: "Provider",
440
- toWallet: "To wallet",
441
- fees: "Fees"
442
- }
443
- },
444
- summary: {
445
- // Lifecycle-honest: this is the submitted amount, not a guaranteed net
446
- // output.
447
- amountReceived: "Amount",
448
- network: "Network"
449
- }
450
- },
451
- markets: {
452
- emptyNoOpen: "No open markets available.",
453
- emptyResolved: "This event has been resolved."
454
- },
455
- home: {
456
- trending: "Trending",
457
- topMarkets: "Trending",
458
- newMarkets: "New Markets",
459
- categoryTabsAria: "Home page category tabs"
460
- },
461
- userProfile: {
462
- tabs: {
463
- positions: "Positions",
464
- openOrders: "Open limit orders",
465
- activity: "Activity"
466
- },
467
- balance: {
468
- availableBalance: "Balance",
469
- manage: "Manage",
470
- reservedForOpenOrders: (amount) => `${amount} reserved for open orders`,
471
- positionsValue: "Positions Value",
472
- kalshiBalance: "Kalshi Balance",
473
- balanceByNetwork: "Balance by network",
474
- venueAccount: "Venue account",
475
- balanceUnavailable: "Balance unavailable",
476
- paperModeNetwork: "Paper",
477
- paperModeWarning: "Paper mode is enabled. These are simulated funds for paper trading.",
478
- networkTooltipDescription: "Funds are stored across networks. We handle routing automatically, but keeping funds on the right network enables faster trades and lower fees. When depositing, you can choose your preferred network."
479
- },
480
- hostedBetdex: {
481
- manageFunds: "Manage funds",
482
- fromWallet: "Transfer from AGG wallet",
483
- toWallet: "Use my AGG wallet",
484
- transferToBetdex: "Transfer to BETDEX",
485
- deposit: "Deposit USDC",
486
- depositInstructions: {
487
- production: "Send USDC on Solana to this BETDEX account address.",
488
- sandbox: "This is a sandbox account. Use sandbox test funds only."
489
- },
490
- depositAddress: "BETDEX Solana deposit address",
491
- transferUnavailable: "This transfer is temporarily unavailable. Check its status before trying again.",
492
- withdraw: "Withdraw USDC",
493
- withdrawalAmount: "Amount (USDC)",
494
- withdrawalDestination: "Your Solana wallet address",
495
- withdrawalSubmit: "Withdraw from BETDEX",
496
- withdrawalCheck: "Check withdrawal",
497
- withdrawalRetry: "Retry the same withdrawal",
498
- withdrawalNew: "New withdrawal",
499
- withdrawalUnknown: "The response was not confirmed. Your request is saved; retrying checks the same withdrawal.",
500
- withdrawalStatuses: {
501
- processing: "Withdrawal is processing.",
502
- confirmed: "Withdrawal confirmed.",
503
- failed: "Withdrawal failed. Funds are available again.",
504
- flagged: "Withdrawal needs review. Funds remain reserved.",
505
- review_required: "Withdrawal needs review. Funds remain reserved."
506
- },
507
- title: "BETDEX account",
508
- description: "USDC held with BETDEX, separate from your connected wallets.",
509
- sandbox: "Sandbox \xB7 simulated funds",
510
- createAccount: "Set up BETDEX account",
511
- checkSetup: "Check account setup",
512
- provisioning: "Account setup is processing. Check again for confirmation.",
513
- suspended: "This BETDEX account is suspended.",
514
- unavailable: "BETDEX balance is temporarily unavailable.",
515
- provisioningUnavailable: "BETDEX account setup is currently unavailable.",
516
- total: "Total balance",
517
- available: "Available to trade",
518
- reserved: "Reserved for open orders",
519
- refresh: "Refresh account",
520
- creationFailed: "We could not confirm account setup. Refresh to check its status before trying again.",
521
- showActivity: "Show account activity",
522
- hideActivity: "Hide account activity",
523
- activityTitle: "BETDEX account activity",
524
- activityDescription: "Observed ledger entries, not spendable balances or per-order fees. A ledger entry alone does not confirm a withdrawal's completion.",
525
- activityEmpty: "No account activity on this page.",
526
- activityUnavailable: "BETDEX account activity is temporarily unavailable.",
527
- activityPrevious: "Previous activity page",
528
- activityNext: "Next activity page",
529
- activityRefresh: "Refresh activity",
530
- activityCodes: {
531
- Deposit: "Deposit",
532
- Withdrawal: "Withdrawal",
533
- TradeCreation: "Trade created",
534
- TradeVoid: "Trade voided",
535
- TradeWin: "Trade payout",
536
- WalletToWallet: "Wallet transfer",
537
- Commission: "Commission",
538
- MarketPositionVoid: "Position voided",
539
- MarketPositionPayout: "Position payout",
540
- MarketPositionRefund: "Position refund",
541
- ManualDebit: "Manual debit",
542
- ManualCredit: "Manual credit",
543
- SettlementResidual: "Settlement adjustment"
544
- }
545
- },
546
- activity: {
547
- depositType: "Deposit",
548
- redeemType: "Claim",
549
- withdrawalType: "Withdrawal",
550
- claimBreakdownModalAriaLabel: "Claim activity breakdown",
551
- claimBreakdownTransactionLinkAria: (venue) => `Open ${venue} claim transaction`,
552
- redeemStatusTitles: {
553
- pending: "Processing claim",
554
- completed: "Successful claim",
555
- failed: "Failed claim",
556
- canceled: "Canceled claim"
557
- },
558
- depositTitles: {
559
- connectedWallet: "Deposit from connected wallet",
560
- externalWallet: "Deposit from external wallet",
561
- card: "Deposit with card"
562
- },
563
- depositStatusTitles: {
564
- connectedWallet: {
565
- pending: "Processing deposit from connected wallet",
566
- completed: "Successful deposit from connected wallet",
567
- failed: "Failed deposit from connected wallet",
568
- canceled: "Canceled deposit from connected wallet"
569
- },
570
- externalWallet: {
571
- pending: "Processing deposit from external wallet",
572
- completed: "Successful deposit from external wallet",
573
- failed: "Failed deposit from external wallet",
574
- canceled: "Canceled deposit from external wallet"
575
- },
576
- card: {
577
- pending: "Processing deposit with card",
578
- completed: "Successful deposit with card",
579
- failed: "Failed deposit with card",
580
- canceled: "Canceled deposit with card"
581
- }
582
- },
583
- withdrawalStatusTitles: {
584
- pending: "Processing withdrawal",
585
- completed: "Successful withdrawal",
586
- failed: "Failed withdrawal",
587
- canceled: "Canceled withdrawal"
588
- },
589
- // Activity-row title for any withdrawal regardless of lifecycle
590
- // state — render the asset rather than implying success. The
591
- // ActivityRow renders a separate status chip when the row is
592
- // failed. Retained for partner overrides that still want a
593
- // status-agnostic title.
594
- withdrawalTitle: (tokenSymbol) => `Withdraw ${tokenSymbol}`
595
- },
596
- positions: {
597
- activeFilter: "Active",
598
- closedFilter: "Closed",
599
- marketHeader: "Market",
600
- totalTradedHeader: "Total traded",
601
- currentValueHeader: "Current value",
602
- statusHeader: "Status",
603
- resolutionHeader: "Resolution",
604
- payoutHeader: "Payout",
605
- resultHeader: "Result",
606
- amountWonHeader: "Amount won",
607
- claimHeader: "Claim",
608
- claim: "Claim",
609
- claimed: "Claimed",
610
- pending: "Pending",
611
- open: "Open",
612
- won: "Won",
613
- lost: "Lost",
614
- sold: "Sold",
615
- resolved: "Resolved",
616
- marketClosed: "Market closed",
617
- closed: "Closed",
618
- searchPlaceholder: "Search...",
619
- noResults: "No results",
620
- avgPrefix: "avg",
621
- nowPrefix: "now",
622
- finalPrefix: "final"
623
- },
624
- openOrders: {
625
- marketHeader: "Market",
626
- limitPriceHeader: "Limit price",
627
- filledHeader: "Filled",
628
- totalHeader: "Total",
629
- filledShort: "Filled",
630
- totalShort: "Total",
631
- expirationHeader: "Expiration",
632
- buy: "Buy",
633
- sell: "Sell",
634
- nowPrefix: "now",
635
- goodTilCanceled: "Good 'til canceled",
636
- expired: "Expired",
637
- cancel: "Cancel",
638
- pending: "Pending",
639
- cancelOrderAria: (orderId) => `Cancel order ${orderId}`,
640
- loading: "Loading open orders",
641
- loadingMore: "Loading more open orders",
642
- errorTitle: "Unable to load open orders",
643
- errorDescription: "Please try again in a moment.",
644
- emptyTitle: "No open orders",
645
- emptyDescription: "Your open limit orders will appear here."
646
- }
647
- },
648
- eventList: {
649
- matchedTab: "Matched",
650
- allTab: "All",
651
- sortByLabel: "Sort by",
652
- sortBy24hVolume: "24h volume",
653
- sortByTopArbitrage: "Top arbitrage",
654
- sortByTotalVolume: "Total volume",
655
- sortByEndingSoon: "Ending soon",
656
- subcategoriesLabel: "Subcategories",
657
- subcategoriesAll: "All",
658
- subcategoriesOpenAria: "Open subcategories",
659
- subcategoriesCloseAria: "Close subcategories",
660
- loading: (title) => `Loading ${title}`,
661
- tabsAria: (title) => `${title} tabs`,
662
- moreVenuesAria: (count) => `${count} more venues`,
663
- moreVenuesListAria: "More venues",
664
- emptyAria: "No events found",
665
- emptyTitle: "No Events Found",
666
- emptyDescription: "We couldn't find any events matching your filters.\nTry adjusting them or check back later.",
667
- empty: "No events found for this tab.",
668
- errorTitle: "Something went wrong",
669
- errorDescription: "We're having trouble loading data right now.\nTry refreshing or check back later.",
670
- viewResolved: "View resolved",
671
- hideResolved: "Hide resolved"
672
- },
673
- search: {
674
- placeholder: "Search...",
675
- inputAria: "Search markets",
676
- resultsAria: "Search results",
677
- resultAria: (title) => `View ${title}`,
678
- resultsSummary: (countLabel, query) => `${countLabel} search results for "${query}"`,
679
- seeAllResults: "See all results",
680
- loadingResults: "Loading search results",
681
- noResultsTitle: "No markets found",
682
- noResultsDescription: "Check your spelling or try a broader search term."
683
- },
684
- eventItem: {
685
- loading: "Loading market tile",
686
- unavailableAria: "Market tile unavailable",
687
- unavailableTitle: "Market unavailable",
688
- unavailableDescription: "We could not load this market right now.",
689
- arbitrage: "Arbitrage",
690
- volumeSuffix: "Vol.",
691
- marketSingular: "Market",
692
- marketPlural: "Markets",
693
- venueSingular: "Venue",
694
- venuePlural: "Venues",
695
- matched: "Matched",
696
- matchedCount: (count) => `${count} ${count === 1 ? "Match" : "Matches"}`,
697
- remainingMarkets: (count) => `+${count} ${count === 1 ? "market" : "markets"}`,
698
- priceGap: "Price Gap"
699
- },
700
- eventItemDetails: {
701
- chartLegend: "Markets on chart",
702
- selectChartMarkets: "Select an outcome above to show its history",
703
- marketHistoryUnavailable: "History unavailable",
704
- comparisonSource: (venue) => `${venue} \xB7 Outcome probabilities`,
705
- comparisonSeriesCount: (shown, total) => `Showing ${shown} of ${total} series`,
706
- comparisonSeriesPage: (page, total) => `Page ${page} of ${total}`,
707
- comparisonSeriesBudget: (limit) => `Up to ${limit} series are live at once. Change pages to compare others; your selected outcome stays visible.`,
708
- comparisonPreviousSeries: "Previous series",
709
- comparisonNextSeries: "Next series",
710
- comparisonSelectedSeries: "Selected",
711
- comparisonHiddenSeries: "Hidden",
712
- loading: "Loading market details",
713
- unavailableAria: "Market details unavailable",
714
- unavailableTitle: "Market details unavailable",
715
- unavailableDescription: "We could not load this market right now.",
716
- notFoundAria: "Event not found",
717
- notFoundTitle: "Event Not Found",
718
- notFoundDescription: "We couldn't find this event or it may no longer exist.",
719
- chartUnavailableAria: "Chart unavailable",
720
- chartUnavailableTitle: "Chart Unavailable",
721
- chartUnavailableDescription: "We couldn't load live chart data for this event.",
722
- historicalLineChartAria: (title) => `${title} historical line chart`,
723
- outcomeSelectorAria: "Outcome selector",
724
- yes: "Yes",
725
- no: "No",
726
- allTimeRange: "All",
727
- volumeSuffix: "Vol.",
728
- marketSelectPlaceholder: "Select market",
729
- marketSelectSearchPlaceholder: "Search markets...",
730
- marketSelectEmpty: "No markets found",
731
- moreMarkets: "More",
732
- liveMarket: "Live"
733
- },
734
- sportsLive: {
735
- scoreAria: (firstName, firstScore, secondName, secondScore, status) => `${firstName} ${firstScore}, ${secondName} ${secondScore}, ${status}`,
736
- scheduled: "Scheduled",
737
- live: "Live",
738
- paused: "Paused",
739
- finished: "Final",
740
- cancelled: "Cancelled",
741
- postponed: "Postponed",
742
- unknown: "Status unavailable"
743
- },
744
- settlementSummary: {
745
- title: "Settlement differences",
746
- readFullDetails: "Read full details",
747
- showLess: "Show less"
748
- },
749
- leaderboard: {
750
- title: "Leaderboard",
751
- subtitle: (appName, periodLabel) => `Top traders${appName ? ` on ${appName}` : ""} \xB7 ${periodLabel} \xB7 updates every 5 minutes`,
752
- periodLabel: "Period",
753
- rankByLabel: "Rank by",
754
- periods: { "1d": "24h", "7d": "7d", "30d": "30d", all: "All time" },
755
- metrics: { realizedPnl: "Profit & loss", volume: "Volume" },
756
- columns: {
757
- rank: "#",
758
- trader: "Trader",
759
- orders: "Trades",
760
- volume: "Volume",
761
- realizedPnl: "P&L"
762
- },
763
- tradesCount: (count) => `${count} ${count === 1 ? "trade" : "trades"}`,
764
- anonymousTrader: "Anonymous trader",
765
- you: "You",
766
- showMore: "Show more traders",
767
- loadingAria: "Loading leaderboard",
768
- emptyTitle: "No trades in this period yet",
769
- emptyDescription: "Rankings appear once traders place orders. Try a longer period or check back later.",
770
- errorTitle: "Couldn't load the leaderboard",
771
- errorDescription: "Something went wrong on our side. Try again in a moment.",
772
- pnlFootnote: "P&L is realized only: sells and settled markets, before fees. Volume counts both buys and sells. Trades are filled orders. Figures refresh every 5 minutes."
773
- },
774
- marketDetails: {
775
- loading: "Loading market details",
776
- unavailableAria: "Market details unavailable",
777
- unavailableTitle: "Market details unavailable",
778
- unavailableDescription: "We could not load this market right now.",
779
- notFoundAria: "Market not found",
780
- notFoundTitle: "Market Not Found",
781
- notFoundDescription: "We couldn't find this market or it may no longer exist.",
782
- chartUnavailableAria: "Chart unavailable",
783
- chartUnavailableTitle: "Chart Unavailable",
784
- chartUnavailableDescription: "We couldn't load live chart data for this market.",
785
- orderBookEmptyAria: "No orders yet",
786
- orderBookEmptyTitle: "No orders yet",
787
- orderBookEmptyDescription: "Be the first to set the price on this market.",
788
- orderBookResolvedAria: "Market resolved",
789
- orderBookResolvedTitle: "Market Resolved",
790
- orderBookResolvedDescription: "This market has been resolved and is no longer trading.",
791
- orderBookUnavailableAria: "Orderbook unavailable",
792
- orderBookUnavailableTitle: "Orderbook Unavailable",
793
- orderBookUnavailableDescription: "We couldn't load live order data for this market.",
794
- marketOutcomesAria: "Market outcomes",
795
- tabsAria: "Market details tabs",
796
- toggleOpenDetailsAria: (title) => `Open details for ${title}`,
797
- toggleCloseDetailsAria: (title) => `Close details for ${title}`,
798
- loadingOrderbookAria: "Loading orderbook",
799
- loadingOrderbookLabel: "Loading orderbook...",
800
- asks: "Asks",
801
- bids: "Bids",
802
- spread: "Spread",
803
- midPrice: "Mid",
804
- tradePrefix: "Trade",
805
- priceColumn: "Price",
806
- sharesColumn: "Shares",
807
- totalColumn: "Total",
808
- lastPrice: "Last",
809
- graphAria: (title) => `${title} price history`,
810
- outcomeSelectorAria: "Outcome selector",
811
- showOutcomeAria: (label) => `Show ${label} outcome`,
812
- viewResolved: "View resolved",
813
- hideResolved: "Hide resolved",
814
- resolvingBadge: "Resolving",
815
- resolvingTitle: "Resolving market\u2026",
816
- resolvingDescription: "This market has closed. We're waiting for final settlement data and will update the result once it's confirmed on-chain.",
817
- volumeUnavailable: "Volume unavailable",
818
- tabs: {
819
- orderBook: "Order Book",
820
- graph: "Graph",
821
- other: "Other"
822
- },
823
- meta: {
824
- status: "Status",
825
- created: "Created",
826
- opens: "Opens",
827
- closes: "Closes",
828
- markets: "Markets",
829
- unknown: "Unknown",
830
- venueSingular: "Venue",
831
- venuePlural: "Venues",
832
- volumeSuffix: "Vol."
833
- }
834
- },
835
- trading: {
836
- settlementSection: "Settlement",
837
- settlementDifferencesTitle: "Key differences across venues",
838
- settlementFullRulesTitle: "Full rules by venue",
839
- settlementCriticalDifferenceLabel: "Critical",
840
- settlementValueUnavailable: "Not provided",
841
- settlementLoading: "Loading settlement",
842
- settlementDetailsLoadError: "Settlement details could not be loaded.",
843
- settlementDetailsAria: (venueLabel) => `${venueLabel} settlement details`,
844
- settlementShowMoreAria: (ctaLabel, venueLabel) => `${ctaLabel} for ${venueLabel}`,
845
- settlementDescriptionLabel: "Description",
846
- settlementRulesPrimaryLabel: "Resolution rules",
847
- settlementRulesSecondaryLabel: "Additional rules",
848
- settlementPrimaryRulesLabel: "Resolution rules",
849
- settlementEmpty: "No settlement details available.",
850
- disclaimer: "By trading, you agree to the Terms of Use of each exchange.",
851
- geoBlockTermsLink: "Terms of Use",
852
- geoBlockGenericMessage: "None of the venues for this market are available in your region. See ",
853
- geoBlockVenueMessage: (venueLabel) => `Trading on ${venueLabel} is not available in your region. See `,
854
- geoBlockMessageSuffix: " for more information.",
855
- geoBlockModalAriaLabel: "Geo-restricted location",
856
- geoBlockModalTitle: "Trading is not available in your current location",
857
- geoBlockModalDescription: "You appear to be located in a restricted jurisdiction. You can still browse markets in view-only mode or return when you're in a supported region.",
858
- geoBlockModalConfirm: "Confirm",
859
- averagePrice: (value) => `${(value * 100).toLocaleString("en-US", {
860
- minimumFractionDigits: 0,
861
- maximumFractionDigits: 2
862
- })}\xA2 avg. price`,
863
- balance: (value) => `Balance ${value}`,
864
- betdexBalance: (value) => `BETDEX balance ${value}`,
865
- betdexBalanceUnavailable: "BETDEX balance unavailable",
866
- manageBetdexAccount: "Manage BETDEX account",
867
- shares: (value) => `${value.toLocaleString("en-US", {
868
- minimumFractionDigits: Number.isInteger(value) ? 0 : 1,
869
- maximumFractionDigits: 2
870
- })} shares`,
871
- maxShares: "Max",
872
- slippage: (value) => `Slippage: ${value}%`,
873
- editSlippage: (value) => `Edit ${value}`,
874
- collapseSlippage: (value) => `Collapse ${value}`,
875
- resetSlippage: "Auto",
876
- slippageWarning: (value) => `Slippage below ${value}% may prevent your order from executing.`,
877
- slippageLow: (value) => `Slippage below ${value}% may prevent your order from executing.`,
878
- slippageHigh: (value) => `Slippage above ${value}% increases the chance of an unfavorable trade.`,
879
- showAdditionalVenues: (count) => `Show ${count} more venue${count === 1 ? "" : "s"}`,
880
- hideAdditionalVenues: "Hide additional venues",
881
- quoteExpired: "Quote expired. Please refresh.",
882
- orderSubmitted: "Order submitted",
883
- orderPending: "Your order is being processed...",
884
- orderFailed: "Order failed. Please try again.",
885
- orderDisabledEventResolved: "This event has been resolved.",
886
- orderDisabledEventClosed: "This event is no longer accepting orders.",
887
- orderDisabledEventPaused: "Trading is temporarily paused for this event.",
888
- orderDisabledEventUnopened: "Trading has not opened yet for this event.",
889
- orderDisabledEventUnavailable: "Trading is currently unavailable.",
890
- orderDisabledMarketResolved: "This market has been resolved.",
891
- orderDisabledMarketClosed: "This market is no longer accepting orders.",
892
- orderDisabledMarketPaused: "Trading is temporarily paused for this market.",
893
- orderDisabledMarketUnopened: "Trading has not opened yet for this market.",
894
- orderDisabledMarketUnavailable: "Trading is currently unavailable for this market.",
895
- orderDisabledNoMarket: "Select a market to place an order.",
896
- orderDisabledNoOutcome: "Select an outcome to place an order.",
897
- orderDisabledNoEvent: "No event selected.",
898
- insufficientBalance: "Insufficient balance",
899
- insufficientBalanceDetails: "Insufficient balance details",
900
- lowLiquidityWarning: "Your avg. price is higher than the market price due to your order size and available market liquidity.",
901
- lowLiquiditySellWarning: "Your avg. price is lower than the market price due to your order size and available market liquidity.",
902
- refreshQuote: "Refresh Quote",
903
- confirmOrder: "Confirm Order",
904
- withdrawSubmitted: "Withdrawal submitted",
905
- withdrawProcessing: "Your withdrawal is being processed...",
906
- estimatedCost: (value) => `Est. cost ${value}`,
907
- partialFill: (filledSize, requestedSize) => `Only ${filledSize} of ${requestedSize} shares available at this price.`,
908
- insufficientLiquidity: "Not enough liquidity available for this order size.",
909
- noMarketSelected: "Select a market to place an order.",
910
- noOrderbooks: "No live orderbooks are available for this market right now.",
911
- quoteUnavailable: "Quote temporarily unavailable. Please try again.",
912
- quoteBalanceMismatch: "Quote balance mismatch. Try a different amount.",
913
- serviceTemporarilyUnavailable: "Service temporarily unavailable. Please try again in a moment.",
914
- orderDeadlineExpiredBeforeSubmission: "Order deadline expired before submission. Please try again.",
915
- sellNoOnchainPosition: "You don't currently hold any on-chain shares of this outcome. If you just sold or redeemed elsewhere, your position display will refresh shortly \u2014 try again after that.",
916
- venueQuoteUnfillable: "The venue couldn't fill this order at the quoted price right now. Try a smaller size, a higher slippage tolerance, or wait a moment and re-quote.",
917
- venueMinOrderSize: "Order size is below the venue minimum. Try a larger amount.",
918
- sourceBalanceChanged: "Your balance changed since the quote. Refresh and try again, or pick a smaller amount.",
919
- venueMarketResolved: "This market just resolved. Pick a different market or wait for the next round.",
920
- dflowWalletUnverified: "This route is unavailable for your wallet. Check your account connection and try again.",
921
- venueNoQuotePath: "No active quote path for this market right now. Try a different size, or wait a moment and re-quote.",
922
- solanaBlockhashExpired: "Solana transaction expired before submission. Please re-quote and try again.",
923
- venueRateLimited: "The venue is rate-limiting requests right now. Please wait a moment and try again.",
924
- serviceBlockedOrder: "Something on our side blocked this order. Please contact support if it keeps happening \u2014 retrying with the same quote will hit the same issue.",
925
- selectedVenueUnavailable: "The venue you selected is no longer available on this route. Review the updated options and try again.",
926
- engineUnavailable: "The routing engine is temporarily unavailable. Please try again in a moment.",
927
- insufficientInputAmount: "Trade amount is too small to cover bridging and execution costs. Increase your spend or deposit funds on the destination chain.",
928
- minOrderSizeViolated: "Order size is below the venue minimum. Increase your spend.",
929
- minimumOrderAmount: (amount) => `Minimum order is $${amount}`,
930
- insufficientPosition: (totalShares) => `You only have ${totalShares} shares available to sell.`,
931
- insufficientPositionGeneric: "You don't have enough shares to sell.",
932
- insufficientSellDepth: "Not enough bid liquidity on the matched venues for this sell amount.",
933
- noBidsAboveMinPrice: "No venue bids above the minimum price.",
934
- signInToTrade: "Sign in to trade",
935
- deposit: "Deposit",
936
- addFundsToKalshi: "Add funds to Kalshi",
937
- fundKalshiModal: {
938
- ariaLabel: "Fund your Kalshi account",
939
- title: "Fund Your Kalshi Account",
940
- description: "Kalshi manages its own account balances, so funds can't be deposited through agg.market. Add funds directly in Kalshi, then return here to trade with your updated balance.",
941
- howItWorks: "How it works",
942
- kalshiLinkLabel: "Kalshi",
943
- kalshiUrl: "https://kalshi.com",
944
- firstStepPrefix: "Go to",
945
- firstStepSuffix: "and sign in to your account.",
946
- remainingSteps: [
947
- "Click Add Funds.",
948
- "Complete your deposit using your preferred payment method.",
949
- "Return here - your Kalshi balance will be available automatically."
950
- ],
951
- doItLater: "I'll do it later",
952
- done: "Done"
953
- },
954
- kycRequired: "Verify to trade Kalshi",
955
- kycNotVerifiedTooltip: "You have not been verified yet",
956
- kycVerify: "Verify Identity",
957
- kycVerifyModalTitle: "Verify Your Identity",
958
- kycVerifyModalDescription: "To start trading on Kalshi, you'll need to complete identity verification through dFlow. It only takes a few minutes and helps us stay compliant with regulations.",
959
- kycStartVerification: "Start Verification",
960
- kycDoItLater: "Do It Later",
961
- kycSuccessTitle: "Verification successful",
962
- kycSuccessDescription: "Your identity has been confirmed and you now have full access to trade on Kalshi markets.",
963
- kycSuccessDone: "Done",
964
- sharedKyc: {
965
- required: "KYC required",
966
- completeToTrade: "Complete KYC to trade",
967
- checkingStatus: "Checking verification status",
968
- modal: {
969
- ariaLabel: "Identity verification",
970
- title: "Verify Your Identity",
971
- freeDescription: "Complete a one-time identity verification to trade all KYC-required venues.",
972
- pendingTitle: "Verification pending",
973
- pendingDescription: "Your verification is being reviewed. Check back for approval before trading.",
974
- checkStatus: "Check verification status",
975
- startVerification: "Start verification",
976
- doItLater: "Do it later",
977
- successTitle: "Verification successful",
978
- successDescription: "Your identity has been verified. You can now trade on all KYC-required venues.",
979
- done: "Done",
980
- error: "We couldn't confirm your verification."
981
- }
982
- },
983
- connectKalshi: "Connect Kalshi to trade",
984
- connectProphetx: "Connect ProphetX to trade",
985
- manageProphetx: "Manage ProphetX connection",
986
- prophetxFundingNotice: "Manage funds on ProphetX",
987
- prophetxSettlementNotice: "This position settles on ProphetX",
988
- connectNovig: "Connect Novig to trade",
989
- manageNovig: "Manage Novig connection",
990
- novigFundingNotice: "Manage funds on Novig",
991
- novigSettlementNotice: "This position settles on Novig",
992
- requiresKalshiAccount: "Requires Kalshi account",
993
- tradingAccessVenues: "Venues",
994
- tradingAccessAvailable: "Available",
995
- tradingAccessAddKalshiAccount: "Add Kalshi Account",
996
- configureBetdexAccount: "Configure account",
997
- outcome: (label) => `Outcome: ${label}`,
998
- smartRouting: "Smart Routing",
999
- limitRoutingCurrentPrice: (priceLabel, feeLabel) => feeLabel ? `Current ${priceLabel} \xB7 Fee ${feeLabel}` : `Current ${priceLabel}`,
1000
- orderTypeMarket: "Market",
1001
- orderTypeLimit: "Limit",
1002
- orderTypeAria: "Order type",
1003
- limitPrice: "Limit price",
1004
- limitPriceInputAria: "Limit price in cents",
1005
- limitPriceInvalid: "Limit price must be greater than 0 and less than 100.",
1006
- limitPriceAdjusted: (venueLabels, tickSizeCents, originalPriceLabel, side, adjustedPriceLabel) => {
1007
- const venues = venueLabels.length <= 1 ? venueLabels.join("") : venueLabels.length === 2 ? `${venueLabels[0]} and ${venueLabels[1]}` : `${venueLabels.slice(0, -1).join(", ")} and ${venueLabels[venueLabels.length - 1]}`;
1008
- const increment = tickSizeCents === 1 ? "whole cents" : `${tickSizeCents.toLocaleString("en-US", { maximumFractionDigits: 4 })}\xA2 increments`;
1009
- const direction = side === "buy" ? "down" : "up";
1010
- return `${venues} price in ${increment}, so your ${originalPriceLabel} ${side} rounds ${direction} to ${adjustedPriceLabel}`;
1011
- },
1012
- limitPriceDecreaseAria: "Decrease limit price",
1013
- limitPriceIncreaseAria: "Increase limit price",
1014
- expiration: "Expiration",
1015
- expirationGoodTilCanceled: "Good 'til canceled",
1016
- expirationFiveMinutes: "5m",
1017
- expirationOneHour: "1h",
1018
- expirationEndOfDay: "End of day (EST)",
1019
- expirationCustom: "Custom",
1020
- expirationMenuAria: "Choose expiration",
1021
- expirationOptions: "Expiration options",
1022
- expirationDateAria: "Limit order expiration date",
1023
- expirationStartTime: "Start time",
1024
- expirationStartTimeHint: "24-hour format",
1025
- expirationCancel: "Cancel",
1026
- expirationApply: "Apply",
1027
- limitOrderPlacedTitle: "Limit order placed",
1028
- limitOrderPlacedDescription: "Your limit order has been submitted.",
1029
- orderSplitting: "Order Splitting",
1030
- splitOrderDescription: "We split your order for the best price:",
1031
- maximizePayout: "Maximize payout",
1032
- maximizePayoutDescription: "We\u2019ll route your shares for the highest payout:",
1033
- venueInventory: (sharesLabel, priceLabel) => `${sharesLabel} \xB7 ${priceLabel}`,
1034
- insufficientVenueInventory: (sharesLabel, priceLabel) => `Only ${sharesLabel} \xB7 ${priceLabel}`,
1035
- viewAllRoutes: (count) => `View all (${count})`,
1036
- venueUnavailableInRegion: "Unavailable in your region",
1037
- venueTemporarilyUnavailable: "Temporarily unavailable",
1038
- verified: "Verified",
1039
- platformFee: "0% platform fees",
1040
- estimatedFees: "Estimated fees",
1041
- betdexSettlementFeeNotice: "BETDEX charges 1% of net profit per market at settlement, not per fill. The final fee depends on all positions in that market.",
1042
- executionReserve: "Execution reserve",
1043
- executionReserveTooltipAria: "Why funds are reserved",
1044
- executionReserveDescription: "Held for price movement or possible venue charges, not a confirmed fee. Unused funds are returned after execution.",
1045
- estimatedFeesTooltipAria: "Estimated fees breakdown",
1046
- feeBreakdownVenueFees: "Venue",
1047
- feeBreakdownBuilderFee: "Builder",
1048
- feeBreakdownBridgeFees: "Bridging",
1049
- feeBreakdownExecutionGas: "Gas",
1050
- feeBreakdownAggMarket: "agg.market",
1051
- feeBreakdownPlatformFeeBadge: "0% fee",
1052
- feeBreakdownTotalFees: "Total fees",
1053
- toWin: (tab) => tab === "buy" ? "To win" : "Payout",
1054
- buyingOutcome: (label) => `Buying ${label}`,
1055
- sellingOutcome: (label) => `Selling ${label}`,
1056
- findingBestRoute: "Finding the best route...",
1057
- findingBestOdds: "Finding best odds\u2026",
1058
- updatingRoute: "Updating route\u2026",
1059
- refreshingQuotes: "Refreshing quotes\u2026",
1060
- checkingBalance: "Checking balance",
1061
- executingOrder: "Executing order...",
1062
- submittingOrderProgress: "Submitting order...",
1063
- executionOrderSubmitted: "Order submitted",
1064
- orderSubmittedProgress: (orderId) => `Order #${orderId.replace(/^#/, "")} submitted`,
1065
- executingOnVenue: (venueLabel) => `Executing on ${venueLabel}...`,
1066
- venueOrder: (venueLabel) => `${venueLabel} order`,
1067
- settingUpBridge: "Setting up bridging...",
1068
- bridgeSetupComplete: "Bridge setup complete",
1069
- bridgingFundsProgress: "Bridging funds...",
1070
- bridgeComplete: "Bridge complete",
1071
- bridgingFunds: (amount, sourceChain, destinationChain, tokenSymbol = "USDC") => `Bridging ${amount} ${tokenSymbol} from ${sourceChain} to ${destinationChain}...`,
1072
- fundsBridged: (amount, sourceChain, destinationChain, tokenSymbol = "USDC") => `Bridged ${amount} ${tokenSymbol} from ${sourceChain} to ${destinationChain}`,
1073
- depositingFunds: (amount, tokenSymbol, destinationChain) => `Depositing ${amount} ${tokenSymbol} to ${destinationChain}...`,
1074
- fundsDeposited: (amount, tokenSymbol, destinationChain) => `Deposited ${amount} ${tokenSymbol} to ${destinationChain}`,
1075
- fillingOnVenue: (venueLabel) => `Filling on ${venueLabel}...`,
1076
- orderStillSettling: "Still settling. This can take a bit \u2014 check your activity feed. You can keep trading.",
1077
- venueFilledAtPriceWithAmount: (venueLabel, amountLabel, priceLabel) => `${venueLabel} filled ${amountLabel} at ${priceLabel}`,
1078
- executionShares: (value) => `${value} shares`,
1079
- confirmTransactionInWallet: "Confirm the transaction in your wallet",
1080
- executionConfirmed: "Execution confirmed",
1081
- orderSuccessTitle: "Order placed",
1082
- orderSuccessDescription: "Your order has been submitted successfully.",
1083
- orderFailureTitle: "Order failed",
1084
- orderFailureDescription: (message) => message || "Something went wrong. Please try again.",
1085
- orderDone: "Done",
1086
- orderNewTrade: "New trade",
1087
- orderShare: "Share",
1088
- orderRetry: "Try again",
1089
- orderContinue: "Continue",
1090
- orderDismiss: "Dismiss",
1091
- orderRetryVenue: (venueLabel) => `Retry ${venueLabel}`,
1092
- orderPartialFillStatus: (venueLabel) => `${venueLabel} order partially filled`,
1093
- orderVenueUnavailableStatus: (venueLabel) => `${venueLabel} unavailable, your funds have not been charged.`,
1094
- orderMarketResolvedStatus: (venueLabel) => `Market resolved on ${venueLabel} and is no longer accepting orders.`,
1095
- orderSummaryShares: "Shares",
1096
- orderSummaryAvgPrice: "Avg. price",
1097
- orderSummaryEstCost: "Est. cost",
1098
- orderSummaryVenue: "Venue",
1099
- orderAmountFilled: "Amount filled",
1100
- orderAmountFilledOf: (requestedAmount) => `of ${requestedAmount}`,
1101
- orderPayout: "Payout",
1102
- orderFullyFilled: "Order fully filled",
1103
- orderPartiallyFilled: "Order partially filled",
1104
- orderAveragePrice: (priceLabel) => `avg. ${priceLabel}`,
1105
- orderAmount: "Order amount",
1106
- orderLimitPrice: (priceLabel) => `limit ${priceLabel}`,
1107
- limitVenueOrder: (venueLabel) => `${venueLabel} limit order`,
1108
- limitOrderSubmitting: "Submitting limit order...",
1109
- limitOrderSubmitted: "Limit order submitted",
1110
- orderComplete: "Order complete",
1111
- orderFilledAtPrice: (venueLabel, priceLabel) => `${venueLabel} order filled at ${priceLabel}`,
1112
- orderFilledAtPriceWithAmount: (venueLabel, priceLabel, amountLabel) => `${venueLabel} order filled at ${priceLabel} (${amountLabel})`,
1113
- orderPartiallyFilledAtPriceWithAmount: (venueLabel, priceLabel, amountLabel) => `${venueLabel} order partially filled at ${priceLabel} (${amountLabel})`,
1114
- orderSkip: "Skip",
1115
- orderRetryRemaining: "Retry remaining",
1116
- orderTryRemaining: (remainingLabel) => `Try remaining ${remainingLabel}`,
1117
- orderClose: "Close",
1118
- resolvedEarningsTitle: "Your Earnings",
1119
- resolvedResolutionDateLabel: "Resolution date",
1120
- resolvedSharesLabel: "Shares",
1121
- resolvedTotalPayoutLabel: "Total payout",
1122
- claimWinnings: "Claim Winnings",
1123
- boughtOutcomeAtPrice: (label, priceLabel) => `Bought ${label} at ${priceLabel}`,
1124
- soldOutcomeAtPrice: (label, priceLabel) => `Sold ${label} at ${priceLabel}`,
1125
- potentialReturnBonus: (value) => `+${value} Better Payout`,
1126
- potentialReturnBetter: (value) => `+${value} Better`,
1127
- withSmartRouting: "with Smart Routing",
1128
- buy: "Buy",
1129
- sell: "Sell",
1130
- amount: (side) => `${side === "buy" ? "Amount" : "Shares"}`
1131
- },
1132
- onboarding: {
1133
- modal: {
1134
- title: "Onboarding",
1135
- stepHowItWorks: "How it works",
1136
- stepProfileSetup: "Set up your profile",
1137
- stepConnectAccounts: "Connect accounts"
1138
- },
1139
- howItWorks: {
1140
- title: "How it works",
1141
- continue: "Continue",
1142
- features: {
1143
- createAccount: {
1144
- title: "Create Your Account",
1145
- description: "Add a few basic details to set up your account and personalize your experience on the platform."
1146
- },
1147
- linkAccounts: {
1148
- title: "Link Trading Accounts",
1149
- description: "Connect supported exchanges to unlock additional markets and liquidity. Trade across decentralized markets in one interface."
1150
- },
1151
- bestPrices: {
1152
- title: "Best Prices Always",
1153
- description: "Our real-time aggregated orderbook lets you shop lines across exchanges and automatically splits predictions to optimize trades."
1154
- },
1155
- stayInControl: {
1156
- title: "You Stay in Control",
1157
- description: "All trades are executed on the original platform. We never custody funds or move money on your behalf."
1158
- }
1159
- }
1160
- },
1161
- profileSetup: {
1162
- title: "Set up your profile",
1163
- uploadProfilePictureAria: "Upload profile picture",
1164
- profilePreviewAlt: "Profile preview",
1165
- usernameLabel: "Username",
1166
- usernamePlaceholder: "e.g. CryptoJohn",
1167
- continue: "Continue"
1168
- },
1169
- connectAccounts: {
1170
- title: "Connect Accounts",
1171
- connect: "Connect",
1172
- connectAccount: "Connect Account",
1173
- continue: "Continue",
1174
- onchainTitle: "Onchain exchanges",
1175
- onchainMobileTitle: (additionalVenueCount) => `Polymarket +${additionalVenueCount} venues`,
1176
- onchainDescription: "Trade multiple venues with one signature.",
1177
- onchainMobileDescription: "Trade multiple exchanges with one signature",
1178
- kalshiTitle: "US regulated exchanges",
1179
- kalshiMobileTitle: "Kalshi",
1180
- kalshiDescription: "Trade on regulated markets via Kalshi.",
1181
- kalshiMobileDescription: "Connect your Kalshi account"
1182
- },
1183
- connectOnchainModal: {
1184
- ariaLabel: "Connect Onchain Exchanges",
1185
- title: "Connect Onchain Exchanges",
1186
- description: "Sign in with your wallet to trade across supported\nonchain prediction markets.",
1187
- supportedVenuesLabel: "Supported venues:",
1188
- connect: "Sign In with Wallet",
1189
- cancel: "Cancel",
1190
- fallbackError: "Signature declined. Please try again."
1191
- },
1192
- connectProphetxModal: {
1193
- disconnect: "Disconnect ProphetX",
1194
- disconnecting: "Disconnecting\u2026",
1195
- disconnectError: "Could not disconnect ProphetX. Finish any open orders and try again.",
1196
- title: "Connect ProphetX Account",
1197
- description: "Add your ProphetX access key and secret key to trade with your existing account.",
1198
- fundingNotice: "Trades use your ProphetX balance. Deposits, withdrawals, and transfers are managed on ProphetX, outside AGG.",
1199
- instructions: "Create an API key in your ProphetX account settings",
1200
- accessKey: "Access key",
1201
- secretKey: "Secret key",
1202
- verify: "Verify connection",
1203
- verifying: "Verifying\u2026",
1204
- error: "Could not connect to ProphetX. Check your credentials and try again.",
1205
- connected: "Your ProphetX account is connected.",
1206
- done: "Done"
1207
- },
1208
- connectNovigModal: {
1209
- disconnect: "Disconnect Novig",
1210
- disconnecting: "Disconnecting\u2026",
1211
- disconnectError: "Could not disconnect Novig. Finish any open orders and try again.",
1212
- title: "Connect Novig Account",
1213
- description: "Add the trading key ID and private key for your funded Novig subaccount.",
1214
- fundingNotice: "Trades use your Novig balance. Deposits, withdrawals, and transfers are managed on Novig, outside AGG.",
1215
- instructions: "Set up a Novig trading subaccount",
1216
- keyId: "Trading key ID",
1217
- privateKey: "Private key",
1218
- verify: "Verify connection",
1219
- verifying: "Verifying\u2026",
1220
- error: "Could not connect to Novig. Check your credentials and try again.",
1221
- connected: "Your Novig account is connected.",
1222
- done: "Done"
1223
- },
1224
- connectKalshiModal: {
1225
- ariaLabel: "Connect Kalshi Account",
1226
- title: "Connect Kalshi Account",
1227
- description: "You'll generate an API key in Kalshi profile and add it to connect your account. These keys are used only to execute trades on your behalf.",
1228
- stepOne: {
1229
- label: "Step 1",
1230
- title: "Generate a Read/Write API Key in Kalshi",
1231
- instructions: {
1232
- signIn: "1. Sign in to your Kalshi account.",
1233
- goToProfilePrefix: "2. Go to your",
1234
- profileText: "Profile",
1235
- goToProfileSeparator: ":",
1236
- profileUrl: "https://kalshi.com/account/profile",
1237
- clickCreateKeyPrefix: "3. Click",
1238
- createKeyText: "Create Key",
1239
- clickCreateKeySuffix: ".",
1240
- selectPermissionsPrefix: "4. Select",
1241
- readWriteText: "Read/Write",
1242
- selectPermissionsSuffix: " permissions.",
1243
- createKey: "5. Create the key."
1244
- },
1245
- footerLineOne: "Kalshi will display your API Key ID and Private Key.",
1246
- footerLineTwo: "You'll need both for the next step."
1247
- },
1248
- stepTwo: {
1249
- label: "Step 2",
1250
- title: "Paste Your Kalshi API Credentials",
1251
- description: "These credentials are encrypted and used only to execute trades on your behalf. We can't access your funds directly.",
1252
- apiKeyIdLabel: "API Key ID",
1253
- apiKeyIdPlaceholder: "a3f9c1b2-7d4e-4c91-9f2a-8b6e1d3c5a77",
1254
- privateKeyLabel: "Private Key",
1255
- privateKeyPlaceholder: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC..."
1256
- },
1257
- actions: {
1258
- cancel: "Cancel",
1259
- verifyConnection: "Verify Connection"
1260
- },
1261
- success: {
1262
- title: "Kalshi Account Connected",
1263
- description: "Your Kalshi account is now connected to AGG. You can start trading Kalshi markets.",
1264
- done: "Done"
1265
- },
1266
- fallbackError: "Verification failed. Please check your credentials and try again."
1267
- }
1268
- },
1269
- eventMarketPage: {
1270
- loadMoreMarkets: "Load more markets",
1271
- loadingMoreMarkets: "Loading markets\u2026",
1272
- openOrders: {
1273
- title: "Open orders",
1274
- limitPriceHeader: "Limit price",
1275
- filledHeader: "Filled",
1276
- totalHeader: "Total",
1277
- expirationHeader: "Expiration",
1278
- // Abbreviated forms for the stacked mobile card.
1279
- limitShort: "Limit",
1280
- filledShort: "Filled",
1281
- totalShort: "Tot.",
1282
- expirationShort: "Exp."
1283
- },
1284
- unavailableAria: "Event market page unavailable",
1285
- unavailableTitle: "Something went wrong",
1286
- unavailableDescription: "We're having trouble loading this event right now.\nTry refreshing or check back later.",
1287
- loadingSettlementQuestion: "Loading settlement",
1288
- loadingSettlementDifferencesTitle: "Loading settlement",
1289
- loadingSettlementPlaceholder: "Loading",
1290
- tradingResolvedBadge: "Resolved",
1291
- tradingResolvedTitle: "Market resolved",
1292
- tradingResolvedDescription: "Trading has ended for this event. You can review the final result.",
1293
- tradingClosedBadge: "Closed",
1294
- tradingClosedTitle: "Trading closed",
1295
- tradingClosedDescription: "This event is no longer accepting new orders.",
1296
- tradingPausedBadge: "Paused",
1297
- tradingPausedTitle: "Trading paused",
1298
- tradingPausedDescription: "Trading is temporarily unavailable for this event.",
1299
- tradingUnopenedBadge: "Upcoming",
1300
- tradingUnopenedTitle: "Trading not open yet",
1301
- tradingUnopenedDescription: "This event is listed, but trading has not opened yet.",
1302
- tradingUnavailableBadge: "Unavailable",
1303
- tradingUnavailableTitle: "Trading unavailable",
1304
- tradingUnavailableDescription: "Trading is currently unavailable for this event.",
1305
- resolvedAt: (dateLabel) => `Resolved ${dateLabel}`,
1306
- closedAt: (dateLabel) => `Closed ${dateLabel}`,
1307
- opensAt: (dateLabel) => `Opens ${dateLabel}`,
1308
- winningOutcome: (label) => `Winning outcome: ${label}`,
1309
- resolvedOutcome: (label) => `Resolved: ${label}`,
1310
- marketDetailsAriaByDate: (dateLabel) => `Market details for ${dateLabel}`,
1311
- marketDetailsAriaByQuestion: (question) => `Market details for ${question}`,
1312
- recurringCountdownAria: (countdown) => `Current market ends in ${countdown}`,
1313
- goToLive: "Go to live",
1314
- liveMarketUnavailable: "A live market is not available yet",
1315
- sports: {
1316
- summaryAria: "Sports event summary",
1317
- sectionTabsAria: "Sports market sections",
1318
- lineSelectorAria: (marketTitle) => `Select line for ${marketTitle}`,
1319
- previousLineAria: (marketTitle) => `Show previous lines for ${marketTitle}`,
1320
- nextLineAria: (marketTitle) => `Show next lines for ${marketTitle}`,
1321
- comparisonToggleAria: (marketTitle, expanded) => `${expanded ? "Hide" : "Show"} venue comparison for ${marketTitle}`,
1322
- comparisonTitle: "Venue alternatives",
1323
- compareVenues: (count) => `Compare ${count} venues`,
1324
- marketCount: (count) => `${count} markets`,
1325
- venueCount: (count) => `${count} venues`,
1326
- volumeShort: "Vol.",
1327
- totalVolumeShort: "Total Vol.",
1328
- gameStarts: "Game starts",
1329
- moreMarketsTitle: "More markets",
1330
- gameLinesTab: "Game Lines",
1331
- halvesTab: "Halves",
1332
- quartersTab: "Quarters",
1333
- setsTab: "Sets",
1334
- playerPropsTab: "Player Props",
1335
- exactScoreTab: "Exact Score",
1336
- cornersTab: "Corners",
1337
- goalsTab: "Goals",
1338
- assistsTab: "Assists",
1339
- shotsTab: "Shots",
1340
- otherTab: "Other",
1341
- moneylineTitle: "Moneyline",
1342
- spreadTitle: "Spreads",
1343
- totalTitle: "Totals",
1344
- fullPeriod: "Regular time",
1345
- firstHalfPeriod: "1st half",
1346
- secondHalfPeriod: "2nd half",
1347
- quarterOnePeriod: "1st quarter",
1348
- quarterTwoPeriod: "2nd quarter",
1349
- quarterThreePeriod: "3rd quarter",
1350
- quarterFourPeriod: "4th quarter",
1351
- overtimePeriod: "Overtime",
1352
- otherPeriod: "Other",
1353
- loadingTitle: "Loading section",
1354
- loadingDescription: "Fetching the latest markets for this game.",
1355
- emptyTitle: "No markets available",
1356
- emptyDescription: (sectionLabel) => `There are no ${sectionLabel} markets yet.`,
1357
- loadMore: "Load more",
1358
- loadingMore: "Loading more",
1359
- bestPriceBadge: "Best price",
1360
- selectOutcomeAria: (marketTitle, outcomeLabel, priceLabel) => `Select ${outcomeLabel} in ${marketTitle} at ${priceLabel}`
1361
- }
1362
- },
1363
- header: {
1364
- bannerAria: "Site header",
1365
- logoAria: "Home"
1366
- },
1367
- paperTrading: {
1368
- badge: "Paper trading",
1369
- badgeTooltip: "Trade real prediction markets with simulated funds. No real money at risk.",
1370
- profile: {
1371
- buyingPower: "Paper Buying Power",
1372
- earnings: "Paper Earnings",
1373
- earningsCaption: "Keep what you earn"
1374
- },
1375
- onboarding: {
1376
- stepEyebrow: ({ current, total }) => `STEP ${current} OF ${total}`,
1377
- skip: "Skip",
1378
- back: "Back",
1379
- next: "Next",
1380
- // Figma reads "Get Strated" (node 4772:31236) — a typo, not copy.
1381
- done: "Get started",
1382
- realMarkets: {
1383
- title: "Real markets, real prices",
1384
- body: "Follow live prediction markets and trade using real-time market prices from leading venues."
1385
- },
1386
- zeroRisk: {
1387
- title: "Paper trading, zero risk",
1388
- body: ({ amount }) => `Start with ${amount} in simulated funds. No deposit, no real money, and no risk.`
1389
- },
1390
- readyToTrade: {
1391
- title: "You're ready to trade",
1392
- body: "Pick a market, make your prediction, and track your performance."
1393
- }
1394
- }
1395
- },
1396
- notifications: {
1397
- order: {
1398
- filledTitle: "Order filled",
1399
- filledMessage: ({ venueLabel, sideLabel, amountLabel, priceLabel }) => {
1400
- const action = sideLabel ? `${sideLabel} filled` : "Filled";
1401
- const amount = amountLabel ? ` ${amountLabel}` : "";
1402
- const price = priceLabel ? ` at ${priceLabel}` : "";
1403
- const venue = venueLabel ? ` on ${venueLabel}` : "";
1404
- return `${action}${amount}${price}${venue}`.trim();
1405
- },
1406
- partialFilledTitle: "Order partially filled",
1407
- partialFilledMessage: ({ venueLabel, sideLabel, amountLabel, priceLabel }) => {
1408
- const action = sideLabel ? `${sideLabel} partially filled` : "Partially filled";
1409
- const amount = amountLabel ? ` ${amountLabel}` : "";
1410
- const price = priceLabel ? ` at ${priceLabel}` : "";
1411
- const venue = venueLabel ? ` on ${venueLabel}` : "";
1412
- return `${action}${amount}${price}${venue}`.trim();
1413
- },
1414
- cancelledTitle: "Order canceled",
1415
- cancelledMessage: "Your open order was canceled.",
1416
- cancelPendingTitle: "Cancellation submitted",
1417
- cancelPendingMessage: "Your cancellation request is being processed.",
1418
- cancelFailedTitle: "Cancellation failed",
1419
- cancelFailedMessage: (errorReason) => errorReason && errorReason.length > 0 ? errorReason : "Your open order could not be canceled. Please try again.",
1420
- failedTitle: "Order failed",
1421
- failedMessage: (errorReason) => errorReason && errorReason.length > 0 ? errorReason : "Your order could not be completed. Please try again."
1422
- },
1423
- deposit: {
1424
- completedTitle: "Deposit complete",
1425
- completedMessage: ({ amountLabel, tokenLabel }) => {
1426
- if (amountLabel && tokenLabel) return `${amountLabel} ${tokenLabel} added to your balance.`;
1427
- if (tokenLabel) return `Your ${tokenLabel} has been added to your balance.`;
1428
- return "Your funds have been added to your balance.";
1429
- },
1430
- failedTitle: "Deposit failed",
1431
- failedMessage: ({ amountLabel, tokenLabel }) => {
1432
- const what = amountLabel && tokenLabel ? `${amountLabel} ${tokenLabel}` : "deposit";
1433
- return `We couldn't complete your ${what}.`;
1434
- }
1435
- },
1436
- withdrawal: {
1437
- completedTitle: "Withdrawal complete",
1438
- completedMessage: ({ amountLabel, tokenLabel }) => {
1439
- if (amountLabel && tokenLabel) return `${amountLabel} ${tokenLabel} sent to your wallet.`;
1440
- if (tokenLabel) return `Your ${tokenLabel} has been sent to your wallet.`;
1441
- return "Your withdrawal has been sent to your wallet.";
1442
- },
1443
- partialTitle: "Withdrawal partially completed",
1444
- partialMessage: ({ amountLabel, tokenLabel }) => {
1445
- if (amountLabel && tokenLabel)
1446
- return `Part of your ${tokenLabel} was sent. The remainder was returned to your balance.`;
1447
- return "Part of your withdrawal was sent. The remainder was returned to your balance.";
1448
- },
1449
- failedTitle: "Withdrawal failed",
1450
- failedMessage: (errorReason) => errorReason && errorReason.length > 0 ? errorReason : "Your funds have been returned to your balance."
1451
- },
1452
- claim: {
1453
- pendingTitle: "Claim started",
1454
- pendingMessage: "Claiming your winnings.",
1455
- submittedTitle: "Claim submitted",
1456
- submittedMessage: "Your claim was submitted. It may take a little while to finish.",
1457
- successTitle: "Claim complete",
1458
- successMessage: "Your winnings have been claimed.",
1459
- partialTitle: "Claim partially completed",
1460
- partialMessage: (errorReason) => errorReason && errorReason.length > 0 ? errorReason : "Some winnings could not be claimed. Please try again.",
1461
- failedTitle: "Claim failed",
1462
- failedMessage: (errorReason) => errorReason && errorReason.length > 0 ? errorReason : "Your winnings could not be claimed. Please try again.",
1463
- missingOutcomeMessage: "This position is missing claimable outcome data. Please refresh."
1464
- }
1465
- }
1466
- };
1467
- var defaultAggUiLabelsByLocale = {
1468
- "en-US": enUsLabels,
1469
- en: enUsLabels
1470
- };
1471
- var resolveAggUiLabels = (locale) => {
1472
- var _a;
1473
- if (defaultAggUiLabelsByLocale[locale]) {
1474
- return defaultAggUiLabelsByLocale[locale];
1475
- }
1476
- const baseLocale = locale.split("-")[0];
1477
- return (_a = defaultAggUiLabelsByLocale[baseLocale]) != null ? _a : enUsLabels;
1478
- };
1479
-
1480
- // src/core/ui-config/utils.ts
1481
- var DEFAULT_LOCALE = "en-US";
1482
- var createFormatters = (locale) => {
1483
- const number = new Intl.NumberFormat(locale, {
1484
- maximumFractionDigits: 2
1485
- });
1486
- const percent = new Intl.NumberFormat(locale, {
1487
- style: "percent",
1488
- minimumFractionDigits: 0,
1489
- maximumFractionDigits: 0
1490
- });
1491
- const currency = new Intl.NumberFormat(locale, {
1492
- style: "currency",
1493
- currency: "USD",
1494
- maximumFractionDigits: 2
1495
- });
1496
- const compactCurrency = new Intl.NumberFormat(locale, {
1497
- style: "currency",
1498
- currency: "USD",
1499
- notation: "compact",
1500
- maximumFractionDigits: 0
1501
- });
1502
- const date = new Intl.DateTimeFormat(locale, {
1503
- month: "long",
1504
- day: "numeric",
1505
- year: "numeric"
1506
- });
1507
- return {
1508
- formatNumber: (value) => number.format(value),
1509
- formatPercent: (value) => percent.format(value),
1510
- formatCurrency: (value) => currency.format(value),
1511
- formatCompactCurrency: (value) => compactCurrency.format(value),
1512
- formatDate: (value) => date.format(value)
1513
- };
1514
- };
1515
- var defaultFormatters = createFormatters(DEFAULT_LOCALE);
1516
- var defaultAggUiSearchConfig = {
1517
- value: "",
1518
- result: null,
1519
- isShowingAllResults: false
1520
- };
1521
- var defaultAggUiConfig = {
1522
- enableLogs: false,
1523
- enableWebsocketsLogs: false,
1524
- enableDebug: false,
1525
- general: {
1526
- locale: DEFAULT_LOCALE,
1527
- theme: "light",
1528
- rootClassName: "",
1529
- labels: resolveAggUiLabels(DEFAULT_LOCALE)
1530
- },
1531
- features: {
1532
- enableAnimations: true,
1533
- enableLiveUpdates: true,
1534
- enablePriceGap: false,
1535
- showFeesBreakdown: false,
1536
- enableGradients: false,
1537
- enableVenueEventDiscoveryFilters: false,
1538
- enableEventDiscoveryUrlPersistence: false,
1539
- enableNotifications: true,
1540
- showLimitOrders: false,
1541
- showSportsMarkets: false
1542
- },
1543
- market: {
1544
- arbitrageThreshold: 0,
1545
- maxMidpointIdsPerRequest: 75
1546
- },
1547
- chart: {
1548
- defaultChartTimeRange: "1D",
1549
- selectedChartTimeRange: "1D",
1550
- setSelectedChartTimeRange: () => {
1551
- }
1552
- },
1553
- formatting: defaultFormatters,
1554
- search: defaultAggUiSearchConfig,
1555
- trading: {
1556
- executionMode: "live"
1557
- }
1558
- };
1559
-
1560
- // src/core/providers/contexts.ts
1561
- var AggClientContext = (0, import_react2.createContext)(null);
1562
- var AggUiContext = (0, import_react2.createContext)(defaultAggUiConfig);
1563
- var AggExecutionModeContext = (0, import_react2.createContext)(null);
1564
- var AggLabelsContext = (0, import_react2.createContext)(defaultAggUiConfig.general.labels);
1565
- var AggAuthContext = (0, import_react2.createContext)(null);
1566
- var AggBalanceContext = (0, import_react2.createContext)(null);
1567
-
1568
- // src/execution/query-keys.ts
1569
- var executionKeys = {
1570
- all: () => ["execution"],
1571
- balances: (mode, custody) => custody && custody !== "managed" ? ["execution", "balances", mode != null ? mode : "live", custody] : mode ? ["execution", "balances", mode] : ["execution", "balances"],
1572
- positions: (cursor, limit, status, mode) => mode ? ["execution", "positions", cursor != null ? cursor : null, limit != null ? limit : null, status != null ? status : null, mode] : ["execution", "positions", cursor != null ? cursor : null, limit != null ? limit : null, status != null ? status : null],
1573
- positionsPrefix: () => ["execution", "positions"],
1574
- claimablePositionsCount: () => ["execution", "positions", "claimable-count"],
1575
- /**
1576
- * @deprecated Misnomer — claimable (redeemStatus "eligible") groups live in
1577
- * the ACTIVE bucket, not closed (won-but-unclaimed stays Active until a
1578
- * redeem stamps redeemedAt). Same key value as `claimablePositionsCount`;
1579
- * kept so existing invalidation call sites keep matching.
1580
- */
1581
- claimableClosedPositionsCount: () => ["execution", "positions", "claimable-count"],
1582
- orders: (status, cursor, limit) => ["execution", "orders", status != null ? status : null, cursor != null ? cursor : null, limit != null ? limit : null],
1583
- ordersPrefix: () => ["execution", "orders"],
1584
- depositAddresses: () => ["execution", "deposit-addresses"],
1585
- balanceRefillPolicies: () => ["execution", "balance-refill-policies"]
1586
- };
1587
-
1588
- // src/execution/balance-invalidation.ts
1589
- var balanceQueryKeys = {
1590
- execution: () => executionKeys.balances(),
1591
- // Kept as an alias for backward compatibility with existing callers.
1592
- // The balance provider now uses the same canonical execution balances key.
1593
- provider: (mode) => executionKeys.balances(mode),
1594
- venue: (venuesKey) => ["venue-balances", venuesKey],
1595
- venuePrefix: () => ["venue-balances"]
1596
- };
1597
- var invalidateBalanceQueries = (queryClient, options) => {
1598
- var _a;
1599
- const refetchType = (_a = options == null ? void 0 : options.refetchType) != null ? _a : "active";
1600
- const executionKey = balanceQueryKeys.execution();
1601
- const providerKey = balanceQueryKeys.provider();
1602
- queryClient.invalidateQueries({
1603
- queryKey: executionKey,
1604
- refetchType
1605
- });
1606
- const isProviderKeyDistinct = providerKey.length !== executionKey.length || providerKey.some((segment, index) => segment !== executionKey[index]);
1607
- if (isProviderKeyDistinct) {
1608
- queryClient.invalidateQueries({
1609
- queryKey: providerKey,
1610
- refetchType
1611
- });
1612
- }
1613
- queryClient.invalidateQueries({
1614
- queryKey: balanceQueryKeys.venuePrefix(),
1615
- refetchType
1616
- });
1617
- queryClient.invalidateQueries({ queryKey: ["agg", "hosted-venue-account"], refetchType });
1618
- };
1619
- var invalidatePositionQueries = (queryClient, options) => {
1620
- var _a;
1621
- queryClient.invalidateQueries({
1622
- queryKey: executionKeys.positionsPrefix(),
1623
- refetchType: (_a = options == null ? void 0 : options.refetchType) != null ? _a : "active"
1624
- });
1625
- };
1626
- var userActivityQueryKeys = {
1627
- all: () => ["user-activity"],
1628
- feed: (type, limit) => ["user-activity", type != null ? type : "all", limit != null ? limit : 50]
1629
- };
1630
- var invalidateUserActivityQueries = (queryClient, options) => {
1631
- var _a;
1632
- const strategy = (_a = options == null ? void 0 : options.strategy) != null ? _a : "remove";
1633
- if (strategy === "remove") {
1634
- queryClient.removeQueries({ queryKey: userActivityQueryKeys.all() });
1635
- return;
1636
- }
1637
- queryClient.invalidateQueries({
1638
- queryKey: userActivityQueryKeys.all(),
1639
- refetchType: "all"
1640
- });
1641
- };
1642
- var invalidateUserMoneyState = (queryClient, options) => {
1643
- invalidateBalanceQueries(queryClient, { refetchType: options == null ? void 0 : options.refetchType });
1644
- invalidatePositionQueries(queryClient, { refetchType: options == null ? void 0 : options.refetchType });
1645
- invalidateUserActivityQueries(queryClient, { strategy: options == null ? void 0 : options.activityStrategy });
1646
- };
1647
-
1648
- // src/core/providers/hooks.ts
1649
- var import_react3 = require("react");
1650
- var useAggClient = () => {
1651
- const client = (0, import_react3.useContext)(AggClientContext);
1652
- if (!client) {
1653
- throw new Error("useAggClient must be used within an <AggProvider>");
1654
- }
1655
- return client;
1656
- };
1657
- var useOptionalAggClient = () => {
1658
- return (0, import_react3.useContext)(AggClientContext);
1659
- };
1660
- var useAggUiConfig = () => {
1661
- return (0, import_react3.useContext)(AggUiContext);
1662
- };
1663
- var useAggAuthContext = () => {
1664
- const context = (0, import_react3.useContext)(AggAuthContext);
1665
- if (!context) {
1666
- throw new Error("useAggAuthContext must be used within an <AggProvider>");
1667
- }
1668
- return context;
1669
- };
1670
- var useAggAuthState = useAggAuthContext;
1671
- var useAggBalanceContext = () => {
1672
- const context = (0, import_react3.useContext)(AggBalanceContext);
1673
- if (!context) {
1674
- throw new Error("useAggBalanceContext must be used within an <AggProvider>");
1675
- }
1676
- return context;
1677
- };
1678
- var useAggBalanceState = useAggBalanceContext;
1679
-
1680
- // src/deposit/svm-connections.ts
75
+ //#endregion
76
+ //#region src/deposit/svm-connections.ts
77
+ /**
78
+ * Resolves the priority-ordered list of Solana RPC URLs to try, with the
79
+ * partner-supplied URL first (when present) and the built-in defaults as a
80
+ * safety net. De-duplicated so we never hit the same endpoint twice in a
81
+ * single failover round.
82
+ */
1681
83
  function resolveSvmRpcEndpoints(partnerUrl) {
1682
- const seen = /* @__PURE__ */ new Set();
1683
- const out = [];
1684
- const candidates = partnerUrl ? [partnerUrl, ...DEFAULT_SOLANA_RPC_ENDPOINTS] : DEFAULT_SOLANA_RPC_ENDPOINTS;
1685
- for (const url of candidates) {
1686
- if (!seen.has(url)) {
1687
- seen.add(url);
1688
- out.push(url);
1689
- }
1690
- }
1691
- return out;
84
+ const seen = /* @__PURE__ */ new Set();
85
+ const out = [];
86
+ const candidates = partnerUrl ? [partnerUrl, ...DEFAULT_SOLANA_RPC_ENDPOINTS] : DEFAULT_SOLANA_RPC_ENDPOINTS;
87
+ for (const url of candidates) if (!seen.has(url)) {
88
+ seen.add(url);
89
+ out.push(url);
90
+ }
91
+ return out;
1692
92
  }
93
+ /**
94
+ * Returns a memoized list of `Connection` instances, one per resolved RPC
95
+ * endpoint, in failover priority order. The primary connection is
96
+ * `connections[0]`; subsequent entries are tried only when an operation
97
+ * against the previous entry throws.
98
+ *
99
+ * `new Connection(...)` is lazy (no socket is opened), so eagerly building
100
+ * fallback connections has negligible cost.
101
+ */
1693
102
  function useSvmConnections(commitment) {
1694
- const { solanaRpcUrl } = useAggUiConfig();
1695
- const client = useOptionalAggClient();
1696
- const { data: tokenData } = (0, import_react_query.useQuery)({
1697
- queryKey: ["alchemy-rpc-token"],
1698
- queryFn: () => client ? client.getRpcToken() : Promise.resolve({ token: "", expiresAt: 0 }),
1699
- enabled: !!client,
1700
- staleTime: 50 * 60 * 1e3
1701
- // 50 minutes cache (token is valid for 1h)
1702
- });
1703
- const token = tokenData == null ? void 0 : tokenData.token;
1704
- return (0, import_react4.useMemo)(() => {
1705
- const endpoints = resolveSvmRpcEndpoints(solanaRpcUrl);
1706
- return endpoints.map((url) => {
1707
- const headers = {};
1708
- if (url.includes("alchemy.com") && token) {
1709
- headers["Authorization"] = `Bearer ${token}`;
1710
- }
1711
- return new import_web3.Connection(url, {
1712
- commitment,
1713
- httpHeaders: Object.keys(headers).length > 0 ? headers : void 0
1714
- });
1715
- });
1716
- }, [solanaRpcUrl, commitment, token]);
103
+ const { solanaRpcUrl } = require_use_sync_balances.useAggUiConfig();
104
+ const client = require_use_sync_balances.useOptionalAggClient();
105
+ const { data: tokenData } = (0, _tanstack_react_query.useQuery)({
106
+ queryKey: ["alchemy-rpc-token"],
107
+ queryFn: () => client ? client.getRpcToken() : Promise.resolve({
108
+ token: "",
109
+ expiresAt: 0
110
+ }),
111
+ enabled: !!client,
112
+ staleTime: 3e6
113
+ });
114
+ const token = tokenData?.token;
115
+ return (0, react.useMemo)(() => {
116
+ return resolveSvmRpcEndpoints(solanaRpcUrl).map((url) => {
117
+ const headers = {};
118
+ if (url.includes("alchemy.com") && token) headers["Authorization"] = `Bearer ${token}`;
119
+ return new _solana_web3_js.Connection(url, {
120
+ commitment,
121
+ httpHeaders: Object.keys(headers).length > 0 ? headers : void 0
122
+ });
123
+ });
124
+ }, [
125
+ solanaRpcUrl,
126
+ commitment,
127
+ token
128
+ ]);
1717
129
  }
1718
- function withSvmFailover(connections, operation) {
1719
- return __async(this, null, function* () {
1720
- if (connections.length === 0) {
1721
- throw new Error("No Solana RPC connections configured");
1722
- }
1723
- let lastError;
1724
- for (const connection of connections) {
1725
- try {
1726
- return yield operation(connection);
1727
- } catch (err) {
1728
- lastError = err;
1729
- }
1730
- }
1731
- throw lastError instanceof Error ? lastError : new Error(typeof lastError === "string" ? lastError : "All Solana RPC endpoints failed");
1732
- });
130
+ /**
131
+ * Runs `operation` against the first connection that returns successfully.
132
+ * Connections are tried in priority order; on any thrown error (network
133
+ * failure, timeout, RPC error) we advance to the next.
134
+ *
135
+ * The happy path issues exactly one underlying RPC call — we only fan out
136
+ * when the previous endpoint failed. If every endpoint fails, the last
137
+ * error is rethrown so the caller (and `useQuery`) sees the real cause.
138
+ */
139
+ async function withSvmFailover(connections, operation) {
140
+ if (connections.length === 0) throw new Error("No Solana RPC connections configured");
141
+ let lastError;
142
+ for (const connection of connections) try {
143
+ return await operation(connection);
144
+ } catch (err) {
145
+ lastError = err;
146
+ }
147
+ throw lastError instanceof Error ? lastError : new Error(typeof lastError === "string" ? lastError : "All Solana RPC endpoints failed");
1733
148
  }
1734
-
1735
- // src/deposit/use-wallet-token-balance.ts
1736
- var ERC20_BALANCE_OF_ABI = [
1737
- {
1738
- name: "balanceOf",
1739
- type: "function",
1740
- stateMutability: "view",
1741
- inputs: [{ name: "account", type: "address" }],
1742
- outputs: [{ name: "", type: "uint256" }]
1743
- }
1744
- ];
1745
- var SVM_BALANCE_RPC_TIMEOUT_MS = 2e3;
1746
- var SVM_BALANCE_STALE_TIME_MS = 3e4;
149
+ //#endregion
150
+ //#region src/deposit/use-wallet-token-balance.ts
151
+ const ERC20_BALANCE_OF_ABI = [{
152
+ name: "balanceOf",
153
+ type: "function",
154
+ stateMutability: "view",
155
+ inputs: [{
156
+ name: "account",
157
+ type: "address"
158
+ }],
159
+ outputs: [{
160
+ name: "",
161
+ type: "uint256"
162
+ }]
163
+ }];
164
+ const SVM_BALANCE_RPC_TIMEOUT_MS = 2e3;
165
+ const SVM_BALANCE_STALE_TIME_MS = 3e4;
1747
166
  var SvmBalanceTimeoutError = class extends Error {
1748
- constructor() {
1749
- super("Solana balance request timed out");
1750
- this.name = "SvmBalanceTimeoutError";
1751
- }
167
+ constructor() {
168
+ super("Solana balance request timed out");
169
+ this.name = "SvmBalanceTimeoutError";
170
+ }
1752
171
  };
1753
172
  function withTimeout(promise, timeoutMs) {
1754
- return new Promise((resolve, reject) => {
1755
- const timer = setTimeout(() => reject(new SvmBalanceTimeoutError()), timeoutMs);
1756
- promise.then(
1757
- (value) => {
1758
- clearTimeout(timer);
1759
- resolve(value);
1760
- },
1761
- (err) => {
1762
- clearTimeout(timer);
1763
- reject(err);
1764
- }
1765
- );
1766
- });
173
+ return new Promise((resolve, reject) => {
174
+ const timer = setTimeout(() => reject(new SvmBalanceTimeoutError()), timeoutMs);
175
+ promise.then((value) => {
176
+ clearTimeout(timer);
177
+ resolve(value);
178
+ }, (err) => {
179
+ clearTimeout(timer);
180
+ reject(err);
181
+ });
182
+ });
1767
183
  }
1768
- function fetchSvmTokenBalance(connections, owner, mint) {
1769
- return __async(this, null, function* () {
1770
- var _a, _b, _c;
1771
- const accounts = yield withSvmFailover(
1772
- connections,
1773
- (connection) => withTimeout(
1774
- connection.getParsedTokenAccountsByOwner(owner, { mint }),
1775
- SVM_BALANCE_RPC_TIMEOUT_MS
1776
- )
1777
- );
1778
- let total = 0;
1779
- for (const entry of accounts.value) {
1780
- const uiAmount = (_c = (_b = (_a = entry.account.data.parsed) == null ? void 0 : _a.info) == null ? void 0 : _b.tokenAmount) == null ? void 0 : _c.uiAmount;
1781
- if (typeof uiAmount === "number" && Number.isFinite(uiAmount)) {
1782
- total += uiAmount;
1783
- }
1784
- }
1785
- return total;
1786
- });
184
+ /**
185
+ * Reads the connected wallet's SPL token balance for `mint`.
186
+ *
187
+ * A Solana wallet routinely owns multiple SPL accounts for the same mint —
188
+ * the canonical ATA plus dust accounts created by dApps (each with their
189
+ * own `closeAuthority`). The RPC does not order them deterministically, so
190
+ * picking `accounts.value[0]` and calling `getTokenAccountBalance` for it
191
+ * (the previous implementation) frequently returned 0 even when the user
192
+ * was funded on a sibling account. Phantom/Solflare display the sum across
193
+ * every account on the mint; we match that here.
194
+ *
195
+ * Uses `getParsedTokenAccountsByOwner` so `uiAmount` arrives on the first
196
+ * response — one RPC round-trip per refetch instead of two. The per-endpoint
197
+ * timeout caps how long we wait before falling over to the next RPC.
198
+ */
199
+ async function fetchSvmTokenBalance(connections, owner, mint) {
200
+ const accounts = await withSvmFailover(connections, (connection) => withTimeout(connection.getParsedTokenAccountsByOwner(owner, { mint }), SVM_BALANCE_RPC_TIMEOUT_MS));
201
+ let total = 0;
202
+ for (const entry of accounts.value) {
203
+ const uiAmount = entry.account.data.parsed?.info?.tokenAmount?.uiAmount;
204
+ if (typeof uiAmount === "number" && Number.isFinite(uiAmount)) total += uiAmount;
205
+ }
206
+ return total;
1787
207
  }
1788
- function useWalletTokenBalance({
1789
- isOpen = true,
1790
- chainId,
1791
- tokenAddress,
1792
- decimals,
1793
- svmAddress
1794
- }) {
1795
- var _a;
1796
- const isSvm = chainId !== void 0 && SVM_CHAIN_IDS.has(chainId);
1797
- const { address: evmAddress } = (0, import_wagmi.useAccount)();
1798
- const evmEnabled = isOpen && !isSvm && !!chainId && !!tokenAddress && !!evmAddress && decimals !== void 0;
1799
- const { data: rawEvmBalance, isLoading: evmLoading } = (0, import_wagmi.useReadContract)({
1800
- address: tokenAddress,
1801
- chainId,
1802
- abi: ERC20_BALANCE_OF_ABI,
1803
- functionName: "balanceOf",
1804
- args: evmAddress ? [evmAddress] : void 0,
1805
- query: { enabled: evmEnabled, staleTime: 0, refetchOnMount: true }
1806
- });
1807
- const detectedSvmAddress = useSvmAddress();
1808
- const resolvedSvmAddress = detectedSvmAddress != null ? detectedSvmAddress : svmAddress;
1809
- const svmEnabled = isOpen && isSvm && !!resolvedSvmAddress && !!tokenAddress;
1810
- const svmConnections = useSvmConnections();
1811
- const svmQuery = (0, import_react_query2.useQuery)({
1812
- queryKey: ["svm-token-balance", resolvedSvmAddress != null ? resolvedSvmAddress : null, tokenAddress != null ? tokenAddress : null, isOpen],
1813
- enabled: svmEnabled,
1814
- staleTime: SVM_BALANCE_STALE_TIME_MS,
1815
- retry: false,
1816
- refetchOnWindowFocus: "always",
1817
- refetchOnReconnect: "always",
1818
- queryFn: () => __async(null, null, function* () {
1819
- if (!resolvedSvmAddress || !tokenAddress) return 0;
1820
- const owner = new import_web32.PublicKey(resolvedSvmAddress);
1821
- const mint = new import_web32.PublicKey(tokenAddress);
1822
- return yield fetchSvmTokenBalance(svmConnections, owner, mint);
1823
- })
1824
- });
1825
- if (isSvm) {
1826
- const awaitingSelection2 = isOpen && !!chainId && !tokenAddress;
1827
- return {
1828
- balance: (_a = svmQuery.data) != null ? _a : 0,
1829
- isLoading: awaitingSelection2 || svmQuery.isLoading || svmQuery.isFetching
1830
- };
1831
- }
1832
- const evmBalance = rawEvmBalance !== void 0 && decimals !== void 0 ? Number((0, import_viem.formatUnits)(rawEvmBalance, decimals)) : 0;
1833
- const awaitingSelection = isOpen && !!chainId && !tokenAddress;
1834
- return { balance: evmBalance, isLoading: awaitingSelection || evmLoading };
208
+ /**
209
+ * Reads the connected wallet's on-chain balance for a given token on a given chain.
210
+ * Dispatches to wagmi (EVM) or @solana/web3.js (SVM) based on chainId.
211
+ */
212
+ function useWalletTokenBalance({ isOpen = true, chainId, tokenAddress, decimals, svmAddress }) {
213
+ const isSvm = chainId !== void 0 && SVM_CHAIN_IDS.has(chainId);
214
+ const { address: evmAddress } = (0, wagmi.useAccount)();
215
+ const { data: rawEvmBalance, isLoading: evmLoading } = (0, wagmi.useReadContract)({
216
+ address: tokenAddress,
217
+ chainId,
218
+ abi: ERC20_BALANCE_OF_ABI,
219
+ functionName: "balanceOf",
220
+ args: evmAddress ? [evmAddress] : void 0,
221
+ query: {
222
+ enabled: isOpen && !isSvm && !!chainId && !!tokenAddress && !!evmAddress && decimals !== void 0,
223
+ staleTime: 0,
224
+ refetchOnMount: true
225
+ }
226
+ });
227
+ const resolvedSvmAddress = useSvmAddress() ?? svmAddress;
228
+ const svmEnabled = isOpen && isSvm && !!resolvedSvmAddress && !!tokenAddress;
229
+ const svmConnections = useSvmConnections();
230
+ const svmQuery = (0, _tanstack_react_query.useQuery)({
231
+ queryKey: [
232
+ "svm-token-balance",
233
+ resolvedSvmAddress ?? null,
234
+ tokenAddress ?? null,
235
+ isOpen
236
+ ],
237
+ enabled: svmEnabled,
238
+ staleTime: SVM_BALANCE_STALE_TIME_MS,
239
+ retry: false,
240
+ refetchOnWindowFocus: "always",
241
+ refetchOnReconnect: "always",
242
+ queryFn: async () => {
243
+ if (!resolvedSvmAddress || !tokenAddress) return 0;
244
+ const owner = new _solana_web3_js.PublicKey(resolvedSvmAddress);
245
+ const mint = new _solana_web3_js.PublicKey(tokenAddress);
246
+ return await fetchSvmTokenBalance(svmConnections, owner, mint);
247
+ }
248
+ });
249
+ if (isSvm) {
250
+ const awaitingSelection = isOpen && !!chainId && !tokenAddress;
251
+ return {
252
+ balance: svmQuery.data ?? 0,
253
+ isLoading: awaitingSelection || svmQuery.isLoading || svmQuery.isFetching
254
+ };
255
+ }
256
+ return {
257
+ balance: rawEvmBalance !== void 0 && decimals !== void 0 ? Number((0, viem.formatUnits)(rawEvmBalance, decimals)) : 0,
258
+ isLoading: isOpen && !!chainId && !tokenAddress || evmLoading
259
+ };
1835
260
  }
1836
-
1837
- // src/deposit/use-wallet-send-token.ts
1838
- var import_react5 = require("react");
1839
- var import_viem2 = require("viem");
1840
- var import_wagmi2 = require("wagmi");
1841
- var import_wallet_adapter_react2 = require("@solana/wallet-adapter-react");
1842
- var import_web33 = require("@solana/web3.js");
1843
- function getPhantomProvider2() {
1844
- var _a, _b;
1845
- if (typeof window === "undefined") return void 0;
1846
- const w = window;
1847
- return (_b = (_a = w.phantom) == null ? void 0 : _a.solana) != null ? _b : w.solana;
261
+ //#endregion
262
+ //#region src/deposit/use-wallet-send-token.ts
263
+ function getPhantomProvider() {
264
+ if (typeof window === "undefined") return void 0;
265
+ const w = window;
266
+ return w.phantom?.solana ?? w.solana;
1848
267
  }
1849
- var ERC20_TRANSFER_ABI = [
1850
- {
1851
- constant: false,
1852
- inputs: [
1853
- { name: "to", type: "address" },
1854
- { name: "amount", type: "uint256" }
1855
- ],
1856
- name: "transfer",
1857
- outputs: [{ name: "", type: "bool" }],
1858
- type: "function"
1859
- }
1860
- ];
268
+ const ERC20_TRANSFER_ABI = [{
269
+ constant: false,
270
+ inputs: [{
271
+ name: "to",
272
+ type: "address"
273
+ }, {
274
+ name: "amount",
275
+ type: "uint256"
276
+ }],
277
+ name: "transfer",
278
+ outputs: [{
279
+ name: "",
280
+ type: "bool"
281
+ }],
282
+ type: "function"
283
+ }];
284
+ /**
285
+ * Dual-chain sendToken implementation:
286
+ * - EVM: uses wagmi writeContract to call ERC-20 transfer
287
+ * - SVM: uses wallet-adapter (or injected Phantom) to submit an SPL TransferChecked tx
288
+ *
289
+ * Matches the `WalletActions.sendToken` signature so it can be passed into
290
+ * `AggProvider` config directly, or composed inside `useDepositFlow`.
291
+ */
1861
292
  function useWalletSendToken() {
1862
- const svmConnections = useSvmConnections("confirmed");
1863
- const { writeContractAsync } = (0, import_wagmi2.useWriteContract)();
1864
- const { publicKey, sendTransaction } = (0, import_wallet_adapter_react2.useWallet)();
1865
- return (0, import_react5.useCallback)(
1866
- (params) => __async(null, null, function* () {
1867
- const isSvm = SVM_CHAIN_IDS.has(params.chainId);
1868
- if (!isSvm) {
1869
- const tokenAddress = params.token.address;
1870
- if (!tokenAddress) {
1871
- throw new Error("Missing ERC-20 token address for EVM transfer");
1872
- }
1873
- const value = (0, import_viem2.parseUnits)(params.amount || "0", params.token.decimals);
1874
- const txHash = yield writeContractAsync({
1875
- chainId: params.chainId,
1876
- address: tokenAddress,
1877
- abi: ERC20_TRANSFER_ABI,
1878
- functionName: "transfer",
1879
- args: [params.to, value]
1880
- });
1881
- return { txId: txHash };
1882
- }
1883
- if (!params.token.address) {
1884
- throw new Error("Missing SPL token mint address for Solana transfer");
1885
- }
1886
- const phantom = getPhantomProvider2();
1887
- let ownerBase58 = publicKey == null ? void 0 : publicKey.toBase58();
1888
- if (!ownerBase58 && phantom) {
1889
- try {
1890
- const res = yield phantom.connect();
1891
- ownerBase58 = res.publicKey.toString();
1892
- } catch (err) {
1893
- throw new Error(
1894
- `Failed to connect Phantom: ${err instanceof Error ? err.message : String(err)}`
1895
- );
1896
- }
1897
- }
1898
- if (!ownerBase58) {
1899
- throw new Error("No Solana wallet connected");
1900
- }
1901
- const TOKEN_PROGRAM_ID = new import_web33.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
1902
- const ASSOCIATED_TOKEN_PROGRAM_ID = new import_web33.PublicKey(
1903
- "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
1904
- );
1905
- const owner = new import_web33.PublicKey(ownerBase58);
1906
- const mint = new import_web33.PublicKey(params.token.address);
1907
- const destinationOwner = new import_web33.PublicKey(params.to);
1908
- const getAta = (walletPk, mintPk) => {
1909
- const [ata] = import_web33.PublicKey.findProgramAddressSync(
1910
- [walletPk.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintPk.toBuffer()],
1911
- ASSOCIATED_TOKEN_PROGRAM_ID
1912
- );
1913
- return ata;
1914
- };
1915
- const sourceAta = getAta(owner, mint);
1916
- const destinationAta = getAta(destinationOwner, mint);
1917
- const signature = yield withSvmFailover(svmConnections, (sendConnection) => __async(null, null, function* () {
1918
- var _a, _b;
1919
- const tx = new import_web33.Transaction();
1920
- let destinationTokenAccountSigner = null;
1921
- const destinationOwnerInfo = yield sendConnection.getAccountInfo(destinationOwner);
1922
- const destinationInfo = yield sendConnection.getAccountInfo(destinationAta);
1923
- let destinationTokenAccount = destinationAta;
1924
- if (!destinationInfo) {
1925
- const rentExemptLamports = yield sendConnection.getMinimumBalanceForRentExemption(165);
1926
- const payerLamports = yield sendConnection.getBalance(owner, "confirmed");
1927
- const feeBufferLamports = 1e4;
1928
- const requiredLamports = rentExemptLamports + feeBufferLamports;
1929
- if (payerLamports < requiredLamports) {
1930
- const requiredSol = (requiredLamports / 1e9).toFixed(6);
1931
- const currentSol = (payerLamports / 1e9).toFixed(6);
1932
- throw new Error(
1933
- `This Solana deposit needs about ${requiredSol} SOL to create the destination token account, but the connected wallet only has ${currentSol} SOL available.`
1934
- );
1935
- }
1936
- const canCreateAta = (_b = (_a = destinationOwnerInfo == null ? void 0 : destinationOwnerInfo.owner) == null ? void 0 : _a.equals(import_web33.SystemProgram.programId)) != null ? _b : false;
1937
- if (canCreateAta) {
1938
- const createIx = new import_web33.TransactionInstruction({
1939
- programId: ASSOCIATED_TOKEN_PROGRAM_ID,
1940
- keys: [
1941
- { pubkey: owner, isSigner: true, isWritable: true },
1942
- { pubkey: destinationAta, isSigner: false, isWritable: true },
1943
- { pubkey: destinationOwner, isSigner: false, isWritable: false },
1944
- { pubkey: mint, isSigner: false, isWritable: false },
1945
- { pubkey: import_web33.SystemProgram.programId, isSigner: false, isWritable: false },
1946
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
1947
- ],
1948
- data: Buffer.alloc(0)
1949
- });
1950
- tx.add(createIx);
1951
- } else {
1952
- destinationTokenAccountSigner = import_web33.Keypair.generate();
1953
- destinationTokenAccount = destinationTokenAccountSigner.publicKey;
1954
- tx.add(
1955
- import_web33.SystemProgram.createAccount({
1956
- fromPubkey: owner,
1957
- newAccountPubkey: destinationTokenAccount,
1958
- lamports: rentExemptLamports,
1959
- space: 165,
1960
- programId: TOKEN_PROGRAM_ID
1961
- })
1962
- );
1963
- const initAccountData = Buffer.concat([
1964
- Buffer.from([18]),
1965
- // InitializeAccount3
1966
- destinationOwner.toBuffer()
1967
- ]);
1968
- tx.add(
1969
- new import_web33.TransactionInstruction({
1970
- programId: TOKEN_PROGRAM_ID,
1971
- keys: [
1972
- { pubkey: destinationTokenAccount, isSigner: false, isWritable: true },
1973
- { pubkey: mint, isSigner: false, isWritable: false }
1974
- ],
1975
- data: initAccountData
1976
- })
1977
- );
1978
- }
1979
- }
1980
- let factor = BigInt(1);
1981
- for (let i = 0; i < params.token.decimals; i += 1) {
1982
- factor *= BigInt(10);
1983
- }
1984
- const amountRaw = BigInt(Math.trunc(Number(params.amount || "0") * Number(factor)));
1985
- const data = new Uint8Array(10);
1986
- data[0] = 12;
1987
- let remaining = amountRaw;
1988
- const mask = BigInt(255);
1989
- for (let i = 0; i < 8; i += 1) {
1990
- data[1 + i] = Number(remaining & mask);
1991
- remaining >>= BigInt(8);
1992
- }
1993
- data[9] = params.token.decimals;
1994
- const transferIx = new import_web33.TransactionInstruction({
1995
- programId: TOKEN_PROGRAM_ID,
1996
- keys: [
1997
- { pubkey: sourceAta, isSigner: false, isWritable: true },
1998
- { pubkey: mint, isSigner: false, isWritable: false },
1999
- { pubkey: destinationTokenAccount, isSigner: false, isWritable: true },
2000
- { pubkey: owner, isSigner: true, isWritable: false }
2001
- ],
2002
- data: Buffer.from(data)
2003
- });
2004
- tx.add(transferIx);
2005
- tx.feePayer = owner;
2006
- const { blockhash } = yield sendConnection.getLatestBlockhash("confirmed");
2007
- tx.recentBlockhash = blockhash;
2008
- if (destinationTokenAccountSigner) {
2009
- tx.partialSign(destinationTokenAccountSigner);
2010
- }
2011
- if (publicKey && sendTransaction) {
2012
- return yield sendTransaction(tx, sendConnection);
2013
- }
2014
- if (phantom) {
2015
- const res = yield phantom.signAndSendTransaction(tx);
2016
- return res.signature;
2017
- }
2018
- throw new Error("No Solana signer available");
2019
- }));
2020
- return { txId: signature };
2021
- }),
2022
- [publicKey, sendTransaction, svmConnections, writeContractAsync]
2023
- );
2024
- }
2025
-
2026
- // src/deposit/use-wallet-transaction-status.ts
2027
- var import_react_query3 = require("@tanstack/react-query");
2028
- var import_viem3 = require("viem");
2029
- var import_wagmi3 = require("wagmi");
2030
- function useWalletTransactionStatus({
2031
- chainId,
2032
- txId
2033
- }) {
2034
- var _a;
2035
- const isSvm = chainId !== void 0 && SVM_CHAIN_IDS.has(chainId);
2036
- const evmHash = !isSvm && txId ? txId : void 0;
2037
- const evmReceipt = (0, import_wagmi3.useWaitForTransactionReceipt)({
2038
- chainId,
2039
- hash: evmHash,
2040
- query: {
2041
- enabled: !!evmHash && !!chainId,
2042
- refetchInterval: 2e3
2043
- }
2044
- });
2045
- const svmConnections = useSvmConnections("confirmed");
2046
- const svmQuery = (0, import_react_query3.useQuery)({
2047
- queryKey: ["wallet-transaction-status", chainId != null ? chainId : null, txId != null ? txId : null],
2048
- enabled: isSvm && !!txId,
2049
- refetchInterval: (query) => query.state.data === "settled" || query.state.data === "error" ? false : 2e3,
2050
- queryFn: () => __async(null, null, function* () {
2051
- if (!txId) return "submitted";
2052
- const [status] = (yield withSvmFailover(
2053
- svmConnections,
2054
- (connection) => connection.getSignatureStatuses([txId], { searchTransactionHistory: true })
2055
- )).value;
2056
- if (!status) return "submitted";
2057
- if (status.err) return "error";
2058
- if (status.confirmationStatus === "confirmed" || status.confirmationStatus === "finalized") {
2059
- return "settled";
2060
- }
2061
- return "confirming";
2062
- })
2063
- });
2064
- if (isSvm) {
2065
- return { status: txId ? (_a = svmQuery.data) != null ? _a : "submitted" : null, gasFee: "" };
2066
- }
2067
- if (!txId) {
2068
- return { status: null, gasFee: "" };
2069
- }
2070
- if (evmReceipt.isError) {
2071
- return { status: "error", gasFee: "" };
2072
- }
2073
- if (!evmReceipt.data) {
2074
- return { status: evmReceipt.isPending ? "confirming" : "submitted", gasFee: "" };
2075
- }
2076
- const effectiveGasPrice = evmReceipt.data.effectiveGasPrice;
2077
- const gasFeeWei = effectiveGasPrice * evmReceipt.data.gasUsed;
2078
- const gasFeeEth = Number((0, import_viem3.formatEther)(gasFeeWei));
2079
- const gasFee = gasFeeEth > 0 ? `${gasFeeEth.toFixed(6)} ETH` : "";
2080
- return { status: "settled", gasFee };
2081
- }
2082
-
2083
- // src/deposit/use-deposit-flow.ts
2084
- var import_react7 = require("react");
2085
- var import_wagmi4 = require("wagmi");
2086
- var import_wallet_adapter_react3 = require("@solana/wallet-adapter-react");
2087
-
2088
- // src/execution/use-deposit-addresses.ts
2089
- var import_react6 = require("react");
2090
- var import_react_query4 = require("@tanstack/react-query");
2091
- var SVM_CHAIN_IDS2 = /* @__PURE__ */ new Set([792703809]);
2092
- function getDepositAddress(chainId, data) {
2093
- return chainId !== void 0 && SVM_CHAIN_IDS2.has(chainId) ? data.svmAddress : data.evmAddress;
2094
- }
2095
- function useDepositAddresses(options) {
2096
- var _a;
2097
- const client = useAggClient();
2098
- const {
2099
- enabled = true,
2100
- poll = true,
2101
- refetchIntervalMs = 5e3,
2102
- timeoutMs = 6e4
2103
- } = options != null ? options : {};
2104
- const [isTimedOut, setIsTimedOut] = (0, import_react6.useState)(false);
2105
- const timeoutRef = (0, import_react6.useRef)(null);
2106
- (0, import_react6.useEffect)(() => {
2107
- if (!enabled || !poll) return void 0;
2108
- setIsTimedOut(false);
2109
- timeoutRef.current = setTimeout(() => setIsTimedOut(true), timeoutMs);
2110
- return () => {
2111
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
2112
- };
2113
- }, [enabled, poll, timeoutMs]);
2114
- const query = (0, import_react_query4.useQuery)({
2115
- queryKey: executionKeys.depositAddresses(),
2116
- queryFn: () => client.getDepositAddresses(),
2117
- enabled,
2118
- staleTime: 6e4,
2119
- gcTime: 5 * 6e4,
2120
- retry: 1,
2121
- refetchInterval: (q) => {
2122
- if (!poll || isTimedOut) return false;
2123
- const data = q.state.data;
2124
- if ((data == null ? void 0 : data.ready) === true) return false;
2125
- return refetchIntervalMs;
2126
- }
2127
- });
2128
- const isReady = ((_a = query.data) == null ? void 0 : _a.ready) === true;
2129
- const readyData = isReady ? query.data : void 0;
2130
- const evmAddress = (0, import_react6.useMemo)(() => readyData == null ? void 0 : readyData.evmAddress, [readyData]);
2131
- const svmAddress = (0, import_react6.useMemo)(() => readyData == null ? void 0 : readyData.svmAddress, [readyData]);
2132
- const supportedChains = (0, import_react6.useMemo)(() => readyData == null ? void 0 : readyData.supportedChains, [readyData]);
2133
- return __spreadProps(__spreadValues({}, query), {
2134
- isReady,
2135
- isTimedOut,
2136
- evmAddress,
2137
- svmAddress,
2138
- supportedChains,
2139
- depositAddresses: query.data,
2140
- /** Resolve the correct address (EVM or SVM) for a given chainId. */
2141
- getAddress: (chainId) => readyData ? getDepositAddress(chainId, readyData) : void 0
2142
- });
2143
- }
2144
-
2145
- // src/execution/use-sync-balances.ts
2146
- var import_react_query5 = require("@tanstack/react-query");
2147
- function useSyncBalances(options) {
2148
- const client = useAggClient();
2149
- const queryClient = (0, import_react_query5.useQueryClient)();
2150
- return (0, import_react_query5.useMutation)({
2151
- mutationFn: () => client.syncManagedBalances(),
2152
- onSuccess: () => {
2153
- var _a;
2154
- invalidateUserMoneyState(queryClient);
2155
- (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
2156
- },
2157
- onError: options == null ? void 0 : options.onError
2158
- });
2159
- }
2160
-
2161
- // src/use-ramp-quotes.ts
2162
- var import_react_query6 = require("@tanstack/react-query");
2163
- function useRampQuotes() {
2164
- const client = useAggClient();
2165
- return (0, import_react_query6.useMutation)({
2166
- mutationFn: (params) => __async(null, null, function* () {
2167
- return client.getRampQuotes(params);
2168
- })
2169
- });
293
+ const svmConnections = useSvmConnections("confirmed");
294
+ const { writeContractAsync } = (0, wagmi.useWriteContract)();
295
+ const { publicKey, sendTransaction } = (0, _solana_wallet_adapter_react.useWallet)();
296
+ return (0, react.useCallback)(async (params) => {
297
+ if (!SVM_CHAIN_IDS.has(params.chainId)) {
298
+ const tokenAddress = params.token.address;
299
+ if (!tokenAddress) throw new Error("Missing ERC-20 token address for EVM transfer");
300
+ const value = (0, viem.parseUnits)(params.amount || "0", params.token.decimals);
301
+ return { txId: await writeContractAsync({
302
+ chainId: params.chainId,
303
+ address: tokenAddress,
304
+ abi: ERC20_TRANSFER_ABI,
305
+ functionName: "transfer",
306
+ args: [params.to, value]
307
+ }) };
308
+ }
309
+ if (!params.token.address) throw new Error("Missing SPL token mint address for Solana transfer");
310
+ const phantom = getPhantomProvider();
311
+ let ownerBase58 = publicKey?.toBase58();
312
+ if (!ownerBase58 && phantom) try {
313
+ ownerBase58 = (await phantom.connect()).publicKey.toString();
314
+ } catch (err) {
315
+ throw new Error(`Failed to connect Phantom: ${err instanceof Error ? err.message : String(err)}`);
316
+ }
317
+ if (!ownerBase58) throw new Error("No Solana wallet connected");
318
+ const TOKEN_PROGRAM_ID = new _solana_web3_js.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
319
+ const ASSOCIATED_TOKEN_PROGRAM_ID = new _solana_web3_js.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
320
+ const owner = new _solana_web3_js.PublicKey(ownerBase58);
321
+ const mint = new _solana_web3_js.PublicKey(params.token.address);
322
+ const destinationOwner = new _solana_web3_js.PublicKey(params.to);
323
+ const getAta = (walletPk, mintPk) => {
324
+ const [ata] = _solana_web3_js.PublicKey.findProgramAddressSync([
325
+ walletPk.toBuffer(),
326
+ TOKEN_PROGRAM_ID.toBuffer(),
327
+ mintPk.toBuffer()
328
+ ], ASSOCIATED_TOKEN_PROGRAM_ID);
329
+ return ata;
330
+ };
331
+ const sourceAta = getAta(owner, mint);
332
+ const destinationAta = getAta(destinationOwner, mint);
333
+ return { txId: await withSvmFailover(svmConnections, async (sendConnection) => {
334
+ const tx = new _solana_web3_js.Transaction();
335
+ let destinationTokenAccountSigner = null;
336
+ const destinationOwnerInfo = await sendConnection.getAccountInfo(destinationOwner);
337
+ const destinationInfo = await sendConnection.getAccountInfo(destinationAta);
338
+ let destinationTokenAccount = destinationAta;
339
+ if (!destinationInfo) {
340
+ const rentExemptLamports = await sendConnection.getMinimumBalanceForRentExemption(165);
341
+ const payerLamports = await sendConnection.getBalance(owner, "confirmed");
342
+ const requiredLamports = rentExemptLamports + 1e4;
343
+ if (payerLamports < requiredLamports) {
344
+ const requiredSol = (requiredLamports / 1e9).toFixed(6);
345
+ const currentSol = (payerLamports / 1e9).toFixed(6);
346
+ throw new Error(`This Solana deposit needs about ${requiredSol} SOL to create the destination token account, but the connected wallet only has ${currentSol} SOL available.`);
347
+ }
348
+ if (destinationOwnerInfo?.owner?.equals(_solana_web3_js.SystemProgram.programId) ?? false) {
349
+ const createIx = new _solana_web3_js.TransactionInstruction({
350
+ programId: ASSOCIATED_TOKEN_PROGRAM_ID,
351
+ keys: [
352
+ {
353
+ pubkey: owner,
354
+ isSigner: true,
355
+ isWritable: true
356
+ },
357
+ {
358
+ pubkey: destinationAta,
359
+ isSigner: false,
360
+ isWritable: true
361
+ },
362
+ {
363
+ pubkey: destinationOwner,
364
+ isSigner: false,
365
+ isWritable: false
366
+ },
367
+ {
368
+ pubkey: mint,
369
+ isSigner: false,
370
+ isWritable: false
371
+ },
372
+ {
373
+ pubkey: _solana_web3_js.SystemProgram.programId,
374
+ isSigner: false,
375
+ isWritable: false
376
+ },
377
+ {
378
+ pubkey: TOKEN_PROGRAM_ID,
379
+ isSigner: false,
380
+ isWritable: false
381
+ }
382
+ ],
383
+ data: Buffer.alloc(0)
384
+ });
385
+ tx.add(createIx);
386
+ } else {
387
+ destinationTokenAccountSigner = _solana_web3_js.Keypair.generate();
388
+ destinationTokenAccount = destinationTokenAccountSigner.publicKey;
389
+ tx.add(_solana_web3_js.SystemProgram.createAccount({
390
+ fromPubkey: owner,
391
+ newAccountPubkey: destinationTokenAccount,
392
+ lamports: rentExemptLamports,
393
+ space: 165,
394
+ programId: TOKEN_PROGRAM_ID
395
+ }));
396
+ const initAccountData = Buffer.concat([Buffer.from([18]), destinationOwner.toBuffer()]);
397
+ tx.add(new _solana_web3_js.TransactionInstruction({
398
+ programId: TOKEN_PROGRAM_ID,
399
+ keys: [{
400
+ pubkey: destinationTokenAccount,
401
+ isSigner: false,
402
+ isWritable: true
403
+ }, {
404
+ pubkey: mint,
405
+ isSigner: false,
406
+ isWritable: false
407
+ }],
408
+ data: initAccountData
409
+ }));
410
+ }
411
+ }
412
+ let factor = BigInt(1);
413
+ for (let i = 0; i < params.token.decimals; i += 1) factor *= BigInt(10);
414
+ const amountRaw = BigInt(Math.trunc(Number(params.amount || "0") * Number(factor)));
415
+ const data = /* @__PURE__ */ new Uint8Array(10);
416
+ data[0] = 12;
417
+ let remaining = amountRaw;
418
+ const mask = BigInt(255);
419
+ for (let i = 0; i < 8; i += 1) {
420
+ data[1 + i] = Number(remaining & mask);
421
+ remaining >>= BigInt(8);
422
+ }
423
+ data[9] = params.token.decimals;
424
+ const transferIx = new _solana_web3_js.TransactionInstruction({
425
+ programId: TOKEN_PROGRAM_ID,
426
+ keys: [
427
+ {
428
+ pubkey: sourceAta,
429
+ isSigner: false,
430
+ isWritable: true
431
+ },
432
+ {
433
+ pubkey: mint,
434
+ isSigner: false,
435
+ isWritable: false
436
+ },
437
+ {
438
+ pubkey: destinationTokenAccount,
439
+ isSigner: false,
440
+ isWritable: true
441
+ },
442
+ {
443
+ pubkey: owner,
444
+ isSigner: true,
445
+ isWritable: false
446
+ }
447
+ ],
448
+ data: Buffer.from(data)
449
+ });
450
+ tx.add(transferIx);
451
+ tx.feePayer = owner;
452
+ const { blockhash } = await sendConnection.getLatestBlockhash("confirmed");
453
+ tx.recentBlockhash = blockhash;
454
+ if (destinationTokenAccountSigner) tx.partialSign(destinationTokenAccountSigner);
455
+ if (publicKey && sendTransaction) return await sendTransaction(tx, sendConnection);
456
+ if (phantom) return (await phantom.signAndSendTransaction(tx)).signature;
457
+ throw new Error("No Solana signer available");
458
+ }) };
459
+ }, [
460
+ publicKey,
461
+ sendTransaction,
462
+ svmConnections,
463
+ writeContractAsync
464
+ ]);
2170
465
  }
2171
-
2172
- // src/use-ramp-session.ts
2173
- var import_react_query7 = require("@tanstack/react-query");
2174
- function useRampSession() {
2175
- const client = useAggClient();
2176
- return (0, import_react_query7.useMutation)({
2177
- mutationFn: (params) => __async(null, null, function* () {
2178
- return client.createRampSession(params);
2179
- })
2180
- });
466
+ //#endregion
467
+ //#region src/deposit/use-wallet-transaction-status.ts
468
+ function useWalletTransactionStatus({ chainId, txId }) {
469
+ const isSvm = chainId !== void 0 && SVM_CHAIN_IDS.has(chainId);
470
+ const evmHash = !isSvm && txId ? txId : void 0;
471
+ const evmReceipt = (0, wagmi.useWaitForTransactionReceipt)({
472
+ chainId,
473
+ hash: evmHash,
474
+ query: {
475
+ enabled: !!evmHash && !!chainId,
476
+ refetchInterval: 2e3
477
+ }
478
+ });
479
+ const svmConnections = useSvmConnections("confirmed");
480
+ const svmQuery = (0, _tanstack_react_query.useQuery)({
481
+ queryKey: [
482
+ "wallet-transaction-status",
483
+ chainId ?? null,
484
+ txId ?? null
485
+ ],
486
+ enabled: isSvm && !!txId,
487
+ refetchInterval: (query) => query.state.data === "settled" || query.state.data === "error" ? false : 2e3,
488
+ queryFn: async () => {
489
+ if (!txId) return "submitted";
490
+ const [status] = (await withSvmFailover(svmConnections, (connection) => connection.getSignatureStatuses([txId], { searchTransactionHistory: true }))).value;
491
+ if (!status) return "submitted";
492
+ if (status.err) return "error";
493
+ if (status.confirmationStatus === "confirmed" || status.confirmationStatus === "finalized") return "settled";
494
+ return "confirming";
495
+ }
496
+ });
497
+ if (isSvm) return {
498
+ status: txId ? svmQuery.data ?? "submitted" : null,
499
+ gasFee: ""
500
+ };
501
+ if (!txId) return {
502
+ status: null,
503
+ gasFee: ""
504
+ };
505
+ if (evmReceipt.isError) return {
506
+ status: "error",
507
+ gasFee: ""
508
+ };
509
+ if (!evmReceipt.data) return {
510
+ status: evmReceipt.isPending ? "confirming" : "submitted",
511
+ gasFee: ""
512
+ };
513
+ const gasFeeWei = evmReceipt.data.effectiveGasPrice * evmReceipt.data.gasUsed;
514
+ const gasFeeEth = Number((0, viem.formatEther)(gasFeeWei));
515
+ return {
516
+ status: "settled",
517
+ gasFee: gasFeeEth > 0 ? `${gasFeeEth.toFixed(6)} ETH` : ""
518
+ };
2181
519
  }
2182
-
2183
- // src/deposit/use-deposit-flow.ts
2184
- var DEFAULT_WALLET_CHAIN_ID = 1;
2185
- var DEFAULT_WALLET_TOKEN_SYMBOL = "USDC";
520
+ //#endregion
521
+ //#region src/deposit/use-deposit-flow.ts
522
+ const DEFAULT_WALLET_CHAIN_ID = 1;
523
+ const DEFAULT_WALLET_TOKEN_SYMBOL = "USDC";
524
+ /**
525
+ * Orchestrator hook that encapsulates all wallet + card deposit state and
526
+ * glue previously hand-wired inside partner apps. Spread the return value
527
+ * onto `<DepositModal>` to get the full plug-and-play deposit experience.
528
+ *
529
+ * Requires wagmi + @solana/wallet-adapter-react providers in the React tree.
530
+ */
2186
531
  function useDepositFlow(options) {
2187
- var _a, _b, _c;
2188
- const { open, onOpenChange } = options;
2189
- const client = useAggClient();
2190
- const { user } = useAggAuthState();
2191
- const { walletActions } = useAggUiConfig();
2192
- const { totalBalance } = useAggBalanceState();
2193
- const deposit = useDepositAddresses({ enabled: !!user });
2194
- const { supportedChains } = deposit;
2195
- const { mutate: syncBalancesMutate } = useSyncBalances();
2196
- const defaultSendToken = useWalletSendToken();
2197
- const sendToken = (_a = walletActions == null ? void 0 : walletActions.sendToken) != null ? _a : defaultSendToken;
2198
- const { mutateAsync: getRampQuotes } = useRampQuotes();
2199
- const { mutateAsync: createRampSession } = useRampSession();
2200
- const [depositAmount, setDepositAmount] = (0, import_react7.useState)("");
2201
- const [cardAmount, setCardAmount] = (0, import_react7.useState)("");
2202
- const [cardNetwork, setCardNetwork] = (0, import_react7.useState)("solana");
2203
- const [walletModalChainId, setWalletModalChainId] = (0, import_react7.useState)(null);
2204
- const [walletModalTokenSymbol, setWalletModalTokenSymbol] = (0, import_react7.useState)(null);
2205
- const [walletTransaction, setWalletTransaction] = (0, import_react7.useState)(null);
2206
- const [walletTransactionError, setWalletTransactionError] = (0, import_react7.useState)(null);
2207
- const [walletTransactionErrorTone, setWalletTransactionErrorTone] = (0, import_react7.useState)(
2208
- "error"
2209
- );
2210
- const [pendingCardPurchaseSummary, setPendingCardPurchaseSummary] = (0, import_react7.useState)(null);
2211
- const rampRedirectHandled = (0, import_react7.useRef)(false);
2212
- (0, import_react7.useEffect)(() => {
2213
- var _a2, _b2;
2214
- if (rampRedirectHandled.current) return;
2215
- if (typeof window === "undefined") return;
2216
- const url = new URL(window.location.href);
2217
- const cryptoAmount = url.searchParams.get("cryptoAmount");
2218
- const cryptoCurrency = url.searchParams.get("cryptoCurrency");
2219
- if (!cryptoAmount) return;
2220
- rampRedirectHandled.current = true;
2221
- const network = (_a2 = url.searchParams.get("network")) != null ? _a2 : "";
2222
- const totalFee = (_b2 = url.searchParams.get("totalFeeInFiat")) != null ? _b2 : "";
2223
- setPendingCardPurchaseSummary({
2224
- amountReceived: `+${cryptoAmount} ${cryptoCurrency != null ? cryptoCurrency : "USDC"}`,
2225
- network: network.charAt(0).toUpperCase() + network.slice(1),
2226
- fees: totalFee ? `$${totalFee}` : ""
2227
- });
2228
- onOpenChange(true);
2229
- }, []);
2230
- const { chainId: connectedChainId, address: connectedAddress } = (0, import_wagmi4.useAccount)();
2231
- const { switchChainAsync } = (0, import_wagmi4.useSwitchChain)();
2232
- const { wallet: solanaWallet } = (0, import_wallet_adapter_react3.useWallet)();
2233
- const resolvedSvmAddress = useSvmAddress();
2234
- const solanaAdapterName = (_b = solanaWallet == null ? void 0 : solanaWallet.adapter) == null ? void 0 : _b.name;
2235
- const isMultiChainSolanaWallet = Boolean(
2236
- solanaAdapterName && MULTI_CHAIN_SOLANA_WALLET_NAMES.has(solanaAdapterName)
2237
- );
2238
- const hasSolanaCapability = Boolean(resolvedSvmAddress || (solanaWallet == null ? void 0 : solanaWallet.adapter));
2239
- const hasEvmCapability = Boolean(connectedAddress) || isMultiChainSolanaWallet;
2240
- const defaultBalanceChainId = hasEvmCapability && (supportedChains == null ? void 0 : supportedChains.some((chain) => chain.chainId === DEFAULT_WALLET_CHAIN_ID)) ? DEFAULT_WALLET_CHAIN_ID : connectedChainId;
2241
- const balanceChainId = walletModalChainId ? Number(walletModalChainId) : defaultBalanceChainId;
2242
- const selectedChainTokens = (0, import_react7.useMemo)(() => {
2243
- var _a2;
2244
- if (!supportedChains || !balanceChainId) return [];
2245
- const chain = supportedChains.find((c) => c.chainId === balanceChainId);
2246
- return (_a2 = chain == null ? void 0 : chain.tokens) != null ? _a2 : [];
2247
- }, [supportedChains, balanceChainId]);
2248
- const selectedTokenMeta = (0, import_react7.useMemo)(() => {
2249
- const preferredTokenSymbol = walletModalTokenSymbol != null ? walletModalTokenSymbol : DEFAULT_WALLET_TOKEN_SYMBOL;
2250
- const match = selectedChainTokens.find((t) => t.symbol === preferredTokenSymbol);
2251
- return match ? { address: match.address, decimals: match.decimals } : void 0;
2252
- }, [selectedChainTokens, walletModalTokenSymbol]);
2253
- const isSvmBalanceChain = balanceChainId !== void 0 && SVM_CHAIN_IDS.has(balanceChainId);
2254
- const walletAddress = (0, import_react7.useMemo)(() => {
2255
- if (isSvmBalanceChain) {
2256
- return resolvedSvmAddress != null ? resolvedSvmAddress : "";
2257
- }
2258
- return connectedAddress != null ? connectedAddress : "";
2259
- }, [connectedAddress, isSvmBalanceChain, resolvedSvmAddress]);
2260
- const walletLabel = (0, import_react7.useMemo)(() => {
2261
- return walletAddress ? `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}` : "\u2014";
2262
- }, [walletAddress]);
2263
- const { balance: walletBalance, isLoading: isWalletBalanceLoading } = useWalletTokenBalance({
2264
- isOpen: open,
2265
- chainId: balanceChainId,
2266
- tokenAddress: selectedTokenMeta == null ? void 0 : selectedTokenMeta.address,
2267
- decimals: selectedTokenMeta == null ? void 0 : selectedTokenMeta.decimals
2268
- });
2269
- const { status: observedWalletTransactionStatus, gasFee: walletTransactionGasFee } = useWalletTransactionStatus({
2270
- chainId: walletTransaction == null ? void 0 : walletTransaction.chainId,
2271
- txId: (_c = walletTransaction == null ? void 0 : walletTransaction.txId) != null ? _c : null
2272
- });
2273
- const walletTransactionStatus = walletTransactionError ? "error" : walletTransaction ? observedWalletTransactionStatus != null ? observedWalletTransactionStatus : "submitted" : void 0;
2274
- const syncedDepositTxIdRef = (0, import_react7.useRef)(null);
2275
- (0, import_react7.useEffect)(() => {
2276
- if (walletTransactionStatus !== "settled" || !(walletTransaction == null ? void 0 : walletTransaction.txId)) return;
2277
- if (syncedDepositTxIdRef.current === walletTransaction.txId) return;
2278
- syncedDepositTxIdRef.current = walletTransaction.txId;
2279
- syncBalancesMutate();
2280
- }, [syncBalancesMutate, walletTransaction == null ? void 0 : walletTransaction.txId, walletTransactionStatus]);
2281
- const handleDepositModalOpenChange = (0, import_react7.useCallback)(
2282
- (isOpen) => {
2283
- if (!isOpen) {
2284
- setDepositAmount("");
2285
- setCardAmount("");
2286
- setCardNetwork("solana");
2287
- setWalletModalChainId(null);
2288
- setWalletModalTokenSymbol(null);
2289
- setWalletTransaction(null);
2290
- setWalletTransactionError(null);
2291
- setWalletTransactionErrorTone("error");
2292
- setPendingCardPurchaseSummary(null);
2293
- syncedDepositTxIdRef.current = null;
2294
- }
2295
- onOpenChange(isOpen);
2296
- },
2297
- [onOpenChange]
2298
- );
2299
- const handleCancelWalletDeposit = (0, import_react7.useCallback)(() => {
2300
- setWalletTransaction(null);
2301
- setWalletTransactionError(null);
2302
- setWalletTransactionErrorTone("error");
2303
- syncedDepositTxIdRef.current = null;
2304
- }, []);
2305
- const handleConfirmWalletDeposit = (0, import_react7.useCallback)(
2306
- (params) => __async(null, null, function* () {
2307
- var _a2, _b2, _c2;
2308
- const { address, amount, chainId, token } = params;
2309
- const chain = (_a2 = supportedChains == null ? void 0 : supportedChains.find((c) => c.chainId === chainId)) != null ? _a2 : null;
2310
- const tokenMeta = (_b2 = chain == null ? void 0 : chain.tokens.find((t) => t.symbol === token)) != null ? _b2 : null;
2311
- try {
2312
- setWalletTransactionError(null);
2313
- setWalletTransactionErrorTone("error");
2314
- const isEvmTarget = !SVM_CHAIN_IDS.has(chainId);
2315
- if (isEvmTarget && connectedChainId && connectedChainId !== chainId) {
2316
- yield switchChainAsync({ chainId });
2317
- }
2318
- const { txId } = yield sendToken({
2319
- chainId,
2320
- token: {
2321
- symbol: token,
2322
- address: tokenMeta == null ? void 0 : tokenMeta.address,
2323
- decimals: (_c2 = tokenMeta == null ? void 0 : tokenMeta.decimals) != null ? _c2 : 6
2324
- },
2325
- to: address,
2326
- amount
2327
- });
2328
- setWalletTransaction({ chainId, txId });
2329
- void client.recordDepositIntent({ chainId, txHash: txId }).catch(() => {
2330
- });
2331
- } catch (err) {
2332
- setWalletTransaction(null);
2333
- const normalizedError = normalizeWalletError(err, supportedChains);
2334
- setWalletTransactionError(normalizedError.message);
2335
- setWalletTransactionErrorTone(normalizedError.tone);
2336
- throw err;
2337
- }
2338
- }),
2339
- [client, connectedChainId, sendToken, supportedChains, switchChainAsync]
2340
- );
2341
- const handleGetCardQuotes = (0, import_react7.useCallback)(
2342
- (params) => __async(null, null, function* () {
2343
- const quotes = yield getRampQuotes(params);
2344
- return quotes.map(
2345
- (q, i) => ({
2346
- id: q.serviceProvider,
2347
- name: q.serviceProvider,
2348
- quote: `~ ${q.destinationAmount.toFixed(2)} USDC`,
2349
- fee: `$${q.totalFee.toFixed(2)}`,
2350
- badge: i === 0 ? "best" : q.lowKyc ? "low-kyc" : void 0
2351
- })
2352
- );
2353
- }),
2354
- [getRampQuotes]
2355
- );
2356
- const handleCreateCardSession = (0, import_react7.useCallback)(
2357
- (params) => __async(null, null, function* () {
2358
- if (!params.walletAddress) {
2359
- throw new Error("Deposit address not available for the selected network");
2360
- }
2361
- const session = yield createRampSession(params);
2362
- return {
2363
- id: session.id,
2364
- widgetUrl: session.widgetUrl,
2365
- serviceProviderWidgetUrl: session.serviceProviderWidgetUrl
2366
- };
2367
- }),
2368
- [createRampSession]
2369
- );
2370
- const cardRedirectUrl = typeof window !== "undefined" ? `${window.location.origin}/profile?tab=activity` : void 0;
2371
- return {
2372
- open,
2373
- onOpenChange: handleDepositModalOpenChange,
2374
- pendingCardPurchaseSummary,
2375
- walletFlow: {
2376
- balance: totalBalance != null ? totalBalance : 0,
2377
- walletLabel,
2378
- walletBalance,
2379
- isWalletBalanceLoading,
2380
- amount: depositAmount,
2381
- formErrorMessage: walletTransaction ? void 0 : walletTransactionError != null ? walletTransactionError : void 0,
2382
- formErrorTone: walletTransactionErrorTone,
2383
- transactionStatus: walletTransactionStatus,
2384
- transactionErrorMessage: walletTransactionError != null ? walletTransactionError : void 0,
2385
- successSummary: {
2386
- fromWallet: walletLabel,
2387
- gasFee: walletTransactionGasFee
2388
- }
2389
- },
2390
- onWalletAmountChange: setDepositAmount,
2391
- onWalletMax: (0, import_react7.useCallback)(() => setDepositAmount(String(walletBalance)), [walletBalance]),
2392
- onConfirmWalletDeposit: handleConfirmWalletDeposit,
2393
- onCancelWalletDeposit: handleCancelWalletDeposit,
2394
- onWalletNetworkChange: setWalletModalChainId,
2395
- onWalletTokenChange: setWalletModalTokenSymbol,
2396
- initialWalletChainId: connectedChainId ? String(connectedChainId) : void 0,
2397
- connectedWalletKind: hasEvmCapability && !hasSolanaCapability ? "evm" : hasSolanaCapability && !hasEvmCapability ? "solana" : void 0,
2398
- sendCryptoConfig: { minDeposit: "$1", eta: "~30s" },
2399
- onDoneSendCrypto: (0, import_react7.useCallback)(
2400
- () => handleDepositModalOpenChange(false),
2401
- [handleDepositModalOpenChange]
2402
- ),
2403
- cardFlow: {
2404
- amount: cardAmount,
2405
- currency: "USD",
2406
- tokenOptions: [{ value: "USDC", label: "USDC" }],
2407
- selectedToken: "USDC",
2408
- selectedNetwork: cardNetwork,
2409
- providers: [],
2410
- purchaseSummary: { amountReceived: "", network: "", fees: "" },
2411
- minAmount: 11
2412
- },
2413
- onCardAmountChange: setCardAmount,
2414
- onCardNetworkChange: setCardNetwork,
2415
- onDoneCardPurchase: (0, import_react7.useCallback)(() => {
2416
- syncBalancesMutate();
2417
- if (typeof window !== "undefined") {
2418
- window.history.replaceState({}, "", window.location.pathname);
2419
- }
2420
- }, [syncBalancesMutate]),
2421
- cardRedirectUrl,
2422
- onGetCardQuotes: handleGetCardQuotes,
2423
- onCreateCardSession: handleCreateCardSession
2424
- };
532
+ const { open, onOpenChange } = options;
533
+ const client = require_use_sync_balances.useAggClient();
534
+ const { user } = require_use_sync_balances.useAggAuthState();
535
+ const { walletActions } = require_use_sync_balances.useAggUiConfig();
536
+ const { totalBalance } = require_use_sync_balances.useAggBalanceState();
537
+ const { supportedChains } = require_use_sync_balances.useDepositAddresses({ enabled: !!user });
538
+ const { mutate: syncBalancesMutate } = require_use_sync_balances.useSyncBalances();
539
+ const defaultSendToken = useWalletSendToken();
540
+ const sendToken = walletActions?.sendToken ?? defaultSendToken;
541
+ const { mutateAsync: getRampQuotes } = require_use_ramp_session.useRampQuotes();
542
+ const { mutateAsync: createRampSession } = require_use_ramp_session.useRampSession();
543
+ const [depositAmount, setDepositAmount] = (0, react.useState)("");
544
+ const [cardAmount, setCardAmount] = (0, react.useState)("");
545
+ const [cardNetwork, setCardNetwork] = (0, react.useState)("solana");
546
+ const [walletModalChainId, setWalletModalChainId] = (0, react.useState)(null);
547
+ const [walletModalTokenSymbol, setWalletModalTokenSymbol] = (0, react.useState)(null);
548
+ const [walletTransaction, setWalletTransaction] = (0, react.useState)(null);
549
+ const [walletTransactionError, setWalletTransactionError] = (0, react.useState)(null);
550
+ const [walletTransactionErrorTone, setWalletTransactionErrorTone] = (0, react.useState)("error");
551
+ const [pendingCardPurchaseSummary, setPendingCardPurchaseSummary] = (0, react.useState)(null);
552
+ const rampRedirectHandled = (0, react.useRef)(false);
553
+ (0, react.useEffect)(() => {
554
+ if (rampRedirectHandled.current) return;
555
+ if (typeof window === "undefined") return;
556
+ const url = new URL(window.location.href);
557
+ const cryptoAmount = url.searchParams.get("cryptoAmount");
558
+ const cryptoCurrency = url.searchParams.get("cryptoCurrency");
559
+ if (!cryptoAmount) return;
560
+ rampRedirectHandled.current = true;
561
+ const network = url.searchParams.get("network") ?? "";
562
+ const totalFee = url.searchParams.get("totalFeeInFiat") ?? "";
563
+ setPendingCardPurchaseSummary({
564
+ amountReceived: `+${cryptoAmount} ${cryptoCurrency ?? "USDC"}`,
565
+ network: network.charAt(0).toUpperCase() + network.slice(1),
566
+ fees: totalFee ? `$${totalFee}` : ""
567
+ });
568
+ onOpenChange(true);
569
+ }, []);
570
+ const { chainId: connectedChainId, address: connectedAddress } = (0, wagmi.useAccount)();
571
+ const { switchChainAsync } = (0, wagmi.useSwitchChain)();
572
+ const { wallet: solanaWallet } = (0, _solana_wallet_adapter_react.useWallet)();
573
+ const resolvedSvmAddress = useSvmAddress();
574
+ const solanaAdapterName = solanaWallet?.adapter?.name;
575
+ const isMultiChainSolanaWallet = Boolean(solanaAdapterName && MULTI_CHAIN_SOLANA_WALLET_NAMES.has(solanaAdapterName));
576
+ const hasSolanaCapability = Boolean(resolvedSvmAddress || solanaWallet?.adapter);
577
+ const hasEvmCapability = Boolean(connectedAddress) || isMultiChainSolanaWallet;
578
+ const defaultBalanceChainId = hasEvmCapability && supportedChains?.some((chain) => chain.chainId === DEFAULT_WALLET_CHAIN_ID) ? DEFAULT_WALLET_CHAIN_ID : connectedChainId;
579
+ const balanceChainId = walletModalChainId ? Number(walletModalChainId) : defaultBalanceChainId;
580
+ const selectedChainTokens = (0, react.useMemo)(() => {
581
+ if (!supportedChains || !balanceChainId) return [];
582
+ return supportedChains.find((c) => c.chainId === balanceChainId)?.tokens ?? [];
583
+ }, [supportedChains, balanceChainId]);
584
+ const selectedTokenMeta = (0, react.useMemo)(() => {
585
+ const preferredTokenSymbol = walletModalTokenSymbol ?? DEFAULT_WALLET_TOKEN_SYMBOL;
586
+ const match = selectedChainTokens.find((t) => t.symbol === preferredTokenSymbol);
587
+ return match ? {
588
+ address: match.address,
589
+ decimals: match.decimals
590
+ } : void 0;
591
+ }, [selectedChainTokens, walletModalTokenSymbol]);
592
+ const isSvmBalanceChain = balanceChainId !== void 0 && SVM_CHAIN_IDS.has(balanceChainId);
593
+ const walletAddress = (0, react.useMemo)(() => {
594
+ if (isSvmBalanceChain) return resolvedSvmAddress ?? "";
595
+ return connectedAddress ?? "";
596
+ }, [
597
+ connectedAddress,
598
+ isSvmBalanceChain,
599
+ resolvedSvmAddress
600
+ ]);
601
+ const walletLabel = (0, react.useMemo)(() => {
602
+ return walletAddress ? `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}` : "—";
603
+ }, [walletAddress]);
604
+ const { balance: walletBalance, isLoading: isWalletBalanceLoading } = useWalletTokenBalance({
605
+ isOpen: open,
606
+ chainId: balanceChainId,
607
+ tokenAddress: selectedTokenMeta?.address,
608
+ decimals: selectedTokenMeta?.decimals
609
+ });
610
+ const { status: observedWalletTransactionStatus, gasFee: walletTransactionGasFee } = useWalletTransactionStatus({
611
+ chainId: walletTransaction?.chainId,
612
+ txId: walletTransaction?.txId ?? null
613
+ });
614
+ const walletTransactionStatus = walletTransactionError ? "error" : walletTransaction ? observedWalletTransactionStatus ?? "submitted" : void 0;
615
+ const syncedDepositTxIdRef = (0, react.useRef)(null);
616
+ (0, react.useEffect)(() => {
617
+ if (walletTransactionStatus !== "settled" || !walletTransaction?.txId) return;
618
+ if (syncedDepositTxIdRef.current === walletTransaction.txId) return;
619
+ syncedDepositTxIdRef.current = walletTransaction.txId;
620
+ syncBalancesMutate();
621
+ }, [
622
+ syncBalancesMutate,
623
+ walletTransaction?.txId,
624
+ walletTransactionStatus
625
+ ]);
626
+ const handleDepositModalOpenChange = (0, react.useCallback)((isOpen) => {
627
+ if (!isOpen) {
628
+ setDepositAmount("");
629
+ setCardAmount("");
630
+ setCardNetwork("solana");
631
+ setWalletModalChainId(null);
632
+ setWalletModalTokenSymbol(null);
633
+ setWalletTransaction(null);
634
+ setWalletTransactionError(null);
635
+ setWalletTransactionErrorTone("error");
636
+ setPendingCardPurchaseSummary(null);
637
+ syncedDepositTxIdRef.current = null;
638
+ }
639
+ onOpenChange(isOpen);
640
+ }, [onOpenChange]);
641
+ const handleCancelWalletDeposit = (0, react.useCallback)(() => {
642
+ setWalletTransaction(null);
643
+ setWalletTransactionError(null);
644
+ setWalletTransactionErrorTone("error");
645
+ syncedDepositTxIdRef.current = null;
646
+ }, []);
647
+ const handleConfirmWalletDeposit = (0, react.useCallback)(async (params) => {
648
+ const { address, amount, chainId, token } = params;
649
+ const tokenMeta = (supportedChains?.find((c) => c.chainId === chainId) ?? null)?.tokens.find((t) => t.symbol === token) ?? null;
650
+ try {
651
+ setWalletTransactionError(null);
652
+ setWalletTransactionErrorTone("error");
653
+ if (!SVM_CHAIN_IDS.has(chainId) && connectedChainId && connectedChainId !== chainId) await switchChainAsync({ chainId });
654
+ const { txId } = await sendToken({
655
+ chainId,
656
+ token: {
657
+ symbol: token,
658
+ address: tokenMeta?.address,
659
+ decimals: tokenMeta?.decimals ?? 6
660
+ },
661
+ to: address,
662
+ amount
663
+ });
664
+ setWalletTransaction({
665
+ chainId,
666
+ txId
667
+ });
668
+ client.recordDepositIntent({
669
+ chainId,
670
+ txHash: txId
671
+ }).catch(() => {});
672
+ } catch (err) {
673
+ setWalletTransaction(null);
674
+ const normalizedError = normalizeWalletError(err, supportedChains);
675
+ setWalletTransactionError(normalizedError.message);
676
+ setWalletTransactionErrorTone(normalizedError.tone);
677
+ throw err;
678
+ }
679
+ }, [
680
+ client,
681
+ connectedChainId,
682
+ sendToken,
683
+ supportedChains,
684
+ switchChainAsync
685
+ ]);
686
+ const handleGetCardQuotes = (0, react.useCallback)(async (params) => {
687
+ return (await getRampQuotes(params)).map((q, i) => ({
688
+ id: q.serviceProvider,
689
+ name: q.serviceProvider,
690
+ quote: `~ ${q.destinationAmount.toFixed(2)} USDC`,
691
+ fee: `$${q.totalFee.toFixed(2)}`,
692
+ badge: i === 0 ? "best" : q.lowKyc ? "low-kyc" : void 0
693
+ }));
694
+ }, [getRampQuotes]);
695
+ const handleCreateCardSession = (0, react.useCallback)(async (params) => {
696
+ if (!params.walletAddress) throw new Error("Deposit address not available for the selected network");
697
+ const session = await createRampSession(params);
698
+ return {
699
+ id: session.id,
700
+ widgetUrl: session.widgetUrl,
701
+ serviceProviderWidgetUrl: session.serviceProviderWidgetUrl
702
+ };
703
+ }, [createRampSession]);
704
+ const cardRedirectUrl = typeof window !== "undefined" ? `${window.location.origin}/profile?tab=activity` : void 0;
705
+ return {
706
+ open,
707
+ onOpenChange: handleDepositModalOpenChange,
708
+ pendingCardPurchaseSummary,
709
+ walletFlow: {
710
+ balance: totalBalance ?? 0,
711
+ walletLabel,
712
+ walletBalance,
713
+ isWalletBalanceLoading,
714
+ amount: depositAmount,
715
+ formErrorMessage: walletTransaction ? void 0 : walletTransactionError ?? void 0,
716
+ formErrorTone: walletTransactionErrorTone,
717
+ transactionStatus: walletTransactionStatus,
718
+ transactionErrorMessage: walletTransactionError ?? void 0,
719
+ successSummary: {
720
+ fromWallet: walletLabel,
721
+ gasFee: walletTransactionGasFee
722
+ }
723
+ },
724
+ onWalletAmountChange: setDepositAmount,
725
+ onWalletMax: (0, react.useCallback)(() => setDepositAmount(String(walletBalance)), [walletBalance]),
726
+ onConfirmWalletDeposit: handleConfirmWalletDeposit,
727
+ onCancelWalletDeposit: handleCancelWalletDeposit,
728
+ onWalletNetworkChange: setWalletModalChainId,
729
+ onWalletTokenChange: setWalletModalTokenSymbol,
730
+ initialWalletChainId: connectedChainId ? String(connectedChainId) : void 0,
731
+ connectedWalletKind: hasEvmCapability && !hasSolanaCapability ? "evm" : hasSolanaCapability && !hasEvmCapability ? "solana" : void 0,
732
+ sendCryptoConfig: {
733
+ minDeposit: "$1",
734
+ eta: "~30s"
735
+ },
736
+ onDoneSendCrypto: (0, react.useCallback)(() => handleDepositModalOpenChange(false), [handleDepositModalOpenChange]),
737
+ cardFlow: {
738
+ amount: cardAmount,
739
+ currency: "USD",
740
+ tokenOptions: [{
741
+ value: "USDC",
742
+ label: "USDC"
743
+ }],
744
+ selectedToken: "USDC",
745
+ selectedNetwork: cardNetwork,
746
+ providers: [],
747
+ purchaseSummary: {
748
+ amountReceived: "",
749
+ network: "",
750
+ fees: ""
751
+ },
752
+ minAmount: 11
753
+ },
754
+ onCardAmountChange: setCardAmount,
755
+ onCardNetworkChange: setCardNetwork,
756
+ onDoneCardPurchase: (0, react.useCallback)(() => {
757
+ syncBalancesMutate();
758
+ if (typeof window !== "undefined") window.history.replaceState({}, "", window.location.pathname);
759
+ }, [syncBalancesMutate]),
760
+ cardRedirectUrl,
761
+ onGetCardQuotes: handleGetCardQuotes,
762
+ onCreateCardSession: handleCreateCardSession
763
+ };
2425
764
  }
2426
- // Annotate the CommonJS export names for ESM import in node:
2427
- 0 && (module.exports = {
2428
- DEFAULT_SOLANA_RPC_ENDPOINT,
2429
- SVM_CHAIN_IDS,
2430
- normalizeWalletError,
2431
- useDepositAddresses,
2432
- useDepositFlow,
2433
- useSyncBalances,
2434
- useWalletSendToken,
2435
- useWalletTokenBalance,
2436
- useWalletTransactionStatus
2437
- });
765
+ //#endregion
766
+ exports.DEFAULT_SOLANA_RPC_ENDPOINT = DEFAULT_SOLANA_RPC_ENDPOINT;
767
+ exports.SVM_CHAIN_IDS = SVM_CHAIN_IDS;
768
+ exports.normalizeWalletError = normalizeWalletError;
769
+ exports.useDepositAddresses = require_use_sync_balances.useDepositAddresses;
770
+ exports.useDepositFlow = useDepositFlow;
771
+ exports.useSyncBalances = require_use_sync_balances.useSyncBalances;
772
+ exports.useWalletSendToken = useWalletSendToken;
773
+ exports.useWalletTokenBalance = useWalletTokenBalance;
774
+ exports.useWalletTransactionStatus = useWalletTransactionStatus;