0xtrails 0.1.2 → 0.1.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 (158) hide show
  1. package/dist/address.d.ts.map +1 -1
  2. package/dist/analytics.d.ts +86 -1
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/apiClient.d.ts +1 -1
  5. package/dist/apiClient.d.ts.map +1 -1
  6. package/dist/{ccip-BmFTEOaB.js → ccip-dLSEJjCf.js} +55 -55
  7. package/dist/cctpqueue.d.ts +1 -1
  8. package/dist/cctpqueue.d.ts.map +1 -1
  9. package/dist/chains.d.ts +9 -3
  10. package/dist/chains.d.ts.map +1 -1
  11. package/dist/constants.d.ts +1 -0
  12. package/dist/constants.d.ts.map +1 -1
  13. package/dist/decoders.d.ts +58 -0
  14. package/dist/decoders.d.ts.map +1 -0
  15. package/dist/ens.d.ts +13 -0
  16. package/dist/ens.d.ts.map +1 -0
  17. package/dist/error.d.ts +9 -0
  18. package/dist/error.d.ts.map +1 -1
  19. package/dist/{index-BPsVj7zK.js → index-BXbaLmtt.js} +28779 -25738
  20. package/dist/index.js +2 -2
  21. package/dist/intents.d.ts +4 -4
  22. package/dist/intents.d.ts.map +1 -1
  23. package/dist/lifi.d.ts +4 -0
  24. package/dist/lifi.d.ts.map +1 -0
  25. package/dist/metaTxns.d.ts +1 -1
  26. package/dist/metaTxns.d.ts.map +1 -1
  27. package/dist/mode.d.ts +1 -1
  28. package/dist/mode.d.ts.map +1 -1
  29. package/dist/preconditions.d.ts +1 -1
  30. package/dist/preconditions.d.ts.map +1 -1
  31. package/dist/prepareSend.d.ts +32 -24
  32. package/dist/prepareSend.d.ts.map +1 -1
  33. package/dist/prices.d.ts +3 -1
  34. package/dist/prices.d.ts.map +1 -1
  35. package/dist/proxyCaller.d.ts +0 -1
  36. package/dist/proxyCaller.d.ts.map +1 -1
  37. package/dist/relaySdk.d.ts.map +1 -1
  38. package/dist/relayer.d.ts.map +1 -1
  39. package/dist/tokenBalances.d.ts +1 -1
  40. package/dist/tokenBalances.d.ts.map +1 -1
  41. package/dist/tokens.d.ts +2 -1
  42. package/dist/tokens.d.ts.map +1 -1
  43. package/dist/trails.d.ts +4 -4
  44. package/dist/trails.d.ts.map +1 -1
  45. package/dist/transactions.d.ts +4 -0
  46. package/dist/transactions.d.ts.map +1 -1
  47. package/dist/utils.d.ts +6 -0
  48. package/dist/utils.d.ts.map +1 -1
  49. package/dist/wallets.d.ts +247 -5
  50. package/dist/wallets.d.ts.map +1 -1
  51. package/dist/widget/components/ChainFilterDropdown.d.ts +2 -0
  52. package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
  53. package/dist/widget/components/ConnectWallet.d.ts +1 -0
  54. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  55. package/dist/widget/components/DebugScreensDropdown.d.ts.map +1 -1
  56. package/dist/widget/components/ErrorDisplay.d.ts +9 -0
  57. package/dist/widget/components/ErrorDisplay.d.ts.map +1 -0
  58. package/dist/widget/components/FundSendForm.d.ts +2 -2
  59. package/dist/widget/components/FundSendForm.d.ts.map +1 -1
  60. package/dist/widget/components/OriginTransferInformation.d.ts +10 -0
  61. package/dist/widget/components/OriginTransferInformation.d.ts.map +1 -0
  62. package/dist/widget/components/PaySendForm.d.ts +2 -2
  63. package/dist/widget/components/PaySendForm.d.ts.map +1 -1
  64. package/dist/widget/components/QrCode.d.ts +1 -1
  65. package/dist/widget/components/QrCode.d.ts.map +1 -1
  66. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  67. package/dist/widget/components/Receipt.d.ts.map +1 -1
  68. package/dist/widget/components/Receive.d.ts +12 -0
  69. package/dist/widget/components/Receive.d.ts.map +1 -0
  70. package/dist/widget/components/RefundAddressInput.d.ts +13 -0
  71. package/dist/widget/components/RefundAddressInput.d.ts.map +1 -0
  72. package/dist/widget/components/Swap.d.ts +47 -0
  73. package/dist/widget/components/Swap.d.ts.map +1 -0
  74. package/dist/widget/components/SwapDisplay.d.ts +9 -0
  75. package/dist/widget/components/SwapDisplay.d.ts.map +1 -0
  76. package/dist/widget/components/TokenList.d.ts +0 -2
  77. package/dist/widget/components/TokenList.d.ts.map +1 -1
  78. package/dist/widget/components/TokenSelector.d.ts +26 -0
  79. package/dist/widget/components/TokenSelector.d.ts.map +1 -0
  80. package/dist/widget/components/TransferPendingVertical.d.ts +2 -0
  81. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  82. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  83. package/dist/widget/components/WalletConnectionPending.d.ts +12 -0
  84. package/dist/widget/components/WalletConnectionPending.d.ts.map +1 -0
  85. package/dist/widget/components/WalletList.d.ts.map +1 -1
  86. package/dist/widget/components/YellowWarningAnimation.d.ts +2 -0
  87. package/dist/widget/components/YellowWarningAnimation.d.ts.map +1 -0
  88. package/dist/widget/hooks/useAmountUsd.d.ts +1 -3
  89. package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -1
  90. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  91. package/dist/widget/hooks/useDebugScreens.d.ts +22 -0
  92. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -0
  93. package/dist/widget/hooks/useSendForm.d.ts +12 -6
  94. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  95. package/dist/widget/hooks/useTokenList.d.ts +2 -3
  96. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  97. package/dist/widget/index.js +1 -1
  98. package/dist/widget/widget.d.ts.map +1 -1
  99. package/package.json +19 -15
  100. package/src/aave.ts +13 -13
  101. package/src/address.ts +3 -0
  102. package/src/analytics.ts +192 -8
  103. package/src/apiClient.ts +1 -1
  104. package/src/cctpqueue.ts +1 -1
  105. package/src/chains.ts +45 -7
  106. package/src/constants.ts +7 -4
  107. package/src/decoders.ts +310 -0
  108. package/src/ens.ts +32 -0
  109. package/src/error.ts +101 -1
  110. package/src/intents.ts +10 -2
  111. package/src/lifi.ts +58 -0
  112. package/src/metaTxns.ts +1 -1
  113. package/src/mode.ts +1 -1
  114. package/src/morpho.ts +3 -3
  115. package/src/pools.ts +18 -18
  116. package/src/preconditions.ts +1 -1
  117. package/src/prepareSend.ts +463 -113
  118. package/src/prices.ts +26 -1
  119. package/src/proxyCaller.ts +2 -14
  120. package/src/relaySdk.ts +1 -0
  121. package/src/relayer.ts +8 -0
  122. package/src/tokenBalances.ts +24 -17
  123. package/src/tokens.ts +147 -22
  124. package/src/trails.ts +4 -4
  125. package/src/transactions.ts +35 -17
  126. package/src/utils.ts +28 -0
  127. package/src/wallets.ts +275 -35
  128. package/src/widget/compiled.css +2 -2
  129. package/src/widget/components/ChainFilterDropdown.tsx +42 -33
  130. package/src/widget/components/ChainImage.tsx +1 -1
  131. package/src/widget/components/ConnectWallet.tsx +92 -128
  132. package/src/widget/components/DebugScreensDropdown.tsx +6 -0
  133. package/src/widget/components/ErrorDisplay.tsx +150 -0
  134. package/src/widget/components/FundSendForm.tsx +78 -11
  135. package/src/widget/components/OriginTransferInformation.tsx +59 -0
  136. package/src/widget/components/PaySendForm.tsx +80 -13
  137. package/src/widget/components/QRCodeDeposit.tsx +6 -6
  138. package/src/widget/components/QrCode.tsx +278 -17
  139. package/src/widget/components/QuoteDetails.tsx +93 -25
  140. package/src/widget/components/Receipt.tsx +296 -103
  141. package/src/widget/components/Receive.tsx +146 -0
  142. package/src/widget/components/RecentTokens.tsx +1 -1
  143. package/src/widget/components/RefundAddressInput.tsx +149 -0
  144. package/src/widget/components/Swap.tsx +769 -0
  145. package/src/widget/components/SwapDisplay.tsx +68 -0
  146. package/src/widget/components/TokenList.tsx +27 -363
  147. package/src/widget/components/TokenSelector.tsx +405 -0
  148. package/src/widget/components/TransferPendingVertical.tsx +162 -112
  149. package/src/widget/components/WalletConnect.tsx +9 -7
  150. package/src/widget/components/WalletConnectionPending.tsx +157 -0
  151. package/src/widget/components/WalletList.tsx +6 -5
  152. package/src/widget/components/YellowWarningAnimation.tsx +146 -0
  153. package/src/widget/hooks/useAmountUsd.ts +3 -8
  154. package/src/widget/hooks/useCheckout.ts +3 -2
  155. package/src/widget/hooks/useDebugScreens.ts +583 -0
  156. package/src/widget/hooks/useSendForm.ts +111 -35
  157. package/src/widget/hooks/useTokenList.ts +155 -122
  158. package/src/widget/widget.tsx +503 -523
