0xtrails 0.2.0 → 0.2.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.
- package/dist/analytics.d.ts +1 -0
- package/dist/analytics.d.ts.map +1 -1
- package/dist/{ccip-D6ToCrWc.js → ccip-BbfANth7.js} +1 -1
- package/dist/chains.d.ts.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/gasless.d.ts +19 -7
- package/dist/gasless.d.ts.map +1 -1
- package/dist/{index-BqgeTLL8.js → index-WpIVoh3X.js} +27626 -26572
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -68
- package/dist/indexerClient.d.ts +10 -0
- package/dist/indexerClient.d.ts.map +1 -1
- package/dist/intentEntrypoint.d.ts +40 -14
- package/dist/intentEntrypoint.d.ts.map +1 -1
- package/dist/intents.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +11 -8
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/relayer.d.ts.map +1 -1
- package/dist/trails.d.ts.map +1 -1
- package/dist/trailsClient.d.ts.map +1 -1
- package/dist/trailsRouter.d.ts +22 -0
- package/dist/trailsRouter.d.ts.map +1 -0
- package/dist/transactions.d.ts +0 -1
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/FeeOption.d.ts +22 -0
- package/dist/widget/components/FeeOption.d.ts.map +1 -0
- package/dist/widget/components/FeeOptions.d.ts +13 -17
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/FundSendForm.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectExchanges.d.ts +5 -2
- package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectFlow.d.ts +2 -0
- package/dist/widget/components/MeshConnectFlow.d.ts.map +1 -1
- package/dist/widget/components/NativeGasOption.d.ts +12 -0
- package/dist/widget/components/NativeGasOption.d.ts.map +1 -0
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PaySendForm.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/hooks/useBack.d.ts +2 -0
- package/dist/widget/hooks/useBack.d.ts.map +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +32 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedMeshExchange.d.ts +14 -0
- package/dist/widget/hooks/useSelectedMeshExchange.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +8 -13
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +29 -28
- package/src/analytics.ts +6 -0
- package/src/chains.ts +10 -0
- package/src/config.ts +25 -10
- package/src/constants.ts +11 -10
- package/src/gasless.ts +162 -109
- package/src/index.ts +1 -1
- package/src/indexerClient.ts +73 -1
- package/src/intentEntrypoint.ts +66 -101
- package/src/intents.ts +0 -2
- package/src/prepareSend.ts +1409 -887
- package/src/relayer.ts +4 -3
- package/src/trails.ts +1 -3
- package/src/trailsClient.ts +4 -1
- package/src/{balanceInjector.ts → trailsRouter.ts} +14 -14
- package/src/transactions.ts +4 -54
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountSettings.tsx +7 -1
- package/src/widget/components/ClassicSwap.tsx +173 -175
- package/src/widget/components/ConfigDisplay.tsx +34 -1
- package/src/widget/components/ConnectWallet.tsx +168 -11
- package/src/widget/components/ConnectedWallets.tsx +184 -102
- package/src/widget/components/DebugToast.tsx +3 -3
- package/src/widget/components/Earn.tsx +4 -27
- package/src/widget/components/FeeOption.tsx +78 -0
- package/src/widget/components/FeeOptions.tsx +192 -127
- package/src/widget/components/Fund.tsx +18 -27
- package/src/widget/components/FundMethods.tsx +3 -3
- package/src/widget/components/FundSendForm.tsx +0 -33
- package/src/widget/components/MeshConnectExchanges.tsx +32 -3
- package/src/widget/components/MeshConnectFlow.tsx +23 -4
- package/src/widget/components/NativeGasOption.tsx +99 -0
- package/src/widget/components/Pay.tsx +36 -32
- package/src/widget/components/PaySendForm.tsx +0 -37
- package/src/widget/components/QuoteDetails.tsx +0 -29
- package/src/widget/components/TokenSelector.tsx +11 -0
- package/src/widget/components/TransferPendingVertical.tsx +1 -1
- package/src/widget/components/UserPreferences.tsx +3 -4
- package/src/widget/hooks/useBack.tsx +4 -0
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDefaultTokenSelection.tsx +3 -7
- package/src/widget/hooks/useSelectedFeeToken.tsx +299 -0
- package/src/widget/hooks/useSelectedMeshExchange.tsx +46 -0
- package/src/widget/hooks/useSendForm.ts +78 -23
- package/src/widget/widget.tsx +173 -111
- package/dist/balanceInjector.d.ts +0 -22
- package/dist/balanceInjector.d.ts.map +0 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useState,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react"
|
|
10
|
+
import { logger } from "../../logger.js"
|
|
11
|
+
import { zeroAddress } from "viem"
|
|
12
|
+
|
|
13
|
+
// Define the FeeOption interface with balance check properties
|
|
14
|
+
export interface FeeOption {
|
|
15
|
+
tokenAddress: string
|
|
16
|
+
tokenSymbol: string
|
|
17
|
+
tokenDecimals: number
|
|
18
|
+
amount: string
|
|
19
|
+
amountUSD: number
|
|
20
|
+
notEnoughBalance?: boolean
|
|
21
|
+
tokenImageUrl?: string
|
|
22
|
+
chainId?: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Token type with balance information
|
|
26
|
+
export interface TokenWithBalance {
|
|
27
|
+
chainId: number
|
|
28
|
+
contractAddress?: string
|
|
29
|
+
balance?: string
|
|
30
|
+
imageUrl?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface SelectedFeeTokenContextType {
|
|
34
|
+
selectedFeeToken: FeeOption | null
|
|
35
|
+
setSelectedFeeToken: (token: FeeOption | null) => void
|
|
36
|
+
clearSelectedFeeToken: () => void
|
|
37
|
+
processedFeeOptions: FeeOption[]
|
|
38
|
+
setRawFeeOptions: (
|
|
39
|
+
feeOptions: any[] | null | undefined,
|
|
40
|
+
originChainId: number | undefined,
|
|
41
|
+
availableTokens: TokenWithBalance[],
|
|
42
|
+
) => void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const SelectedFeeTokenContext = createContext<
|
|
46
|
+
SelectedFeeTokenContextType | undefined
|
|
47
|
+
>(undefined)
|
|
48
|
+
|
|
49
|
+
interface SelectedFeeTokenProviderProps {
|
|
50
|
+
children: ReactNode
|
|
51
|
+
initialToken?: FeeOption | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const SelectedFeeTokenProvider: React.FC<
|
|
55
|
+
SelectedFeeTokenProviderProps
|
|
56
|
+
> = ({ children, initialToken = null }) => {
|
|
57
|
+
const [selectedFeeToken, setSelectedFeeTokenInternalRaw] =
|
|
58
|
+
useState<FeeOption | null>(initialToken)
|
|
59
|
+
const [hasUserSelectedFeeOption, setHasUserSelectedFeeOption] =
|
|
60
|
+
useState(false)
|
|
61
|
+
const [rawFeeOptions, setRawFeeOptionsInternal] = useState<any[]>([])
|
|
62
|
+
const [originTokenChainId, setOriginTokenChainId] = useState<
|
|
63
|
+
number | undefined
|
|
64
|
+
>(undefined)
|
|
65
|
+
const [availableTokens, setAvailableTokens] = useState<TokenWithBalance[]>([])
|
|
66
|
+
|
|
67
|
+
// Wrapper to log all state changes to selectedFeeToken
|
|
68
|
+
const setSelectedFeeTokenInternal = useCallback(
|
|
69
|
+
(token: FeeOption | null) => {
|
|
70
|
+
logger.console.log(
|
|
71
|
+
"[trails-sdk] [FEE-SELECT] selectedFeeToken state changing:",
|
|
72
|
+
{
|
|
73
|
+
from: selectedFeeToken,
|
|
74
|
+
to: token,
|
|
75
|
+
fromNull: selectedFeeToken === null,
|
|
76
|
+
toNull: token === null,
|
|
77
|
+
stackTrace: new Error().stack?.split("\n").slice(2, 5).join("\n"), // Get call stack
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
setSelectedFeeTokenInternalRaw(token)
|
|
81
|
+
},
|
|
82
|
+
[selectedFeeToken],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// Wrapper to track when user makes an explicit selection
|
|
86
|
+
const setSelectedFeeToken = useCallback(
|
|
87
|
+
(token: FeeOption | null) => {
|
|
88
|
+
logger.console.log(
|
|
89
|
+
"[trails-sdk] [FEE-SELECT] setSelectedFeeToken called (user selection):",
|
|
90
|
+
{
|
|
91
|
+
token,
|
|
92
|
+
isNull: token === null,
|
|
93
|
+
isUndefined: token === undefined,
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
setSelectedFeeTokenInternal(token)
|
|
97
|
+
setHasUserSelectedFeeOption(true)
|
|
98
|
+
},
|
|
99
|
+
[setSelectedFeeTokenInternal],
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
const clearSelectedFeeToken = useCallback(() => {
|
|
103
|
+
logger.console.log("[trails-sdk] [FEE-SELECT] Clearing selected fee token")
|
|
104
|
+
setSelectedFeeTokenInternal(null)
|
|
105
|
+
setHasUserSelectedFeeOption(false)
|
|
106
|
+
}, [setSelectedFeeTokenInternal])
|
|
107
|
+
|
|
108
|
+
// Process raw fee options with balance checks
|
|
109
|
+
const processedFeeOptions = useMemo(() => {
|
|
110
|
+
if (!rawFeeOptions || rawFeeOptions.length === 0) {
|
|
111
|
+
return []
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
logger.console.log("[trails-sdk] [FEE-SELECT] Processing fee options:", {
|
|
115
|
+
rawFeeOptions,
|
|
116
|
+
originTokenChainId,
|
|
117
|
+
availableTokensCount: availableTokens.length,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Add balance check and additional properties to each fee option
|
|
121
|
+
const feeOptionsWithBalanceCheck = rawFeeOptions.map((option: any) => {
|
|
122
|
+
// For native token (zero address), check if user has enough native balance
|
|
123
|
+
if (option.tokenAddress === zeroAddress) {
|
|
124
|
+
// Find the native token balance for the origin chain
|
|
125
|
+
const nativeTokenInfo = availableTokens.find(
|
|
126
|
+
(token) =>
|
|
127
|
+
token.contractAddress?.toLowerCase() ===
|
|
128
|
+
zeroAddress.toLowerCase() && token.chainId === originTokenChainId,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
const nativeBalance = nativeTokenInfo?.balance || "0"
|
|
132
|
+
const requiredAmount = option.amount
|
|
133
|
+
const notEnoughBalance = BigInt(nativeBalance) < BigInt(requiredAmount)
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
...option,
|
|
137
|
+
notEnoughBalance,
|
|
138
|
+
tokenImageUrl: nativeTokenInfo?.imageUrl,
|
|
139
|
+
chainId: originTokenChainId, // Native token is on the same chain as origin
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// For ERC-20 tokens, check user's token balances
|
|
144
|
+
const userTokenBalance = availableTokens.find(
|
|
145
|
+
(token) =>
|
|
146
|
+
token.contractAddress?.toLowerCase() ===
|
|
147
|
+
option.tokenAddress.toLowerCase() &&
|
|
148
|
+
token.chainId === originTokenChainId,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if (userTokenBalance) {
|
|
152
|
+
const userBalance = userTokenBalance.balance || "0"
|
|
153
|
+
const requiredAmount = option.amount
|
|
154
|
+
const notEnoughBalance = BigInt(userBalance) < BigInt(requiredAmount)
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
...option,
|
|
158
|
+
notEnoughBalance,
|
|
159
|
+
tokenImageUrl: userTokenBalance.imageUrl,
|
|
160
|
+
chainId: userTokenBalance.chainId, // Use the actual token's chain ID
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// If token balance not found, assume insufficient balance
|
|
165
|
+
return {
|
|
166
|
+
...option,
|
|
167
|
+
notEnoughBalance: true,
|
|
168
|
+
tokenImageUrl: undefined,
|
|
169
|
+
chainId: originTokenChainId, // Fallback to origin chain
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
// Sort fee options: available options first, then disabled options at the bottom
|
|
174
|
+
const sortedFeeOptions = feeOptionsWithBalanceCheck.sort(
|
|
175
|
+
(a: FeeOption, b: FeeOption) => {
|
|
176
|
+
// If both have the same balance status, maintain original order
|
|
177
|
+
if (a.notEnoughBalance === b.notEnoughBalance) {
|
|
178
|
+
return 0
|
|
179
|
+
}
|
|
180
|
+
// Put available options (notEnoughBalance: false) before disabled options (notEnoughBalance: true)
|
|
181
|
+
return a.notEnoughBalance ? 1 : -1
|
|
182
|
+
},
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
logger.console.log(
|
|
186
|
+
"[trails-sdk] [FEE-SELECT] Processed and sorted fee options:",
|
|
187
|
+
sortedFeeOptions,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return sortedFeeOptions
|
|
191
|
+
}, [rawFeeOptions, originTokenChainId, availableTokens])
|
|
192
|
+
|
|
193
|
+
// Auto-select first fee option with sufficient balance (non-native token)
|
|
194
|
+
// Only auto-select on initial load, not when user explicitly chooses native gas
|
|
195
|
+
// If no ERC20 fee options are available, selectedFeeToken stays null (native gas)
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
logger.console.log(
|
|
198
|
+
"[trails-sdk] [FEE-SELECT] Auto-selection useEffect triggered:",
|
|
199
|
+
{
|
|
200
|
+
processedFeeOptionsLength: processedFeeOptions.length,
|
|
201
|
+
hasUserSelectedFeeOption,
|
|
202
|
+
selectedFeeToken,
|
|
203
|
+
willAutoSelect:
|
|
204
|
+
processedFeeOptions.length > 0 &&
|
|
205
|
+
!hasUserSelectedFeeOption &&
|
|
206
|
+
!selectedFeeToken,
|
|
207
|
+
},
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
// Only auto-select if:
|
|
211
|
+
// 1. We have fee options
|
|
212
|
+
// 2. User hasn't made an explicit selection yet
|
|
213
|
+
// 3. No fee token is currently selected
|
|
214
|
+
if (
|
|
215
|
+
processedFeeOptions.length > 0 &&
|
|
216
|
+
!hasUserSelectedFeeOption &&
|
|
217
|
+
!selectedFeeToken
|
|
218
|
+
) {
|
|
219
|
+
// Find first non-native token option with sufficient balance
|
|
220
|
+
const firstValidOption = processedFeeOptions.find(
|
|
221
|
+
(option: FeeOption) =>
|
|
222
|
+
option.tokenAddress !== zeroAddress && !option.notEnoughBalance,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if (firstValidOption) {
|
|
226
|
+
logger.console.log(
|
|
227
|
+
"[trails-sdk] [FEE-SELECT] Auto-selecting first valid fee option:",
|
|
228
|
+
firstValidOption,
|
|
229
|
+
)
|
|
230
|
+
// Strip extra fields to match the format expected by prepareSend
|
|
231
|
+
const cleanOption: FeeOption = {
|
|
232
|
+
tokenAddress: firstValidOption.tokenAddress,
|
|
233
|
+
tokenSymbol: firstValidOption.tokenSymbol,
|
|
234
|
+
tokenDecimals: firstValidOption.tokenDecimals,
|
|
235
|
+
amount: firstValidOption.amount,
|
|
236
|
+
amountUSD: firstValidOption.amountUSD,
|
|
237
|
+
}
|
|
238
|
+
// Use internal setter to avoid marking as user selection
|
|
239
|
+
setSelectedFeeTokenInternal(cleanOption)
|
|
240
|
+
} else {
|
|
241
|
+
logger.console.log(
|
|
242
|
+
"[trails-sdk] [FEE-SELECT] No valid ERC20 fee options available, will use native gas",
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}, [
|
|
247
|
+
processedFeeOptions,
|
|
248
|
+
selectedFeeToken,
|
|
249
|
+
hasUserSelectedFeeOption,
|
|
250
|
+
setSelectedFeeTokenInternal,
|
|
251
|
+
])
|
|
252
|
+
|
|
253
|
+
// Function to set raw fee options and process them
|
|
254
|
+
const setRawFeeOptions = useCallback(
|
|
255
|
+
(
|
|
256
|
+
feeOptions: any[] | null | undefined,
|
|
257
|
+
originChainId: number | undefined,
|
|
258
|
+
tokens: TokenWithBalance[],
|
|
259
|
+
) => {
|
|
260
|
+
const apiFeeOptions = feeOptions ?? []
|
|
261
|
+
setRawFeeOptionsInternal(apiFeeOptions)
|
|
262
|
+
setOriginTokenChainId(originChainId)
|
|
263
|
+
setAvailableTokens(tokens)
|
|
264
|
+
|
|
265
|
+
logger.console.log("[trails-sdk] [FEE-SELECT] Raw fee options set:", {
|
|
266
|
+
feeOptionsCount: apiFeeOptions.length,
|
|
267
|
+
originChainId: originChainId,
|
|
268
|
+
tokensCount: tokens.length,
|
|
269
|
+
})
|
|
270
|
+
},
|
|
271
|
+
[],
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
const value: SelectedFeeTokenContextType = {
|
|
275
|
+
selectedFeeToken,
|
|
276
|
+
setSelectedFeeToken,
|
|
277
|
+
clearSelectedFeeToken,
|
|
278
|
+
processedFeeOptions,
|
|
279
|
+
setRawFeeOptions,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return (
|
|
283
|
+
<SelectedFeeTokenContext.Provider value={value}>
|
|
284
|
+
{children}
|
|
285
|
+
</SelectedFeeTokenContext.Provider>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export const useSelectedFeeToken = (): SelectedFeeTokenContextType => {
|
|
290
|
+
const context = useContext(SelectedFeeTokenContext)
|
|
291
|
+
|
|
292
|
+
if (context === undefined) {
|
|
293
|
+
throw new Error(
|
|
294
|
+
"useSelectedFeeToken must be used within a SelectedFeeTokenProvider",
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return context
|
|
299
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createContext, useContext, useState, useMemo } from "react"
|
|
2
|
+
|
|
3
|
+
export interface SelectedMeshExchange {
|
|
4
|
+
integrationId: string
|
|
5
|
+
exchangeName: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface SelectedMeshExchangeContextType {
|
|
9
|
+
selectedExchange: SelectedMeshExchange | null
|
|
10
|
+
setSelectedExchange: (exchange: SelectedMeshExchange | null) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const SelectedMeshExchangeContext = createContext<
|
|
14
|
+
SelectedMeshExchangeContextType | undefined
|
|
15
|
+
>(undefined)
|
|
16
|
+
|
|
17
|
+
export const SelectedMeshExchangeProvider: React.FC<{
|
|
18
|
+
children: React.ReactNode
|
|
19
|
+
}> = ({ children }) => {
|
|
20
|
+
const [selectedExchange, setSelectedExchange] =
|
|
21
|
+
useState<SelectedMeshExchange | null>(null)
|
|
22
|
+
|
|
23
|
+
const value = useMemo(
|
|
24
|
+
() => ({
|
|
25
|
+
selectedExchange,
|
|
26
|
+
setSelectedExchange,
|
|
27
|
+
}),
|
|
28
|
+
[selectedExchange],
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<SelectedMeshExchangeContext.Provider value={value}>
|
|
33
|
+
{children}
|
|
34
|
+
</SelectedMeshExchangeContext.Provider>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const useSelectedMeshExchange = () => {
|
|
39
|
+
const context = useContext(SelectedMeshExchangeContext)
|
|
40
|
+
if (context === undefined) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"useSelectedMeshExchange must be used within a SelectedMeshExchangeProvider",
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
return context
|
|
46
|
+
}
|
|
@@ -40,6 +40,8 @@ import { etherlink } from "viem/chains"
|
|
|
40
40
|
import { logger } from "../../logger.js"
|
|
41
41
|
import { getIsContract } from "../../contractUtils.js"
|
|
42
42
|
import { useTrailsClient } from "../../trailsClient.js"
|
|
43
|
+
import { useTokenList } from "./useTokenList.js"
|
|
44
|
+
import { useSelectedFeeToken } from "./useSelectedFeeToken.js"
|
|
43
45
|
|
|
44
46
|
export interface Token {
|
|
45
47
|
id: number
|
|
@@ -117,19 +119,14 @@ export type UseSendProps = {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
export type FeeOption = {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
tokenID: string | null
|
|
129
|
-
}
|
|
130
|
-
to: string
|
|
131
|
-
value: string
|
|
132
|
-
gasLimit: number
|
|
122
|
+
tokenAddress: string
|
|
123
|
+
tokenSymbol: string
|
|
124
|
+
tokenDecimals: number
|
|
125
|
+
amount: string
|
|
126
|
+
amountUSD: number
|
|
127
|
+
notEnoughBalance?: boolean
|
|
128
|
+
tokenImageUrl?: string
|
|
129
|
+
chainId?: number
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
export type UseSendReturn = {
|
|
@@ -436,6 +433,14 @@ export function useSendForm({
|
|
|
436
433
|
const apiClient = useAPIClient()
|
|
437
434
|
const trailsClient = useTrailsClient()
|
|
438
435
|
|
|
436
|
+
// Get user's token balances for balance checking
|
|
437
|
+
const { filteredTokensFormatted } = useTokenList({
|
|
438
|
+
onContinue: () => {}, // Not used for balance checking
|
|
439
|
+
onError: () => {}, // Not used for balance checking
|
|
440
|
+
fundMethod: undefined,
|
|
441
|
+
allSupportedTokens: true, // Get all tokens for balance checking
|
|
442
|
+
})
|
|
443
|
+
|
|
439
444
|
const destTokenAddress = useTokenAddress({
|
|
440
445
|
chainId: selectedDestinationChain?.id,
|
|
441
446
|
tokenSymbol: selectedDestToken?.symbol,
|
|
@@ -569,9 +574,14 @@ export function useSendForm({
|
|
|
569
574
|
return formatUsdAmountDisplay(amountUsd)
|
|
570
575
|
}, [amount, destTokenPrices, sourceTokenPrices, tradeType])
|
|
571
576
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
577
|
+
// Use the fee token selection hook
|
|
578
|
+
const {
|
|
579
|
+
selectedFeeToken,
|
|
580
|
+
setSelectedFeeToken,
|
|
581
|
+
processedFeeOptions: feeOptions,
|
|
582
|
+
setRawFeeOptions,
|
|
583
|
+
} = useSelectedFeeToken()
|
|
584
|
+
|
|
575
585
|
const [isRecipientContract, setIsRecipientContract] = useState(false)
|
|
576
586
|
const [isSenderContractOnOrigin, setIsSenderContractOnOrigin] =
|
|
577
587
|
useState(false)
|
|
@@ -794,7 +804,10 @@ export function useSendForm({
|
|
|
794
804
|
originChainId: selectedToken.chainId,
|
|
795
805
|
originTokenBalance:
|
|
796
806
|
fundMethod === "qr-code" || fundMethod === "exchange"
|
|
797
|
-
?
|
|
807
|
+
? parseUnits(
|
|
808
|
+
"100",
|
|
809
|
+
selectedToken.contractInfo?.decimals ?? 18,
|
|
810
|
+
).toString() // needs to be an amount that is greater than the minimum amount for the swap
|
|
798
811
|
: selectedToken.balance,
|
|
799
812
|
destinationChainId: selectedDestinationChain.id,
|
|
800
813
|
recipient,
|
|
@@ -827,8 +840,16 @@ export function useSendForm({
|
|
|
827
840
|
mode,
|
|
828
841
|
fundMethod,
|
|
829
842
|
checkoutOnHandlers,
|
|
843
|
+
selectedFeeToken,
|
|
830
844
|
}
|
|
831
845
|
|
|
846
|
+
logger.console.log(
|
|
847
|
+
"[trails-sdk] [FEE-SELECT] getQuote using selectedFeeToken:",
|
|
848
|
+
{
|
|
849
|
+
selectedFeeToken,
|
|
850
|
+
},
|
|
851
|
+
)
|
|
852
|
+
|
|
832
853
|
const result = await prepareSend(options)
|
|
833
854
|
|
|
834
855
|
logger.console.log("[trails-sdk] prepareSend quote:", result.quote)
|
|
@@ -873,6 +894,7 @@ export function useSendForm({
|
|
|
873
894
|
amountRaw,
|
|
874
895
|
checkoutOnHandlers,
|
|
875
896
|
mode,
|
|
897
|
+
selectedFeeToken,
|
|
876
898
|
])
|
|
877
899
|
|
|
878
900
|
// Auto-fetch quotes when inputs change (debounced)
|
|
@@ -907,6 +929,7 @@ export function useSendForm({
|
|
|
907
929
|
selectedToken?.chainId,
|
|
908
930
|
selectedToken?.balance,
|
|
909
931
|
selectedToken?.tokenPriceUsd,
|
|
932
|
+
// selectedFeeToken is passed to send() at execution time, not needed here
|
|
910
933
|
])
|
|
911
934
|
|
|
912
935
|
// Calculate destination amount from quote if available
|
|
@@ -922,9 +945,31 @@ export function useSendForm({
|
|
|
922
945
|
return formatAmountDisplay(quotedDestinationAmount || "0")
|
|
923
946
|
}, [quotedDestinationAmount])
|
|
924
947
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
948
|
+
// Set raw fee options in the hook whenever prepareSendResult or tokens change
|
|
949
|
+
useEffect(() => {
|
|
950
|
+
const apiFeeOptions = prepareSendResult?.feeOptions?.feeOptions ?? []
|
|
951
|
+
logger.console.log(
|
|
952
|
+
"[trails-sdk] [FEE-SELECT] useSendForm setting raw fee options:",
|
|
953
|
+
{
|
|
954
|
+
prepareSendResult,
|
|
955
|
+
feeOptions: prepareSendResult?.feeOptions,
|
|
956
|
+
apiFeeOptions,
|
|
957
|
+
length: apiFeeOptions.length,
|
|
958
|
+
},
|
|
959
|
+
)
|
|
960
|
+
|
|
961
|
+
setRawFeeOptions(
|
|
962
|
+
apiFeeOptions,
|
|
963
|
+
selectedToken?.chainId,
|
|
964
|
+
filteredTokensFormatted,
|
|
965
|
+
)
|
|
966
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
967
|
+
}, [
|
|
968
|
+
prepareSendResult,
|
|
969
|
+
selectedToken?.chainId,
|
|
970
|
+
filteredTokensFormatted,
|
|
971
|
+
setRawFeeOptions,
|
|
972
|
+
])
|
|
928
973
|
|
|
929
974
|
const processSend = useCallback(async () => {
|
|
930
975
|
try {
|
|
@@ -1008,7 +1053,17 @@ export function useSendForm({
|
|
|
1008
1053
|
|
|
1009
1054
|
async function handleSend() {
|
|
1010
1055
|
logger.console.log(
|
|
1011
|
-
"[trails-sdk]
|
|
1056
|
+
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] handleSend called, about to call send()",
|
|
1057
|
+
)
|
|
1058
|
+
logger.console.log(
|
|
1059
|
+
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] selectedFeeToken value at send() call time:",
|
|
1060
|
+
{
|
|
1061
|
+
selectedFeeToken,
|
|
1062
|
+
isNull: selectedFeeToken === null,
|
|
1063
|
+
isUndefined: selectedFeeToken === undefined,
|
|
1064
|
+
type: typeof selectedFeeToken,
|
|
1065
|
+
stringified: JSON.stringify(selectedFeeToken),
|
|
1066
|
+
},
|
|
1012
1067
|
)
|
|
1013
1068
|
// Wait for full send to complete
|
|
1014
1069
|
const {
|
|
@@ -1017,7 +1072,7 @@ export function useSendForm({
|
|
|
1017
1072
|
destinationMetaTxnReceipt,
|
|
1018
1073
|
} = await send({
|
|
1019
1074
|
onOriginSend,
|
|
1020
|
-
|
|
1075
|
+
selectedFeeToken, // Pass current value at execution time
|
|
1021
1076
|
})
|
|
1022
1077
|
logger.console.log("[trails-sdk] send() completed, receipts:", {
|
|
1023
1078
|
originUserTxReceipt,
|
|
@@ -1078,7 +1133,7 @@ export function useSendForm({
|
|
|
1078
1133
|
onError,
|
|
1079
1134
|
fundMethod,
|
|
1080
1135
|
onNavigateToMeshConnect,
|
|
1081
|
-
selectedFeeToken
|
|
1136
|
+
selectedFeeToken, // Include so handleSend captures latest value
|
|
1082
1137
|
])
|
|
1083
1138
|
|
|
1084
1139
|
const handleSubmit = async (e: React.FormEvent) => {
|