0xtrails 0.9.2 → 0.9.4

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 (79) hide show
  1. package/dist/{ccip-g6lDdnrD.js → ccip-lAtzqne5.js} +1 -1
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/error.d.ts.map +1 -1
  7. package/dist/{index-D-QngA_s.js → index-D5AG6huo.js} +22290 -21786
  8. package/dist/index.js +3 -3
  9. package/dist/intents.d.ts +1 -1
  10. package/dist/intents.d.ts.map +1 -1
  11. package/dist/mutations.d.ts +5 -2
  12. package/dist/mutations.d.ts.map +1 -1
  13. package/dist/tokens.d.ts.map +1 -1
  14. package/dist/transactionIntent/constants.d.ts +1 -0
  15. package/dist/transactionIntent/constants.d.ts.map +1 -1
  16. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +3 -1
  17. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  18. package/dist/transactionIntent/deposits/standardDeposit.d.ts +4 -1
  19. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  20. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  21. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  22. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  23. package/dist/transactionIntent/types.d.ts +2 -0
  24. package/dist/transactionIntent/types.d.ts.map +1 -1
  25. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts +25 -0
  26. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts.map +1 -0
  27. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  28. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  29. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  30. package/dist/widget/components/DynamicInputStyles.d.ts +2 -2
  31. package/dist/widget/components/Earn.d.ts.map +1 -1
  32. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  33. package/dist/widget/components/Fund.d.ts.map +1 -1
  34. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  35. package/dist/widget/components/Receipt.d.ts.map +1 -1
  36. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  37. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  38. package/dist/widget/components/UserPreferences.d.ts.map +1 -1
  39. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  40. package/dist/widget/css/compiled.css +1 -1
  41. package/dist/widget/hooks/useQuote.d.ts +2 -0
  42. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  43. package/dist/widget/index.js +1 -1
  44. package/dist/widget/providers/TrailsProvider.d.ts +2 -0
  45. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -1
  46. package/dist/widget/widget.d.ts +1 -0
  47. package/dist/widget/widget.d.ts.map +1 -1
  48. package/package.json +2 -2
  49. package/src/config.ts +1 -0
  50. package/src/constants.ts +1 -0
  51. package/src/error.ts +6 -1
  52. package/src/intents.ts +22 -1
  53. package/src/prices.ts +1 -1
  54. package/src/tokens.ts +4 -3
  55. package/src/transactionIntent/constants.ts +2 -0
  56. package/src/transactionIntent/deposits/depositOrchestrator.ts +7 -0
  57. package/src/transactionIntent/deposits/standardDeposit.ts +194 -37
  58. package/src/transactionIntent/handlers/crossChain.ts +152 -105
  59. package/src/transactionIntent/handlers/sameChainSameToken.ts +1 -0
  60. package/src/transactionIntent/quote/normalizeQuote.ts +7 -4
  61. package/src/transactionIntent/types.ts +2 -0
  62. package/src/transactionIntent/utils/resilientDepositTracker.ts +281 -0
  63. package/src/widget/compiled.css +1 -1
  64. package/src/widget/components/AccountIntentTransactionHistory.tsx +170 -87
  65. package/src/widget/components/ClassicSwap.tsx +7 -1
  66. package/src/widget/components/ConfigDisplay.tsx +5 -0
  67. package/src/widget/components/Earn.tsx +14 -1
  68. package/src/widget/components/EarnPools.tsx +180 -59
  69. package/src/widget/components/Fund.tsx +3 -1
  70. package/src/widget/components/PoolWithdraw.tsx +1 -1
  71. package/src/widget/components/QuoteDetails.tsx +12 -35
  72. package/src/widget/components/Receipt.tsx +66 -40
  73. package/src/widget/components/SlippageToleranceSettings.tsx +86 -44
  74. package/src/widget/components/TransactionDetails.tsx +138 -218
  75. package/src/widget/components/UserPreferences.tsx +114 -41
  76. package/src/widget/components/WalletConnect.tsx +111 -48
  77. package/src/widget/hooks/useQuote.ts +389 -352
  78. package/src/widget/providers/TrailsProvider.tsx +5 -0
  79. package/src/widget/widget.tsx +2 -0