package/src/chains.ts CHANGED
@@ -2,7 +2,9 @@ import { useQuery } from "@tanstack/react-query"
2
2
  import type { Chain } from "viem"
3
3
  import * as chains from "viem/chains"
4
4
  import { getRelaySupportedChains } from "./relaySdk.js"
5
+ import { getLifiSupportedChains } from "./lifi.js"
5
6
  import { getRpcSequenceProjectAccessKey } from "./config.js"
7
+ import type { QuoteProvider } from "./intents.js"
6
8
 
7
9
  export const sequenceRpcUrls: Record<number, string> = {
8
10
  [chains.arbitrum.id]: "https://nodes.sequence.app/arbitrum",
@@ -19,6 +21,8 @@ export const sequenceRpcUrls: Record<number, string> = {
19
21
  [chains.b3.id]: "https://nodes.sequence.app/b3",
20
22
  [chains.blast.id]: "https://nodes.sequence.app/blast",
21
23
  [chains.bsc.id]: "https://nodes.sequence.app/bsc",
24
+ [chains.katana.id]: "https://nodes.sequence.app/katana",
25
+ [chains.etherlink.id]: "https://nodes.sequence.app/etherlink",
22
26
  }
23
27
 
24
28
  export const getRpcUrl = (
@@ -46,6 +50,8 @@ export const supportedSequenceChains: Record<number, Chain> = {
46
50
  [chains.polygon.id]: getChainInfo(chains.polygon.id)!,
47
51
  [chains.soneium.id]: getChainInfo(chains.soneium.id)!,
48
52
  [chains.xai.id]: getChainInfo(chains.xai.id)!,
53
+ [chains.katana.id]: getChainInfo(chains.katana.id)!,
54
+ [chains.etherlink.id]: getChainInfo(chains.etherlink.id)!,
49
55
  }
50
56
 
51
57
  export const supportedSequenceTestnetChains: Record<number, Chain> = {
@@ -61,6 +67,7 @@ export const supportedSequenceTestnetChains: Record<number, Chain> = {
61
67
  [chains.optimismSepolia.id]: getChainInfo(chains.optimismSepolia.id)!,
62
68
  [chains.soneiumMinato.id]: getChainInfo(chains.soneiumMinato.id)!,
63
69
  [chains.xaiTestnet.id]: getChainInfo(chains.xaiTestnet.id)!,
70
+ [chains.etherlinkTestnet.id]: getChainInfo(chains.etherlinkTestnet.id)!,
64
71
  }
65
72
 
66
73
  export const mainnetChainsToTestnetChains: Record<number, Chain> = {
@@ -78,13 +85,15 @@ export const mainnetChainsToTestnetChains: Record<number, Chain> = {
78
85
  [chains.bsc.id]: chains.bscTestnet,
79
86
  [chains.arbitrumNova.id]: chains.arbitrumSepolia,
80
87
  [chains.apeChain.id]: chains.sepolia,
88
+ [chains.etherlink.id]: chains.etherlinkTestnet,
81
89
  }
82
90
 
83
91
  // Helper to get chain info
84
92
  export function getChainInfo(
85
- chainId: number,
93
+ chainId?: number,
86
94
  options?: { usePublicRpc?: boolean },
87
95
  ): Chain | null {
96
+ if (!chainId) return null
88
97
  const chainInfo =
89
98
  (Object.values(chains) as Array<Chain>).find(
90
99
  (chain: Chain) => chain.id === chainId,
@@ -155,13 +164,36 @@ function sortChains(chainList: Chain[]): Chain[] {
155
164
  })
156
165
  }
157
166
 
158
- export async function getSupportedChains(): Promise<Chain[]> {
159
- const sequenceChains = await getSupportedSequenceChains()
167
+ export async function getAllQuoteProviderChains(): Promise<Chain[]> {
160
168
  const relayChains = await getRelaySupportedChains()
169
+ const lifiChains = await getLifiSupportedChains()
170
+ const allChains = [...relayChains, ...lifiChains]
171
+ return allChains.filter(
172
+ (chain, index, self) => index === self.findIndex((c) => c.id === chain.id),
173
+ )
174
+ }
175
+
176
+ export async function getSupportedChains({
177
+ quoteProvider,
178
+ }: {
179
+ quoteProvider?: QuoteProvider | string
180
+ } = {}): Promise<Chain[]> {
181
+ let quoteProviderChains: Chain[] = []
182
+ if (quoteProvider === "relay") {
183
+ quoteProviderChains = await getRelaySupportedChains()
184
+ } else if (quoteProvider === "lifi") {
185
+ quoteProviderChains = await getLifiSupportedChains()
186
+ } else {
187
+ quoteProviderChains = await getAllQuoteProviderChains()
188
+ }
189
+
190
+ const sequenceChains = await getSupportedSequenceChains()
161
191
 
162
192
  // Find intersection of sequence chains and relay chains
163
193
  const supportedChains = sequenceChains.filter((sequenceChain) =>
164
- relayChains.some((relayChain) => relayChain.id === sequenceChain.id),
194
+ quoteProviderChains.some(
195
+ (quoteProviderChain) => quoteProviderChain.id === sequenceChain.id,
196
+ ),
165
197
  )
166
198
 
167
199
  // Ensure unique chain IDs by filtering duplicates
@@ -169,17 +201,23 @@ export async function getSupportedChains(): Promise<Chain[]> {
169
201
  (chain, index, self) => index === self.findIndex((c) => c.id === chain.id),
170
202
  )
171
203
 
204
+ const sortedChains = sortChains(uniqueChains)
205
+
172
206
  // Sort chains by priority and then by name
173
- return sortChains(uniqueChains)
207
+ return sortedChains
174
208
  }
175
209
 
176
- export function useSupportedChains(): {
210
+ export function useSupportedChains({
211
+ quoteProvider,
212
+ }: {
213
+ quoteProvider?: QuoteProvider | string
214
+ } = {}): {
177
215
  supportedChains: Chain[]
178
216
  isLoadingChains: boolean
179
217
  } {
180
218
  const { data: supportedChains = [], isLoading: isLoadingChains } = useQuery({
181
219
  queryKey: ["supportedChains"],
182
- queryFn: getSupportedChains,
220
+ queryFn: () => getSupportedChains({ quoteProvider }),
183
221
  staleTime: 60 * 60 * 1000, // 1 hour - chains rarely change
184
222
  gcTime: 24 * 60 * 60 * 1000, // 24 hours - keep in cache for a full day
185
223
  refetchOnWindowFocus: false, // Don't refetch when window regains focus
package/src/constants.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  import type { Context as ContextLike } from "@0xsequence/wallet-primitives"
2
2
 
3
3
  export const SEQUENCE_V3_CONTRACT_ADDRESSES: ContextLike.Context = {
4
- factory: "0xBd0F8abD58B4449B39C57Ac9D5C67433239aC447" as `0x${string}`,
5
- stage1: "0x53bA242E7C2501839DF2972c75075dc693176Cd0" as `0x${string}`,
6
- stage2: "0xa29874c88b8Fd557e42219B04b0CeC693e1712f5" as `0x${string}`,
4
+ factory: "0x7aaaD48b90Ea2c1DaE03cb68ea1Ed8E1DD26dB38" as `0x${string}`,
5
+ stage1: "0x4d7c112790F03caFc7287b1a29Aa03da1Bb00C10" as `0x${string}`,
6
+ stage2: "0x7C96ff440BCE51EEF0C9f748D69246B4b3F28173" as `0x${string}`,
7
7
  creationCode:
8
- "0x603e600e3d39601e805130553df33d3d34601c57363d3d373d363d30545af43d82803e903d91601c57fd5bf3" as `0x${string}`,
8
+ "0x6041600e3d396021805130553df33d3d36153402601f57363d3d373d363d30545af43d82803e903d91601f57fd5bf3" as `0x${string}`,
9
9
  }
10
10
 
11
+ export const TRAILS_BALANCE_INJECTOR_ADDRESS =
12
+ "0x9eCA6CEf73799402a1afe4779f588f03034c5D0f"
13
+
11
14
  export const ATTESATION_SIGNER_ADDRESS =
12
15
  "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
13
16
 
@@ -0,0 +1,310 @@
1
+ import type { TransactionReceipt, Log } from "viem"
2
+ import { decodeEventLog, parseAbiItem } from "viem"
3
+
4
+ // Corrected ABI items
5
+ const CALL_SUCCEEDED_ABI = parseAbiItem(
6
+ "event CallSucceeded(bytes32 _opHash, uint256 _index)",
7
+ )
8
+
9
+ const CALL_FAILED_ABI = parseAbiItem(
10
+ "event CallFailed(bytes32 _opHash, uint256 _index, bytes _returnData)",
11
+ )
12
+
13
+ const CALL_ABORTED_ABI = parseAbiItem(
14
+ "event CallAborted(bytes32 _opHash, uint256 _index, bytes _returnData)",
15
+ )
16
+
17
+ // only `deploymentId` is indexed
18
+ const CALL_SKIPPED_ABI = parseAbiItem(
19
+ "event CallSkipped(bytes32 indexed deploymentId, uint256 actionIndex)",
20
+ )
21
+
22
+ // Refund / Sweep events come from the Trails Token Sweeper contract.
23
+ // Contract source and event definitions:
24
+ // - https://github.com/0xsequence/trails-contracts/pull/28
25
+ // - https://github.com/0xsequence/stack/pull/1249
26
+ const REFUND_ABI = parseAbiItem(
27
+ "event Refund(address indexed token, address indexed recipient, uint256 amount)",
28
+ )
29
+
30
+ const SWEEP_ABI = parseAbiItem(
31
+ "event Sweep(address indexed token, address indexed recipient, uint256 amount)",
32
+ )
33
+
34
+ // Event types
35
+ export interface CallSucceededEvent {
36
+ type: "CallSucceeded"
37
+ opHash: string
38
+ index: bigint
39
+ log: Log
40
+ }
41
+
42
+ export interface CallFailedEvent {
43
+ type: "CallFailed"
44
+ opHash: string
45
+ index: bigint
46
+ returnData: string
47
+ log: Log
48
+ }
49
+
50
+ export interface CallAbortedEvent {
51
+ type: "CallAborted"
52
+ opHash: string
53
+ index: bigint
54
+ returnData: string
55
+ log: Log
56
+ }
57
+
58
+ export interface CallSkippedEvent {
59
+ type: "CallSkipped"
60
+ deploymentId: string
61
+ actionIndex: bigint
62
+ log: Log
63
+ }
64
+
65
+ export interface RefundEvent {
66
+ type: "Refund"
67
+ token: string
68
+ recipient: string
69
+ amount: bigint
70
+ log: Log
71
+ }
72
+
73
+ export interface SweepEvent {
74
+ type: "Sweep"
75
+ token: string
76
+ recipient: string
77
+ amount: bigint
78
+ log: Log
79
+ }
80
+
81
+ export type GuestModuleEvent =
82
+ | CallSucceededEvent
83
+ | CallFailedEvent
84
+ | CallAbortedEvent
85
+ | CallSkippedEvent
86
+
87
+ // Trails Token Sweeper events: see PR references above for canonical specs.
88
+ export type TrailsTokenSweeperEvent = RefundEvent | SweepEvent
89
+
90
+ // === Decoders ===
91
+
92
+ export function decodeCallSucceeded(log: Log): CallSucceededEvent | null {
93
+ try {
94
+ const decoded = decodeEventLog({
95
+ abi: [CALL_SUCCEEDED_ABI],
96
+ data: log.data,
97
+ topics: log.topics,
98
+ strict: false,
99
+ }) as {
100
+ eventName: "CallSucceeded"
101
+ args: { _opHash: string; _index: bigint }
102
+ }
103
+
104
+ return {
105
+ type: "CallSucceeded",
106
+ opHash: decoded.args._opHash,
107
+ index: decoded.args._index,
108
+ log,
109
+ }
110
+ } catch {
111
+ return null
112
+ }
113
+ }
114
+
115
+ export function decodeCallFailed(log: Log): CallFailedEvent | null {
116
+ try {
117
+ const decoded = decodeEventLog({
118
+ abi: [CALL_FAILED_ABI],
119
+ data: log.data,
120
+ topics: log.topics,
121
+ strict: false,
122
+ }) as {
123
+ eventName: "CallFailed"
124
+ args: { _opHash: string; _index: bigint; _returnData: string }
125
+ }
126
+
127
+ return {
128
+ type: "CallFailed",
129
+ opHash: decoded.args._opHash,
130
+ index: decoded.args._index,
131
+ returnData: decoded.args._returnData,
132
+ log,
133
+ }
134
+ } catch {
135
+ return null
136
+ }
137
+ }
138
+
139
+ export function decodeCallAborted(log: Log): CallAbortedEvent | null {
140
+ try {
141
+ const decoded = decodeEventLog({
142
+ abi: [CALL_ABORTED_ABI],
143
+ data: log.data,
144
+ topics: log.topics,
145
+ strict: false,
146
+ }) as {
147
+ eventName: "CallAborted"
148
+ args: { _opHash: string; _index: bigint; _returnData: string }
149
+ }
150
+
151
+ return {
152
+ type: "CallAborted",
153
+ opHash: decoded.args._opHash,
154
+ index: decoded.args._index,
155
+ returnData: decoded.args._returnData,
156
+ log,
157
+ }
158
+ } catch {
159
+ return null
160
+ }
161
+ }
162
+
163
+ export function decodeCallSkipped(log: Log): CallSkippedEvent | null {
164
+ try {
165
+ const decoded = decodeEventLog({
166
+ abi: [CALL_SKIPPED_ABI],
167
+ data: log.data,
168
+ topics: log.topics,
169
+ strict: false,
170
+ }) as {
171
+ eventName: "CallSkipped"
172
+ args: { deploymentId: string; actionIndex: bigint }
173
+ }
174
+
175
+ return {
176
+ type: "CallSkipped",
177
+ deploymentId: decoded.args.deploymentId,
178
+ actionIndex: decoded.args.actionIndex,
179
+ log,
180
+ }
181
+ } catch {
182
+ return null
183
+ }
184
+ }
185
+
186
+ export function decodeRefund(log: Log): RefundEvent | null {
187
+ try {
188
+ const decoded = decodeEventLog({
189
+ abi: [REFUND_ABI],
190
+ data: log.data,
191
+ topics: log.topics,
192
+ strict: false,
193
+ }) as {
194
+ eventName: "Refund"
195
+ args: { token: string; recipient: string; amount: bigint }
196
+ }
197
+
198
+ return {
199
+ type: "Refund",
200
+ token: decoded.args.token,
201
+ recipient: decoded.args.recipient,
202
+ amount: decoded.args.amount,
203
+ log,
204
+ }
205
+ } catch {
206
+ return null
207
+ }
208
+ }
209
+
210
+ export function decodeSweep(log: Log): SweepEvent | null {
211
+ try {
212
+ const decoded = decodeEventLog({
213
+ abi: [SWEEP_ABI],
214
+ data: log.data,
215
+ topics: log.topics,
216
+ strict: false,
217
+ }) as {
218
+ eventName: "Sweep"
219
+ args: { token: string; recipient: string; amount: bigint }
220
+ }
221
+
222
+ return {
223
+ type: "Sweep",
224
+ token: decoded.args.token,
225
+ recipient: decoded.args.recipient,
226
+ amount: decoded.args.amount,
227
+ log,
228
+ }
229
+ } catch {
230
+ return null
231
+ }
232
+ }
233
+
234
+ // === Main decoder ===
235
+
236
+ export function decodeTrailsTokenSweeperEvents(
237
+ receipt: TransactionReceipt,
238
+ ): TrailsTokenSweeperEvent[] {
239
+ const events: TrailsTokenSweeperEvent[] = []
240
+
241
+ for (const log of receipt.logs) {
242
+ const refund = decodeRefund(log)
243
+ if (refund) {
244
+ events.push(refund)
245
+ continue
246
+ }
247
+
248
+ const sweep = decodeSweep(log)
249
+ if (sweep) {
250
+ events.push(sweep)
251
+ }
252
+ }
253
+
254
+ return events
255
+ }
256
+
257
+ export function decodeGuestModuleEvents(
258
+ receipt: TransactionReceipt,
259
+ ): GuestModuleEvent[] {
260
+ const events: GuestModuleEvent[] = []
261
+
262
+ for (const log of receipt.logs) {
263
+ const succeeded = decodeCallSucceeded(log)
264
+ if (succeeded) {
265
+ events.push(succeeded)
266
+ continue
267
+ }
268
+
269
+ const failed = decodeCallFailed(log)
270
+ if (failed) {
271
+ events.push(failed)
272
+ continue
273
+ }
274
+
275
+ const aborted = decodeCallAborted(log)
276
+ if (aborted) {
277
+ events.push(aborted)
278
+ continue
279
+ }
280
+
281
+ const skipped = decodeCallSkipped(log)
282
+ if (skipped) {
283
+ events.push(skipped)
284
+ }
285
+ }
286
+
287
+ return events
288
+ }
289
+
290
+ // === Utilities ===
291
+
292
+ export function getEventsByType<T extends GuestModuleEvent["type"]>(
293
+ events: GuestModuleEvent[],
294
+ type: T,
295
+ ): Extract<GuestModuleEvent, { type: T }>[] {
296
+ return events.filter(
297
+ (event): event is Extract<GuestModuleEvent, { type: T }> =>
298
+ event.type === type,
299
+ )
300
+ }
301
+
302
+ export function getFirstEventByType<T extends GuestModuleEvent["type"]>(
303
+ events: GuestModuleEvent[],
304
+ type: T,
305
+ ): Extract<GuestModuleEvent, { type: T }> | undefined {
306
+ return events.find(
307
+ (event): event is Extract<GuestModuleEvent, { type: T }> =>
308
+ event.type === type,
309
+ )
310
+ }
package/src/ens.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { mainnet } from "viem/chains"
2
+ import { useEnsAddress, useEnsName } from "wagmi"
3
+
4
+ export function useResolveEnsAddress({ textInput }: { textInput: string }) {
5
+ const { data: ensAddress, isLoading } = useEnsAddress({
6
+ name: textInput?.endsWith(".eth") ? textInput : undefined,
7
+ chainId: mainnet.id,
8
+ query: {
9
+ enabled: !!textInput && textInput.endsWith(".eth"),
10
+ },
11
+ })
12
+
13
+ return {
14
+ ensAddress,
15
+ isLoading,
16
+ }
17
+ }
18
+
19
+ export function useResolveEnsName({ address }: { address: string }) {
20
+ const { data: ensName, isLoading } = useEnsName({
21
+ address: address?.startsWith("0x") ? (address as `0x${string}`) : undefined,
22
+ chainId: mainnet.id,
23
+ query: {
24
+ enabled: !!address && address.startsWith("0x"),
25
+ },
26
+ })
27
+
28
+ return {
29
+ ensName,
30
+ isLoading,
31
+ }
32
+ }
package/src/error.ts CHANGED
@@ -3,7 +3,10 @@ export function getFullErrorMessage(err: any) {
3
3
 
4
4
  let current = err
5
5
  while (current) {
6
- if (current.message) {
6
+ if (typeof current === "string") {
7
+ messages.push(current)
8
+ }
9
+ if (typeof current.message === "string") {
7
10
  messages.push(current.message)
8
11
  }
9
12
 
@@ -37,3 +40,100 @@ export class InsufficientBalanceError extends Error {
37
40
  this.name = "InsufficientBalanceError"
38
41
  }
39
42
  }
43
+
44
+ export function getIsApiError(err: unknown) {
45
+ const isApiError = /request aborted|not deployed/gi.test(
46
+ getErrorString(err).toLowerCase(),
47
+ )
48
+ return isApiError
49
+ }
50
+
51
+ export function getIsRateLimitedError(err: unknown) {
52
+ const isRateLimited = /slow down|request rate|rate limit/gi.test(
53
+ getErrorString(err).toLowerCase(),
54
+ )
55
+ return isRateLimited
56
+ }
57
+
58
+ export function getIsRequiredAmountNotMetError(err: unknown) {
59
+ // Example error:
60
+ // GetIntentsQuote failed: total required amount (196159816026182793237) exceeds user-specified maximum (21960919303474978846)
61
+ const isRequiredAmountNotMet = /exceeds user-specified maximum/gi.test(
62
+ getErrorString(err).toLowerCase(),
63
+ )
64
+ return isRequiredAmountNotMet
65
+ }
66
+
67
+ export function getIsNoAvailableQuoteError(err: unknown) {
68
+ const isNoAvailableQuote =
69
+ /no available quotes|failed to get quote from any provider/gi.test(
70
+ getErrorString(err).toLowerCase(),
71
+ )
72
+ return isNoAvailableQuote
73
+ }
74
+
75
+ export function getIsQuoteFailedError(err: unknown) {
76
+ const isQuoteFailed = /GetIntentsQuote failed/gi.test(
77
+ getErrorString(err).toLowerCase(),
78
+ )
79
+ return isQuoteFailed
80
+ }
81
+
82
+ export function getIsQuoteTokenError(err: unknown) {
83
+ const isQuoteTokenError =
84
+ /requires destination token to be USDC|Token or chain not found/gi.test(
85
+ getErrorString(err).toLowerCase(),
86
+ )
87
+ return isQuoteTokenError
88
+ }
89
+
90
+ export function getIsQuoteInputError(err: unknown) {
91
+ const isQuoteInputError =
92
+ /Invalid input or output currency|originTokenAmount must be greater than zero|trails fee is greater than the origin token amount/gi.test(
93
+ getErrorString(err).toLowerCase(),
94
+ )
95
+ return isQuoteInputError
96
+ }
97
+
98
+ export function getIsInsufficientLiquidityError(err: unknown) {
99
+ const isInsufficientLiquidity =
100
+ /insufficient liquidity|higher than the available liquidity/gi.test(
101
+ getErrorString(err).toLowerCase(),
102
+ )
103
+ return isInsufficientLiquidity
104
+ }
105
+
106
+ export function getPrettifiedErrorMessage(
107
+ err: unknown,
108
+ defaultMessage: string = "",
109
+ ) {
110
+ const isRequiredAmountNotMet = getIsRequiredAmountNotMetError(err)
111
+ if (isRequiredAmountNotMet) {
112
+ return "The requested amount is too low to retrieve a quote or the account has insufficient funds to meet the required amount. Try again with a higher amount or make sure you have enough funds."
113
+ }
114
+ const isInsufficientLiquidity = getIsInsufficientLiquidityError(err)
115
+ if (isInsufficientLiquidity) {
116
+ return "The requested amount is too high to retrieve a quote. Try again with a lower amount."
117
+ }
118
+ const isNoAvailableQuote = getIsNoAvailableQuoteError(err)
119
+ if (isNoAvailableQuote) {
120
+ return "No quote found for the selected pair and/or amount. Try again with a different pair and/or amount."
121
+ }
122
+ const isQuoteTokenError = getIsQuoteTokenError(err)
123
+ if (isQuoteTokenError) {
124
+ return "The selected token is not supported. Please try again with a different token."
125
+ }
126
+ const isQuoteInputError = getIsQuoteInputError(err)
127
+ if (isQuoteInputError) {
128
+ return "No quote found for the input amount. Try again with a higher amount."
129
+ }
130
+ const isQuoteFailed = getIsQuoteFailedError(err)
131
+ if (isQuoteFailed) {
132
+ return "No quote found for the selected pair and amount."
133
+ }
134
+ const isApiError = getIsApiError(err)
135
+ if (isApiError) {
136
+ return "An API error occurred. Please try again later."
137
+ }
138
+ return defaultMessage
139
+ }
package/src/intents.ts CHANGED
@@ -6,12 +6,12 @@ import type {
6
6
  IntentCallsPayload,
7
7
  IntentPrecondition,
8
8
  SequenceAPIClient,
9
- } from "@0xsequence/api"
9
+ } from "@0xsequence/trails-api"
10
10
 
11
11
  export type {
12
12
  IntentCallsPayload,
13
13
  IntentPrecondition,
14
- } from "@0xsequence/api"
14
+ } from "@0xsequence/trails-api"
15
15
 
16
16
  import { Config, type Context, Payload } from "@0xsequence/wallet-primitives"
17
17
  import {
@@ -116,6 +116,7 @@ export type SendOriginCallTxArgs = {
116
116
  export async function getIntentCallsPayloads(
117
117
  apiClient: SequenceAPIClient,
118
118
  args: GetIntentCallsPayloadsArgs,
119
+ additionalTrackingProps: Record<string, string> = {},
119
120
  ): Promise<GetIntentCallsPayloadsReturn> {
120
121
  const localApiIntent = getQueryParam("localapiintent") === "true"
121
122
  if (localApiIntent) {
@@ -133,6 +134,7 @@ export async function getIntentCallsPayloads(
133
134
  originTokenAddress: args.originTokenAddress,
134
135
  destinationTokenAddress: args.destinationTokenAddress,
135
136
  userAddress: args.userAddress,
137
+ ...additionalTrackingProps,
136
138
  })
137
139
 
138
140
  try {
@@ -162,6 +164,7 @@ export async function getIntentCallsPayloads(
162
164
  feeToken: result.trailsFee?.feeToken,
163
165
  userAddress: args.userAddress,
164
166
  intentAddress: result.originIntentAddress,
167
+ ...additionalTrackingProps,
165
168
  })
166
169
 
167
170
  return result
@@ -174,6 +177,7 @@ export async function getIntentCallsPayloads(
174
177
  destinationChainId: args.destinationChainId || 0,
175
178
  originTokenAddress: args.originTokenAddress,
176
179
  destinationTokenAddress: args.destinationTokenAddress,
180
+ ...additionalTrackingProps,
177
181
  })
178
182
  throw error
179
183
  }
@@ -259,6 +263,7 @@ export async function commitIntentConfig(
259
263
  mainSignerAddress: string,
260
264
  calls: Array<IntentCallsPayload>,
261
265
  preconditions: Array<IntentPrecondition>,
266
+ additionalTrackingProps: Record<string, string> = {},
262
267
  ): Promise<CommitIntentConfigReturn> {
263
268
  console.log("[trails-sdk] commitIntentConfig inputs:", {
264
269
  mainSignerAddress,
@@ -323,6 +328,7 @@ export async function commitIntentConfig(
323
328
  destinationChainId: destinationChainIdStr
324
329
  ? Number(destinationChainIdStr)
325
330
  : undefined,
331
+ ...additionalTrackingProps,
326
332
  })
327
333
 
328
334
  const result = await apiClient.commitIntentConfig({
@@ -338,6 +344,7 @@ export async function commitIntentConfig(
338
344
  destinationChainId: destinationChainIdStr
339
345
  ? Number(destinationChainIdStr)
340
346
  : undefined,
347
+ ...additionalTrackingProps,
341
348
  })
342
349
 
343
350
  return result
@@ -351,6 +358,7 @@ export async function commitIntentConfig(
351
358
  destinationChainId: destinationChainIdStr
352
359
  ? Number(destinationChainIdStr)
353
360
  : undefined,
361
+ ...additionalTrackingProps,
354
362
  })
355
363
  throw error
356
364
  }