0xtrails 0.6.0 → 0.6.2

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 (88) hide show
  1. package/dist/{ccip-Dw5AN7oU.js → ccip-CZfykYU7.js} +4 -4
  2. package/dist/chains.d.ts +9 -2
  3. package/dist/chains.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/contractUtils.d.ts +2 -1
  7. package/dist/contractUtils.d.ts.map +1 -1
  8. package/dist/{index-BtVUTbEZ.js → index-S9pphnT9.js} +29732 -36767
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +300 -242
  12. package/dist/prepareSend.d.ts.map +1 -1
  13. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  14. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  15. package/dist/transactionIntent/types.d.ts +3 -1
  16. package/dist/transactionIntent/types.d.ts.map +1 -1
  17. package/dist/widget/components/ChainImage.d.ts.map +1 -1
  18. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  19. package/dist/widget/components/DepositTracker.d.ts +12 -0
  20. package/dist/widget/components/DepositTracker.d.ts.map +1 -0
  21. package/dist/widget/components/Disconnect.d.ts.map +1 -1
  22. package/dist/widget/components/FeeBreakdown.d.ts.map +1 -1
  23. package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
  24. package/dist/widget/components/QRCodeOptions.d.ts +9 -0
  25. package/dist/widget/components/QRCodeOptions.d.ts.map +1 -0
  26. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  27. package/dist/widget/components/Receipt.d.ts.map +1 -1
  28. package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
  29. package/dist/widget/components/Toast.d.ts.map +1 -1
  30. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  31. package/dist/widget/components/WalletConnectionPending.d.ts.map +1 -1
  32. package/dist/widget/css/compiled.css +1 -1
  33. package/dist/widget/css/index.css +103 -38
  34. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  35. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  36. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  37. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  38. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  39. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  40. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  41. package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -1
  42. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  43. package/dist/widget/index.js +1 -1
  44. package/dist/widget/widget.d.ts.map +1 -1
  45. package/package.json +6 -9
  46. package/src/chains.ts +37 -4
  47. package/src/constants.ts +1 -0
  48. package/src/contractUtils.ts +8 -7
  49. package/src/estimate.ts +2 -2
  50. package/src/index.ts +2 -0
  51. package/src/intents.ts +2 -2
  52. package/src/paymasterSend.ts +2 -2
  53. package/src/prepareSend.ts +34 -3
  54. package/src/sendUserOp.ts +2 -2
  55. package/src/tokens.ts +2 -2
  56. package/src/transactionIntent/deposits/gaslessDeposit.ts +2 -2
  57. package/src/transactionIntent/handlers/crossChain.ts +51 -2
  58. package/src/transactionIntent/handlers/sameChainSameToken.ts +52 -2
  59. package/src/transactionIntent/quote/normalizeQuote.ts +2 -2
  60. package/src/transactionIntent/types.ts +9 -1
  61. package/src/widget/compiled.css +1 -1
  62. package/src/widget/components/ChainImage.tsx +10 -7
  63. package/src/widget/components/ChainList.tsx +1 -1
  64. package/src/widget/components/ClassicSwap.tsx +8 -4
  65. package/src/widget/components/ConnectedWallets.tsx +1 -1
  66. package/src/widget/components/DepositTracker.tsx +298 -0
  67. package/src/widget/components/Disconnect.tsx +24 -3
  68. package/src/widget/components/FeeBreakdown.tsx +3 -3
  69. package/src/widget/components/QRCodeDeposit.tsx +29 -19
  70. package/src/widget/components/QRCodeOptions.tsx +65 -0
  71. package/src/widget/components/QuoteDetails.tsx +694 -803
  72. package/src/widget/components/Receipt.tsx +76 -40
  73. package/src/widget/components/ThemeProvider.tsx +7 -12
  74. package/src/widget/components/Toast.tsx +3 -2
  75. package/src/widget/components/TokenSelector.tsx +1 -1
  76. package/src/widget/components/Tooltip.tsx +1 -1
  77. package/src/widget/components/TransferPendingVertical.tsx +11 -2
  78. package/src/widget/components/WalletConnectionPending.tsx +28 -5
  79. package/src/widget/hooks/useCheckout.ts +10 -2
  80. package/src/widget/hooks/useCurrentScreen.tsx +1 -0
  81. package/src/widget/hooks/useDebugScreens.ts +1 -0
  82. package/src/widget/hooks/useIntentTransactionHistory.ts +114 -143
  83. package/src/widget/hooks/useQuote.ts +92 -6
  84. package/src/widget/hooks/useSelectedFeeOption.tsx +86 -29
  85. package/src/widget/hooks/useSendForm.ts +43 -7
  86. package/src/widget/index.css +103 -38
  87. package/src/widget/widget.tsx +48 -5
  88. package/dist/0xtrails.css +0 -1