package/src/intents.ts CHANGED
@@ -120,6 +120,7 @@ export async function quoteIntent(
120
120
  trailsClient: TrailsApi,
121
121
  args: QuoteIntentRequest,
122
122
  additionalTrackingProps: Record<string, string> = {},
123
+ abortSignal?: AbortSignal,
123
124
  ): Promise<{
124
125
  intent: Intent
125
126
  gasFeeOptions?: GasFeeOptions
@@ -137,7 +138,27 @@ export async function quoteIntent(
137
138
 
138
139
  try {
139
140
  logger.console.log("[trails-sdk] quote intent args:", args)
140
- const response = await trailsClient.quoteIntent(args)
141
+
142
+ // Create a promise that rejects when the abort signal fires
143
+ let response: any
144
+ if (abortSignal) {
145
+ const abortPromise = new Promise((_, reject) => {
146
+ if (abortSignal.aborted) {
147
+ reject(new Error("Request aborted"))
148
+ }
149
+ abortSignal.addEventListener("abort", () => {
150
+ reject(new Error("Request aborted"))
151
+ })
152
+ })
153
+
154
+ // Race between the API call and the abort signal
155
+ response = await Promise.race([
156
+ trailsClient.quoteIntent(args, {}, abortSignal),
157
+ abortPromise,
158
+ ])
159
+ } else {
160
+ response = await trailsClient.quoteIntent(args)
161
+ }
141
162
 
142
163
  if (!response || !response.intent) {
143
164
  logger.console.error("[trails-sdk] No result from quoteIntent")
package/src/prices.ts CHANGED
@@ -10,7 +10,7 @@ const CACHE_CONFIG = {
10
10
  // Time configurations
11
11
  staleTime: 5000, // 5 seconds - max cache time for token balance related prices
12
12
  gcTime: 5000, // 5 seconds cache time
13
- refetchInterval: 60000, // Background refetch every minute for prices
13
+ refetchInterval: 15000, // Background refetch every 15 seconds for prices
14
14
 
15
15
  // Retry configurations
16
16
  retry: 2,
package/src/tokens.ts CHANGED
@@ -529,11 +529,12 @@ export function useSupportedTokens({ chainId }: { chainId?: number } = {}): {
529
529
  trailsConfig.trailsApiUrl,
530
530
  trailsConfig.trailsApiKey,
531
531
  ],
532
- queryFn: () =>
533
- getSupportedTokens({
532
+ queryFn: async () => {
533
+ return getSupportedTokens({
534
534
  trailsApiKey: trailsConfig.trailsApiKey,
535
535
  trailsApiUrl: trailsConfig.trailsApiUrl,
536
- }),
536
+ })
537
+ },
537
538
  staleTime: 60 * 60 * 1000, // 1 hour - tokens rarely change
538
539
  gcTime: 24 * 60 * 60 * 1000, // 24 hours - keep in cache for a full day
539
540
  refetchOnWindowFocus: false, // Don't refetch when window regains focus
@@ -8,4 +8,6 @@ export const POLLING_INTERVALS = {
8
8
  CCTP_QUEUE: 5000,
9
9
  // Consistent interval for failure polling (2 seconds)
10
10
  FAILURE_POLLING: 2000,
11
+ // Consistent interval for transaction receipt polling (3 seconds)
12
+ TRANSACTION_RECEIPT: 3000,
11
13
  } as const
@@ -52,6 +52,8 @@ export async function attemptUserDepositTx({
52
52
  depositRecipientOverride,
53
53
  isSameChainSameToken,
54
54
  destinationCalldata,
55
+ sequenceProjectAccessKey,
56
+ sequenceIndexerUrl,
55
57
  }: {
56
58
  originTokenAddress: string
57
59
  paymasterUrl?: string
@@ -89,6 +91,8 @@ export async function attemptUserDepositTx({
89
91
  depositRecipientOverride?: string
90
92
  isSameChainSameToken?: boolean
91
93
  destinationCalldata?: string
94
+ sequenceProjectAccessKey?: string
95
+ sequenceIndexerUrl?: string
92
96
  }): Promise<TransactionReceipt | null> {
93
97
  let depositUserTxnReceipt: TransactionReceipt | null = null
94
98
  const originChainId = chain.id
@@ -207,6 +211,9 @@ export async function attemptUserDepositTx({
207
211
  isSameChainSameToken,
208
212
  recipient: effectiveDepositRecipient,
209
213
  destinationCalldata,
214
+ sequenceProjectAccessKey,
215
+ sequenceIndexerUrl,
216
+ abortSignal,
210
217
  })
211
218
  }
212
219
 
@@ -22,6 +22,10 @@ import { updatePersistentToast } from "../../toast.js"
22
22
  import { getChainInfo } from "../../chains.js"
23
23
  import { trackTransactionConfirmed } from "../../analytics.js"
24
24
  import { getIsUserRejectionError } from "../../error.js"
25
+ import {
26
+ trackDepositResilient,
27
+ isRecoverableDepositError,
28
+ } from "../utils/resilientDepositTracker.js"
25
29
 
26
30
  export async function attemptStandardDeposit({
27
31
  originTokenAddress,
@@ -42,6 +46,9 @@ export async function attemptStandardDeposit({
42
46
  isSameChainSameToken,
43
47
  recipient,
44
48
  destinationCalldata,
49
+ sequenceProjectAccessKey,
50
+ sequenceIndexerUrl,
51
+ abortSignal,
45
52
  }: {
46
53
  originTokenAddress: string
47
54
  depositAmount: string
@@ -66,6 +73,9 @@ export async function attemptStandardDeposit({
66
73
  isSameChainSameToken?: boolean
67
74
  recipient?: string
68
75
  destinationCalldata?: string
76
+ sequenceProjectAccessKey?: string
77
+ sequenceIndexerUrl?: string
78
+ abortSignal?: AbortSignal
69
79
  }): Promise<TransactionReceipt | null> {
70
80
  logger.console.log("[trails-sdk] [STANDARD DEPOSIT] initiating deposit...")
71
81
  let depositUserTxnReceipt: TransactionReceipt | null = null
@@ -444,7 +454,9 @@ export async function attemptStandardDeposit({
444
454
  checkoutOnHandlers.triggerCheckoutSignatureRequest()
445
455
  }
446
456
 
447
- let txHash: `0x${string}`
457
+ let txHash: `0x${string}` | null = null
458
+ let sendError: unknown = null
459
+
448
460
  try {
449
461
  txHash = await sendOriginTransaction(
450
462
  account,
@@ -456,63 +468,208 @@ export async function attemptStandardDeposit({
456
468
  ) // TODO: Add proper type
457
469
  logger.console.log("[trails-sdk] origin tx", txHash)
458
470
 
471
+ // SIMULATE RPC ERROR: Throw error after successful transaction send
472
+ // This simulates the scenario where tx is broadcast but RPC fails immediately after
473
+ // if (true) { // Always enabled for testing
474
+ // logger.console.warn(
475
+ // "[trails-sdk] SIMULATING RPC ERROR after transaction send",
476
+ // { txHash }
477
+ // )
478
+ // throw new Error("SIMULATED: RPC connection lost after transaction broadcast")
479
+ // }
480
+
459
481
  // Trigger signature confirmed callback after successful signing
460
482
  if (checkoutOnHandlers?.triggerCheckoutSignatureConfirmed) {
461
- checkoutOnHandlers.triggerCheckoutSignatureConfirmed()
483
+ checkoutOnHandlers?.triggerCheckoutSignatureConfirmed?.()
462
484
  }
463
485
  } catch (error) {
486
+ sendError = error
487
+ logger.console.error(
488
+ "[trails-sdk] Error sending deposit transaction",
489
+ error,
490
+ )
491
+
464
492
  // Check if this is a user rejection error
465
493
  if (getIsUserRejectionError(error)) {
466
494
  if (checkoutOnHandlers?.triggerCheckoutSignatureRejected) {
467
495
  checkoutOnHandlers.triggerCheckoutSignatureRejected(error)
468
496
  }
497
+ throw error // User rejections should fail immediately
469
498
  }
470
- throw error
471
- }
472
499
 
473
- if (onOriginSend) {
474
- onOriginSend()
500
+ // For recoverable errors, log but don't throw yet
501
+ if (!isRecoverableDepositError(error)) {
502
+ throw error // Non-recoverable errors should fail
503
+ }
504
+
505
+ logger.console.log(
506
+ "[trails-sdk] Deposit send failed with recoverable error, will attempt polling",
507
+ { error: (error as Error)?.message },
508
+ )
475
509
  }
476
510
 
477
- if (transactionStates[0]) {
478
- transactionStates[0].state = "pending"
511
+ // Handle successful transaction hash or fall back to resilient tracking
512
+ if (txHash) {
513
+ if (onOriginSend) {
514
+ onOriginSend()
515
+ }
516
+
517
+ if (transactionStates[0]) {
518
+ transactionStates[0].state = "pending"
519
+ transactionStates[0].transactionHash = txHash
520
+
521
+ try {
522
+ onTransactionStateChange(transactionStates)
523
+ } catch (error) {
524
+ logger.console.error(
525
+ "[trails-sdk] Error calling onTransactionStateChange:",
526
+ error,
527
+ )
528
+ }
529
+ }
479
530
 
531
+ // Try normal receipt retrieval first
480
532
  try {
481
- onTransactionStateChange(transactionStates)
482
- } catch (error) {
483
- logger.console.error(
484
- "[trails-sdk] Error calling onTransactionStateChange:",
485
- error,
533
+ // Wait for transaction receipt
534
+ const receipt = await publicClient.waitForTransactionReceipt({
535
+ hash: txHash,
536
+ retryCount: 10,
537
+ })
538
+
539
+ const chainInfo = getChainInfo(originChainId)
540
+ updatePersistentToast(
541
+ "Transfer Confirmed",
542
+ `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
543
+ "info",
486
544
  )
545
+
546
+ trackTransactionConfirmed({
547
+ transactionHash: txHash,
548
+ chainId: originChainId,
549
+ userAddress: account.address,
550
+ blockNumber: Number(receipt.blockNumber),
551
+ originIntentAddress,
552
+ originTokenSymbol,
553
+ destinationTokenSymbol,
554
+ depositTokenAmountUsd: depositAmountUsd?.toString(),
555
+ })
556
+
557
+ logger.console.log("[trails-sdk] receipt", receipt)
558
+ depositUserTxnReceipt = receipt
559
+ } catch (receiptError) {
560
+ logger.console.warn(
561
+ "[trails-sdk] Could not get receipt, using resilient tracking",
562
+ { txHash, error: (receiptError as Error)?.message },
563
+ )
564
+
565
+ // Fall back to resilient tracking with known tx hash
566
+ depositUserTxnReceipt = await trackDepositResilient({
567
+ publicClient,
568
+ originChainId,
569
+ originIntentAddress,
570
+ originTokenAddress,
571
+ depositAmount,
572
+ txHash,
573
+ abortSignal,
574
+ sequenceProjectAccessKey,
575
+ sequenceIndexerUrl,
576
+ onDepositDetected: (hash, receipt) => {
577
+ const chainInfo = getChainInfo(originChainId)
578
+ updatePersistentToast(
579
+ "Transfer Confirmed",
580
+ `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
581
+ "info",
582
+ )
583
+
584
+ if (receipt?.status === "success" && hash) {
585
+ trackTransactionConfirmed({
586
+ transactionHash: hash,
587
+ chainId: originChainId,
588
+ userAddress: account.address,
589
+ blockNumber: Number(receipt.blockNumber || 0),
590
+ originIntentAddress,
591
+ originTokenSymbol,
592
+ destinationTokenSymbol,
593
+ depositTokenAmountUsd: depositAmountUsd?.toString(),
594
+ })
595
+ }
596
+ },
597
+ })
487
598
  }
488
- }
599
+ } else if (sendError && isRecoverableDepositError(sendError)) {
600
+ // No transaction hash but error is recoverable - start polling
601
+ logger.console.log(
602
+ "[trails-sdk] Starting resilient deposit tracking after send failure",
603
+ )
489
604
 
490
- // Wait for transaction receipt
491
- const receipt = await publicClient.waitForTransactionReceipt({
492
- hash: txHash,
493
- retryCount: 10,
494
- })
605
+ updatePersistentToast(
606
+ "Checking Transaction",
607
+ "Verifying transaction status...",
608
+ "info",
609
+ )
495
610
 
496
- const chainInfo = getChainInfo(originChainId)
497
- updatePersistentToast(
498
- "Transfer Confirmed",
499
- `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
500
- "info",
501
- )
611
+ depositUserTxnReceipt = await trackDepositResilient({
612
+ publicClient,
613
+ originChainId,
614
+ originIntentAddress,
615
+ originTokenAddress,
616
+ depositAmount,
617
+ txHash: null,
618
+ abortSignal,
619
+ sequenceProjectAccessKey,
620
+ sequenceIndexerUrl,
621
+ onDepositDetected: (detectedHash, receipt) => {
622
+ logger.console.log(
623
+ "[trails-sdk] Deposit detected via resilient tracking",
624
+ { hash: detectedHash },
625
+ )
626
+
627
+ if (onOriginSend) {
628
+ onOriginSend()
629
+ }
502
630
 
503
- trackTransactionConfirmed({
504
- transactionHash: txHash,
505
- chainId: originChainId,
506
- userAddress: account.address,
507
- blockNumber: Number(receipt.blockNumber),
508
- originIntentAddress,
509
- originTokenSymbol,
510
- destinationTokenSymbol,
511
- depositTokenAmountUsd: depositAmountUsd?.toString(),
512
- })
631
+ if (transactionStates[0] && detectedHash) {
632
+ transactionStates[0].state = "pending"
633
+ transactionStates[0].transactionHash = detectedHash
634
+
635
+ try {
636
+ onTransactionStateChange(transactionStates)
637
+ } catch (error) {
638
+ logger.console.error(
639
+ "[trails-sdk] Error calling onTransactionStateChange:",
640
+ error,
641
+ )
642
+ }
643
+ }
513
644
 
514
- logger.console.log("[trails-sdk] receipt", receipt)
515
- depositUserTxnReceipt = receipt
645
+ const chainInfo = getChainInfo(originChainId)
646
+ updatePersistentToast(
647
+ "Transfer Confirmed",
648
+ `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
649
+ "info",
650
+ )
651
+
652
+ if (receipt?.status === "success" && detectedHash) {
653
+ trackTransactionConfirmed({
654
+ transactionHash: detectedHash,
655
+ chainId: originChainId,
656
+ userAddress: account.address,
657
+ blockNumber: Number(receipt.blockNumber || 0),
658
+ originIntentAddress,
659
+ originTokenSymbol,
660
+ destinationTokenSymbol,
661
+ depositTokenAmountUsd: depositAmountUsd?.toString(),
662
+ })
663
+ }
664
+ },
665
+ })
666
+
667
+ if (!depositUserTxnReceipt) {
668
+ throw new Error(
669
+ "Deposit transaction could not be confirmed. Please check your wallet and try again.",
670
+ )
671
+ }
672
+ }
516
673
  }
517
674
 
518
675
  return depositUserTxnReceipt