0xtrails 0.2.5 → 0.3.0
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 +2 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/abortController.d.ts +8 -0
- package/dist/abortController.d.ts.map +1 -0
- package/dist/{ccip-CXlshvBY.js → ccip-BMB3uDZt.js} +1 -1
- package/dist/config.d.ts +0 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +4 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +4 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/fees.d.ts +19 -0
- package/dist/fees.d.ts.map +1 -0
- package/dist/{index-_QuyGrjU.js → index-QXPUrZVv.js} +48719 -50852
- package/dist/index.d.ts +9 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +811 -784
- package/dist/intentReceiptMonitor.d.ts +24 -0
- package/dist/intentReceiptMonitor.d.ts.map +1 -0
- package/dist/intentReceiptPoller.d.ts +69 -0
- package/dist/intentReceiptPoller.d.ts.map +1 -0
- package/dist/intents.d.ts +15 -11
- package/dist/intents.d.ts.map +1 -1
- package/dist/morpho.d.ts +6 -5
- package/dist/morpho.d.ts.map +1 -1
- package/dist/mutations.d.ts +16 -0
- package/dist/mutations.d.ts.map +1 -0
- package/dist/preconditions.d.ts +5 -4
- package/dist/preconditions.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +7 -258
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/prices.d.ts +9 -6
- package/dist/prices.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +3 -16
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts +17 -13
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/trails.d.ts +24 -40
- package/dist/trails.d.ts.map +1 -1
- package/dist/transactionIntent/constants.d.ts +7 -0
- package/dist/transactionIntent/constants.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +44 -0
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +30 -0
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/index.d.ts +4 -0
- package/dist/transactionIntent/deposits/index.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/standardDeposit.d.ts +30 -0
- package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -0
- package/dist/transactionIntent/execution/index.d.ts +2 -0
- package/dist/transactionIntent/execution/index.d.ts.map +1 -0
- package/dist/transactionIntent/execution/transactionState.d.ts +5 -0
- package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/crossChain.d.ts +82 -0
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/index.d.ts +4 -0
- package/dist/transactionIntent/handlers/index.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +62 -0
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +72 -0
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -0
- package/dist/transactionIntent/index.d.ts +9 -0
- package/dist/transactionIntent/index.d.ts.map +1 -0
- package/dist/transactionIntent/quote/feeExtractors.d.ts +17 -0
- package/dist/transactionIntent/quote/feeExtractors.d.ts.map +1 -0
- package/dist/transactionIntent/quote/index.d.ts +4 -0
- package/dist/transactionIntent/quote/index.d.ts.map +1 -0
- package/dist/transactionIntent/quote/normalizeQuote.d.ts +34 -0
- package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -0
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +5 -0
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/types.d.ts +131 -0
- package/dist/transactionIntent/types.d.ts.map +1 -0
- package/dist/transactionIntent/utils/balanceChecker.d.ts +18 -0
- package/dist/transactionIntent/utils/balanceChecker.d.ts.map +1 -0
- package/dist/transactionIntent/utils/index.d.ts +4 -0
- package/dist/transactionIntent/utils/index.d.ts.map +1 -0
- package/dist/transactionIntent/utils/lifiHelpers.d.ts +10 -0
- package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/utils/testnetHelpers.d.ts +3 -0
- package/dist/transactionIntent/utils/testnetHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/validators.d.ts +6 -0
- package/dist/transactionIntent/validators.d.ts.map +1 -0
- package/dist/transactions.d.ts +6 -3
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts +4 -0
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts.map +1 -0
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -3
- 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/DynamicInputStyles.d.ts +18 -0
- package/dist/widget/components/DynamicInputStyles.d.ts.map +1 -0
- package/dist/widget/components/DynamicSizeInputField.d.ts +13 -0
- package/dist/widget/components/DynamicSizeInputField.d.ts.map +1 -0
- package/dist/widget/components/Earn.d.ts +2 -3
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/ErrorAnimationIcon.d.ts +2 -0
- package/dist/widget/components/ErrorAnimationIcon.d.ts.map +1 -0
- package/dist/widget/components/FeeBreakdown.d.ts +9 -0
- package/dist/widget/components/FeeBreakdown.d.ts.map +1 -0
- package/dist/widget/components/FeeOptions.d.ts +5 -13
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts +2 -3
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/FundSwap.d.ts +2 -3
- package/dist/widget/components/FundSwap.d.ts.map +1 -1
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Identicon.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectExchanges.d.ts +0 -3
- package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts +2 -3
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts +3 -3
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/PoolWithdraw.d.ts +3 -20
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts +2 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receipt.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +2 -3
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts +11 -0
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts.map +1 -0
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Tooltip.d.ts +9 -0
- package/dist/widget/components/Tooltip.d.ts.map +1 -0
- package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +1 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -2
- package/dist/widget/hooks/useCheckout.d.ts +17 -4
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/useQuote.d.ts +82 -0
- package/dist/widget/hooks/useQuote.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +1 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +5 -6
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/hooks/useWalletConnectionContext.d.ts +25 -0
- package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -0
- package/dist/widget/index.js +2 -2
- package/dist/widget/widget.d.ts +17 -7
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +19 -21
- package/src/aave.ts +54 -1
- package/src/abortController.ts +35 -0
- package/src/config.ts +57 -58
- package/src/constants.ts +11 -9
- package/src/error.ts +21 -3
- package/src/fees.ts +210 -0
- package/src/index.ts +35 -13
- package/src/intentReceiptMonitor.ts +102 -0
- package/src/intentReceiptPoller.ts +299 -0
- package/src/intents.ts +205 -171
- package/src/morpho.ts +58 -9
- package/src/mutations.ts +129 -0
- package/src/preconditions.ts +16 -21
- package/src/prepareSend.ts +92 -4699
- package/src/prices.ts +26 -22
- package/src/relaySdk.ts +2 -2
- package/src/sequenceWallet.ts +6 -73
- package/src/tokenBalances.ts +175 -69
- package/src/trails.ts +230 -722
- package/src/transactionIntent/constants.ts +11 -0
- package/src/transactionIntent/deposits/depositOrchestrator.ts +210 -0
- package/src/transactionIntent/deposits/gaslessDeposit.ts +588 -0
- package/src/transactionIntent/deposits/index.ts +3 -0
- package/src/transactionIntent/deposits/standardDeposit.ts +379 -0
- package/src/transactionIntent/execution/index.ts +1 -0
- package/src/transactionIntent/execution/transactionState.ts +35 -0
- package/src/transactionIntent/handlers/crossChain.ts +1707 -0
- package/src/transactionIntent/handlers/index.ts +3 -0
- package/src/transactionIntent/handlers/sameChainDifferentToken.ts +323 -0
- package/src/transactionIntent/handlers/sameChainSameToken.ts +712 -0
- package/src/transactionIntent/index.ts +9 -0
- package/src/transactionIntent/quote/feeExtractors.ts +81 -0
- package/src/transactionIntent/quote/index.ts +3 -0
- package/src/transactionIntent/quote/normalizeQuote.ts +367 -0
- package/src/transactionIntent/quote/quoteHelpers.ts +53 -0
- package/src/transactionIntent/types.ts +157 -0
- package/src/transactionIntent/utils/balanceChecker.ts +96 -0
- package/src/transactionIntent/utils/index.ts +3 -0
- package/src/transactionIntent/utils/lifiHelpers.ts +68 -0
- package/src/transactionIntent/utils/testnetHelpers.ts +10 -0
- package/src/transactionIntent/validators.ts +57 -0
- package/src/transactions.ts +98 -71
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountIntentTransactionHistory.tsx +36 -36
- package/src/widget/components/AccountIntentTransactionHistoryButton.tsx +22 -0
- package/src/widget/components/AccountSettings.tsx +70 -41
- package/src/widget/components/ChainFilterDropdown.tsx +24 -3
- package/src/widget/components/ClassicSwap.tsx +44 -107
- package/src/widget/components/ConfigDisplay.tsx +0 -11
- package/src/widget/components/ConnectWallet.tsx +4 -1
- package/src/widget/components/ConnectedWallets.tsx +51 -25
- package/src/widget/components/DynamicInputStyles.tsx +76 -0
- package/src/widget/components/DynamicSizeInputField.tsx +109 -0
- package/src/widget/components/Earn.tsx +34 -45
- package/src/widget/components/ErrorAnimationIcon.tsx +130 -0
- package/src/widget/components/FeeBreakdown.tsx +155 -0
- package/src/widget/components/FeeOption.tsx +2 -2
- package/src/widget/components/FeeOptions.tsx +151 -112
- package/src/widget/components/Fund.tsx +10 -29
- package/src/widget/components/FundMethods.tsx +4 -3
- package/src/widget/components/FundSwap.tsx +2 -3
- package/src/widget/components/FundingMethodSelectorButton.tsx +24 -14
- package/src/widget/components/Identicon.tsx +164 -95
- package/src/widget/components/MeshConnectExchanges.tsx +2 -15
- package/src/widget/components/Modal.tsx +0 -12
- package/src/widget/components/Pay.tsx +72 -75
- package/src/widget/components/PoolDeposit.tsx +221 -242
- package/src/widget/components/PoolWithdraw.tsx +347 -469
- package/src/widget/components/PriceImpactWarning.tsx +1 -1
- package/src/widget/components/QuoteDetails.tsx +906 -484
- package/src/widget/components/Receipt.tsx +16 -2
- package/src/widget/components/RecipientSelectorButton.tsx +7 -5
- package/src/widget/components/Recipients.tsx +1 -1
- package/src/widget/components/ScreenHeader.tsx +60 -36
- package/src/widget/components/Swap.tsx +2 -3
- package/src/widget/components/ThemeProvider.tsx +2 -1
- package/src/widget/components/TokenDisplayNonSelectable.tsx +40 -0
- package/src/widget/components/TokenImage.tsx +1 -1
- package/src/widget/components/TokenSelector.tsx +62 -53
- package/src/widget/components/TokenSelectorButton.tsx +38 -15
- package/src/widget/components/Tooltip.tsx +51 -0
- package/src/widget/components/TransferPendingVertical.tsx +12 -8
- package/src/widget/components/WaasFeeOptions.tsx +139 -4
- package/src/widget/components/WalletConfirmation.tsx +23 -13
- package/src/widget/components/WalletConnect.tsx +93 -29
- package/src/widget/hooks/useAmountUsd.ts +9 -9
- package/src/widget/hooks/useCheckout.ts +97 -9
- package/src/widget/hooks/useDefaultTokenSelection.tsx +27 -21
- package/src/widget/hooks/useQuote.ts +466 -0
- package/src/widget/hooks/useSelectedFeeToken.tsx +32 -37
- package/src/widget/hooks/useSendForm.ts +45 -51
- package/src/widget/hooks/useTokenList.ts +34 -26
- package/src/widget/hooks/useWalletConnectionContext.tsx +128 -0
- package/src/widget/widget.tsx +365 -390
- package/dist/apiClient.d.ts +0 -9
- package/dist/apiClient.d.ts.map +0 -1
- package/dist/intentEntrypoint.d.ts +0 -114
- package/dist/intentEntrypoint.d.ts.map +0 -1
- package/dist/metaTxnMonitor.d.ts +0 -15
- package/dist/metaTxnMonitor.d.ts.map +0 -1
- package/dist/metaTxns.d.ts +0 -11
- package/dist/metaTxns.d.ts.map +0 -1
- package/dist/relayer.d.ts +0 -43
- package/dist/relayer.d.ts.map +0 -1
- package/src/apiClient.ts +0 -35
- package/src/intentEntrypoint.ts +0 -203
- package/src/metaTxnMonitor.ts +0 -171
- package/src/metaTxns.ts +0 -45
- package/src/relayer.ts +0 -289
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { TrendingUp, ChevronRight, Search, Loader2 } from "lucide-react"
|
|
2
2
|
import { useEffect, useState, useRef, useMemo } from "react"
|
|
3
3
|
import type React from "react"
|
|
4
|
-
import type { Account, WalletClient } from "viem"
|
|
5
|
-
import {
|
|
4
|
+
import type { Account, Chain, WalletClient } from "viem"
|
|
5
|
+
import { parseUnits, formatUnits, parseAbi } from "viem"
|
|
6
6
|
import type { TransactionState } from "../../transactions.js"
|
|
7
7
|
import type { OnCompleteProps } from "../hooks/useSendForm.js"
|
|
8
8
|
import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
|
|
9
|
-
import { useSendForm } from "../hooks/useSendForm.js"
|
|
10
|
-
import { TradeType } from "../../prepareSend.js"
|
|
11
9
|
import { useEarnPool } from "../hooks/useEarnPool.js"
|
|
12
|
-
import { useMode } from "../hooks/useMode.js"
|
|
13
10
|
import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
|
|
14
11
|
import { TokenImage } from "./TokenImage.js"
|
|
15
12
|
import { EarnPools } from "./EarnPools.js"
|
|
16
|
-
import { QuoteDetails } from "./QuoteDetails.js"
|
|
17
13
|
import { PercentageMaxButtons } from "./PercentageMaxButtons.js"
|
|
18
14
|
import { formatTvl } from "../../prices.js"
|
|
19
15
|
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
@@ -21,40 +17,29 @@ import { getChainInfo } from "../../chains.js"
|
|
|
21
17
|
import { useAmountUsd } from "../hooks/useAmountUsd.js"
|
|
22
18
|
import aaveLogo from "../assets/aave.svg"
|
|
23
19
|
import morphoLogo from "../assets/morpho.svg"
|
|
24
|
-
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
25
20
|
import type { SupportedToken } from "../../tokens.js"
|
|
26
21
|
import { logger } from "../../logger.js"
|
|
27
22
|
import { generateAaveWithdrawCalldata } from "../../aave.js"
|
|
28
23
|
import { generateMorphoWithdrawCalldata } from "../../morpho.js"
|
|
29
24
|
import { formatAmount } from "../../tokenBalances.js"
|
|
25
|
+
import { DynamicSizeInputField } from "./DynamicSizeInputField.js"
|
|
26
|
+
import { TokenDisplayNonSelectable } from "./TokenDisplayNonSelectable.js"
|
|
27
|
+
import { estimateGasCostFormatted, estimateGasLimit } from "../../estimate.js"
|
|
28
|
+
import { sendOriginTransaction } from "../../intents.js"
|
|
29
|
+
import { usePublicClient } from "wagmi"
|
|
30
|
+
import { getTransactionStateFromReceipt } from "../../transactionIntent/index.js"
|
|
30
31
|
|
|
31
32
|
interface PoolWithdrawProps {
|
|
32
|
-
account
|
|
33
|
-
walletClient
|
|
33
|
+
account?: Account
|
|
34
|
+
walletClient?: WalletClient
|
|
34
35
|
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
35
36
|
onError: (error: Error | string | null) => void
|
|
36
|
-
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
37
|
-
onConfirm: () => void
|
|
38
37
|
onComplete: (result: OnCompleteProps) => void
|
|
39
|
-
onSend: (amount: string, recipient: string) => void
|
|
40
|
-
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
41
|
-
gasless?: boolean
|
|
42
|
-
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
43
|
-
quoteProvider?: string
|
|
44
|
-
fundMethod?: string
|
|
45
|
-
onNavigateToMeshConnect?: (
|
|
46
|
-
props: {
|
|
47
|
-
toTokenSymbol: string
|
|
48
|
-
toTokenAmount: string
|
|
49
|
-
toChainId: number
|
|
50
|
-
toRecipientAddress: string
|
|
51
|
-
},
|
|
52
|
-
quote?: PrepareSendQuote | null,
|
|
53
|
-
) => void
|
|
54
38
|
checkoutOnHandlers?: CheckoutOnHandlers
|
|
55
39
|
recentTokens?: SupportedToken[]
|
|
56
40
|
onRecentTokenSelect?: (token: SupportedToken) => void
|
|
57
41
|
onTrackToken?: (token: any) => void
|
|
42
|
+
onPoolSelectorStateChange?: (isShowing: boolean) => void
|
|
58
43
|
}
|
|
59
44
|
|
|
60
45
|
export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
@@ -62,22 +47,14 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
62
47
|
walletClient,
|
|
63
48
|
onTransactionStateChange,
|
|
64
49
|
onError,
|
|
65
|
-
onWaitingForWalletConfirm,
|
|
66
|
-
onConfirm,
|
|
67
50
|
onComplete,
|
|
68
|
-
|
|
69
|
-
paymasterUrls,
|
|
70
|
-
gasless,
|
|
71
|
-
setWalletConfirmRetryHandler,
|
|
72
|
-
quoteProvider,
|
|
73
|
-
fundMethod,
|
|
74
|
-
onNavigateToMeshConnect,
|
|
75
|
-
checkoutOnHandlers,
|
|
51
|
+
onPoolSelectorStateChange,
|
|
76
52
|
}) => {
|
|
77
|
-
const { mode } = useMode()
|
|
78
53
|
const { isBalanceVisible } = useBalanceVisible()
|
|
79
54
|
const { selectedPool, setSelectedPool } = useEarnPool()
|
|
55
|
+
const publicClient = usePublicClient()
|
|
80
56
|
|
|
57
|
+
const [amountToWithdraw, setAmountToWithdraw] = useState("")
|
|
81
58
|
const [showEarnPools, setShowEarnPools] = useState(false)
|
|
82
59
|
const [amount, setAmount] = useState("")
|
|
83
60
|
const [aTokenAddress, setATokenAddress] = useState<string | null>(null)
|
|
@@ -134,14 +111,8 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
134
111
|
)
|
|
135
112
|
return
|
|
136
113
|
}
|
|
137
|
-
|
|
138
|
-
const publicClient = createPublicClient({
|
|
139
|
-
chain,
|
|
140
|
-
transport: http(),
|
|
141
|
-
})
|
|
142
|
-
|
|
143
114
|
// Call getReserveAToken on the pool contract to get aToken address
|
|
144
|
-
const aTokenAddr = (await publicClient
|
|
115
|
+
const aTokenAddr = (await publicClient?.readContract({
|
|
145
116
|
address: selectedPool.depositAddress as `0x${string}`,
|
|
146
117
|
abi: [
|
|
147
118
|
{
|
|
@@ -178,7 +149,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
178
149
|
}
|
|
179
150
|
|
|
180
151
|
fetchATokenAddress()
|
|
181
|
-
}, [selectedPool])
|
|
152
|
+
}, [publicClient, selectedPool])
|
|
182
153
|
|
|
183
154
|
// Fetch pool balance (aToken balance for Aave, pool contract balance for Morpho, pool token balance for others)
|
|
184
155
|
useEffect(() => {
|
|
@@ -214,11 +185,6 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
214
185
|
return
|
|
215
186
|
}
|
|
216
187
|
|
|
217
|
-
const publicClient = createPublicClient({
|
|
218
|
-
chain,
|
|
219
|
-
transport: http(),
|
|
220
|
-
})
|
|
221
|
-
|
|
222
188
|
// Determine which token address to query
|
|
223
189
|
let tokenToQuery: string
|
|
224
190
|
if (selectedPool.protocol === "Aave" && aTokenAddress) {
|
|
@@ -238,7 +204,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
238
204
|
})
|
|
239
205
|
|
|
240
206
|
// Fetch balance using balanceOf
|
|
241
|
-
const balance = (await publicClient
|
|
207
|
+
const balance = (await publicClient?.readContract({
|
|
242
208
|
address: tokenToQuery as `0x${string}`,
|
|
243
209
|
abi: [
|
|
244
210
|
{
|
|
@@ -254,7 +220,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
254
220
|
})) as bigint
|
|
255
221
|
|
|
256
222
|
// Fetch decimals
|
|
257
|
-
const decimals = (await publicClient
|
|
223
|
+
const decimals = (await publicClient?.readContract({
|
|
258
224
|
address: tokenToQuery as `0x${string}`,
|
|
259
225
|
abi: [
|
|
260
226
|
{
|
|
@@ -297,10 +263,17 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
297
263
|
}
|
|
298
264
|
|
|
299
265
|
fetchPoolBalance()
|
|
300
|
-
}, [selectedPool, aTokenAddress, account])
|
|
266
|
+
}, [publicClient, selectedPool, aTokenAddress, account])
|
|
301
267
|
|
|
302
268
|
// Generate withdraw calldata dynamically based on user's entered amount
|
|
303
269
|
const withdrawCalldata = useMemo(() => {
|
|
270
|
+
if (!account?.address) {
|
|
271
|
+
logger.console.log(
|
|
272
|
+
"[pool-withdraw] No account found, skipping calldata generation",
|
|
273
|
+
)
|
|
274
|
+
return undefined
|
|
275
|
+
}
|
|
276
|
+
|
|
304
277
|
const isAave = selectedPool?.protocol === "Aave"
|
|
305
278
|
const isMorpho = selectedPool?.protocol === "Morpho"
|
|
306
279
|
|
|
@@ -330,9 +303,9 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
330
303
|
)
|
|
331
304
|
} else if (isMorpho) {
|
|
332
305
|
calldata = generateMorphoWithdrawCalldata(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
account.address, //
|
|
306
|
+
amountWei, // amount of underlying assets to withdraw in wei
|
|
307
|
+
account.address, // receiver (user's wallet)
|
|
308
|
+
account.address, // owner (user's wallet - owns the shares)
|
|
336
309
|
)
|
|
337
310
|
} else {
|
|
338
311
|
return undefined
|
|
@@ -356,128 +329,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
356
329
|
)
|
|
357
330
|
return undefined
|
|
358
331
|
}
|
|
359
|
-
}, [selectedPool, amount, account
|
|
360
|
-
|
|
361
|
-
// Convert pool to token format for useSendForm
|
|
362
|
-
// For Aave, use the aToken address
|
|
363
|
-
// For Morpho, use the pool contract address
|
|
364
|
-
// For others, use the underlying token address
|
|
365
|
-
const poolToken = useMemo(() => {
|
|
366
|
-
if (!selectedPool) {
|
|
367
|
-
logger.console.log("[pool-withdraw] No pool selected, poolToken is null")
|
|
368
|
-
return null
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const isAave = selectedPool.protocol === "Aave"
|
|
372
|
-
const isMorpho = selectedPool.protocol === "Morpho"
|
|
373
|
-
|
|
374
|
-
let contractAddressToUse: string
|
|
375
|
-
if (isAave && aTokenAddress) {
|
|
376
|
-
contractAddressToUse = aTokenAddress
|
|
377
|
-
} else if (isMorpho) {
|
|
378
|
-
contractAddressToUse = selectedPool.depositAddress
|
|
379
|
-
} else {
|
|
380
|
-
contractAddressToUse = selectedPool.token.address
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
logger.console.log("[pool-withdraw] Constructing poolToken object:", {
|
|
384
|
-
poolName: selectedPool.name,
|
|
385
|
-
protocol: selectedPool.protocol,
|
|
386
|
-
isAave,
|
|
387
|
-
isMorpho,
|
|
388
|
-
aTokenAddress,
|
|
389
|
-
depositAddress: selectedPool.depositAddress,
|
|
390
|
-
underlyingTokenAddress: selectedPool.token.address,
|
|
391
|
-
willUseAddress: contractAddressToUse,
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
const token = {
|
|
395
|
-
symbol: selectedPool.token.symbol,
|
|
396
|
-
imageUrl: selectedPool.token.logoUrl,
|
|
397
|
-
chainId: selectedPool.chainId,
|
|
398
|
-
contractAddress: contractAddressToUse,
|
|
399
|
-
decimals: selectedPool.token.decimals || 18,
|
|
400
|
-
contractInfo: {
|
|
401
|
-
decimals: selectedPool.token.decimals || 18,
|
|
402
|
-
contractAddress: contractAddressToUse,
|
|
403
|
-
symbol: selectedPool.token.symbol,
|
|
404
|
-
name: selectedPool.token.name || selectedPool.token.symbol,
|
|
405
|
-
},
|
|
406
|
-
} as any
|
|
407
|
-
|
|
408
|
-
logger.console.log("[pool-withdraw] ✅ Constructed poolToken:", token)
|
|
409
|
-
|
|
410
|
-
return token
|
|
411
|
-
}, [selectedPool, aTokenAddress])
|
|
412
|
-
|
|
413
|
-
// Use useSendForm for quote functionality
|
|
414
|
-
// Transaction is always sent TO the pool contract (depositAddress)
|
|
415
|
-
// For Aave, withdraw() calldata specifies the recipient (user's address)
|
|
416
|
-
// Set up source token (aToken for Aave, pool shares for Morpho)
|
|
417
|
-
const finalSelectedToken = poolToken
|
|
418
|
-
? {
|
|
419
|
-
chainId: selectedPool?.chainId,
|
|
420
|
-
...poolToken,
|
|
421
|
-
}
|
|
422
|
-
: null
|
|
423
|
-
|
|
424
|
-
// Log what we're passing to useSendForm
|
|
425
|
-
useEffect(() => {
|
|
426
|
-
logger.console.log("[pool-withdraw] useSendForm configuration:", {
|
|
427
|
-
hasAccount: !!account,
|
|
428
|
-
accountAddress: account?.address,
|
|
429
|
-
toRecipient: selectedPool?.depositAddress,
|
|
430
|
-
toChainId: selectedPool?.chainId,
|
|
431
|
-
toToken: finalSelectedToken?.contractAddress, // Use aToken/pool address as destination token
|
|
432
|
-
hasCalldata: !!withdrawCalldata,
|
|
433
|
-
calldataLength: withdrawCalldata?.length,
|
|
434
|
-
selectedToken: finalSelectedToken,
|
|
435
|
-
selectedTokenChainId: finalSelectedToken?.chainId,
|
|
436
|
-
selectedTokenAddress: finalSelectedToken?.contractAddress,
|
|
437
|
-
tradeType: "EXACT_INPUT",
|
|
438
|
-
amount: amount,
|
|
439
|
-
isSameChain: selectedPool?.chainId === finalSelectedToken?.chainId,
|
|
440
|
-
willBeSameToken: true, // toToken is same as selectedToken's contractAddress
|
|
441
|
-
})
|
|
442
|
-
}, [account, selectedPool, withdrawCalldata, finalSelectedToken, amount])
|
|
443
|
-
|
|
444
|
-
const {
|
|
445
|
-
balanceFormatted: _unusedBalanceFormatted, // Not used, we fetch balance separately
|
|
446
|
-
isLoadingQuote,
|
|
447
|
-
prepareSendQuote,
|
|
448
|
-
setAmount: setSendFormAmount,
|
|
449
|
-
handleSubmit,
|
|
450
|
-
isSubmitting,
|
|
451
|
-
buttonText,
|
|
452
|
-
isValidRecipient,
|
|
453
|
-
selectedDestToken: returnedDestToken, // Get the destination token set by useSendForm
|
|
454
|
-
setSelectedDestinationChain, // Function to set destination chain
|
|
455
|
-
supportedChains, // Available chains
|
|
456
|
-
} = useSendForm({
|
|
457
|
-
account,
|
|
458
|
-
toAmount: undefined,
|
|
459
|
-
toRecipient: selectedPool?.depositAddress, // Always the pool contract address
|
|
460
|
-
toChainId: selectedPool?.chainId,
|
|
461
|
-
toToken: finalSelectedToken?.contractAddress, // aToken address (Aave) or pool address (Morpho)
|
|
462
|
-
toCalldata: withdrawCalldata, // Aave/Morpho withdraw calldata
|
|
463
|
-
walletClient,
|
|
464
|
-
onTransactionStateChange,
|
|
465
|
-
onError,
|
|
466
|
-
onWaitingForWalletConfirm,
|
|
467
|
-
paymasterUrls,
|
|
468
|
-
gasless,
|
|
469
|
-
onConfirm,
|
|
470
|
-
onComplete,
|
|
471
|
-
onSend,
|
|
472
|
-
selectedToken: finalSelectedToken, // Source token (what we're withdrawing from)
|
|
473
|
-
setWalletConfirmRetryHandler,
|
|
474
|
-
tradeType: TradeType.EXACT_INPUT, // User specifies exact input amount to withdraw
|
|
475
|
-
quoteProvider,
|
|
476
|
-
fundMethod,
|
|
477
|
-
mode,
|
|
478
|
-
onNavigateToMeshConnect,
|
|
479
|
-
checkoutOnHandlers,
|
|
480
|
-
})
|
|
332
|
+
}, [selectedPool, amount, account?.address])
|
|
481
333
|
|
|
482
334
|
// Calculate USD value using the underlying token (for pool tokens like aBasUSDC)
|
|
483
335
|
const { amountUsdFormatted: underlyingTokenUsdDisplay } = useAmountUsd({
|
|
@@ -495,58 +347,92 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
495
347
|
})
|
|
496
348
|
}, [poolBalance, isLoadingBalance])
|
|
497
349
|
|
|
498
|
-
//
|
|
350
|
+
// Auto-focus input field on component mount
|
|
499
351
|
useEffect(() => {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
sourceTokenAddress: finalSelectedToken?.contractAddress,
|
|
505
|
-
})
|
|
506
|
-
}, [returnedDestToken, finalSelectedToken])
|
|
352
|
+
if (inputRef.current) {
|
|
353
|
+
inputRef.current.focus()
|
|
354
|
+
}
|
|
355
|
+
}, [])
|
|
507
356
|
|
|
508
|
-
//
|
|
357
|
+
// Notify parent component about pool selector visibility
|
|
509
358
|
useEffect(() => {
|
|
510
|
-
if (
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
359
|
+
if (onPoolSelectorStateChange) {
|
|
360
|
+
// Hide tabs when showing EarnPools selector (no token selector in withdraw)
|
|
361
|
+
onPoolSelectorStateChange(showEarnPools)
|
|
362
|
+
}
|
|
363
|
+
}, [showEarnPools, onPoolSelectorStateChange])
|
|
514
364
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
365
|
+
const [gasCostFormatted, setGasCostFormatted] = useState("")
|
|
366
|
+
|
|
367
|
+
// For Aave, check if wallet has enough aTokens in order to withdraw
|
|
368
|
+
const [hasEnoughATokens, setHasEnoughATokens] = useState<boolean | null>(null)
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
if (
|
|
371
|
+
publicClient &&
|
|
372
|
+
selectedPool &&
|
|
373
|
+
selectedPool.protocol === "Aave" &&
|
|
374
|
+
amountToWithdraw
|
|
375
|
+
) {
|
|
376
|
+
try {
|
|
377
|
+
const checkHasEnoughATokens = async () => {
|
|
378
|
+
const aTokenAddress = selectedPool.token.address
|
|
379
|
+
const decimals = selectedPool.token.decimals || 18
|
|
380
|
+
const aTokenBalance = await publicClient?.readContract({
|
|
381
|
+
address: aTokenAddress as `0x${string}`,
|
|
382
|
+
abi: parseAbi([
|
|
383
|
+
"function balanceOf(address) view returns (uint256)",
|
|
384
|
+
]),
|
|
385
|
+
functionName: "balanceOf",
|
|
386
|
+
args: [account?.address as `0x${string}`],
|
|
387
|
+
})
|
|
388
|
+
const aTokenBalanceFormatted = formatUnits(aTokenBalance, decimals)
|
|
389
|
+
setHasEnoughATokens(aTokenBalanceFormatted >= amountToWithdraw)
|
|
390
|
+
}
|
|
391
|
+
checkHasEnoughATokens()
|
|
392
|
+
} catch (error) {
|
|
393
|
+
logger.console.error(
|
|
394
|
+
"[pool-withdraw] ❌ Error checking has enough aTokens:",
|
|
395
|
+
error,
|
|
530
396
|
)
|
|
531
397
|
}
|
|
532
398
|
}
|
|
533
|
-
}, [selectedPool,
|
|
399
|
+
}, [publicClient, selectedPool, account, amountToWithdraw])
|
|
534
400
|
|
|
535
|
-
//
|
|
401
|
+
// Estimate gas when pool selected and amount is set
|
|
536
402
|
useEffect(() => {
|
|
537
|
-
|
|
538
|
-
|
|
403
|
+
const estimateGas = async () => {
|
|
404
|
+
if (publicClient && selectedPool && amountToWithdraw) {
|
|
405
|
+
try {
|
|
406
|
+
const gasLimit = await estimateGasLimit(publicClient, {
|
|
407
|
+
account: account?.address as `0x${string}`,
|
|
408
|
+
to: selectedPool.depositAddress as `0x${string}`,
|
|
409
|
+
data: withdrawCalldata as `0x${string}`,
|
|
410
|
+
value: 0n,
|
|
411
|
+
})
|
|
412
|
+
const gasCostFormatted = await estimateGasCostFormatted(
|
|
413
|
+
publicClient,
|
|
414
|
+
gasLimit || 100_000n,
|
|
415
|
+
18,
|
|
416
|
+
)
|
|
417
|
+
setGasCostFormatted(gasCostFormatted)
|
|
418
|
+
} catch (error) {
|
|
419
|
+
logger.console.error(
|
|
420
|
+
"[pool-withdraw] ❌ Error estimating gas:",
|
|
421
|
+
error,
|
|
422
|
+
)
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
logger.console.error(
|
|
426
|
+
"[pool-withdraw] ❌ Error estimating gas: no public client or selected pool or amount to withdraw",
|
|
427
|
+
)
|
|
428
|
+
}
|
|
539
429
|
}
|
|
540
|
-
|
|
430
|
+
estimateGas()
|
|
431
|
+
}, [publicClient, selectedPool, withdrawCalldata, account, amountToWithdraw])
|
|
541
432
|
|
|
542
433
|
const handleAmountChange = (value: string) => {
|
|
543
|
-
// Validate decimal places (max 8 decimals)
|
|
544
|
-
const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
|
|
545
|
-
if (!decimalMatch && value !== "") {
|
|
546
|
-
return // Don't update if more than 8 decimals
|
|
547
|
-
}
|
|
548
434
|
setAmount(value)
|
|
549
|
-
|
|
435
|
+
setAmountToWithdraw(value) // Sync with useSendForm for quote functionality
|
|
550
436
|
}
|
|
551
437
|
|
|
552
438
|
const handlePoolSelect = (pool: any) => {
|
|
@@ -558,9 +444,71 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
558
444
|
// Handle amount selection from percentage buttons
|
|
559
445
|
const handleAmountSelect = (selectedAmount: string) => {
|
|
560
446
|
setAmount(selectedAmount)
|
|
561
|
-
|
|
447
|
+
setAmountToWithdraw(selectedAmount)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const [isLoadingWithdraw, setIsLoadingWithdraw] = useState(false)
|
|
451
|
+
|
|
452
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
453
|
+
e.preventDefault()
|
|
454
|
+
if (!account || !walletClient) {
|
|
455
|
+
throw new Error("No account or wallet client found")
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
setIsLoadingWithdraw(true)
|
|
460
|
+
|
|
461
|
+
// Create initial pending state
|
|
462
|
+
const initialState: TransactionState = {
|
|
463
|
+
transactionHash: "", // Will be set after tx is sent
|
|
464
|
+
explorerUrl: "",
|
|
465
|
+
chainId: selectedPool?.chainId as number,
|
|
466
|
+
state: "pending",
|
|
467
|
+
label: "Withdraw",
|
|
468
|
+
}
|
|
469
|
+
onTransactionStateChange([initialState])
|
|
470
|
+
|
|
471
|
+
const txHash = await sendOriginTransaction(account, walletClient, {
|
|
472
|
+
to: selectedPool?.depositAddress as `0x${string}`,
|
|
473
|
+
data: withdrawCalldata as `0x${string}`,
|
|
474
|
+
value: 0n,
|
|
475
|
+
chain: walletClient.chain as Chain,
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
const receipt = await publicClient!.waitForTransactionReceipt({
|
|
479
|
+
hash: txHash,
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
// Convert receipt to TransactionState
|
|
483
|
+
const finalState = getTransactionStateFromReceipt(
|
|
484
|
+
receipt,
|
|
485
|
+
selectedPool?.chainId as number,
|
|
486
|
+
"Withdraw",
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
onTransactionStateChange([finalState])
|
|
490
|
+
|
|
491
|
+
// Navigate to receipt screen
|
|
492
|
+
onComplete({ transactionStates: [finalState] })
|
|
493
|
+
|
|
494
|
+
setIsLoadingWithdraw(false)
|
|
495
|
+
} catch (error) {
|
|
496
|
+
logger.console.error(
|
|
497
|
+
"[pool-withdraw] ❌ Error submitting withdraw:",
|
|
498
|
+
error,
|
|
499
|
+
)
|
|
500
|
+
setIsLoadingWithdraw(false)
|
|
501
|
+
onError(
|
|
502
|
+
error instanceof Error ? error.message : "Failed to withdraw from pool",
|
|
503
|
+
)
|
|
504
|
+
}
|
|
562
505
|
}
|
|
563
506
|
|
|
507
|
+
// Get chain info for selected pool
|
|
508
|
+
const chainInfo = useMemo(() => {
|
|
509
|
+
return selectedPool ? getChainInfo(selectedPool.chainId) : null
|
|
510
|
+
}, [selectedPool])
|
|
511
|
+
|
|
564
512
|
if (showEarnPools) {
|
|
565
513
|
return (
|
|
566
514
|
<EarnPools
|
|
@@ -572,273 +520,215 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
572
520
|
|
|
573
521
|
return (
|
|
574
522
|
<div className="space-y-2">
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
<div className="
|
|
582
|
-
|
|
583
|
-
Withdraw From
|
|
584
|
-
</div>
|
|
523
|
+
{/* Pool Selection (Primary Section) */}
|
|
524
|
+
<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">
|
|
525
|
+
{selectedPool ? (
|
|
526
|
+
<div className="p-3 trails-border-radius-container trails-bg-secondary transition-all overflow-hidden">
|
|
527
|
+
{/* Vault Label */}
|
|
528
|
+
<div className="flex justify-between items-center mb-2">
|
|
529
|
+
<div className="text-sm font-semibold trails-text-secondary text-left">
|
|
530
|
+
From
|
|
585
531
|
</div>
|
|
532
|
+
</div>
|
|
586
533
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
534
|
+
<div className="px-1">
|
|
535
|
+
<div className="flex items-center justify-between">
|
|
536
|
+
<div className="flex items-center space-x-3">
|
|
537
|
+
<div style={{ width: "32px", height: "32px" }}>
|
|
538
|
+
<a
|
|
539
|
+
href={getExplorerUrlForAddress({
|
|
540
|
+
address: selectedPool.token.address,
|
|
541
|
+
chainId: selectedPool.chainId,
|
|
542
|
+
})}
|
|
543
|
+
target="_blank"
|
|
544
|
+
rel="noopener noreferrer"
|
|
545
|
+
className="cursor-pointer"
|
|
546
|
+
>
|
|
547
|
+
<TokenImage
|
|
548
|
+
symbol={selectedPool.token.symbol}
|
|
549
|
+
imageUrl={selectedPool.token.logoUrl}
|
|
550
|
+
chainId={selectedPool.chainId}
|
|
551
|
+
contractAddress={selectedPool.token.address}
|
|
552
|
+
size={32}
|
|
553
|
+
/>
|
|
554
|
+
</a>
|
|
555
|
+
</div>
|
|
556
|
+
<div>
|
|
557
|
+
<h3 className="font-medium text-gray-900 dark:text-white text-sm">
|
|
558
|
+
{selectedPool.poolUrl ? (
|
|
559
|
+
<a
|
|
560
|
+
href={selectedPool.poolUrl}
|
|
561
|
+
target="_blank"
|
|
562
|
+
rel="noopener noreferrer"
|
|
563
|
+
className="hover:underline cursor-pointer"
|
|
564
|
+
>
|
|
565
|
+
{selectedPool.name}
|
|
566
|
+
</a>
|
|
567
|
+
) : (
|
|
568
|
+
selectedPool.name
|
|
569
|
+
)}
|
|
570
|
+
</h3>
|
|
571
|
+
<div className="flex items-center space-x-2">
|
|
572
|
+
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
573
|
+
{selectedPool.protocol === "Aave" && (
|
|
574
|
+
<img
|
|
575
|
+
src={aaveLogo}
|
|
576
|
+
alt="Aave"
|
|
577
|
+
className="w-3 h-3 mr-1"
|
|
578
|
+
/>
|
|
579
|
+
)}
|
|
580
|
+
{selectedPool.protocol === "Morpho" && (
|
|
581
|
+
<img
|
|
582
|
+
src={morphoLogo}
|
|
583
|
+
alt="Morpho"
|
|
584
|
+
className="w-3 h-3 mr-1"
|
|
585
|
+
/>
|
|
586
|
+
)}
|
|
587
|
+
{selectedPool.protocolUrl ? (
|
|
612
588
|
<a
|
|
613
|
-
href={selectedPool.
|
|
589
|
+
href={selectedPool.protocolUrl}
|
|
614
590
|
target="_blank"
|
|
615
591
|
rel="noopener noreferrer"
|
|
616
592
|
className="hover:underline cursor-pointer"
|
|
617
593
|
>
|
|
618
|
-
{selectedPool.
|
|
594
|
+
{selectedPool.protocol}
|
|
619
595
|
</a>
|
|
620
596
|
) : (
|
|
621
|
-
selectedPool.
|
|
597
|
+
selectedPool.protocol
|
|
622
598
|
)}
|
|
623
|
-
</
|
|
624
|
-
<div className="flex items-center space-x-2">
|
|
625
|
-
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
626
|
-
{selectedPool.protocol === "Aave" && (
|
|
627
|
-
<img
|
|
628
|
-
src={aaveLogo}
|
|
629
|
-
alt="Aave"
|
|
630
|
-
className="w-3 h-3 mr-1"
|
|
631
|
-
/>
|
|
632
|
-
)}
|
|
633
|
-
{selectedPool.protocol === "Morpho" && (
|
|
634
|
-
<img
|
|
635
|
-
src={morphoLogo}
|
|
636
|
-
alt="Morpho"
|
|
637
|
-
className="w-3 h-3 mr-1"
|
|
638
|
-
/>
|
|
639
|
-
)}
|
|
640
|
-
{selectedPool.protocolUrl ? (
|
|
641
|
-
<a
|
|
642
|
-
href={selectedPool.protocolUrl}
|
|
643
|
-
target="_blank"
|
|
644
|
-
rel="noopener noreferrer"
|
|
645
|
-
className="hover:underline cursor-pointer"
|
|
646
|
-
>
|
|
647
|
-
{selectedPool.protocol}
|
|
648
|
-
</a>
|
|
649
|
-
) : (
|
|
650
|
-
selectedPool.protocol
|
|
651
|
-
)}
|
|
652
|
-
</span>
|
|
653
|
-
</div>
|
|
599
|
+
</span>
|
|
654
600
|
</div>
|
|
655
601
|
</div>
|
|
656
|
-
<button
|
|
657
|
-
type="button"
|
|
658
|
-
title="Select Vault"
|
|
659
|
-
onClick={() => setShowEarnPools(true)}
|
|
660
|
-
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"
|
|
661
|
-
>
|
|
662
|
-
<div>
|
|
663
|
-
<div className="flex items-center justify-end space-x-1 text-green-600 dark:text-green-400 mb-1 whitespace-nowrap">
|
|
664
|
-
<TrendingUp className="w-3 h-3" />
|
|
665
|
-
<span className="font-semibold text-sm">
|
|
666
|
-
{selectedPool.apy.toFixed(1)}% APY
|
|
667
|
-
</span>
|
|
668
|
-
</div>
|
|
669
|
-
<p className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
670
|
-
TVL: {formatTvl(selectedPool.tvl)}
|
|
671
|
-
</p>
|
|
672
|
-
</div>
|
|
673
|
-
<ChevronRight className="w-4 h-4 text-gray-400" />
|
|
674
|
-
</button>
|
|
675
602
|
</div>
|
|
603
|
+
<button
|
|
604
|
+
type="button"
|
|
605
|
+
title="Select Vault"
|
|
606
|
+
onClick={() => setShowEarnPools(true)}
|
|
607
|
+
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"
|
|
608
|
+
>
|
|
609
|
+
<div>
|
|
610
|
+
<div className="flex items-center justify-end space-x-1 text-green-600 dark:text-green-400 mb-1 whitespace-nowrap">
|
|
611
|
+
<TrendingUp className="w-3 h-3" />
|
|
612
|
+
<span className="font-semibold text-sm">
|
|
613
|
+
{selectedPool.apy.toFixed(1)}% APY
|
|
614
|
+
</span>
|
|
615
|
+
</div>
|
|
616
|
+
<p className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
617
|
+
TVL: {formatTvl(selectedPool.tvl)}
|
|
618
|
+
</p>
|
|
619
|
+
</div>
|
|
620
|
+
<ChevronRight className="w-4 h-4 text-gray-400" />
|
|
621
|
+
</button>
|
|
676
622
|
</div>
|
|
677
623
|
</div>
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
624
|
+
</div>
|
|
625
|
+
) : (
|
|
626
|
+
<button
|
|
627
|
+
type="button"
|
|
628
|
+
onClick={() => setShowEarnPools(true)}
|
|
629
|
+
className="w-full py-6 px-4 trails-list-item trails-border-radius-container transition-all duration-200 cursor-pointer"
|
|
630
|
+
>
|
|
631
|
+
<div className="flex items-center justify-between">
|
|
632
|
+
<div className="flex items-center space-x-3 flex-1">
|
|
633
|
+
<div className="w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center">
|
|
634
|
+
<Search className="w-4 h-4 text-gray-400" />
|
|
635
|
+
</div>
|
|
636
|
+
<div className="text-left flex-1">
|
|
637
|
+
<div className="font-semibold text-gray-900 dark:text-white text-sm">
|
|
638
|
+
Select vault to withdraw from
|
|
693
639
|
</div>
|
|
694
640
|
</div>
|
|
695
|
-
<ChevronRight className="w-4 h-4 trails-text-muted flex-shrink-0" />
|
|
696
641
|
</div>
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
642
|
+
<ChevronRight className="w-4 h-4 trails-text-muted flex-shrink-0" />
|
|
643
|
+
</div>
|
|
644
|
+
</button>
|
|
645
|
+
)}
|
|
646
|
+
</div>
|
|
700
647
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
648
|
+
{/* Amount Input Section */}
|
|
649
|
+
{selectedPool && (
|
|
650
|
+
<div className="pt-4 pb-4 mb-4 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 min-h-[120px] flex flex-col">
|
|
651
|
+
{/* Withdraw Label */}
|
|
652
|
+
<div className="mb-4 flex justify-between items-center">
|
|
653
|
+
<div className="text-sm font-medium trails-text-secondary text-left m-0">
|
|
654
|
+
Amount
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
|
|
658
|
+
<div className="flex items-center space-x-2 flex-1">
|
|
659
|
+
{/* Amount Input */}
|
|
660
|
+
<div className="flex-1">
|
|
661
|
+
<div className="flex items-center space-x-2">
|
|
662
|
+
<DynamicSizeInputField
|
|
663
|
+
ref={inputRef}
|
|
664
|
+
value={amount}
|
|
665
|
+
onChange={(e) => handleAmountChange(e.target.value)}
|
|
666
|
+
isLoading={isLoadingWithdraw}
|
|
667
|
+
variant="default"
|
|
668
|
+
/>
|
|
708
669
|
</div>
|
|
709
670
|
</div>
|
|
710
671
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
672
|
+
{/* Token Display (Not Selectable) */}
|
|
673
|
+
<TokenDisplayNonSelectable
|
|
674
|
+
symbol={selectedPool.token.symbol}
|
|
675
|
+
imageUrl={selectedPool.token.logoUrl}
|
|
676
|
+
chainId={selectedPool.chainId}
|
|
677
|
+
contractAddress={selectedPool.token.address}
|
|
678
|
+
chainName={chainInfo?.name}
|
|
679
|
+
/>
|
|
680
|
+
</div>
|
|
681
|
+
|
|
682
|
+
{/* Bottom Info Row */}
|
|
683
|
+
<div className="mt-4 flex justify-between items-center">
|
|
684
|
+
{/* USD Amount */}
|
|
685
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
686
|
+
{selectedPool && amount ? (
|
|
687
|
+
<>≈ {underlyingTokenUsdDisplay || "$0.00"}</>
|
|
688
|
+
) : (
|
|
689
|
+
<span> </span>
|
|
690
|
+
)}
|
|
691
|
+
</div>
|
|
692
|
+
|
|
693
|
+
{/* Pool Balance and Percentage Buttons */}
|
|
694
|
+
{poolBalance && (
|
|
695
|
+
<div className="flex items-center space-x-2">
|
|
714
696
|
<button
|
|
715
697
|
type="button"
|
|
716
|
-
className="
|
|
717
|
-
onClick={() =>
|
|
698
|
+
className="text-xs text-gray-500 dark:text-gray-400 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 transition-colors bg-transparent border-none p-0"
|
|
699
|
+
onClick={() => handleAmountSelect(poolBalance || "0")}
|
|
700
|
+
onKeyDown={(e) => {
|
|
701
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
702
|
+
e.preventDefault()
|
|
703
|
+
handleAmountSelect(poolBalance || "0")
|
|
704
|
+
}
|
|
705
|
+
}}
|
|
706
|
+
title="Click to withdraw full balance"
|
|
718
707
|
>
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
placeholder="0"
|
|
726
|
-
className={`bg-transparent border-none outline-none font-bold text-left trails-text-primary placeholder-trails-text-primary ${
|
|
727
|
-
isLoadingQuote ? "animate-pulse" : ""
|
|
728
|
-
}`}
|
|
729
|
-
style={{
|
|
730
|
-
fontSize:
|
|
731
|
-
amount.length > 12
|
|
732
|
-
? "0.875rem"
|
|
733
|
-
: amount.length > 9
|
|
734
|
-
? "1rem"
|
|
735
|
-
: amount.length > 6
|
|
736
|
-
? "1.125rem"
|
|
737
|
-
: amount.length > 3
|
|
738
|
-
? "1.25rem"
|
|
739
|
-
: "1.5rem",
|
|
740
|
-
width: `${Math.max((amount || "0").length, 1)}ch`,
|
|
741
|
-
minWidth: "1ch",
|
|
742
|
-
maxWidth: "270px",
|
|
743
|
-
padding: "0",
|
|
744
|
-
margin: "0",
|
|
745
|
-
transition: "all 0.1s ease-in-out",
|
|
746
|
-
}}
|
|
747
|
-
inputMode="decimal"
|
|
748
|
-
/>
|
|
749
|
-
<span
|
|
750
|
-
className="font-bold text-gray-400 dark:text-gray-500"
|
|
751
|
-
style={{
|
|
752
|
-
fontSize:
|
|
753
|
-
amount.length > 12
|
|
754
|
-
? "0.875rem"
|
|
755
|
-
: amount.length > 9
|
|
756
|
-
? "1rem"
|
|
757
|
-
: amount.length > 6
|
|
758
|
-
? "1.125rem"
|
|
759
|
-
: amount.length > 3
|
|
760
|
-
? "1.25rem"
|
|
761
|
-
: "1.5rem",
|
|
762
|
-
marginLeft: "0.1em",
|
|
763
|
-
padding: "0",
|
|
764
|
-
transition: "all 0.2s ease-in-out",
|
|
765
|
-
}}
|
|
766
|
-
>
|
|
767
|
-
{selectedPool?.token.symbol.slice(0, 4) || ""}
|
|
768
|
-
</span>
|
|
769
|
-
{isLoadingQuote && (
|
|
770
|
-
<div className="ml-2 animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
|
|
771
|
-
)}
|
|
772
|
-
</div>
|
|
708
|
+
Pool Balance:{" "}
|
|
709
|
+
{isBalanceVisible
|
|
710
|
+
? isLoadingBalance
|
|
711
|
+
? "Loading..."
|
|
712
|
+
: poolBalance || "0.00"
|
|
713
|
+
: "••••••"}
|
|
773
714
|
</button>
|
|
774
|
-
</div>
|
|
775
715
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
716
|
+
{/* Percentage Buttons */}
|
|
717
|
+
<PercentageMaxButtons
|
|
718
|
+
userBalance={poolBalance || undefined}
|
|
719
|
+
isNativeToken={false} // Pool tokens are never native tokens
|
|
720
|
+
gasCostFormatted={gasCostFormatted}
|
|
781
721
|
chainId={selectedPool.chainId}
|
|
782
|
-
|
|
783
|
-
|
|
722
|
+
onAmountSelect={handleAmountSelect}
|
|
723
|
+
className="opacity-100"
|
|
784
724
|
/>
|
|
785
|
-
<span className="font-medium trails-text-primary text-sm">
|
|
786
|
-
{selectedPool.token.symbol}
|
|
787
|
-
</span>
|
|
788
725
|
</div>
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
{/* Bottom Info Row */}
|
|
792
|
-
<div className="mt-2 flex justify-between items-center">
|
|
793
|
-
{/* USD Amount */}
|
|
794
|
-
<div className="text-xs trails-text-muted">
|
|
795
|
-
{selectedPool && amount ? (
|
|
796
|
-
<>≈ {underlyingTokenUsdDisplay || "$0.00"}</>
|
|
797
|
-
) : (
|
|
798
|
-
<span> </span>
|
|
799
|
-
)}
|
|
800
|
-
</div>
|
|
801
|
-
|
|
802
|
-
{/* Pool Balance and Percentage Buttons */}
|
|
803
|
-
{poolBalance && (
|
|
804
|
-
<div className="flex items-center space-x-2">
|
|
805
|
-
<button
|
|
806
|
-
type="button"
|
|
807
|
-
className="text-xs trails-text-muted cursor-pointer hover:trails-hover-text transition-colors bg-transparent border-none p-0"
|
|
808
|
-
onClick={() => handleAmountSelect(poolBalance || "0")}
|
|
809
|
-
onKeyDown={(e) => {
|
|
810
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
811
|
-
e.preventDefault()
|
|
812
|
-
handleAmountSelect(poolBalance || "0")
|
|
813
|
-
}
|
|
814
|
-
}}
|
|
815
|
-
title="Click to withdraw full balance"
|
|
816
|
-
>
|
|
817
|
-
Pool Balance:{" "}
|
|
818
|
-
{isBalanceVisible
|
|
819
|
-
? isLoadingBalance
|
|
820
|
-
? "Loading..."
|
|
821
|
-
: poolBalance || "0.00"
|
|
822
|
-
: "••••••"}
|
|
823
|
-
</button>
|
|
824
|
-
|
|
825
|
-
{/* Percentage Buttons */}
|
|
826
|
-
<PercentageMaxButtons
|
|
827
|
-
userBalance={poolBalance || undefined}
|
|
828
|
-
isNativeToken={false} // Pool tokens are never native tokens
|
|
829
|
-
gasCostFormatted={prepareSendQuote?.gasCostFormatted}
|
|
830
|
-
chainId={selectedPool.chainId}
|
|
831
|
-
onAmountSelect={handleAmountSelect}
|
|
832
|
-
className="opacity-100"
|
|
833
|
-
/>
|
|
834
|
-
</div>
|
|
835
|
-
)}
|
|
836
|
-
</div>
|
|
726
|
+
)}
|
|
837
727
|
</div>
|
|
838
|
-
|
|
839
|
-
|
|
728
|
+
</div>
|
|
729
|
+
)}
|
|
840
730
|
|
|
841
|
-
{
|
|
731
|
+
{hasEnoughATokens === false ? (
|
|
842
732
|
<div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
|
|
843
733
|
<div className="flex items-center space-x-2">
|
|
844
734
|
<svg
|
|
@@ -862,35 +752,23 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
862
752
|
</div>
|
|
863
753
|
) : null}
|
|
864
754
|
|
|
865
|
-
{/* Quote Details */}
|
|
866
|
-
{prepareSendQuote && (
|
|
867
|
-
<div className="space-y-2">
|
|
868
|
-
<QuoteDetails quote={prepareSendQuote} showContent={true} />
|
|
869
|
-
</div>
|
|
870
|
-
)}
|
|
871
|
-
|
|
872
755
|
{selectedPool && (
|
|
873
756
|
<form onSubmit={handleSubmit}>
|
|
874
757
|
<button
|
|
875
758
|
type="submit"
|
|
876
759
|
disabled={
|
|
877
|
-
!amount ||
|
|
878
|
-
!isValidRecipient ||
|
|
879
|
-
isSubmitting ||
|
|
880
|
-
isLoadingQuote ||
|
|
881
|
-
!prepareSendQuote ||
|
|
882
|
-
prepareSendQuote?.noSufficientBalance
|
|
760
|
+
!amount || isLoadingWithdraw || hasEnoughATokens === false
|
|
883
761
|
}
|
|
884
762
|
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`}
|
|
885
763
|
>
|
|
886
|
-
{
|
|
764
|
+
{isLoadingWithdraw ? (
|
|
887
765
|
<div className="flex items-center justify-center">
|
|
888
766
|
<Loader2
|
|
889
767
|
className={`w-5 h-5 animate-spin mr-2 ${"text-gray-400"}`}
|
|
890
768
|
/>
|
|
891
|
-
<span>
|
|
769
|
+
<span>Processing...</span>
|
|
892
770
|
</div>
|
|
893
|
-
) :
|
|
771
|
+
) : hasEnoughATokens === false ? (
|
|
894
772
|
"Insufficient Balance"
|
|
895
773
|
) : (
|
|
896
774
|
"Withdraw"
|