@@ -11,7 +11,7 @@ import {
11
11
  import type { TransactionState } from "./transactions.js"
12
12
  import { logger } from "./logger.js"
13
13
  import { getIsCustomCalldata } from "./contractUtils.js"
14
- import { getChainInfo, getPublicRpcClient } from "./chains.js"
14
+ import { getChainInfo, getChainRpcClient } from "./chains.js"
15
15
 
16
16
  // Import from transactionIntent module
17
17
  import {
@@ -88,6 +88,34 @@ export async function prepareSend(
88
88
  } = options
89
89
  let { sourceTokenPriceUsd, destinationTokenPriceUsd } = options
90
90
 
91
+ if (!originChainId) {
92
+ throw new Error("Origin chain ID is required")
93
+ }
94
+
95
+ if (!destinationChainId) {
96
+ throw new Error("Destination chain ID is required")
97
+ }
98
+
99
+ // Sanity check: verify originPublicClient chain ID matches originChainId
100
+ if (options.originPublicClient) {
101
+ const clientChainId = options.originPublicClient?.chain?.id
102
+ if (clientChainId !== originChainId) {
103
+ throw new Error(
104
+ `Origin public client chain ID mismatch: expected ${originChainId}, got ${clientChainId}`,
105
+ )
106
+ }
107
+ }
108
+
109
+ // Sanity check: verify destinationPublicClient chain ID matches destinationChainId
110
+ if (options.destinationPublicClient) {
111
+ const clientChainId = options.destinationPublicClient?.chain?.id
112
+ if (clientChainId !== destinationChainId) {
113
+ throw new Error(
114
+ `Destination public client chain ID mismatch: expected ${destinationChainId}, got ${clientChainId}`,
115
+ )
116
+ }
117
+ }
118
+
91
119
  // Use slippage from options, or get from localStorage with config default fallback
92
120
  // The config default (slippageToleranceFromOptions) comes from React component context
93
121
  const slippageTolerance = getSlippageToleranceValue(
@@ -261,13 +289,16 @@ export async function prepareSend(
261
289
  })
262
290
  throw new Error(`Chain ${originChainId} not found`)
263
291
  }
292
+ const isToSelf =
293
+ account.address.toLowerCase() === effectiveDestinationAddress.toLowerCase()
264
294
  const isToSameChain = isSameChain(originChainId, destinationChainId)
265
295
  const isToSameToken = isSameToken(originTokenAddress, destinationTokenAddress)
266
296
 
267
297
  logger.console.log("[trails-sdk] isToSameChain", isToSameChain)
268
298
  logger.console.log("[trails-sdk] isToSameToken", isToSameToken)
269
299
 
270
- const publicClient = getPublicRpcClient(chain)
300
+ const publicClient =
301
+ options.originPublicClient ?? getChainRpcClient(originChainId)
271
302
 
272
303
  // origin tx
273
304
  transactionStates.push({
@@ -311,7 +342,7 @@ export async function prepareSend(
311
342
  explorerUrl: "",
312
343
  chainId: destinationChainId,
313
344
  state: "pending",
314
- label: hasCustomCalldata ? "Execute" : "Receive",
345
+ label: hasCustomCalldata ? "Execute" : isToSelf ? "Receive" : "Send",
315
346
  })
316
347
  }
317
348
 
package/src/sendUserOp.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  slice,
14
14
  toHex,
15
15
  } from "viem"
16
- import { getHttpTransport, getPublicRpcClient } from "./chains.js"
16
+ import { getHttpTransport, getChainRpcClient } from "./chains.js"
17
17
  import { privateKeyToAccount } from "viem/accounts"
18
18
  import { logger } from "./logger.js"
19
19
 
@@ -190,7 +190,7 @@ export async function sendUserOperationDirectly({
190
190
  account: relayerAccount,
191
191
  })
192
192
 
193
- const publicClient = getPublicRpcClient(chain)
193
+ const publicClient = getChainRpcClient(chain.id)
194
194
 
195
195
  const packedOp = toPackedUserOperation(userOp) // converts to PackedUserOperation
196
196
 
package/src/tokens.ts CHANGED
@@ -3,7 +3,7 @@ import { zeroAddress, erc20Abi } from "viem"
3
3
  import {
4
4
  getChainInfo,
5
5
  getSupportedChains,
6
- getPublicRpcClient,
6
+ getChainRpcClient,
7
7
  } from "./chains.js"
