@agg-build/hooks 1.0.0 → 1.0.1

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.
@@ -0,0 +1,1402 @@
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/withdraw/index.ts
58
+ var withdraw_exports = {};
59
+ __export(withdraw_exports, {
60
+ useDepositAddresses: () => useDepositAddresses,
61
+ useManagedBalances: () => useManagedBalances,
62
+ useWithdrawFlow: () => useWithdrawFlow,
63
+ useWithdrawManaged: () => useWithdrawManaged,
64
+ useWithdrawalLifecycle: () => useWithdrawalLifecycle
65
+ });
66
+ module.exports = __toCommonJS(withdraw_exports);
67
+
68
+ // src/withdraw/use-withdraw-flow.ts
69
+ var import_react5 = require("react");
70
+
71
+ // src/core/providers/contexts.ts
72
+ var import_react = require("react");
73
+
74
+ // src/core/ui-config/labels.ts
75
+ var enUsLabels = {
76
+ common: {
77
+ close: "Close",
78
+ loading: "Loading",
79
+ retry: "Retry",
80
+ errorPrefix: "Error",
81
+ tabsAria: "Tabs",
82
+ hiddenTabsAria: "Hidden tabs",
83
+ selectAria: "Select",
84
+ lineChartAria: "Line chart",
85
+ candlestickChartAria: "Candlestick chart",
86
+ lineChartSeriesSwitchAria: "Chart series switch",
87
+ lineChartSeriesOptionAria: (seriesLabel) => `Show ${seriesLabel} series`,
88
+ chartTypeSwitchAria: "Chart type switch",
89
+ lineChartType: "Line",
90
+ candlestickChartType: "Candlestick"
91
+ },
92
+ venues: {
93
+ polymarket: "Polymarket",
94
+ kalshi: "Kalshi",
95
+ opinion: "Opinion",
96
+ predict: "Predict",
97
+ limitless: "Limitless",
98
+ probable: "Probable",
99
+ myriad: "Myriad",
100
+ hyperliquid: "Hyperliquid"
101
+ },
102
+ auth: {
103
+ connect: (connectorName) => connectorName ? `Sign in with ${connectorName}` : "Sign in",
104
+ signIn: "Sign in",
105
+ signingIn: "Signing in...",
106
+ signInStatement: "Sign in to AGG",
107
+ emailAddress: "Email address",
108
+ continue: "Continue",
109
+ emailUnavailable: "Email sign-in is currently unavailable.",
110
+ signInWithMethod: (methodLabel) => `Sign in with ${methodLabel}`,
111
+ socialWalletNotice: "A wallet will automatically be created for you when signing up with a social account.",
112
+ learnMore: "Learn more",
113
+ dividerOr: "OR",
114
+ connectWallet: "Connect wallet",
115
+ terms: "Terms",
116
+ privacyPolicy: "Privacy Policy",
117
+ legalNoticePrefix: "By signing in, you agree to our",
118
+ legalNoticeSeparator: "&",
119
+ deposit: "Deposit",
120
+ depositGeoBlocked: "Deposits are not available in your region.",
121
+ balances: "Balances",
122
+ viewAll: "View All",
123
+ loadingBalances: "Loading balances...",
124
+ myProfile: "My Profile",
125
+ withdraw: "Withdraw",
126
+ disconnect: "Disconnect",
127
+ claimWinnings: "Claim Now",
128
+ claimableWinningsBadge: (count) => `${count} claimable winning${count === 1 ? "" : "s"}`,
129
+ claimableWinningsTooltip: (count) => `${count} position${count === 1 ? "" : "s"} ready to claim`,
130
+ walletMenuFor: (profileLabel) => `Profile menu for ${profileLabel}`
131
+ },
132
+ deposit: {
133
+ title: "Deposit",
134
+ back: "Go back",
135
+ balancePrefix: "Balance:",
136
+ balanceLabel: "Balance",
137
+ done: "Done",
138
+ methods: {
139
+ walletTitle: (walletLabel) => `Use your wallet (${walletLabel})`,
140
+ walletDescription: "Deposit instantly from your connected wallet",
141
+ cryptoTitle: "Send crypto",
142
+ cryptoDescription: "Transfer from any wallet or exchange",
143
+ cardTitle: "Deposit with card",
144
+ cardDescription: "Buy crypto instantly with your card"
145
+ },
146
+ walletFlow: {
147
+ title: "Use your wallet",
148
+ tokenLabel: "Token",
149
+ networkLabel: "Network",
150
+ amountLabel: "Amount",
151
+ max: "Max",
152
+ feePrefix: "Fee ~",
153
+ confirm: "Confirm Deposit"
154
+ },
155
+ sendCrypto: {
156
+ title: "Send crypto",
157
+ tokenLabel: "Supported token",
158
+ networkLabel: "Supported network",
159
+ depositAddressLabel: "Your deposit address",
160
+ copy: "Copy",
161
+ copied: "Copied!",
162
+ minDepositPrefix: "Min deposit",
163
+ warning: "Send only the selected token on the selected network. Wrong token or network may results in permanently lost funds.",
164
+ qrPlaceholder: "QR code placeholder",
165
+ addressLoadingTitle: "Preparing your deposit address...",
166
+ addressLoadingDescription: "We're generating your address, this usually takes a few seconds."
167
+ },
168
+ cardFlow: {
169
+ title: "Buy crypto",
170
+ amountLabel: "Amount",
171
+ currencyLabel: "Currency",
172
+ tokenLabel: "Token",
173
+ networkLabel: "Network",
174
+ destinationWalletLabel: "Destination wallet",
175
+ getQuotes: "Get Quotes",
176
+ minRequired: (amount) => `Min required: ${amount}`,
177
+ minAmountError: (amount) => `Enter at least ${amount} to continue`,
178
+ selectProviderTitle: "Select provider",
179
+ feeLabel: "Fee",
180
+ providerBadges: {
181
+ best: "BEST",
182
+ lowKyc: "LOW KYC"
183
+ },
184
+ successTitle: "Purchase complete",
185
+ successDescription: "Your USDC has been successfully added to your balance.",
186
+ pendingTitle: (provider) => `Complete your payment on ${provider}`,
187
+ 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.",
188
+ pendingWalletAddressHelp: "Some providers may ask for a wallet address during checkout, use this one to receive your deposit:",
189
+ pendingCopyAddress: "Copy deposit address",
190
+ viewActivity: "View Activity",
191
+ chooseAnotherProvider: "Choose another provider",
192
+ summary: {
193
+ provider: "Provider",
194
+ fees: "Fees"
195
+ },
196
+ loadingQuotes: "Finding the best rates...",
197
+ errorLoadingQuotesTitle: "Failed to load quotes",
198
+ errorLoadingQuotesDescription: "Please try again.",
199
+ retry: "Retry",
200
+ noQuotes: "No quotes available for this configuration.",
201
+ widgetTitle: "Complete Purchase"
202
+ },
203
+ processingTitle: "Processing deposit",
204
+ processingSteps: {
205
+ submitting: "Waiting for wallet confirmation",
206
+ submitted: "Wallet confirmed",
207
+ confirming: "Processing transaction\u2026",
208
+ updatingBalance: "Updating balance",
209
+ fundsAvailable: "Funds available"
210
+ },
211
+ successTitle: "Deposit complete",
212
+ successDescription: "Your USDC has been successfully added to your balance.",
213
+ summary: {
214
+ amountReceived: "Amount received",
215
+ network: "Network",
216
+ fromWallet: "From wallet",
217
+ gasFee: "Gas fee"
218
+ }
219
+ },
220
+ withdraw: {
221
+ title: "Withdraw",
222
+ back: "Go back",
223
+ done: "Done",
224
+ balancePrefix: "Balance:",
225
+ methods: {
226
+ walletTitle: "Withdraw to wallet",
227
+ walletDescription: "Withdraw funds instantly to your crypto wallet",
228
+ cardTitle: "Withdraw with card",
229
+ cardDescription: "Withdraw funds to your card"
230
+ },
231
+ walletFlow: {
232
+ title: "Withdraw to wallet",
233
+ recipientAddressLabel: "Recipient address",
234
+ amountLabel: "Amount",
235
+ max: "Max",
236
+ tokenLabel: "Receive token",
237
+ networkLabel: "Receive network",
238
+ confirm: "Confirm withdrawal",
239
+ successTitle: "Withdrawal submitted",
240
+ successDescription: (tokenSymbol) => `Your ${tokenSymbol} withdrawal is being processed and will arrive shortly.`,
241
+ // Terminal-state copy. The success step swaps `successTitle` /
242
+ // `successDescription` for these once the lifecycle has reached a
243
+ // terminal status — otherwise a finished withdrawal would keep showing
244
+ // "submitted / processing" forever and force the user to hard-refresh.
245
+ successTitleCompleted: "Withdrawal complete",
246
+ successDescriptionCompleted: (tokenSymbol) => `Your ${tokenSymbol} withdrawal has been delivered.`,
247
+ successTitlePartial: "Withdrawal partially completed",
248
+ successDescriptionPartial: (tokenSymbol) => `Some legs of your ${tokenSymbol} withdrawal completed; see details below.`,
249
+ successTitleFailed: "Withdrawal failed",
250
+ successDescriptionFailed: (tokenSymbol) => `Your ${tokenSymbol} withdrawal could not be completed.`,
251
+ summary: {
252
+ // The response is `pricingStatus: "unquoted"` — we don't know net
253
+ // output until on-chain settlement. Calling this "Amount received"
254
+ // would imply receipt before the lifecycle has confirmed. Keep it
255
+ // honest as the submitted amount until the multi-stable quote
256
+ // layer (PR-E) populates `expected.outputRaw`.
257
+ amountReceived: "Amount",
258
+ network: "Network",
259
+ toWallet: "To wallet",
260
+ fees: "Fees"
261
+ },
262
+ lifecycle: {
263
+ pending: "Submitted \u2014 preparing your withdrawal\u2026",
264
+ bridging: "Bridging funds across chains\u2026",
265
+ transferring: "Transferring to your wallet\u2026",
266
+ completed: "Withdrawal complete.",
267
+ partial: "Withdrawal partially completed \u2014 see details below.",
268
+ failed: "Withdrawal failed.",
269
+ steps: {
270
+ bridge: (sourceChainName, destChainName) => `Bridging from ${sourceChainName} to ${destChainName}`,
271
+ transfer: (destChainName) => `Transferring on ${destChainName}`
272
+ }
273
+ }
274
+ },
275
+ cardFlow: {
276
+ title: "Sell crypto",
277
+ amountLabel: "Amount",
278
+ currencyLabel: "Currency",
279
+ tokenLabel: "Token",
280
+ networkLabel: "Network",
281
+ destinationWalletLabel: "Destination wallet",
282
+ getQuotes: "Get Quotes",
283
+ selectProviderTitle: "Select provider",
284
+ feeLabel: "Fee",
285
+ providerBadges: {
286
+ best: "BEST",
287
+ lowKyc: "LOW KYC"
288
+ },
289
+ successTitle: "Withdrawal complete",
290
+ successDescription: "Your USDC has been successfully sent to your wallet.",
291
+ summary: {
292
+ provider: "Provider",
293
+ toWallet: "To wallet",
294
+ fees: "Fees"
295
+ }
296
+ },
297
+ summary: {
298
+ // Lifecycle-honest: until quoting is live (PR-E) the response is
299
+ // `pricingStatus: "unquoted"` so this is the submitted amount, not
300
+ // a guaranteed net output.
301
+ amountReceived: "Amount",
302
+ network: "Network"
303
+ }
304
+ },
305
+ markets: {
306
+ emptyNoOpen: "No open markets available.",
307
+ emptyResolved: "This event has been resolved."
308
+ },
309
+ home: {
310
+ trending: "Trending",
311
+ topMarkets: "Top Markets",
312
+ newMarkets: "New Markets",
313
+ categoryTabsAria: "Home page category tabs"
314
+ },
315
+ userProfile: {
316
+ activity: {
317
+ depositType: "Deposit",
318
+ withdrawalType: "Withdrawal",
319
+ depositTitles: {
320
+ connectedWallet: "Deposit from connected wallet",
321
+ externalWallet: "Deposit from external wallet",
322
+ card: "Deposit with card"
323
+ },
324
+ // Activity-row title for any withdrawal regardless of lifecycle
325
+ // state (pending / completed / failed) — render the asset rather
326
+ // than implying success. The ActivityRow renders a separate status
327
+ // chip when the row is failed.
328
+ withdrawalTitle: (tokenSymbol) => `Withdraw ${tokenSymbol}`
329
+ },
330
+ positions: {
331
+ totalTradedHeader: "Total traded",
332
+ amountWonHeader: "Amount won",
333
+ claimHeader: "Claim",
334
+ claim: "Claim",
335
+ claimed: "Claimed",
336
+ pending: "Pending",
337
+ won: "Won",
338
+ lost: "Lost",
339
+ resolved: "Resolved",
340
+ marketClosed: "Market closed",
341
+ closed: "Closed"
342
+ }
343
+ },
344
+ eventList: {
345
+ matchedTab: "Matched",
346
+ loading: (title) => `Loading ${title}`,
347
+ tabsAria: (title) => `${title} tabs`,
348
+ emptyAria: "No events found",
349
+ emptyTitle: "No Events Found",
350
+ emptyDescription: "We couldn't find any events matching your filters.\nTry adjusting them or check back later.",
351
+ empty: "No events found for this tab.",
352
+ errorTitle: "Something went wrong",
353
+ errorDescription: "We're having trouble loading data right now.\nTry refreshing or check back later.",
354
+ viewResolved: "View resolved",
355
+ hideResolved: "Hide resolved"
356
+ },
357
+ search: {
358
+ placeholder: "Search...",
359
+ inputAria: "Search markets",
360
+ resultsAria: "Search results",
361
+ resultAria: (title) => `View ${title}`,
362
+ resultsSummary: (countLabel, query) => `${countLabel} search results for "${query}"`,
363
+ seeAllResults: "See all results",
364
+ loadingResults: "Loading search results",
365
+ noResultsTitle: "No markets found",
366
+ noResultsDescription: "Check your spelling or try a broader search term."
367
+ },
368
+ eventItem: {
369
+ loading: "Loading market tile",
370
+ unavailableAria: "Market tile unavailable",
371
+ unavailableTitle: "Market unavailable",
372
+ unavailableDescription: "We could not load this market right now.",
373
+ arbitrage: "Arbitrage",
374
+ priceGap: "Price Gap",
375
+ volumeSuffix: "Vol.",
376
+ marketSingular: "Market",
377
+ marketPlural: "Markets",
378
+ venueSingular: "Venue",
379
+ venuePlural: "Venues"
380
+ },
381
+ eventItemDetails: {
382
+ loading: "Loading market details",
383
+ unavailableAria: "Market details unavailable",
384
+ unavailableTitle: "Market details unavailable",
385
+ unavailableDescription: "We could not load this market right now.",
386
+ notFoundAria: "Event not found",
387
+ notFoundTitle: "Event Not Found",
388
+ notFoundDescription: "We couldn't find this event or it may no longer exist.",
389
+ chartUnavailableAria: "Chart unavailable",
390
+ chartUnavailableTitle: "Chart Unavailable",
391
+ chartUnavailableDescription: "We couldn't load live chart data for this event.",
392
+ historicalLineChartAria: (title) => `${title} historical line chart`,
393
+ outcomeSelectorAria: "Outcome selector",
394
+ yes: "Yes",
395
+ no: "No",
396
+ allTimeRange: "All",
397
+ volumeSuffix: "Vol.",
398
+ marketSelectPlaceholder: "Select market",
399
+ marketSelectSearchPlaceholder: "Search markets...",
400
+ marketSelectEmpty: "No markets found"
401
+ },
402
+ settlementSummary: {
403
+ title: "Settlement",
404
+ readFullDetails: "Read full details",
405
+ showLess: "Show less"
406
+ },
407
+ marketDetails: {
408
+ loading: "Loading market details",
409
+ unavailableAria: "Market details unavailable",
410
+ unavailableTitle: "Market details unavailable",
411
+ unavailableDescription: "We could not load this market right now.",
412
+ notFoundAria: "Market not found",
413
+ notFoundTitle: "Market Not Found",
414
+ notFoundDescription: "We couldn't find this market or it may no longer exist.",
415
+ chartUnavailableAria: "Chart unavailable",
416
+ chartUnavailableTitle: "Chart Unavailable",
417
+ chartUnavailableDescription: "We couldn't load live chart data for this market.",
418
+ orderBookEmptyAria: "No orders yet",
419
+ orderBookEmptyTitle: "No orders yet",
420
+ orderBookEmptyDescription: "Be the first to set the price on this market.",
421
+ orderBookResolvedAria: "Market resolved",
422
+ orderBookResolvedTitle: "Market Resolved",
423
+ orderBookResolvedDescription: "This market has been resolved and is no longer trading.",
424
+ orderBookUnavailableAria: "Orderbook unavailable",
425
+ orderBookUnavailableTitle: "Orderbook Unavailable",
426
+ orderBookUnavailableDescription: "We couldn't load live order data for this market.",
427
+ marketOutcomesAria: "Market outcomes",
428
+ tabsAria: "Market details tabs",
429
+ toggleOpenDetailsAria: (title) => `Open details for ${title}`,
430
+ toggleCloseDetailsAria: (title) => `Close details for ${title}`,
431
+ loadingOrderbookAria: "Loading orderbook",
432
+ loadingOrderbookLabel: "Loading orderbook...",
433
+ asks: "Asks",
434
+ bids: "Bids",
435
+ spread: "Spread",
436
+ midPrice: "Mid",
437
+ tradePrefix: "Trade",
438
+ priceColumn: "Price",
439
+ sharesColumn: "Shares",
440
+ totalColumn: "Total",
441
+ lastPrice: "Last",
442
+ graphAria: (title) => `${title} price history`,
443
+ outcomeSelectorAria: "Outcome selector",
444
+ showOutcomeAria: (label) => `Show ${label} outcome`,
445
+ viewResolved: "View resolved",
446
+ hideResolved: "Hide resolved",
447
+ volumeUnavailable: "Volume unavailable",
448
+ tabs: {
449
+ orderBook: "Order Book",
450
+ graph: "Graph",
451
+ other: "Other"
452
+ },
453
+ meta: {
454
+ status: "Status",
455
+ created: "Created",
456
+ opens: "Opens",
457
+ closes: "Closes",
458
+ markets: "Markets",
459
+ unknown: "Unknown",
460
+ venueSingular: "Venue",
461
+ venuePlural: "Venues",
462
+ volumeSuffix: "Vol."
463
+ }
464
+ },
465
+ trading: {
466
+ settlementSection: "Settlement",
467
+ settlementDifferencesTitle: "Key differences across venues",
468
+ settlementLoading: "Loading settlement",
469
+ settlementDetailsAria: (venueLabel) => `${venueLabel} settlement details`,
470
+ settlementShowMoreAria: (ctaLabel, venueLabel) => `${ctaLabel} for ${venueLabel}`,
471
+ settlementDescriptionLabel: "Description",
472
+ settlementRulesPrimaryLabel: "Resolution rules",
473
+ settlementRulesSecondaryLabel: "Additional rules",
474
+ disclaimer: "By trading, you agree to the Terms of Use of each exchange.",
475
+ geoBlockTermsLink: "Terms of Use",
476
+ geoBlockGenericMessage: "Trading is not available in your region. See ",
477
+ geoBlockVenueMessage: (venueLabel) => `Trading on ${venueLabel} is not available in your region. See `,
478
+ geoBlockMessageSuffix: " for more information.",
479
+ geoBlockModalAriaLabel: "Geo-restricted location",
480
+ geoBlockModalTitle: "Trading is not available in your current location",
481
+ 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.",
482
+ geoBlockModalConfirm: "Confirm",
483
+ averagePrice: (value) => `${(value * 100).toLocaleString("en-US", {
484
+ minimumFractionDigits: 0,
485
+ maximumFractionDigits: 2
486
+ })}\xA2 avg. price`,
487
+ balance: (value) => `Balance ${value}`,
488
+ shares: (value) => `${value.toLocaleString("en-US", {
489
+ minimumFractionDigits: Number.isInteger(value) ? 0 : 2,
490
+ maximumFractionDigits: 6
491
+ })} shares`,
492
+ slippage: (value) => `Slippage: ${value}%`,
493
+ editSlippage: (value) => `Edit ${value}`,
494
+ collapseSlippage: (value) => `Collapse ${value}`,
495
+ resetSlippage: "Auto",
496
+ slippageWarning: (value) => `Slippage below ${value}% may prevent your order from executing.`,
497
+ slippageLow: (value) => `Slippage below ${value}% may prevent your order from executing.`,
498
+ slippageHigh: (value) => `Slippage above ${value}% increases the chance of an unfavorable trade.`,
499
+ showAdditionalVenues: (count) => `Show ${count} more venue${count === 1 ? "" : "s"}`,
500
+ hideAdditionalVenues: "Hide additional venues",
501
+ quoteExpired: "Quote expired. Please refresh.",
502
+ orderSubmitted: "Order submitted",
503
+ orderPending: "Your order is being processed...",
504
+ orderFailed: "Order failed. Please try again.",
505
+ orderDisabledEventResolved: "This event has been resolved.",
506
+ orderDisabledEventClosed: "This event is no longer accepting orders.",
507
+ orderDisabledEventPaused: "Trading is temporarily paused for this event.",
508
+ orderDisabledEventUnopened: "Trading has not opened yet for this event.",
509
+ orderDisabledEventUnavailable: "Trading is currently unavailable.",
510
+ orderDisabledMarketResolved: "This market has been resolved.",
511
+ orderDisabledMarketClosed: "This market is no longer accepting orders.",
512
+ orderDisabledMarketPaused: "Trading is temporarily paused for this market.",
513
+ orderDisabledMarketUnopened: "Trading has not opened yet for this market.",
514
+ orderDisabledMarketUnavailable: "Trading is currently unavailable for this market.",
515
+ orderDisabledNoMarket: "Select a market to place an order.",
516
+ orderDisabledNoOutcome: "Select an outcome to place an order.",
517
+ orderDisabledNoEvent: "No event selected.",
518
+ insufficientBalance: "Insufficient balance",
519
+ refreshQuote: "Refresh Quote",
520
+ confirmOrder: "Confirm Order",
521
+ withdrawSubmitted: "Withdrawal submitted",
522
+ withdrawProcessing: "Your withdrawal is being processed...",
523
+ estimatedCost: (value) => `Est. cost ${value}`,
524
+ partialFill: (filledSize, requestedSize) => `Only ${filledSize} of ${requestedSize} shares available at this price.`,
525
+ insufficientLiquidity: "Not enough liquidity available for this order size.",
526
+ noMarketSelected: "Select a market to place an order.",
527
+ noOrderbooks: "No live orderbooks are available for this market right now.",
528
+ quoteUnavailable: "Quote temporarily unavailable. Please try again.",
529
+ selectedVenueUnavailable: "The venue you selected is no longer available on this route. Review the updated options and try again.",
530
+ engineUnavailable: "The routing engine is temporarily unavailable. Please try again in a moment.",
531
+ insufficientInputAmount: "Trade amount is too small to cover bridging and execution costs. Increase your spend or deposit funds on the destination chain.",
532
+ minOrderSizeViolated: "Order size is below the venue minimum. Increase your spend.",
533
+ minimumOrderAmount: (amount) => `Minimum order is $${amount}`,
534
+ insufficientPosition: (totalShares) => `You only have ${totalShares} shares available to sell.`,
535
+ insufficientPositionGeneric: "You don't have enough shares to sell.",
536
+ insufficientSellDepth: "Not enough bid liquidity on the matched venues for this sell amount.",
537
+ noBidsAboveMinPrice: "No venue bids above the minimum price.",
538
+ signInRequired: "Sign in to get a routed quote",
539
+ kycRequired: "Verify to trade Kalshi",
540
+ kycNotVerifiedTooltip: "You have not been verified yet",
541
+ kycVerifyModalTitle: "Verify Your Identity",
542
+ 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.",
543
+ kycStartVerification: "Start Verification",
544
+ kycDoItLater: "Do It Later",
545
+ kycSuccessTitle: "Verification successful",
546
+ kycSuccessDescription: "Your identity has been confirmed and you now have full access to trade on Kalshi markets.",
547
+ kycSuccessDone: "Done",
548
+ outcome: (label) => `Outcome: ${label}`,
549
+ smartRouting: "Smart Routing",
550
+ orderSplitting: "Order Splitting",
551
+ splitOrderDescription: "We split your order for the best price:",
552
+ viewAllRoutes: (count) => `View all (${count})`,
553
+ hideRoutes: "Hide routes",
554
+ venueUnavailableInRegion: "Unavailable in your region",
555
+ toWin: (tab) => tab === "buy" ? "To win" : "Payout",
556
+ buyingOutcome: (label) => `Buying ${label}`,
557
+ sellingOutcome: (label) => `Selling ${label}`,
558
+ findingBestRoute: "Finding the best route...",
559
+ submittingOrderProgress: "Submitting order...",
560
+ orderSubmittedProgress: (orderId) => `Order #${orderId.replace(/^#/, "")} submitted`,
561
+ executingOnVenue: (venueLabel) => `Executing on ${venueLabel}...`,
562
+ confirmTransactionInWallet: "Confirm the transaction in your wallet",
563
+ executionConfirmed: "Execution confirmed",
564
+ orderSuccessTitle: "Order placed",
565
+ orderSuccessDescription: "Your order has been submitted successfully.",
566
+ orderFailureTitle: "Order failed",
567
+ orderFailureDescription: (message) => message || "Something went wrong. Please try again.",
568
+ orderDone: "Done",
569
+ orderNewTrade: "New Trade",
570
+ orderShare: "Share",
571
+ orderRetry: "Try again",
572
+ orderContinue: "Continue",
573
+ orderDismiss: "Dismiss",
574
+ orderRetryVenue: (venueLabel) => `Retry ${venueLabel}`,
575
+ orderPartialFillStatus: (venueLabel) => `${venueLabel} order partially filled`,
576
+ orderVenueUnavailableStatus: (venueLabel) => `${venueLabel} unavailable, your funds have not been charged.`,
577
+ orderMarketResolvedStatus: (venueLabel) => `Market resolved on ${venueLabel} and is no longer accepting orders.`,
578
+ orderSummaryShares: "Shares",
579
+ orderSummaryAvgPrice: "Avg. price",
580
+ orderSummaryEstCost: "Est. cost",
581
+ orderSummaryVenue: "Venue",
582
+ orderComplete: "Order complete",
583
+ orderFilledAtPrice: (venueLabel, priceLabel) => `${venueLabel} order filled at ${priceLabel}`,
584
+ orderFilledAtPriceWithAmount: (venueLabel, priceLabel, amountLabel) => `${venueLabel} order filled at ${priceLabel} (${amountLabel})`,
585
+ orderPartiallyFilledAtPriceWithAmount: (venueLabel, priceLabel, amountLabel) => `${venueLabel} order partially filled at ${priceLabel} (${amountLabel})`,
586
+ orderSkip: "Skip",
587
+ orderRetryRemaining: "Retry remaining",
588
+ resolvedEarningsTitle: "Your Earnings",
589
+ resolvedSharesLabel: "Shares",
590
+ resolvedTotalPayoutLabel: "Total payout",
591
+ claimWinnings: "Claim Winnings",
592
+ boughtOutcomeAtPrice: (label, priceLabel) => `Bought ${label} at ${priceLabel}`,
593
+ soldOutcomeAtPrice: (label, priceLabel) => `Sold ${label} at ${priceLabel}`,
594
+ potentialReturnBonus: (value) => `+${value} Better Payout`,
595
+ withSmartRouting: "with Smart Routing",
596
+ buy: "Buy",
597
+ sell: "Sell",
598
+ amount: (side) => `${side === "buy" ? "Amount" : "Shares"}`
599
+ },
600
+ onboarding: {
601
+ modal: {
602
+ title: "Onboarding",
603
+ stepHowItWorks: "How it works",
604
+ stepProfileSetup: "Set up your profile",
605
+ stepConnectAccounts: "Connect accounts"
606
+ },
607
+ howItWorks: {
608
+ title: "How it works",
609
+ continue: "Continue",
610
+ features: {
611
+ createAccount: {
612
+ title: "Create Your Account",
613
+ description: "Add a few basic details to set up your account and personalize your experience on the platform."
614
+ },
615
+ linkAccounts: {
616
+ title: "Link Trading Accounts",
617
+ description: "Connect supported exchanges to unlock additional markets and liquidity. Trade across decentralized markets in one interface."
618
+ },
619
+ bestPrices: {
620
+ title: "Best Prices Always",
621
+ description: "Our real-time aggregated orderbook lets you shop lines across exchanges and automatically splits predictions to optimize trades."
622
+ },
623
+ stayInControl: {
624
+ title: "You Stay in Control",
625
+ description: "All trades are executed on the original platform. We never custody funds or move money on your behalf."
626
+ }
627
+ }
628
+ },
629
+ profileSetup: {
630
+ title: "Set up your profile",
631
+ uploadProfilePictureAria: "Upload profile picture",
632
+ profilePreviewAlt: "Profile preview",
633
+ usernameLabel: "Username",
634
+ usernamePlaceholder: "e.g. CryptoJohn",
635
+ continue: "Continue"
636
+ },
637
+ connectAccounts: {
638
+ title: "Connect Accounts",
639
+ connect: "Connect",
640
+ connectAccount: "Connect Account",
641
+ continue: "Continue",
642
+ onchainTitle: "Onchain exchanges",
643
+ onchainMobileTitle: (additionalVenueCount) => `Polymarket +${additionalVenueCount} venues`,
644
+ onchainDescription: "Trade multiple venues with one signature.",
645
+ onchainMobileDescription: "Trade multiple exchanges with one signature",
646
+ kalshiTitle: "US regulated exchanges",
647
+ kalshiMobileTitle: "Kalshi",
648
+ kalshiDescription: "Trade on regulated markets via Kalshi.",
649
+ kalshiMobileDescription: "Connect your Kalshi account"
650
+ },
651
+ connectOnchainModal: {
652
+ ariaLabel: "Connect Onchain Exchanges",
653
+ title: "Connect Onchain Exchanges",
654
+ description: "Sign in with your wallet to trade across supported\nonchain prediction markets.",
655
+ supportedVenuesLabel: "Supported venues:",
656
+ connect: "Sign In with Wallet",
657
+ cancel: "Cancel",
658
+ fallbackError: "Signature declined. Please try again."
659
+ },
660
+ connectKalshiModal: {
661
+ ariaLabel: "Connect Kalshi Account",
662
+ title: "Connect Kalshi Account",
663
+ 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.",
664
+ stepOne: {
665
+ label: "Step 1",
666
+ title: "Generate a Read/Write API Key in Kalshi",
667
+ instructions: {
668
+ signIn: "1. Sign in to your Kalshi account.",
669
+ goToProfilePrefix: "2. Go to your",
670
+ profileText: "Profile",
671
+ goToProfileSeparator: ":",
672
+ profileUrl: "https://kalshi.com/account/profile",
673
+ clickCreateKeyPrefix: "3. Click",
674
+ createKeyText: "Create Key",
675
+ clickCreateKeySuffix: ".",
676
+ selectPermissionsPrefix: "4. Select",
677
+ readWriteText: "Read/Write",
678
+ selectPermissionsSuffix: " permissions.",
679
+ createKey: "5. Create the key."
680
+ },
681
+ footerLineOne: "Kalshi will display your API Key ID and Private Key.",
682
+ footerLineTwo: "You'll need both for the next step."
683
+ },
684
+ stepTwo: {
685
+ label: "Step 2",
686
+ title: "Paste Your Kalshi API Credentials",
687
+ description: "These credentials are encrypted and used only to execute trades on your behalf. We can't access your funds directly.",
688
+ apiKeyIdLabel: "API Key ID",
689
+ apiKeyIdPlaceholder: "a3f9c1b2-7d4e-4c91-9f2a-8b6e1d3c5a77",
690
+ privateKeyLabel: "Private Key",
691
+ privateKeyPlaceholder: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC..."
692
+ },
693
+ help: {
694
+ label: "Having trouble?",
695
+ docsLinkLabel: "View Kalshi docs",
696
+ tutorialLinkLabel: "Watch tutorial video"
697
+ },
698
+ actions: {
699
+ cancel: "Cancel",
700
+ verifyConnection: "Verify Connection"
701
+ },
702
+ fallbackError: "Verification failed. Please check your credentials and try again."
703
+ }
704
+ },
705
+ eventMarketPage: {
706
+ unavailableAria: "Event market page unavailable",
707
+ unavailableTitle: "Something went wrong",
708
+ unavailableDescription: "We're having trouble loading this event right now.\nTry refreshing or check back later.",
709
+ loadingSettlementQuestion: "Loading settlement",
710
+ loadingSettlementDifferencesTitle: "Loading settlement",
711
+ loadingSettlementPlaceholder: "Loading",
712
+ tradingResolvedBadge: "Resolved",
713
+ tradingResolvedTitle: "Market resolved",
714
+ tradingResolvedDescription: "Trading has ended for this event. You can review the final result.",
715
+ tradingClosedBadge: "Closed",
716
+ tradingClosedTitle: "Trading closed",
717
+ tradingClosedDescription: "This event is no longer accepting new orders.",
718
+ tradingPausedBadge: "Paused",
719
+ tradingPausedTitle: "Trading paused",
720
+ tradingPausedDescription: "Trading is temporarily unavailable for this event.",
721
+ tradingUnopenedBadge: "Upcoming",
722
+ tradingUnopenedTitle: "Trading not open yet",
723
+ tradingUnopenedDescription: "This event is listed, but trading has not opened yet.",
724
+ tradingUnavailableBadge: "Unavailable",
725
+ tradingUnavailableTitle: "Trading unavailable",
726
+ tradingUnavailableDescription: "Trading is currently unavailable for this event.",
727
+ resolvedAt: (dateLabel) => `Resolved ${dateLabel}`,
728
+ closedAt: (dateLabel) => `Closed ${dateLabel}`,
729
+ opensAt: (dateLabel) => `Opens ${dateLabel}`,
730
+ winningOutcome: (label) => `Winning outcome: ${label}`,
731
+ resolvedOutcome: (label) => `Resolved: ${label}`,
732
+ marketDetailsAriaByDate: (dateLabel) => `Market details for ${dateLabel}`,
733
+ marketDetailsAriaByQuestion: (question) => `Market details for ${question}`
734
+ },
735
+ header: {
736
+ bannerAria: "Site header",
737
+ logoAria: "Home"
738
+ }
739
+ };
740
+ var defaultAggUiLabelsByLocale = {
741
+ "en-US": enUsLabels,
742
+ en: enUsLabels
743
+ };
744
+ var resolveAggUiLabels = (locale) => {
745
+ var _a;
746
+ if (defaultAggUiLabelsByLocale[locale]) {
747
+ return defaultAggUiLabelsByLocale[locale];
748
+ }
749
+ const baseLocale = locale.split("-")[0];
750
+ return (_a = defaultAggUiLabelsByLocale[baseLocale]) != null ? _a : enUsLabels;
751
+ };
752
+
753
+ // src/core/ui-config/utils.ts
754
+ var DEFAULT_LOCALE = "en-US";
755
+ var createFormatters = (locale) => {
756
+ const number = new Intl.NumberFormat(locale, {
757
+ maximumFractionDigits: 2
758
+ });
759
+ const percent = new Intl.NumberFormat(locale, {
760
+ style: "percent",
761
+ minimumFractionDigits: 0,
762
+ maximumFractionDigits: 0
763
+ });
764
+ const currency = new Intl.NumberFormat(locale, {
765
+ style: "currency",
766
+ currency: "USD",
767
+ maximumFractionDigits: 2
768
+ });
769
+ const compactCurrency = new Intl.NumberFormat(locale, {
770
+ style: "currency",
771
+ currency: "USD",
772
+ notation: "compact",
773
+ maximumFractionDigits: 0
774
+ });
775
+ const date = new Intl.DateTimeFormat(locale, {
776
+ month: "long",
777
+ day: "numeric",
778
+ year: "numeric"
779
+ });
780
+ return {
781
+ formatNumber: (value) => number.format(value),
782
+ formatPercent: (value) => percent.format(value),
783
+ formatCurrency: (value) => currency.format(value),
784
+ formatCompactCurrency: (value) => compactCurrency.format(value),
785
+ formatDate: (value) => date.format(value)
786
+ };
787
+ };
788
+ var defaultFormatters = createFormatters(DEFAULT_LOCALE);
789
+ var defaultAggUiSearchConfig = {
790
+ value: "",
791
+ result: null,
792
+ isShowingAllResults: false
793
+ };
794
+ var defaultAggUiConfig = {
795
+ enableLogs: false,
796
+ enableWebsocketsLogs: false,
797
+ general: {
798
+ locale: DEFAULT_LOCALE,
799
+ theme: "light",
800
+ rootClassName: "",
801
+ labels: resolveAggUiLabels(DEFAULT_LOCALE)
802
+ },
803
+ features: {
804
+ enableAnimations: true,
805
+ enableLiveUpdates: true,
806
+ enableGradients: false
807
+ },
808
+ market: {
809
+ arbitrageThreshold: 0
810
+ },
811
+ chart: {
812
+ defaultChartTimeRange: "1D",
813
+ selectedChartTimeRange: "1D",
814
+ setSelectedChartTimeRange: () => {
815
+ }
816
+ },
817
+ formatting: defaultFormatters,
818
+ search: defaultAggUiSearchConfig
819
+ };
820
+
821
+ // src/core/providers/contexts.ts
822
+ var AggClientContext = (0, import_react.createContext)(null);
823
+ var AggUiContext = (0, import_react.createContext)(defaultAggUiConfig);
824
+ var AggLabelsContext = (0, import_react.createContext)(defaultAggUiConfig.general.labels);
825
+ var AggAuthContext = (0, import_react.createContext)(null);
826
+ var AggBalanceContext = (0, import_react.createContext)(null);
827
+
828
+ // src/execution/query-keys.ts
829
+ var executionKeys = {
830
+ all: () => ["execution"],
831
+ balances: () => ["execution", "balances"],
832
+ positions: (cursor, limit, status) => ["execution", "positions", cursor != null ? cursor : null, limit != null ? limit : null, status != null ? status : null],
833
+ positionsPrefix: () => ["execution", "positions"],
834
+ claimableClosedPositionsCount: () => ["execution", "positions", "claimable-count"],
835
+ orders: (status, cursor, limit) => ["execution", "orders", status != null ? status : null, cursor != null ? cursor : null, limit != null ? limit : null],
836
+ ordersPrefix: () => ["execution", "orders"],
837
+ depositAddresses: () => ["execution", "deposit-addresses"]
838
+ };
839
+
840
+ // src/execution/balance-invalidation.ts
841
+ var balanceQueryKeys = {
842
+ execution: () => executionKeys.balances(),
843
+ // Kept as an alias for backward compatibility with existing callers.
844
+ // The balance provider now uses the same canonical execution balances key.
845
+ provider: () => executionKeys.balances(),
846
+ venue: (venuesKey) => ["venue-balances", venuesKey],
847
+ venuePrefix: () => ["venue-balances"]
848
+ };
849
+ var invalidateBalanceQueries = (queryClient, options) => {
850
+ var _a;
851
+ const refetchType = (_a = options == null ? void 0 : options.refetchType) != null ? _a : "active";
852
+ const executionKey = balanceQueryKeys.execution();
853
+ const providerKey = balanceQueryKeys.provider();
854
+ queryClient.invalidateQueries({
855
+ queryKey: executionKey,
856
+ refetchType
857
+ });
858
+ const isProviderKeyDistinct = providerKey.length !== executionKey.length || providerKey.some((segment, index) => segment !== executionKey[index]);
859
+ if (isProviderKeyDistinct) {
860
+ queryClient.invalidateQueries({
861
+ queryKey: providerKey,
862
+ refetchType
863
+ });
864
+ }
865
+ queryClient.invalidateQueries({
866
+ queryKey: balanceQueryKeys.venuePrefix(),
867
+ refetchType
868
+ });
869
+ };
870
+
871
+ // src/core/providers/ws-provider.tsx
872
+ var import_react3 = require("react");
873
+ var import_react_query = require("@tanstack/react-query");
874
+
875
+ // src/core/providers/hooks.ts
876
+ var import_react2 = require("react");
877
+ var useAggClient = () => {
878
+ const client = (0, import_react2.useContext)(AggClientContext);
879
+ if (!client) {
880
+ throw new Error("useAggClient must be used within an <AggProvider>");
881
+ }
882
+ return client;
883
+ };
884
+ var useAggBalanceContext = () => {
885
+ const context = (0, import_react2.useContext)(AggBalanceContext);
886
+ if (!context) {
887
+ throw new Error("useAggBalanceContext must be used within an <AggProvider>");
888
+ }
889
+ return context;
890
+ };
891
+ var useAggBalanceState = useAggBalanceContext;
892
+
893
+ // src/core/providers/ws-provider.tsx
894
+ var import_jsx_runtime = require("react/jsx-runtime");
895
+ var AggWebSocketContext = (0, import_react3.createContext)(null);
896
+ var AggWebSocketConnectionContext = (0, import_react3.createContext)(false);
897
+ var AggWsUserEventContext = (0, import_react3.createContext)(null);
898
+ function useAggWebSocket() {
899
+ return (0, import_react3.useContext)(AggWebSocketContext);
900
+ }
901
+ function useAggWebSocketConnectionState() {
902
+ return (0, import_react3.useContext)(AggWebSocketConnectionContext);
903
+ }
904
+ function useOnWithdrawalLifecycle(callback) {
905
+ const listeners = (0, import_react3.useContext)(AggWsUserEventContext);
906
+ const callbackRef = (0, import_react3.useRef)(callback);
907
+ callbackRef.current = callback;
908
+ const hasCallback = callback !== null;
909
+ (0, import_react3.useEffect)(() => {
910
+ if (!listeners || !callbackRef.current) return;
911
+ const handler = (msg) => {
912
+ var _a;
913
+ (_a = callbackRef.current) == null ? void 0 : _a.call(callbackRef, msg);
914
+ };
915
+ return listeners.addWithdrawalLifecycleListener(handler);
916
+ }, [listeners, hasCallback]);
917
+ }
918
+
919
+ // src/execution/use-withdraw-managed.ts
920
+ var import_react_query2 = require("@tanstack/react-query");
921
+ function useWithdrawManaged(options) {
922
+ const client = useAggClient();
923
+ const queryClient = (0, import_react_query2.useQueryClient)();
924
+ return (0, import_react_query2.useMutation)({
925
+ mutationFn: (params) => client.withdrawManaged(params),
926
+ onSuccess: (data) => {
927
+ var _a;
928
+ invalidateBalanceQueries(queryClient);
929
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
930
+ },
931
+ onError: options == null ? void 0 : options.onError
932
+ });
933
+ }
934
+
935
+ // src/execution/use-managed-balances.ts
936
+ var import_react_query3 = require("@tanstack/react-query");
937
+ function useManagedBalances(options) {
938
+ const client = useAggClient();
939
+ const { enabled = true } = options != null ? options : {};
940
+ const query = (0, import_react_query3.useQuery)({
941
+ queryKey: executionKeys.balances(),
942
+ queryFn: () => client.getManagedBalances(),
943
+ enabled,
944
+ staleTime: 1e4,
945
+ gcTime: 5 * 6e4,
946
+ retry: 1
947
+ });
948
+ return __spreadProps(__spreadValues({}, query), {
949
+ balances: query.data
950
+ });
951
+ }
952
+
953
+ // src/execution/use-deposit-addresses.ts
954
+ var import_react4 = require("react");
955
+ var import_react_query4 = require("@tanstack/react-query");
956
+ var SVM_CHAIN_IDS = /* @__PURE__ */ new Set([792703809]);
957
+ function getDepositAddress(chainId, data) {
958
+ return chainId !== void 0 && SVM_CHAIN_IDS.has(chainId) ? data.svmAddress : data.evmAddress;
959
+ }
960
+ function useDepositAddresses(options) {
961
+ var _a;
962
+ const client = useAggClient();
963
+ const {
964
+ enabled = true,
965
+ poll = true,
966
+ refetchIntervalMs = 5e3,
967
+ timeoutMs = 6e4
968
+ } = options != null ? options : {};
969
+ const [isTimedOut, setIsTimedOut] = (0, import_react4.useState)(false);
970
+ const timeoutRef = (0, import_react4.useRef)(null);
971
+ (0, import_react4.useEffect)(() => {
972
+ if (!enabled || !poll) return void 0;
973
+ setIsTimedOut(false);
974
+ timeoutRef.current = setTimeout(() => setIsTimedOut(true), timeoutMs);
975
+ return () => {
976
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
977
+ };
978
+ }, [enabled, poll, timeoutMs]);
979
+ const query = (0, import_react_query4.useQuery)({
980
+ queryKey: executionKeys.depositAddresses(),
981
+ queryFn: () => client.getDepositAddresses(),
982
+ enabled,
983
+ staleTime: 6e4,
984
+ gcTime: 5 * 6e4,
985
+ retry: 1,
986
+ refetchInterval: (q) => {
987
+ if (!poll || isTimedOut) return false;
988
+ const data = q.state.data;
989
+ if ((data == null ? void 0 : data.ready) === true) return false;
990
+ return refetchIntervalMs;
991
+ }
992
+ });
993
+ const isReady = ((_a = query.data) == null ? void 0 : _a.ready) === true;
994
+ const readyData = isReady ? query.data : void 0;
995
+ const evmAddress = (0, import_react4.useMemo)(() => readyData == null ? void 0 : readyData.evmAddress, [readyData]);
996
+ const svmAddress = (0, import_react4.useMemo)(() => readyData == null ? void 0 : readyData.svmAddress, [readyData]);
997
+ const supportedChains = (0, import_react4.useMemo)(() => readyData == null ? void 0 : readyData.supportedChains, [readyData]);
998
+ return __spreadProps(__spreadValues({}, query), {
999
+ isReady,
1000
+ isTimedOut,
1001
+ evmAddress,
1002
+ svmAddress,
1003
+ supportedChains,
1004
+ depositAddresses: query.data,
1005
+ /** Resolve the correct address (EVM or SVM) for a given chainId. */
1006
+ getAddress: (chainId) => readyData ? getDepositAddress(chainId, readyData) : void 0
1007
+ });
1008
+ }
1009
+
1010
+ // src/execution/use-sync-balances.ts
1011
+ var import_react_query5 = require("@tanstack/react-query");
1012
+ function useSyncBalances(options) {
1013
+ const client = useAggClient();
1014
+ const queryClient = (0, import_react_query5.useQueryClient)();
1015
+ return (0, import_react_query5.useMutation)({
1016
+ mutationFn: () => client.syncManagedBalances(),
1017
+ onSuccess: () => {
1018
+ var _a;
1019
+ invalidateBalanceQueries(queryClient);
1020
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
1021
+ },
1022
+ onError: options == null ? void 0 : options.onError
1023
+ });
1024
+ }
1025
+
1026
+ // src/withdraw/use-withdraw-flow.ts
1027
+ var EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
1028
+ var SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
1029
+ var SOLANA_CHAIN_ID = 792703809;
1030
+ var WITHDRAWAL_SUPPORTED_CHAIN_IDS = /* @__PURE__ */ new Set([
1031
+ 1,
1032
+ // Ethereum
1033
+ 137,
1034
+ // Polygon
1035
+ 42161,
1036
+ // Arbitrum
1037
+ 8453,
1038
+ // Base
1039
+ 56,
1040
+ // BNB
1041
+ SOLANA_CHAIN_ID
1042
+ ]);
1043
+ var isValidDestinationAddress = (address, chainId) => {
1044
+ if (chainId === SOLANA_CHAIN_ID) return SOLANA_ADDRESS_REGEX.test(address);
1045
+ return EVM_ADDRESS_REGEX.test(address);
1046
+ };
1047
+ var DEFAULT_WITHDRAW_SUMMARY = {
1048
+ amountReceived: "",
1049
+ network: "",
1050
+ toWallet: "",
1051
+ fees: "\u2014"
1052
+ };
1053
+ var formatRawTokenAmount = (rawAmount, decimals) => {
1054
+ if (!rawAmount) return "0";
1055
+ const raw = BigInt(rawAmount);
1056
+ const divisor = BigInt(`1${"0".repeat(decimals)}`);
1057
+ const whole = raw / divisor;
1058
+ const remainder = raw % divisor;
1059
+ if (remainder === BigInt(0)) return whole.toString();
1060
+ return `${whole.toString()}.${remainder.toString().padStart(decimals, "0").replace(/0+$/, "")}`;
1061
+ };
1062
+ var formatRawTokenAmountForDisplay = (rawAmount, decimals, fractionDigits = 2) => {
1063
+ const [wholePart, fractionalPart = ""] = formatRawTokenAmount(rawAmount, decimals).split(".");
1064
+ const normalizedFraction = fractionalPart.padEnd(fractionDigits, "0").slice(0, fractionDigits);
1065
+ return `${wholePart}.${normalizedFraction}`;
1066
+ };
1067
+ var parseTokenAmountToRaw = (amount, decimals) => {
1068
+ const normalizedAmount = amount.trim();
1069
+ if (!normalizedAmount || !/^\d*(?:\.\d*)?$/.test(normalizedAmount)) {
1070
+ return null;
1071
+ }
1072
+ const [wholePart = "0", fractionalPart = ""] = normalizedAmount.split(".");
1073
+ if (fractionalPart.length > decimals) return null;
1074
+ const normalizedWhole = wholePart === "" ? "0" : wholePart;
1075
+ const normalizedFraction = fractionalPart.padEnd(decimals, "0");
1076
+ try {
1077
+ return `${BigInt(normalizedWhole)}${normalizedFraction}`.replace(/^0+(?=\d)/, "");
1078
+ } catch (e) {
1079
+ return null;
1080
+ }
1081
+ };
1082
+ var shortenAddress = (address) => address.length > 12 ? `${address.slice(0, 6)}....${address.slice(-4)}` : address;
1083
+ function useWithdrawFlow(options) {
1084
+ var _a, _b;
1085
+ const { open, onOpenChange } = options;
1086
+ const { totalBalance } = useAggBalanceState();
1087
+ const { balances } = useManagedBalances({ enabled: open });
1088
+ const { supportedChains } = useDepositAddresses({ enabled: open });
1089
+ const withdrawMutation = useWithdrawManaged();
1090
+ const syncBalances = useSyncBalances();
1091
+ const ws = useAggWebSocket();
1092
+ (0, import_react5.useEffect)(() => {
1093
+ if (!open) return;
1094
+ syncBalances.mutate(void 0, {
1095
+ onError: () => {
1096
+ }
1097
+ });
1098
+ }, [open]);
1099
+ const [withdrawDestination, setWithdrawDestination] = (0, import_react5.useState)("");
1100
+ const [withdrawAmount, setWithdrawAmount] = (0, import_react5.useState)("");
1101
+ const [withdrawToken, setWithdrawToken] = (0, import_react5.useState)("USDC");
1102
+ const [withdrawNetwork, setWithdrawNetwork] = (0, import_react5.useState)("");
1103
+ const [withdrawSummary, setWithdrawSummary] = (0, import_react5.useState)(DEFAULT_WITHDRAW_SUMMARY);
1104
+ const [withdrawalId, setWithdrawalId] = (0, import_react5.useState)(null);
1105
+ const networkOptions = (0, import_react5.useMemo)(
1106
+ () => (supportedChains != null ? supportedChains : []).filter((chain) => WITHDRAWAL_SUPPORTED_CHAIN_IDS.has(chain.chainId)).map((chain) => ({
1107
+ value: String(chain.chainId),
1108
+ label: chain.name
1109
+ })),
1110
+ [supportedChains]
1111
+ );
1112
+ const resolvedWithdrawNetwork = withdrawNetwork || ((_a = networkOptions[0]) == null ? void 0 : _a.value) || "";
1113
+ (0, import_react5.useEffect)(() => {
1114
+ if (!networkOptions.length) return;
1115
+ if (!withdrawNetwork || !networkOptions.some((option) => option.value === withdrawNetwork)) {
1116
+ setWithdrawNetwork(networkOptions[0].value);
1117
+ }
1118
+ }, [networkOptions, withdrawNetwork]);
1119
+ const tokenOptions = (0, import_react5.useMemo)(() => {
1120
+ var _a2, _b2, _c;
1121
+ const selectedChainId = Number(resolvedWithdrawNetwork);
1122
+ const supportedTokensForNetwork = (_b2 = (_a2 = supportedChains == null ? void 0 : supportedChains.find((chain) => chain.chainId === selectedChainId)) == null ? void 0 : _a2.tokens) != null ? _b2 : [];
1123
+ const withdrawableSymbols = new Set(supportedTokensForNetwork.map((token) => token.symbol));
1124
+ return ((_c = balances == null ? void 0 : balances.cash) != null ? _c : []).filter((cashEntry) => withdrawableSymbols.has(cashEntry.tokenSymbol)).map((cashEntry) => ({
1125
+ value: cashEntry.tokenSymbol,
1126
+ label: cashEntry.tokenSymbol
1127
+ }));
1128
+ }, [balances, resolvedWithdrawNetwork, supportedChains]);
1129
+ const resolvedWithdrawToken = tokenOptions.some((option) => option.value === withdrawToken) ? withdrawToken : ((_b = tokenOptions[0]) == null ? void 0 : _b.value) || "";
1130
+ (0, import_react5.useEffect)(() => {
1131
+ if (!tokenOptions.length) return;
1132
+ if (!tokenOptions.some((option) => option.value === withdrawToken)) {
1133
+ setWithdrawToken(tokenOptions[0].value);
1134
+ }
1135
+ }, [tokenOptions, withdrawToken]);
1136
+ const selectedCashEntry = (0, import_react5.useMemo)(
1137
+ () => balances == null ? void 0 : balances.cash.find((cashEntry) => cashEntry.tokenSymbol === resolvedWithdrawToken),
1138
+ [balances, resolvedWithdrawToken]
1139
+ );
1140
+ const selectedTokenDecimals = (0, import_react5.useMemo)(() => {
1141
+ var _a2, _b2, _c, _d;
1142
+ const selectedChainId = Number(resolvedWithdrawNetwork);
1143
+ return (_d = (_c = (_b2 = (_a2 = supportedChains == null ? void 0 : supportedChains.find((chain) => chain.chainId === selectedChainId)) == null ? void 0 : _a2.tokens.find((token) => token.symbol === resolvedWithdrawToken)) == null ? void 0 : _b2.decimals) != null ? _c : selectedCashEntry == null ? void 0 : selectedCashEntry.decimals) != null ? _d : 6;
1144
+ }, [
1145
+ resolvedWithdrawNetwork,
1146
+ resolvedWithdrawToken,
1147
+ selectedCashEntry == null ? void 0 : selectedCashEntry.decimals,
1148
+ supportedChains
1149
+ ]);
1150
+ const exactBalance = (0, import_react5.useMemo)(() => {
1151
+ if (!selectedCashEntry) return "0";
1152
+ return formatRawTokenAmount(selectedCashEntry.totalRaw, selectedCashEntry.decimals);
1153
+ }, [selectedCashEntry]);
1154
+ const balanceDisplay = (0, import_react5.useMemo)(() => {
1155
+ if (!selectedCashEntry) return `0.00 ${resolvedWithdrawToken || withdrawToken}`;
1156
+ return `${formatRawTokenAmountForDisplay(
1157
+ selectedCashEntry.totalRaw,
1158
+ selectedCashEntry.decimals
1159
+ )} ${resolvedWithdrawToken}`;
1160
+ }, [resolvedWithdrawToken, selectedCashEntry, withdrawToken]);
1161
+ const resetFlowState = (0, import_react5.useCallback)(() => {
1162
+ setWithdrawDestination("");
1163
+ setWithdrawAmount("");
1164
+ setWithdrawToken("USDC");
1165
+ setWithdrawNetwork("");
1166
+ setWithdrawSummary(DEFAULT_WITHDRAW_SUMMARY);
1167
+ setWithdrawalId(null);
1168
+ }, []);
1169
+ const handleWithdrawOpenChange = (0, import_react5.useCallback)(
1170
+ (isOpen) => {
1171
+ if (!isOpen) resetFlowState();
1172
+ onOpenChange(isOpen);
1173
+ },
1174
+ [onOpenChange, resetFlowState]
1175
+ );
1176
+ (0, import_react5.useEffect)(() => {
1177
+ if (!open) resetFlowState();
1178
+ }, [open, resetFlowState]);
1179
+ const handleWithdrawProvider = (0, import_react5.useCallback)(() => __async(null, null, function* () {
1180
+ var _a2, _b2;
1181
+ const destinationChainId = Number(resolvedWithdrawNetwork);
1182
+ const trimmedDestination = withdrawDestination.trim();
1183
+ const amountRaw = parseTokenAmountToRaw(withdrawAmount, selectedTokenDecimals);
1184
+ if (!amountRaw || BigInt(amountRaw) <= BigInt(0)) {
1185
+ throw new Error("Enter a withdrawal amount greater than zero.");
1186
+ }
1187
+ if (!Number.isFinite(destinationChainId) || destinationChainId <= 0) {
1188
+ throw new Error("Select a destination network.");
1189
+ }
1190
+ if (!isValidDestinationAddress(trimmedDestination, destinationChainId)) {
1191
+ const expected = destinationChainId === SOLANA_CHAIN_ID ? "a Solana wallet address (base58, 32\u201344 chars)" : "an EVM destination address (0x\u2026 40 hex chars)";
1192
+ throw new Error(`Enter ${expected}.`);
1193
+ }
1194
+ if (selectedCashEntry) {
1195
+ const scaleBy = (n, exp) => {
1196
+ if (exp <= 0) return n;
1197
+ return n * BigInt(`1${"0".repeat(exp)}`);
1198
+ };
1199
+ const balanceInDestFrame = (() => {
1200
+ const native = BigInt(selectedCashEntry.totalRaw);
1201
+ if (selectedCashEntry.decimals === selectedTokenDecimals) return native;
1202
+ if (selectedCashEntry.decimals > selectedTokenDecimals) {
1203
+ return native / scaleBy(BigInt(1), selectedCashEntry.decimals - selectedTokenDecimals);
1204
+ }
1205
+ return scaleBy(native, selectedTokenDecimals - selectedCashEntry.decimals);
1206
+ })();
1207
+ if (BigInt(amountRaw) > balanceInDestFrame) {
1208
+ throw new Error("Withdrawal amount exceeds your available balance.");
1209
+ }
1210
+ }
1211
+ ws == null ? void 0 : ws.connect();
1212
+ yield new Promise((resolve, reject) => {
1213
+ withdrawMutation.mutate(
1214
+ {
1215
+ amountRaw,
1216
+ tokenSymbol: resolvedWithdrawToken,
1217
+ destinationAddress: trimmedDestination,
1218
+ destinationChainId
1219
+ },
1220
+ {
1221
+ onSuccess: (data) => {
1222
+ setWithdrawalId(data.withdrawalId);
1223
+ resolve();
1224
+ },
1225
+ onError: reject
1226
+ }
1227
+ );
1228
+ });
1229
+ setWithdrawSummary({
1230
+ amountReceived: `${formatRawTokenAmountForDisplay(amountRaw, selectedTokenDecimals)} ${resolvedWithdrawToken}`,
1231
+ network: (_b2 = (_a2 = supportedChains == null ? void 0 : supportedChains.find((chain) => chain.chainId === destinationChainId)) == null ? void 0 : _a2.name) != null ? _b2 : resolvedWithdrawNetwork,
1232
+ toWallet: shortenAddress(trimmedDestination),
1233
+ fees: "\u2014"
1234
+ });
1235
+ }), [
1236
+ resolvedWithdrawNetwork,
1237
+ resolvedWithdrawToken,
1238
+ selectedCashEntry,
1239
+ selectedTokenDecimals,
1240
+ supportedChains,
1241
+ withdrawAmount,
1242
+ withdrawDestination,
1243
+ withdrawMutation,
1244
+ ws
1245
+ ]);
1246
+ return {
1247
+ open,
1248
+ onOpenChange: handleWithdrawOpenChange,
1249
+ withdrawFlow: {
1250
+ balance: totalBalance,
1251
+ balanceDisplay,
1252
+ amount: withdrawAmount,
1253
+ destinationWallet: withdrawDestination,
1254
+ tokenOptions,
1255
+ networkOptions,
1256
+ selectedToken: resolvedWithdrawToken,
1257
+ selectedNetwork: resolvedWithdrawNetwork,
1258
+ purchaseSummary: withdrawSummary,
1259
+ withdrawalId
1260
+ },
1261
+ onWithdrawDestinationChange: setWithdrawDestination,
1262
+ onWithdrawAmountChange: setWithdrawAmount,
1263
+ onWithdrawTokenChange: setWithdrawToken,
1264
+ onWithdrawNetworkChange: setWithdrawNetwork,
1265
+ onMaxClick: (0, import_react5.useCallback)(() => {
1266
+ setWithdrawAmount(exactBalance === "0" ? "0" : exactBalance);
1267
+ }, [exactBalance]),
1268
+ onSelectWithdrawProvider: (0, import_react5.useCallback)(
1269
+ (_providerId) => __async(null, null, function* () {
1270
+ return handleWithdrawProvider();
1271
+ }),
1272
+ [handleWithdrawProvider]
1273
+ ),
1274
+ onDoneWithdraw: (0, import_react5.useCallback)(() => handleWithdrawOpenChange(false), [handleWithdrawOpenChange])
1275
+ };
1276
+ }
1277
+
1278
+ // src/withdraw/use-withdrawal-lifecycle.ts
1279
+ var import_react6 = require("react");
1280
+ var import_react_query6 = require("@tanstack/react-query");
1281
+ var INITIAL_STATE = {
1282
+ pending: true,
1283
+ status: null,
1284
+ terminal: false,
1285
+ lastLeg: null,
1286
+ legs: [],
1287
+ errorMessage: null,
1288
+ timestamp: null
1289
+ };
1290
+ var restLegToWsLeg = (leg) => ({
1291
+ sourceChainId: leg.sourceChainId,
1292
+ destChainId: leg.destChainId,
1293
+ type: leg.type,
1294
+ // The wire-level WS leg status enum and the REST leg status enum are the
1295
+ // same union (planned/submitted/confirmed/failed). Keep the cast narrow to
1296
+ // avoid pulling the SDK enum apart for a one-line bridge.
1297
+ status: leg.status,
1298
+ amountRaw: leg.amountRaw,
1299
+ txHash: leg.txHash,
1300
+ bridgeOperationId: leg.bridgeOperationId
1301
+ });
1302
+ var mergeLegs = (prev, snapshot, delta) => {
1303
+ if (snapshot) return snapshot;
1304
+ if (!delta) return prev;
1305
+ const idx = prev.findIndex(
1306
+ (l) => l.sourceChainId === delta.sourceChainId && l.destChainId === delta.destChainId && l.type === delta.type
1307
+ );
1308
+ if (idx === -1) return [...prev, delta];
1309
+ const next = prev.slice();
1310
+ next[idx] = delta;
1311
+ return next;
1312
+ };
1313
+ var restToLifecycleState = (response) => {
1314
+ var _a;
1315
+ return {
1316
+ pending: false,
1317
+ status: response.status,
1318
+ terminal: response.status === "completed" || response.status === "partial" || response.status === "failed",
1319
+ lastLeg: null,
1320
+ legs: response.legs.map(restLegToWsLeg),
1321
+ errorMessage: (_a = response.errorMessage) != null ? _a : null,
1322
+ // No server timestamp on the REST response — we use 0 as "older than any
1323
+ // WS timestamp" so a subsequent WS event always wins. Callers that read
1324
+ // `timestamp` should treat 0/null interchangeably as "unset".
1325
+ timestamp: 0
1326
+ };
1327
+ };
1328
+ function useWithdrawalLifecycle(withdrawalId) {
1329
+ const client = useAggClient();
1330
+ const wsConnected = useAggWebSocketConnectionState();
1331
+ const queryClient = (0, import_react_query6.useQueryClient)();
1332
+ const [state, setState] = (0, import_react6.useState)(INITIAL_STATE);
1333
+ const stateRef = (0, import_react6.useRef)(state);
1334
+ stateRef.current = state;
1335
+ const balanceRefetchedForRef = (0, import_react6.useRef)(null);
1336
+ (0, import_react6.useEffect)(() => {
1337
+ setState(INITIAL_STATE);
1338
+ }, [withdrawalId]);
1339
+ (0, import_react6.useEffect)(() => {
1340
+ if (!withdrawalId) return;
1341
+ let cancelled = false;
1342
+ (() => __async(null, null, function* () {
1343
+ try {
1344
+ const response = yield client.getWithdrawalStatus(withdrawalId);
1345
+ if (cancelled) return;
1346
+ if (response.withdrawalId !== withdrawalId) return;
1347
+ const current = stateRef.current;
1348
+ const wsAlreadyWon = current.timestamp != null && current.timestamp > 0;
1349
+ if (wsAlreadyWon) return;
1350
+ setState(restToLifecycleState(response));
1351
+ } catch (e) {
1352
+ }
1353
+ }))();
1354
+ return () => {
1355
+ cancelled = true;
1356
+ };
1357
+ }, [client, withdrawalId, wsConnected]);
1358
+ const handler = (0, import_react6.useMemo)(() => {
1359
+ if (!withdrawalId) return null;
1360
+ return (msg) => {
1361
+ if (msg.withdrawalId !== withdrawalId) return;
1362
+ setState((prev) => {
1363
+ var _a, _b;
1364
+ return {
1365
+ pending: false,
1366
+ status: msg.status,
1367
+ terminal: msg.terminal,
1368
+ lastLeg: (_a = msg.leg) != null ? _a : null,
1369
+ // `legs[]` is the cumulative server-known truth. Snapshots
1370
+ // (`pending` / terminal rollup) carry a full `legs[]` and replace
1371
+ // it. Intermediate per-leg deltas carry only `leg` (no `legs[]`)
1372
+ // — merge the delta into the existing array by
1373
+ // (sourceChainId, destChainId, type) so the timeline UI doesn't
1374
+ // collapse to empty between snapshots.
1375
+ legs: mergeLegs(prev.legs, msg.legs, msg.leg),
1376
+ errorMessage: (_b = msg.errorMessage) != null ? _b : null,
1377
+ timestamp: msg.timestamp
1378
+ };
1379
+ });
1380
+ };
1381
+ }, [withdrawalId]);
1382
+ useOnWithdrawalLifecycle(handler);
1383
+ (0, import_react6.useEffect)(() => {
1384
+ if (!withdrawalId) return;
1385
+ if (!state.terminal) return;
1386
+ if (balanceRefetchedForRef.current === withdrawalId) return;
1387
+ balanceRefetchedForRef.current = withdrawalId;
1388
+ invalidateBalanceQueries(queryClient);
1389
+ client.syncManagedBalances().catch(() => {
1390
+ });
1391
+ }, [client, queryClient, state.terminal, withdrawalId]);
1392
+ const reset = (0, import_react6.useCallback)(() => setState(INITIAL_STATE), []);
1393
+ return { state, reset };
1394
+ }
1395
+ // Annotate the CommonJS export names for ESM import in node:
1396
+ 0 && (module.exports = {
1397
+ useDepositAddresses,
1398
+ useManagedBalances,
1399
+ useWithdrawFlow,
1400
+ useWithdrawManaged,
1401
+ useWithdrawalLifecycle
1402
+ });