0xtrails 0.2.4 → 0.2.5
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/aave.d.ts +8 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/{ccip-BlV1Mry3.js → ccip-CXlshvBY.js} +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/estimate.d.ts +52 -0
- package/dist/estimate.d.ts.map +1 -1
- package/dist/{index-BNWCIGfQ.js → index-_QuyGrjU.js} +72332 -72246
- package/dist/index.js +2 -2
- package/dist/intents.d.ts +40 -0
- package/dist/intents.d.ts.map +1 -1
- package/dist/metaTxnMonitor.d.ts +3 -3
- package/dist/metaTxnMonitor.d.ts.map +1 -1
- package/dist/metaTxns.d.ts +3 -3
- package/dist/metaTxns.d.ts.map +1 -1
- package/dist/morpho.d.ts +8 -0
- package/dist/morpho.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +16 -6
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/queryParams.d.ts.map +1 -1
- package/dist/relayer.d.ts +6 -6
- package/dist/relayer.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +2 -2
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -0
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts +4 -0
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/{FundSendForm.d.ts → FundSwap.d.ts} +11 -5
- package/dist/widget/components/FundSwap.d.ts.map +1 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts +4 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PercentageMaxButtons.d.ts +12 -0
- package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -0
- package/dist/widget/components/{PaySendForm.d.ts → PoolDeposit.d.ts} +11 -34
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
- package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +16 -8
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receive.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts +4 -0
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Recipients.d.ts.map +1 -1
- package/dist/widget/components/RequiredPropsError.d.ts +8 -0
- package/dist/widget/components/RequiredPropsError.d.ts.map +1 -0
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +1 -0
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapSettings.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts +1 -0
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/TokenList.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts +16 -0
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +8 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -0
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletList.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -0
- package/dist/widget/css/index.css +554 -0
- package/dist/widget/hooks/useBack.d.ts +1 -0
- package/dist/widget/hooks/useBack.d.ts.map +1 -1
- package/dist/widget/hooks/useCheckout.d.ts +1 -1
- package/dist/widget/hooks/useCheckout.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 +3 -3
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/usePayMessage.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFundMethod.d.ts +12 -0
- package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts +4 -4
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +18 -12
- package/src/aave.ts +32 -0
- package/src/config.ts +12 -4
- package/src/constants.ts +2 -0
- package/src/error.ts +19 -1
- package/src/estimate.ts +416 -5
- package/src/intents.ts +161 -11
- package/src/metaTxnMonitor.ts +3 -3
- package/src/metaTxns.ts +3 -5
- package/src/morpho.ts +32 -0
- package/src/prepareSend.ts +503 -166
- package/src/queryParams.ts +2 -1
- package/src/relayer.ts +11 -11
- package/src/sequenceWallet.ts +2 -2
- package/src/tokens.ts +7 -1
- package/src/wallets.ts +8 -0
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountActionsDropdown.tsx +3 -13
- package/src/widget/components/AccountSettings.tsx +6 -24
- package/src/widget/components/ClassicSwap.tsx +111 -155
- package/src/widget/components/ConnectWallet.tsx +4 -37
- package/src/widget/components/ConnectedWallets.tsx +113 -58
- package/src/widget/components/Earn.tsx +73 -589
- package/src/widget/components/Fund.tsx +31 -82
- package/src/widget/components/FundMethods.tsx +82 -159
- package/src/widget/components/FundSwap.tsx +52 -0
- package/src/widget/components/FundingMethodSelectorButton.tsx +60 -0
- package/src/widget/components/Modal.tsx +6 -2
- package/src/widget/components/Pay.tsx +183 -208
- package/src/widget/components/PercentageMaxButtons.tsx +77 -0
- package/src/widget/components/PoolDeposit.tsx +593 -0
- package/src/widget/components/PoolWithdraw.tsx +903 -0
- package/src/widget/components/QuoteDetails.tsx +22 -8
- package/src/widget/components/Receive.tsx +0 -2
- package/src/widget/components/RecipientSelectorButton.tsx +42 -0
- package/src/widget/components/Recipients.tsx +62 -156
- package/src/widget/components/RequiredPropsError.tsx +33 -0
- package/src/widget/components/ScreenHeader.tsx +5 -1
- package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
- package/src/widget/components/Swap.tsx +2 -43
- package/src/widget/components/SwapSettings.tsx +2 -14
- package/src/widget/components/TokenImage.tsx +21 -4
- package/src/widget/components/TokenList.tsx +0 -1
- package/src/widget/components/TokenSelector.tsx +1 -0
- package/src/widget/components/TokenSelectorButton.tsx +75 -0
- package/src/widget/components/UserPreferences.tsx +6 -24
- package/src/widget/components/WaasFeeOptions.tsx +331 -0
- package/src/widget/components/WalletConfirmation.tsx +55 -3
- package/src/widget/components/WalletList.tsx +4 -2
- package/src/widget/hooks/useBack.tsx +2 -0
- package/src/widget/hooks/useCheckout.ts +36 -20
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDefaultTokenSelection.tsx +104 -28
- package/src/widget/hooks/usePayMessage.tsx +86 -11
- package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
- package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
- package/src/widget/hooks/useSendForm.ts +24 -2
- package/src/widget/index.css +27 -0
- package/src/widget/widget.tsx +169 -111
- package/dist/widget/components/FundSendForm.d.ts.map +0 -1
- package/dist/widget/components/PaySendForm.d.ts.map +0 -1
- package/dist/widget/components/SimpleSwap.d.ts.map +0 -1
- package/dist/widget/hooks/useSwapSettings.d.ts +0 -16
- package/dist/widget/hooks/useSwapSettings.d.ts.map +0 -1
- package/src/widget/components/FundSendForm.tsx +0 -903
- package/src/widget/components/PaySendForm.tsx +0 -869
- package/src/widget/components/SimpleSwap.tsx +0 -983
- package/src/widget/hooks/useSwapSettings.tsx +0 -100
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TrendingUp,
|
|
3
|
+
ArrowDown,
|
|
4
|
+
ChevronRight,
|
|
5
|
+
Search,
|
|
6
|
+
Loader2,
|
|
7
|
+
} from "lucide-react"
|
|
8
|
+
import { useEffect, useState, useRef } from "react"
|
|
9
|
+
import type React from "react"
|
|
10
|
+
import type { Account, WalletClient } from "viem"
|
|
11
|
+
import { zeroAddress } from "viem"
|
|
12
|
+
import type { TransactionState } from "../../transactions.js"
|
|
13
|
+
import type { OnCompleteProps } from "../hooks/useSendForm.js"
|
|
14
|
+
import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
|
|
15
|
+
import { useSendForm } from "../hooks/useSendForm.js"
|
|
16
|
+
import { TradeType } from "../../prepareSend.js"
|
|
17
|
+
import { useOriginSelectedToken } from "../hooks/useOriginSelectedToken.js"
|
|
18
|
+
import { useEarnPool } from "../hooks/useEarnPool.js"
|
|
19
|
+
import { useTokenList } from "../hooks/useTokenList.js"
|
|
20
|
+
import { useMode } from "../hooks/useMode.js"
|
|
21
|
+
import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
|
|
22
|
+
import { TokenImage } from "./TokenImage.js"
|
|
23
|
+
import { TokenSelector } from "./TokenSelector.js"
|
|
24
|
+
import { EarnPools } from "./EarnPools.js"
|
|
25
|
+
import { ChainList } from "./ChainList.js"
|
|
26
|
+
import { QuoteDetails } from "./QuoteDetails.js"
|
|
27
|
+
import { PercentageMaxButtons } from "./PercentageMaxButtons.js"
|
|
28
|
+
import { TokenSelectorButton } from "./TokenSelectorButton.js"
|
|
29
|
+
import { FundingMethodSelectorButton } from "./FundingMethodSelectorButton.js"
|
|
30
|
+
import { formatTvl } from "../../prices.js"
|
|
31
|
+
import { useAmountUsd } from "../hooks/useAmountUsd.js"
|
|
32
|
+
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
33
|
+
import aaveLogo from "../assets/aave.svg"
|
|
34
|
+
import morphoLogo from "../assets/morpho.svg"
|
|
35
|
+
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
36
|
+
import type { SupportedToken } from "../../tokens.js"
|
|
37
|
+
import { logger } from "../../logger.js"
|
|
38
|
+
|
|
39
|
+
interface PoolDepositProps {
|
|
40
|
+
account: Account
|
|
41
|
+
walletClient: WalletClient
|
|
42
|
+
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
43
|
+
onError: (error: Error | string | null) => void
|
|
44
|
+
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
45
|
+
onConfirm: () => void
|
|
46
|
+
onComplete: (result: OnCompleteProps) => void
|
|
47
|
+
onSend: (amount: string, recipient: string) => void
|
|
48
|
+
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
49
|
+
gasless?: boolean
|
|
50
|
+
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
51
|
+
quoteProvider?: string
|
|
52
|
+
fundMethod?: string
|
|
53
|
+
onNavigateToMeshConnect?: (
|
|
54
|
+
props: {
|
|
55
|
+
toTokenSymbol: string
|
|
56
|
+
toTokenAmount: string
|
|
57
|
+
toChainId: number
|
|
58
|
+
toRecipientAddress: string
|
|
59
|
+
},
|
|
60
|
+
quote?: PrepareSendQuote | null,
|
|
61
|
+
) => void
|
|
62
|
+
checkoutOnHandlers?: CheckoutOnHandlers
|
|
63
|
+
recentTokens?: SupportedToken[]
|
|
64
|
+
onRecentTokenSelect?: (token: SupportedToken) => void
|
|
65
|
+
onTrackToken?: (token: any) => void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const PoolDeposit: React.FC<PoolDepositProps> = ({
|
|
69
|
+
account,
|
|
70
|
+
walletClient,
|
|
71
|
+
onTransactionStateChange,
|
|
72
|
+
onError,
|
|
73
|
+
onWaitingForWalletConfirm,
|
|
74
|
+
onConfirm,
|
|
75
|
+
onComplete,
|
|
76
|
+
onSend,
|
|
77
|
+
paymasterUrls,
|
|
78
|
+
gasless,
|
|
79
|
+
setWalletConfirmRetryHandler,
|
|
80
|
+
quoteProvider,
|
|
81
|
+
fundMethod,
|
|
82
|
+
onNavigateToMeshConnect,
|
|
83
|
+
checkoutOnHandlers,
|
|
84
|
+
recentTokens,
|
|
85
|
+
onRecentTokenSelect,
|
|
86
|
+
onTrackToken,
|
|
87
|
+
}) => {
|
|
88
|
+
const { mode } = useMode()
|
|
89
|
+
const { isBalanceVisible } = useBalanceVisible()
|
|
90
|
+
const { selectedToken: originToken, setSelectedToken: setOriginToken } =
|
|
91
|
+
useOriginSelectedToken()
|
|
92
|
+
const { selectedPool, setSelectedPool } = useEarnPool()
|
|
93
|
+
|
|
94
|
+
const [showEarnPools, setShowEarnPools] = useState(false)
|
|
95
|
+
const [showOriginTokenSelector, setShowOriginTokenSelector] = useState(false)
|
|
96
|
+
const [showOriginChainList, setShowOriginChainList] = useState(false)
|
|
97
|
+
const [amount, setAmount] = useState("")
|
|
98
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
99
|
+
|
|
100
|
+
// Get sorted tokens to auto-select the highest USD value token
|
|
101
|
+
const { filteredTokensFormatted, isLoadingTokens } = useTokenList({
|
|
102
|
+
onContinue: () => {}, // Not used for auto-selection
|
|
103
|
+
onError: () => {}, // Not used for auto-selection
|
|
104
|
+
fundMethod: undefined,
|
|
105
|
+
allSupportedTokens: false,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Use useSendForm for quote functionality when both token and pool are selected
|
|
109
|
+
const {
|
|
110
|
+
balanceFormatted,
|
|
111
|
+
isLoadingQuote,
|
|
112
|
+
prepareSendQuote,
|
|
113
|
+
setAmount: setSendFormAmount,
|
|
114
|
+
handleSubmit,
|
|
115
|
+
isSubmitting,
|
|
116
|
+
buttonText,
|
|
117
|
+
isValidRecipient,
|
|
118
|
+
} = useSendForm({
|
|
119
|
+
account,
|
|
120
|
+
toAmount: undefined,
|
|
121
|
+
toRecipient: selectedPool?.depositAddress,
|
|
122
|
+
toChainId: selectedPool?.chainId,
|
|
123
|
+
toToken: selectedPool?.token.address,
|
|
124
|
+
toCalldata: undefined,
|
|
125
|
+
walletClient,
|
|
126
|
+
onTransactionStateChange,
|
|
127
|
+
onError,
|
|
128
|
+
onWaitingForWalletConfirm,
|
|
129
|
+
paymasterUrls,
|
|
130
|
+
gasless,
|
|
131
|
+
onConfirm,
|
|
132
|
+
onComplete,
|
|
133
|
+
onSend,
|
|
134
|
+
selectedToken: originToken as any,
|
|
135
|
+
setWalletConfirmRetryHandler,
|
|
136
|
+
tradeType: TradeType.EXACT_INPUT,
|
|
137
|
+
quoteProvider,
|
|
138
|
+
fundMethod,
|
|
139
|
+
mode,
|
|
140
|
+
onNavigateToMeshConnect,
|
|
141
|
+
checkoutOnHandlers,
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// Calculate USD value using the underlying token (for pool tokens like aBasUSDC)
|
|
145
|
+
const { amountUsdFormatted: underlyingTokenUsdDisplay } = useAmountUsd({
|
|
146
|
+
amount: amount,
|
|
147
|
+
token: originToken?.contractAddress, // Use the origin token's address for USD calculation
|
|
148
|
+
chainId: originToken?.chainId,
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Auto-select the highest USD value token as origin token
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (
|
|
154
|
+
!originToken &&
|
|
155
|
+
!isLoadingTokens &&
|
|
156
|
+
filteredTokensFormatted?.length > 0
|
|
157
|
+
) {
|
|
158
|
+
const highestValueToken = filteredTokensFormatted[0] // First token is highest USD value
|
|
159
|
+
if (highestValueToken && Number(highestValueToken.balanceUsd) > 0) {
|
|
160
|
+
const decimals =
|
|
161
|
+
highestValueToken.contractInfo?.decimals ??
|
|
162
|
+
(highestValueToken as any)?.decimals
|
|
163
|
+
setOriginToken({
|
|
164
|
+
...highestValueToken,
|
|
165
|
+
contractInfo: {
|
|
166
|
+
decimals,
|
|
167
|
+
contractAddress: highestValueToken.contractAddress,
|
|
168
|
+
symbol: highestValueToken.symbol,
|
|
169
|
+
name: highestValueToken.name,
|
|
170
|
+
},
|
|
171
|
+
} as any)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}, [originToken, isLoadingTokens, filteredTokensFormatted, setOriginToken])
|
|
175
|
+
|
|
176
|
+
// Auto-focus input field on component mount
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (inputRef.current) {
|
|
179
|
+
inputRef.current.focus()
|
|
180
|
+
}
|
|
181
|
+
}, [])
|
|
182
|
+
|
|
183
|
+
const handleAmountChange = (value: string) => {
|
|
184
|
+
// Validate decimal places (max 8 decimals)
|
|
185
|
+
const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
|
|
186
|
+
if (!decimalMatch && value !== "") {
|
|
187
|
+
return // Don't update if more than 8 decimals
|
|
188
|
+
}
|
|
189
|
+
setAmount(value)
|
|
190
|
+
setSendFormAmount(value) // Sync with useSendForm for quote functionality
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const handlePoolSelect = (pool: any) => {
|
|
194
|
+
logger.console.log("Selected pool:", pool)
|
|
195
|
+
setSelectedPool(pool)
|
|
196
|
+
setShowEarnPools(false)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const handleOriginTokenSelect = (token: any) => {
|
|
200
|
+
const formattedToken = {
|
|
201
|
+
...token,
|
|
202
|
+
decimals: token.contractInfo?.decimals || token.decimals,
|
|
203
|
+
contractInfo: {
|
|
204
|
+
decimals: token.contractInfo?.decimals || token.decimals,
|
|
205
|
+
contractAddress: token.contractAddress,
|
|
206
|
+
symbol: token.symbol,
|
|
207
|
+
name: token.name,
|
|
208
|
+
},
|
|
209
|
+
} as any
|
|
210
|
+
setOriginToken(formattedToken)
|
|
211
|
+
logger.console.log("[trails-sdk] selected origin token", token)
|
|
212
|
+
setShowOriginTokenSelector(false)
|
|
213
|
+
// Track the token selection
|
|
214
|
+
onTrackToken?.(token)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Handle amount selection from percentage buttons
|
|
218
|
+
const handleAmountSelect = (selectedAmount: string) => {
|
|
219
|
+
setAmount(selectedAmount)
|
|
220
|
+
setSendFormAmount(selectedAmount)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (showOriginChainList) {
|
|
224
|
+
return (
|
|
225
|
+
<ChainList
|
|
226
|
+
onBack={() => {
|
|
227
|
+
setShowOriginChainList(false)
|
|
228
|
+
setShowOriginTokenSelector(true)
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (showEarnPools) {
|
|
235
|
+
return (
|
|
236
|
+
<EarnPools
|
|
237
|
+
onBack={() => setShowEarnPools(false)}
|
|
238
|
+
onPoolSelect={handlePoolSelect}
|
|
239
|
+
/>
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (showOriginTokenSelector) {
|
|
244
|
+
return (
|
|
245
|
+
<div className="space-y-2">
|
|
246
|
+
<TokenSelector
|
|
247
|
+
onTokenSelect={handleOriginTokenSelect}
|
|
248
|
+
onError={onError}
|
|
249
|
+
fundMethod={fundMethod}
|
|
250
|
+
showContinueButton={false}
|
|
251
|
+
compactMode={false}
|
|
252
|
+
recentTokens={recentTokens}
|
|
253
|
+
onRecentTokenSelect={onRecentTokenSelect}
|
|
254
|
+
allSupportedTokens={false}
|
|
255
|
+
chainListScreen={true}
|
|
256
|
+
onNavigateToChainList={() => {
|
|
257
|
+
setShowOriginTokenSelector(false)
|
|
258
|
+
setShowOriginChainList(true)
|
|
259
|
+
}}
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<div className="space-y-2">
|
|
267
|
+
<div className="space-y-1">
|
|
268
|
+
{/* Origin Token Selection */}
|
|
269
|
+
<div className="trails-bg-secondary trails-bg-secondary-hover trails-border-radius-container p-3 group transition-all duration-200 border border-transparent focus-within:!bg-white dark:focus-within:!bg-gray-800 trails-focus-border-secondary">
|
|
270
|
+
{/* Deposit Label */}
|
|
271
|
+
<div className="flex justify-between items-center mb-2">
|
|
272
|
+
<div className="text-sm font-semibold trails-text-secondary text-left">
|
|
273
|
+
From
|
|
274
|
+
</div>
|
|
275
|
+
<FundingMethodSelectorButton />
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<div className="flex items-center space-x-2">
|
|
279
|
+
{/* Amount Input */}
|
|
280
|
+
<div className="flex-1">
|
|
281
|
+
<button
|
|
282
|
+
type="button"
|
|
283
|
+
className="flex items-center justify-start cursor-text bg-transparent border-none p-0 w-full"
|
|
284
|
+
onClick={() => inputRef.current?.focus()}
|
|
285
|
+
>
|
|
286
|
+
<div className="flex items-center">
|
|
287
|
+
<input
|
|
288
|
+
ref={inputRef}
|
|
289
|
+
type="text"
|
|
290
|
+
value={amount}
|
|
291
|
+
onChange={(e) => handleAmountChange(e.target.value)}
|
|
292
|
+
placeholder="0"
|
|
293
|
+
className={`bg-transparent border-none outline-none font-bold text-left trails-text-primary placeholder-trails-text-primary ${
|
|
294
|
+
isLoadingQuote ? "animate-pulse" : ""
|
|
295
|
+
}`}
|
|
296
|
+
style={{
|
|
297
|
+
fontSize:
|
|
298
|
+
amount.length > 12
|
|
299
|
+
? "0.875rem"
|
|
300
|
+
: amount.length > 9
|
|
301
|
+
? "1rem"
|
|
302
|
+
: amount.length > 6
|
|
303
|
+
? "1.125rem"
|
|
304
|
+
: amount.length > 3
|
|
305
|
+
? "1.25rem"
|
|
306
|
+
: "1.5rem",
|
|
307
|
+
width: `${Math.max((amount || "0").length, 1)}ch`,
|
|
308
|
+
minWidth: "1ch",
|
|
309
|
+
maxWidth: "270px",
|
|
310
|
+
padding: "0",
|
|
311
|
+
margin: "0",
|
|
312
|
+
transition: "all 0.1s ease-in-out",
|
|
313
|
+
}}
|
|
314
|
+
inputMode="decimal"
|
|
315
|
+
/>
|
|
316
|
+
<span
|
|
317
|
+
className="font-bold text-gray-400 dark:text-gray-500"
|
|
318
|
+
style={{
|
|
319
|
+
fontSize:
|
|
320
|
+
amount.length > 12
|
|
321
|
+
? "0.875rem"
|
|
322
|
+
: amount.length > 9
|
|
323
|
+
? "1rem"
|
|
324
|
+
: amount.length > 6
|
|
325
|
+
? "1.125rem"
|
|
326
|
+
: amount.length > 3
|
|
327
|
+
? "1.25rem"
|
|
328
|
+
: "1.5rem",
|
|
329
|
+
marginLeft: "0.1em",
|
|
330
|
+
padding: "0",
|
|
331
|
+
transition: "all 0.2s ease-in-out",
|
|
332
|
+
}}
|
|
333
|
+
>
|
|
334
|
+
{originToken?.symbol.slice(0, 4) || ""}
|
|
335
|
+
</span>
|
|
336
|
+
{isLoadingQuote && (
|
|
337
|
+
<div className="ml-2 animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
|
|
338
|
+
)}
|
|
339
|
+
</div>
|
|
340
|
+
</button>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
{/* Token Selection Button */}
|
|
344
|
+
<TokenSelectorButton
|
|
345
|
+
token={originToken}
|
|
346
|
+
chainId={originToken?.chainId}
|
|
347
|
+
onSelect={() => setShowOriginTokenSelector(true)}
|
|
348
|
+
/>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
{/* Bottom Info Row */}
|
|
352
|
+
<div className="mt-2 flex justify-between items-center">
|
|
353
|
+
{/* USD Amount */}
|
|
354
|
+
<div className="text-xs trails-text-muted">
|
|
355
|
+
{originToken?.symbol && amount ? (
|
|
356
|
+
<>≈ {underlyingTokenUsdDisplay || "$0.00"}</>
|
|
357
|
+
) : (
|
|
358
|
+
<span> </span>
|
|
359
|
+
)}
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
{/* Origin Token Balance and Percentage Buttons */}
|
|
363
|
+
{originToken && balanceFormatted && (
|
|
364
|
+
<div className="flex items-center space-x-2">
|
|
365
|
+
<button
|
|
366
|
+
type="button"
|
|
367
|
+
className="text-xs trails-text-muted cursor-pointer hover:trails-hover-text transition-colors bg-transparent border-none p-0"
|
|
368
|
+
onClick={() => handleAmountSelect(balanceFormatted || "0")}
|
|
369
|
+
onKeyDown={(e) => {
|
|
370
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
371
|
+
e.preventDefault()
|
|
372
|
+
handleAmountSelect(balanceFormatted || "0")
|
|
373
|
+
}
|
|
374
|
+
}}
|
|
375
|
+
title="Click to use full balance"
|
|
376
|
+
>
|
|
377
|
+
Balance:{" "}
|
|
378
|
+
{isBalanceVisible ? balanceFormatted || "0.00" : "••••••"}
|
|
379
|
+
</button>
|
|
380
|
+
|
|
381
|
+
{/* Percentage Buttons */}
|
|
382
|
+
<PercentageMaxButtons
|
|
383
|
+
userBalance={balanceFormatted}
|
|
384
|
+
isNativeToken={originToken.contractAddress === zeroAddress}
|
|
385
|
+
gasCostFormatted={prepareSendQuote?.gasCostFormatted}
|
|
386
|
+
chainId={originToken.chainId}
|
|
387
|
+
onAmountSelect={handleAmountSelect}
|
|
388
|
+
className="opacity-100"
|
|
389
|
+
/>
|
|
390
|
+
</div>
|
|
391
|
+
)}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
{/* Arrow Down Between Sections */}
|
|
396
|
+
<div className="relative">
|
|
397
|
+
<div className="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 p-1.5 trails-border-radius-button trails-bg-tertiary transition-colors border-2 border-white dark:border-gray-800 z-1">
|
|
398
|
+
<ArrowDown
|
|
399
|
+
className="w-5 h-5 text-gray-900 dark:text-white"
|
|
400
|
+
strokeWidth={2.5}
|
|
401
|
+
/>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
{/* Destination Vault Selection */}
|
|
406
|
+
<div className="trails-bg-secondary trails-border-radius-container transition-all duration-200 border border-transparent hover:!bg-white dark:hover:!bg-white hover:border-gray-400 dark:hover:border-gray-500">
|
|
407
|
+
{selectedPool ? (
|
|
408
|
+
<div className="p-3 trails-border-radius-container trails-bg-secondary transition-all overflow-hidden">
|
|
409
|
+
{/* Vault Label */}
|
|
410
|
+
<div className="flex justify-between items-center mb-2">
|
|
411
|
+
<div className="text-sm font-semibold trails-text-secondary text-left">
|
|
412
|
+
Vault
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<div className="px-1">
|
|
417
|
+
<div className="flex items-center justify-between">
|
|
418
|
+
<div className="flex items-center space-x-3">
|
|
419
|
+
<div style={{ width: "32px", height: "32px" }}>
|
|
420
|
+
<a
|
|
421
|
+
href={getExplorerUrlForAddress({
|
|
422
|
+
address: selectedPool.token.address,
|
|
423
|
+
chainId: selectedPool.chainId,
|
|
424
|
+
})}
|
|
425
|
+
target="_blank"
|
|
426
|
+
rel="noopener noreferrer"
|
|
427
|
+
className="cursor-pointer"
|
|
428
|
+
>
|
|
429
|
+
<TokenImage
|
|
430
|
+
symbol={selectedPool.token.symbol}
|
|
431
|
+
imageUrl={selectedPool.token.logoUrl}
|
|
432
|
+
chainId={selectedPool.chainId}
|
|
433
|
+
contractAddress={selectedPool.token.address}
|
|
434
|
+
size={32}
|
|
435
|
+
/>
|
|
436
|
+
</a>
|
|
437
|
+
</div>
|
|
438
|
+
<div>
|
|
439
|
+
<h3 className="font-medium text-gray-900 dark:text-white text-sm">
|
|
440
|
+
{selectedPool.poolUrl ? (
|
|
441
|
+
<a
|
|
442
|
+
href={selectedPool.poolUrl}
|
|
443
|
+
target="_blank"
|
|
444
|
+
rel="noopener noreferrer"
|
|
445
|
+
className="hover:underline cursor-pointer"
|
|
446
|
+
>
|
|
447
|
+
{selectedPool.name}
|
|
448
|
+
</a>
|
|
449
|
+
) : (
|
|
450
|
+
selectedPool.name
|
|
451
|
+
)}
|
|
452
|
+
</h3>
|
|
453
|
+
<div className="flex items-center space-x-2">
|
|
454
|
+
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
455
|
+
{selectedPool.protocol === "Aave" && (
|
|
456
|
+
<img
|
|
457
|
+
src={aaveLogo}
|
|
458
|
+
alt="Aave"
|
|
459
|
+
className="w-3 h-3 mr-1"
|
|
460
|
+
/>
|
|
461
|
+
)}
|
|
462
|
+
{selectedPool.protocol === "Morpho" && (
|
|
463
|
+
<img
|
|
464
|
+
src={morphoLogo}
|
|
465
|
+
alt="Morpho"
|
|
466
|
+
className="w-3 h-3 mr-1"
|
|
467
|
+
/>
|
|
468
|
+
)}
|
|
469
|
+
{selectedPool.protocolUrl ? (
|
|
470
|
+
<a
|
|
471
|
+
href={selectedPool.protocolUrl}
|
|
472
|
+
target="_blank"
|
|
473
|
+
rel="noopener noreferrer"
|
|
474
|
+
className="hover:underline cursor-pointer"
|
|
475
|
+
>
|
|
476
|
+
{selectedPool.protocol}
|
|
477
|
+
</a>
|
|
478
|
+
) : (
|
|
479
|
+
selectedPool.protocol
|
|
480
|
+
)}
|
|
481
|
+
</span>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
<button
|
|
486
|
+
type="button"
|
|
487
|
+
title="Select Vault"
|
|
488
|
+
onClick={() => setShowEarnPools(true)}
|
|
489
|
+
className="text-right flex items-center space-x-3 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 rounded p-2 transition-colors"
|
|
490
|
+
>
|
|
491
|
+
<div>
|
|
492
|
+
<div className="flex items-center justify-end space-x-1 text-green-600 dark:text-green-400 mb-1 whitespace-nowrap">
|
|
493
|
+
<TrendingUp className="w-3 h-3" />
|
|
494
|
+
<span className="font-semibold text-sm">
|
|
495
|
+
{selectedPool.apy.toFixed(1)}% APY
|
|
496
|
+
</span>
|
|
497
|
+
</div>
|
|
498
|
+
<p className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
499
|
+
TVL: {formatTvl(selectedPool.tvl)}
|
|
500
|
+
</p>
|
|
501
|
+
</div>
|
|
502
|
+
<ChevronRight className="w-4 h-4 text-gray-400" />
|
|
503
|
+
</button>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
</div>
|
|
507
|
+
) : (
|
|
508
|
+
<button
|
|
509
|
+
type="button"
|
|
510
|
+
onClick={() => setShowEarnPools(true)}
|
|
511
|
+
className="w-full py-6 px-4 trails-list-item trails-border-radius-container transition-all duration-200 cursor-pointer"
|
|
512
|
+
>
|
|
513
|
+
<div className="flex items-center justify-between">
|
|
514
|
+
<div className="flex items-center space-x-3 flex-1">
|
|
515
|
+
<div className="w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center">
|
|
516
|
+
<Search className="w-4 h-4 text-gray-400" />
|
|
517
|
+
</div>
|
|
518
|
+
<div className="text-left flex-1">
|
|
519
|
+
<div className="font-semibold text-gray-900 dark:text-white text-sm">
|
|
520
|
+
Select vault to earn yield with
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
<ChevronRight className="w-4 h-4 trails-text-muted flex-shrink-0" />
|
|
525
|
+
</div>
|
|
526
|
+
</button>
|
|
527
|
+
)}
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
{prepareSendQuote?.noSufficientBalance ? (
|
|
532
|
+
<div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
|
|
533
|
+
<div className="flex items-center space-x-2">
|
|
534
|
+
<svg
|
|
535
|
+
className="w-4 h-4 text-amber-500 flex-shrink-0"
|
|
536
|
+
fill="none"
|
|
537
|
+
stroke="currentColor"
|
|
538
|
+
viewBox="0 0 24 24"
|
|
539
|
+
aria-hidden="true"
|
|
540
|
+
>
|
|
541
|
+
<path
|
|
542
|
+
strokeLinecap="round"
|
|
543
|
+
strokeLinejoin="round"
|
|
544
|
+
strokeWidth={2}
|
|
545
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
546
|
+
/>
|
|
547
|
+
</svg>
|
|
548
|
+
<p className="text-sm text-amber-600 dark:text-amber-400">
|
|
549
|
+
Insufficient balance to complete this transaction
|
|
550
|
+
</p>
|
|
551
|
+
</div>
|
|
552
|
+
</div>
|
|
553
|
+
) : null}
|
|
554
|
+
|
|
555
|
+
{/* Quote Details */}
|
|
556
|
+
{prepareSendQuote && (
|
|
557
|
+
<div className="space-y-2">
|
|
558
|
+
<QuoteDetails quote={prepareSendQuote} showContent={true} />
|
|
559
|
+
</div>
|
|
560
|
+
)}
|
|
561
|
+
|
|
562
|
+
<form onSubmit={handleSubmit}>
|
|
563
|
+
<button
|
|
564
|
+
type="submit"
|
|
565
|
+
disabled={
|
|
566
|
+
!amount ||
|
|
567
|
+
!isValidRecipient ||
|
|
568
|
+
isSubmitting ||
|
|
569
|
+
!originToken ||
|
|
570
|
+
!selectedPool ||
|
|
571
|
+
isLoadingQuote ||
|
|
572
|
+
!prepareSendQuote ||
|
|
573
|
+
prepareSendQuote?.noSufficientBalance
|
|
574
|
+
}
|
|
575
|
+
className={`w-full font-semibold py-4 px-4 trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white disabled:text-gray-500 disabled:cursor-not-allowed cursor-pointer relative`}
|
|
576
|
+
>
|
|
577
|
+
{isSubmitting ? (
|
|
578
|
+
<div className="flex items-center justify-center">
|
|
579
|
+
<Loader2
|
|
580
|
+
className={`w-5 h-5 animate-spin mr-2 ${"text-gray-400"}`}
|
|
581
|
+
/>
|
|
582
|
+
<span>{buttonText}</span>
|
|
583
|
+
</div>
|
|
584
|
+
) : prepareSendQuote?.noSufficientBalance ? (
|
|
585
|
+
"Insufficient Balance"
|
|
586
|
+
) : (
|
|
587
|
+
buttonText || "Deposit"
|
|
588
|
+
)}
|
|
589
|
+
</button>
|
|
590
|
+
</form>
|
|
591
|
+
</div>
|
|
592
|
+
)
|
|
593
|
+
}
|