8
8
  import {
9
9
  arbitrum,
@@ -492,7 +492,7 @@ export async function getTokenInfo(
492
492
  }
493
493
 
494
494
  // Create a public client for the specific chain
495
- const publicClient = getPublicRpcClient(chainInfo)
495
+ const publicClient = getChainRpcClient(chainId)
496
496
 
497
497
  // Read token data on-chain
498
498
  const [name, symbol, decimals] = await Promise.all([
@@ -27,7 +27,7 @@ import {
27
27
  validateGaslessSignature,
28
28
  } from "../../gasless.js"
29
29
  import { getIsUserRejectionError } from "../../error.js"
30
- import { getPublicRpcClient } from "../../chains.js"
30
+ import { getChainRpcClient } from "../../chains.js"
31
31
 
32
32
  export async function attemptGaslessDeposit({
33
33
  paymasterUrl,
@@ -86,7 +86,7 @@ export async function attemptGaslessDeposit({
86
86
  },
87
87
  )
88
88
 
89
- const publicClient = getPublicRpcClient(chain)
89
+ const publicClient = getChainRpcClient(chain.id)
90
90
 
91
91
  logger.console.log("[trails-sdk] [GASLESS-FLOW] Intent entrypoint check:", {
92
92
  chainId: chain.id,
@@ -6,7 +6,7 @@ import type {
6
6
  TransactionReceipt,
7
7
  } from "viem"
8
8
  import { JsonEncode } from "@0xsequence/trails-api"
9
- import { getPublicRpcClient } from "../../chains.js"
9
+ import { getChainRpcClient } from "../../chains.js"
10
10
  import type { FeeOption, TrailsApi } from "@0xsequence/trails-api"
11
11
  import type { IntentTransaction } from "@0xsequence/trails-api"
12
12
  import type { PrepareSendReturn, SendReturn } from "../types.js"
@@ -458,7 +458,9 @@ export async function handleCrossChain({
458
458
  if (!destinationChainInfo) {
459
459
  throw new Error(`Chain ${destinationChainId} not found`)
460
460
  }
461
- const destinationPublicClient = getPublicRpcClient(destinationChainInfo)
461
+ const destinationPublicClient = getChainRpcClient(
462
+ destinationChainInfo.id,
463
+ )
462
464
 
463
465
  const depositPromise = async () => {
464
466
  logger.console.log(
@@ -695,6 +697,53 @@ export async function handleCrossChain({
695
697
  hash: tx.txnHash as `0x${string}`,
696
698
  })
697
699
 
700
+ // Validate that the deposit amount is sufficient before proceeding
701
+ logger.console.log(
702
+ "[trails-sdk] Checking if deposit amount is sufficient (cross-chain)",
703
+ {
704
+ depositAddress: originIntentAddress,
705
+ requiredAmount: quote.originAmount,
706
+ tokenAddress: originTokenAddress,
707
+ },
708
+ )
709
+
710
+ const balanceCheck = await checkAccountBalance({
711
+ account: {
712
+ address: originIntentAddress as `0x${string}`,
713
+ } as Account,
714
+ tokenAddress: originTokenAddress,
715
+ depositAmount: quote.originAmount,
716
+ publicClient: publicClient,
717
+ })
718
+
719
+ if (!balanceCheck.hasEnoughBalance) {
720
+ logger.console.warn(
721
+ "[trails-sdk] Deposit amount is insufficient, continuing to poll (cross-chain)",
722
+ {
723
+ balance: balanceCheck.balanceFormatted,
724
+ required: balanceCheck.requiredAmountFormatted,
725
+ percentComplete: (
726
+ (Number(balanceCheck.balance) /
727
+ Number(balanceCheck.requiredAmount)) *
728
+ 100
729
+ ).toFixed(2),
730
+ },
731
+ )
732
+ // Continue polling - don't break out of the loop yet
733
+ await new Promise((resolve) =>
734
+ setTimeout(resolve, POLLING_INTERVALS.TRANSACTION_HISTORY),
735
+ )
736
+ continue
737
+ }
738
+
739
+ logger.console.log(
740
+ "[trails-sdk] Deposit amount is sufficient, proceeding (cross-chain)",
741
+ {
742
+ balance: balanceCheck.balanceFormatted,
743
+ required: balanceCheck.requiredAmountFormatted,
744
+ },
745
+ )
746
+
698
747
  depositUserTxnReceipt = originDepositTxReceipt
699
748
 
700
749
  transactionStates[0] = getTransactionStateFromReceipt(
@@ -1,6 +1,6 @@
1
1
  import type { Account, Chain, WalletClient, TransactionReceipt } from "viem"
2
2
  import { formatUnits } from "viem"
3
- import { getPublicRpcClient } from "../../chains.js"
3
+ import { getChainRpcClient } from "../../chains.js"
4
4
  import type { FeeOption, TrailsApi } from "@0xsequence/trails-api"
5
5
  import type { PrepareSendReturn, SendReturn } from "../types.js"
6
6
  import type { IntentTransaction } from "@0xsequence/trails-api"
@@ -116,7 +116,7 @@ export async function handleSameChainSameToken({
116
116
  const effectiveOriginTokenAddress = testnet
117
117
  ? getTestnetOriginTokenAddress(effectiveOriginChainId)
118
118
  : originTokenAddress
119
- const effectivePublicClient = getPublicRpcClient(effectiveOriginChain)
119
+ const effectivePublicClient = getChainRpcClient(effectiveOriginChain.id)
120
120
 
121
121
  let noSufficientBalance = false
122
122
 
@@ -503,6 +503,56 @@ export async function handleSameChainSameToken({
503
503
  hash: tx.txnHash as `0x${string}`,
504
504
  })
505
505
 
506
+ // Validate that the deposit amount is sufficient before proceeding
507
+ logger.console.log(
508
+ "[trails-sdk] Checking if deposit amount is sufficient",
509
+ {
510
+ depositAddress: intent.originIntentAddress,
511
+ requiredAmount: quote.originAmount,
512
+ tokenAddress: effectiveOriginTokenAddress,
513
+ },
514
+ )
515
+
516
+ const balanceCheck = await checkAccountBalance({
517
+ account: {
518
+ address: intent.originIntentAddress as `0x${string}`,
519
+ } as Account,
520
+ tokenAddress: effectiveOriginTokenAddress,
521
+ depositAmount: quote.originAmount,
522
+ publicClient: effectivePublicClient,
523
+ })
524
+
525
+ if (!balanceCheck.hasEnoughBalance) {
526
+ logger.console.warn(
527
+ "[trails-sdk] Deposit amount is insufficient, continuing to poll",
528
+ {
529
+ balance: balanceCheck.balanceFormatted,
530
+ required: balanceCheck.requiredAmountFormatted,
531
+ percentComplete: (
532
+ (Number(balanceCheck.balance) /
533
+ Number(balanceCheck.requiredAmount)) *
534
+ 100
535
+ ).toFixed(2),
536
+ },
537
+ )
538
+ // Continue polling - don't break out of the loop yet
539
+ await new Promise((resolve) =>
540
+ setTimeout(
541
+ resolve,
542
+ POLLING_INTERVALS.TRANSACTION_HISTORY,
543
+ ),
544
+ )
545
+ continue
546
+ }
547
+
548
+ logger.console.log(
549
+ "[trails-sdk] Deposit amount is sufficient, proceeding",
550
+ {
551
+ balance: balanceCheck.balanceFormatted,
552
+ required: balanceCheck.requiredAmountFormatted,
553
+ },
554
+ )
555
+
506
556
  depositUserTxnReceipt = depositTxReceipt
507
557
 
508
558
  localTransactionStates[0] = getTransactionStateFromReceipt(
@@ -5,7 +5,7 @@ import type { QuoteProviderInfo } from "../../widget/hooks/useQuote.js"
5
5
  import { formatUnits } from "viem"
6
6
  import { mainnet } from "viem/chains"
7
7
  import { getTokenInfo } from "../../tokens.js"
8
- import { getChainInfo, getPublicRpcClient } from "../../chains.js"
8
+ import { getChainInfo, getChainRpcClient } from "../../chains.js"
9
9
  import { logger } from "../../logger.js"
10
10
  import {
11
11
  formatRawAmount,
@@ -186,7 +186,7 @@ export async function getNormalizedQuoteObject({
186
186
 
187
187
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
188
188
 
189
- const publicClient = getPublicRpcClient(originChain)
189
+ const publicClient = getChainRpcClient(originChain.id)
190
190
 
191
191
  let gasCostUsd: number = 0
192
192
  let gasCostUsdDisplay: string = "0"
@@ -1,4 +1,10 @@
1
- import type { Account, Chain, TransactionReceipt, WalletClient } from "viem"
1
+ import type {
2
+ Account,
3
+ Chain,
4
+ PublicClient,
5
+ TransactionReceipt,
6
+ WalletClient,
7
+ } from "viem"
2
8
  import type {
3
9
  TrailsApi,
4
10
  Intent,
@@ -51,6 +57,8 @@ export type PrepareSendOptions = {
51
57
  quoteProvider?: string | null
52
58
  fundMethod?: string
53
59
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
60
+ originPublicClient?: PublicClient
61
+ destinationPublicClient?: PublicClient
54
62
  checkoutOnHandlers?: Partial<CheckoutOnHandlers>
55
63
  refundAddress?: string
56
64
  selectedFeeOption?: FeeOption | null