0xtrails 0.2.4 → 0.2.6
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/abortController.d.ts +8 -0
- package/dist/abortController.d.ts.map +1 -0
- package/dist/{ccip-BlV1Mry3.js → ccip-Xjh9d1gb.js} +7 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +3 -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/fees.d.ts +19 -0
- package/dist/fees.d.ts.map +1 -0
- package/dist/{index-BNWCIGfQ.js → index-BnhdZ8Ho.js} +76406 -75798
- package/dist/index.js +726 -520
- 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 +19 -75
- 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/transactions.d.ts +4 -2
- package/dist/transactions.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/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 +4 -2
- 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/DynamicInputStyles.d.ts +18 -0
- package/dist/widget/components/DynamicInputStyles.d.ts.map +1 -0
- package/dist/widget/components/Earn.d.ts +2 -2
- 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/Fund.d.ts +2 -2
- 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} +13 -7
- 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/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 -2
- 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} +14 -36
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
- package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +19 -10
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
- package/dist/widget/components/QuoteDetails.d.ts +1 -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/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 +3 -2
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapSettings.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/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/Tooltip.d.ts +9 -0
- package/dist/widget/components/Tooltip.d.ts.map +1 -0
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +9 -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/WalletConnect.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/useQuote.d.ts +83 -0
- package/dist/widget/hooks/useQuote.d.ts.map +1 -0
- 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 +2 -2
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +2 -2
- package/dist/widget/widget.d.ts +9 -4
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +18 -12
- package/src/aave.ts +32 -0
- package/src/abortController.ts +35 -0
- package/src/config.ts +12 -4
- package/src/constants.ts +5 -0
- package/src/error.ts +19 -1
- package/src/estimate.ts +416 -5
- package/src/fees.ts +199 -0
- 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 +714 -550
- 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/trails.ts +3 -3
- package/src/transactions.ts +62 -18
- 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/AccountIntentTransactionHistoryButton.tsx +22 -0
- package/src/widget/components/AccountSettings.tsx +48 -54
- package/src/widget/components/ChainFilterDropdown.tsx +24 -3
- package/src/widget/components/ClassicSwap.tsx +131 -213
- package/src/widget/components/ConnectWallet.tsx +8 -38
- package/src/widget/components/ConnectedWallets.tsx +132 -77
- package/src/widget/components/DynamicInputStyles.tsx +76 -0
- package/src/widget/components/Earn.tsx +82 -593
- package/src/widget/components/ErrorAnimationIcon.tsx +130 -0
- package/src/widget/components/FeeBreakdown.tsx +155 -0
- package/src/widget/components/Fund.tsx +41 -108
- package/src/widget/components/FundMethods.tsx +82 -159
- package/src/widget/components/FundSwap.tsx +52 -0
- package/src/widget/components/FundingMethodSelectorButton.tsx +70 -0
- package/src/widget/components/Identicon.tsx +164 -95
- package/src/widget/components/MeshConnectExchanges.tsx +2 -15
- package/src/widget/components/Modal.tsx +0 -8
- package/src/widget/components/Pay.tsx +214 -237
- package/src/widget/components/PercentageMaxButtons.tsx +77 -0
- package/src/widget/components/PoolDeposit.tsx +569 -0
- package/src/widget/components/PoolWithdraw.tsx +884 -0
- package/src/widget/components/PriceImpactWarning.tsx +1 -1
- package/src/widget/components/QuoteDetails.tsx +43 -12
- package/src/widget/components/Receipt.tsx +16 -2
- package/src/widget/components/Receive.tsx +0 -2
- package/src/widget/components/RecipientSelectorButton.tsx +44 -0
- package/src/widget/components/Recipients.tsx +63 -157
- package/src/widget/components/RequiredPropsError.tsx +33 -0
- package/src/widget/components/ScreenHeader.tsx +62 -34
- package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
- package/src/widget/components/Swap.tsx +4 -45
- package/src/widget/components/SwapSettings.tsx +2 -14
- package/src/widget/components/ThemeProvider.tsx +2 -1
- package/src/widget/components/TokenDisplayNonSelectable.tsx +40 -0
- package/src/widget/components/TokenImage.tsx +22 -5
- package/src/widget/components/TokenList.tsx +0 -1
- package/src/widget/components/TokenSelector.tsx +63 -53
- package/src/widget/components/TokenSelectorButton.tsx +98 -0
- package/src/widget/components/Tooltip.tsx +51 -0
- package/src/widget/components/TransferPendingVertical.tsx +1 -1
- package/src/widget/components/UserPreferences.tsx +6 -24
- package/src/widget/components/WaasFeeOptions.tsx +450 -0
- package/src/widget/components/WalletConfirmation.tsx +76 -14
- package/src/widget/components/WalletConnect.tsx +93 -29
- 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/useQuote.ts +413 -0
- package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
- package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
- package/src/widget/hooks/useSendForm.ts +32 -6
- package/src/widget/index.css +27 -0
- package/src/widget/widget.tsx +326 -283
- 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
|
@@ -1,869 +0,0 @@
|
|
|
1
|
-
import { ChevronDown, Loader2, RefreshCcw, TrendingUp } from "lucide-react"
|
|
2
|
-
import type React from "react"
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react"
|
|
4
|
-
import type { Account, WalletClient } from "viem"
|
|
5
|
-
import { isAddress } from "viem"
|
|
6
|
-
import type { TransactionState } from "../../transactions.js"
|
|
7
|
-
import type { OnCompleteProps, Token, TokenInfo } from "../hooks/useSendForm.js"
|
|
8
|
-
import { useSendForm } from "../hooks/useSendForm.js"
|
|
9
|
-
import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
|
|
10
|
-
import { ChainImage } from "./ChainImage.js"
|
|
11
|
-
import { TokenImage } from "./TokenImage.js"
|
|
12
|
-
import { QuoteDetails } from "./QuoteDetails.js"
|
|
13
|
-
import { TruncatedAddress } from "./TruncatedAddress.js"
|
|
14
|
-
// import { RefundAddressInput } from "./RefundAddressInput.js"
|
|
15
|
-
import { type PrepareSendQuote, TradeType } from "../../prepareSend.js"
|
|
16
|
-
import { getChainInfo, getChainColor } from "../../chains.js"
|
|
17
|
-
import { formatTvl } from "../../prices.js"
|
|
18
|
-
import aaveLogo from "../assets/aave.svg"
|
|
19
|
-
import morphoLogo from "../assets/morpho.svg"
|
|
20
|
-
import { ScreenHeader } from "./ScreenHeader.js"
|
|
21
|
-
import { ErrorDisplay } from "./ErrorDisplay.js"
|
|
22
|
-
import { useMode } from "../hooks/useMode.js"
|
|
23
|
-
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
24
|
-
import { logger } from "../../logger.js"
|
|
25
|
-
import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
|
|
26
|
-
|
|
27
|
-
interface PaySendFormProps {
|
|
28
|
-
selectedToken: Token
|
|
29
|
-
onSend: (amount: string, recipient: string) => void
|
|
30
|
-
onBack?: () => void
|
|
31
|
-
onConfirm: () => void
|
|
32
|
-
onComplete: (result: OnCompleteProps) => void
|
|
33
|
-
account: Account
|
|
34
|
-
toRecipient?: string
|
|
35
|
-
toAmount?: string
|
|
36
|
-
toChainId?: number
|
|
37
|
-
toToken?: string
|
|
38
|
-
toCalldata?: string
|
|
39
|
-
walletClient: WalletClient
|
|
40
|
-
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
41
|
-
onError: (error: Error | string | null) => void
|
|
42
|
-
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
43
|
-
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
44
|
-
gasless?: boolean
|
|
45
|
-
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
46
|
-
quoteProvider?: string
|
|
47
|
-
fundMethod?: string
|
|
48
|
-
onNavigateToMeshConnect?: (
|
|
49
|
-
props: {
|
|
50
|
-
toTokenSymbol: string
|
|
51
|
-
toTokenAmount: string
|
|
52
|
-
toChainId: number
|
|
53
|
-
toRecipientAddress: string
|
|
54
|
-
},
|
|
55
|
-
quote?: PrepareSendQuote | null,
|
|
56
|
-
) => void
|
|
57
|
-
onAmountUpdate?: (amount: string) => void
|
|
58
|
-
selectedPool?: {
|
|
59
|
-
id: string
|
|
60
|
-
name: string
|
|
61
|
-
protocol: string
|
|
62
|
-
chainId: number
|
|
63
|
-
apy: number
|
|
64
|
-
tvl: number
|
|
65
|
-
token: {
|
|
66
|
-
symbol: string
|
|
67
|
-
name: string
|
|
68
|
-
address: string
|
|
69
|
-
decimals: number
|
|
70
|
-
logoUrl?: string
|
|
71
|
-
}
|
|
72
|
-
depositAddress: string
|
|
73
|
-
isActive: boolean
|
|
74
|
-
poolUrl?: string
|
|
75
|
-
protocolUrl?: string
|
|
76
|
-
} | null
|
|
77
|
-
checkoutOnHandlers?: CheckoutOnHandlers
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export const PaySendForm: React.FC<PaySendFormProps> = ({
|
|
81
|
-
selectedToken,
|
|
82
|
-
onSend,
|
|
83
|
-
onBack,
|
|
84
|
-
onConfirm,
|
|
85
|
-
onComplete,
|
|
86
|
-
account,
|
|
87
|
-
toAmount,
|
|
88
|
-
toRecipient,
|
|
89
|
-
toChainId,
|
|
90
|
-
toToken,
|
|
91
|
-
toCalldata,
|
|
92
|
-
walletClient,
|
|
93
|
-
onTransactionStateChange,
|
|
94
|
-
onError,
|
|
95
|
-
onWaitingForWalletConfirm,
|
|
96
|
-
paymasterUrls,
|
|
97
|
-
gasless,
|
|
98
|
-
setWalletConfirmRetryHandler,
|
|
99
|
-
quoteProvider,
|
|
100
|
-
fundMethod,
|
|
101
|
-
onNavigateToMeshConnect,
|
|
102
|
-
onAmountUpdate,
|
|
103
|
-
selectedPool,
|
|
104
|
-
checkoutOnHandlers,
|
|
105
|
-
}) => {
|
|
106
|
-
const { mode } = useMode()
|
|
107
|
-
const { isBalanceVisible } = useBalanceVisible()
|
|
108
|
-
// const [isRefundAddressOpen, setIsRefundAddressOpen] = useState(false)
|
|
109
|
-
// const [refundAddress, setRefundAddress] = useState<string>(account.address)
|
|
110
|
-
const [refetchTrigger, setRefetchTrigger] = useState(0)
|
|
111
|
-
const {
|
|
112
|
-
amount,
|
|
113
|
-
amountRaw,
|
|
114
|
-
amountUsdDisplay,
|
|
115
|
-
balanceUsdDisplay,
|
|
116
|
-
chainInfo,
|
|
117
|
-
balanceFormatted,
|
|
118
|
-
handleRecipientInputChange,
|
|
119
|
-
handleSubmit,
|
|
120
|
-
isChainDropdownOpen,
|
|
121
|
-
isSubmitting,
|
|
122
|
-
isLoadingQuote,
|
|
123
|
-
isTokenDropdownOpen,
|
|
124
|
-
recipient,
|
|
125
|
-
recipientInput,
|
|
126
|
-
selectedDestinationChain,
|
|
127
|
-
selectedDestToken,
|
|
128
|
-
setAmount,
|
|
129
|
-
setRecipient,
|
|
130
|
-
setRecipientInput,
|
|
131
|
-
setSelectedDestinationChain,
|
|
132
|
-
setSelectedDestToken,
|
|
133
|
-
buttonText,
|
|
134
|
-
isValidRecipient,
|
|
135
|
-
ensAddress,
|
|
136
|
-
supportedTokens,
|
|
137
|
-
setIsChainDropdownOpen,
|
|
138
|
-
setIsTokenDropdownOpen,
|
|
139
|
-
toAmountDisplay,
|
|
140
|
-
destinationTokenAddress,
|
|
141
|
-
supportedChains,
|
|
142
|
-
isValidCustomToken,
|
|
143
|
-
prepareSendQuote,
|
|
144
|
-
quoteError,
|
|
145
|
-
quoteErrorPrettified,
|
|
146
|
-
isSameTokenWithoutCustomCalldata,
|
|
147
|
-
} = useSendForm({
|
|
148
|
-
account,
|
|
149
|
-
toAmount,
|
|
150
|
-
toRecipient,
|
|
151
|
-
toChainId,
|
|
152
|
-
toToken,
|
|
153
|
-
toCalldata,
|
|
154
|
-
// refundAddress,
|
|
155
|
-
walletClient,
|
|
156
|
-
onTransactionStateChange,
|
|
157
|
-
onError,
|
|
158
|
-
onWaitingForWalletConfirm,
|
|
159
|
-
paymasterUrls,
|
|
160
|
-
gasless,
|
|
161
|
-
onConfirm,
|
|
162
|
-
onComplete,
|
|
163
|
-
onSend,
|
|
164
|
-
selectedToken,
|
|
165
|
-
setWalletConfirmRetryHandler,
|
|
166
|
-
tradeType: TradeType.EXACT_OUTPUT,
|
|
167
|
-
quoteProvider,
|
|
168
|
-
fundMethod,
|
|
169
|
-
mode,
|
|
170
|
-
onNavigateToMeshConnect,
|
|
171
|
-
checkoutOnHandlers,
|
|
172
|
-
refetchTrigger,
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
// Handle amount input changes with decimal validation
|
|
176
|
-
const handleAmountChange = useCallback(
|
|
177
|
-
(value: string) => {
|
|
178
|
-
// Validate decimal places (max 8 decimals)
|
|
179
|
-
const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
|
|
180
|
-
if (!decimalMatch && value !== "") {
|
|
181
|
-
return // Don't update if more than 8 decimals
|
|
182
|
-
}
|
|
183
|
-
setAmount(value)
|
|
184
|
-
},
|
|
185
|
-
[setAmount],
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
// Handle manual quote refetch
|
|
189
|
-
const handleRefetchQuote = useCallback(() => {
|
|
190
|
-
setRefetchTrigger((prev) => prev + 1)
|
|
191
|
-
}, [])
|
|
192
|
-
|
|
193
|
-
// Call onAmountUpdate when amountRaw changes
|
|
194
|
-
useEffect(() => {
|
|
195
|
-
if (onAmountUpdate) {
|
|
196
|
-
onAmountUpdate(amountRaw)
|
|
197
|
-
}
|
|
198
|
-
}, [amountRaw, onAmountUpdate])
|
|
199
|
-
|
|
200
|
-
const chainDropdownRef = useRef<HTMLDivElement>(null)
|
|
201
|
-
const tokenDropdownRef = useRef<HTMLDivElement>(null)
|
|
202
|
-
|
|
203
|
-
useEffect(() => {
|
|
204
|
-
const handleClickOutside = (event: MouseEvent) => {
|
|
205
|
-
logger.console.log(
|
|
206
|
-
"[trails-sdk] click outside handler called, isChainDropdownOpen:",
|
|
207
|
-
isChainDropdownOpen,
|
|
208
|
-
)
|
|
209
|
-
if (
|
|
210
|
-
chainDropdownRef.current &&
|
|
211
|
-
!chainDropdownRef.current.contains(event.target as Node)
|
|
212
|
-
) {
|
|
213
|
-
logger.console.log(
|
|
214
|
-
"[trails-sdk] closing chain dropdown from outside click",
|
|
215
|
-
)
|
|
216
|
-
setIsChainDropdownOpen(false)
|
|
217
|
-
}
|
|
218
|
-
if (
|
|
219
|
-
tokenDropdownRef.current &&
|
|
220
|
-
!tokenDropdownRef.current.contains(event.target as Node)
|
|
221
|
-
) {
|
|
222
|
-
setIsTokenDropdownOpen(false)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (isChainDropdownOpen || isTokenDropdownOpen) {
|
|
227
|
-
document.addEventListener("click", handleClickOutside)
|
|
228
|
-
return () => document.removeEventListener("click", handleClickOutside)
|
|
229
|
-
}
|
|
230
|
-
}, [
|
|
231
|
-
setIsChainDropdownOpen,
|
|
232
|
-
setIsTokenDropdownOpen,
|
|
233
|
-
isChainDropdownOpen,
|
|
234
|
-
isTokenDropdownOpen,
|
|
235
|
-
])
|
|
236
|
-
|
|
237
|
-
if (!selectedDestinationChain) {
|
|
238
|
-
return null
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (!selectedToken) {
|
|
242
|
-
return null
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return (
|
|
246
|
-
<div className="space-y-2">
|
|
247
|
-
<ScreenHeader
|
|
248
|
-
onBack={onBack}
|
|
249
|
-
headerContent={mode === "earn" ? "Earn" : "Send Payment"}
|
|
250
|
-
headerContentAlign="left"
|
|
251
|
-
showAccountActions={true}
|
|
252
|
-
/>
|
|
253
|
-
|
|
254
|
-
<div className="flex items-center space-x-2 p-4 trails-border-radius-container trails-bg-secondary">
|
|
255
|
-
<div className="flex items-start justify-between w-full">
|
|
256
|
-
{/* Left side - Chain and Token images with token name */}
|
|
257
|
-
<div className="flex items-start space-x-2">
|
|
258
|
-
{/* Token Image and Name */}
|
|
259
|
-
<div className="flex items-center space-x-2">
|
|
260
|
-
<div style={{ width: "32px", height: "32px" }} className="mr-2">
|
|
261
|
-
<a
|
|
262
|
-
href={getExplorerUrlForAddress({
|
|
263
|
-
address: selectedToken.contractAddress,
|
|
264
|
-
chainId: selectedToken.chainId,
|
|
265
|
-
})}
|
|
266
|
-
target="_blank"
|
|
267
|
-
rel="noopener noreferrer"
|
|
268
|
-
className="cursor-pointer"
|
|
269
|
-
>
|
|
270
|
-
<TokenImage
|
|
271
|
-
symbol={selectedToken.symbol}
|
|
272
|
-
imageUrl={selectedToken.imageUrl}
|
|
273
|
-
chainId={selectedToken.chainId}
|
|
274
|
-
size={32}
|
|
275
|
-
/>
|
|
276
|
-
</a>
|
|
277
|
-
</div>
|
|
278
|
-
<div className="flex flex-col">
|
|
279
|
-
<span className="text-sm font-medium max-w-[135px] truncate text-left text-gray-900 dark:text-white">
|
|
280
|
-
{selectedToken.name}
|
|
281
|
-
</span>
|
|
282
|
-
<span className="text-sm text-gray-500 dark:text-gray-400">
|
|
283
|
-
on {chainInfo?.name || "Unknown Chain"}
|
|
284
|
-
</span>
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
|
|
289
|
-
{/* Right side - USD value and amount */}
|
|
290
|
-
{fundMethod !== "qr-code" && fundMethod !== "exchange" && (
|
|
291
|
-
<div className="text-right">
|
|
292
|
-
<div className="text-sm font-medium text-gray-900 dark:text-white">
|
|
293
|
-
<span className="text-gray-600 dark:text-gray-400">
|
|
294
|
-
Balance:{" "}
|
|
295
|
-
</span>
|
|
296
|
-
{isBalanceVisible ? balanceUsdDisplay : "••••••"}
|
|
297
|
-
</div>
|
|
298
|
-
<div className="text-sm text-gray-600 dark:text-gray-400">
|
|
299
|
-
{isBalanceVisible
|
|
300
|
-
? `${balanceFormatted} ${selectedToken.symbol}`
|
|
301
|
-
: "••••••"}
|
|
302
|
-
</div>
|
|
303
|
-
</div>
|
|
304
|
-
)}
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
|
|
308
|
-
{/* Pool Information - Only show in earn mode when selectedPool is available */}
|
|
309
|
-
{mode === "earn" && selectedPool && (
|
|
310
|
-
<div className="p-4 trails-border-radius-container trails-bg-secondary">
|
|
311
|
-
<div className="flex items-center justify-between mb-2">
|
|
312
|
-
<div className="flex items-center space-x-3">
|
|
313
|
-
<div style={{ width: "32px", height: "32px" }}>
|
|
314
|
-
<a
|
|
315
|
-
href={getExplorerUrlForAddress({
|
|
316
|
-
address: selectedPool.token.address,
|
|
317
|
-
chainId: selectedPool.chainId,
|
|
318
|
-
})}
|
|
319
|
-
target="_blank"
|
|
320
|
-
rel="noopener noreferrer"
|
|
321
|
-
className="cursor-pointer"
|
|
322
|
-
>
|
|
323
|
-
<TokenImage
|
|
324
|
-
symbol={selectedPool.token.symbol}
|
|
325
|
-
imageUrl={selectedPool.token.logoUrl}
|
|
326
|
-
chainId={selectedPool.chainId}
|
|
327
|
-
size={32}
|
|
328
|
-
/>
|
|
329
|
-
</a>
|
|
330
|
-
</div>
|
|
331
|
-
<div>
|
|
332
|
-
<h3 className="font-medium text-gray-900 dark:text-white text-sm">
|
|
333
|
-
{selectedPool.poolUrl ? (
|
|
334
|
-
<a
|
|
335
|
-
href={selectedPool.poolUrl}
|
|
336
|
-
target="_blank"
|
|
337
|
-
rel="noopener noreferrer"
|
|
338
|
-
className="hover:underline cursor-pointer"
|
|
339
|
-
>
|
|
340
|
-
{selectedPool.name}
|
|
341
|
-
</a>
|
|
342
|
-
) : (
|
|
343
|
-
selectedPool.name
|
|
344
|
-
)}
|
|
345
|
-
</h3>
|
|
346
|
-
<div className="flex items-center space-x-2">
|
|
347
|
-
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
348
|
-
{selectedPool.protocol === "Aave" && (
|
|
349
|
-
<img src={aaveLogo} alt="Aave" className="w-3 h-3 mr-1" />
|
|
350
|
-
)}
|
|
351
|
-
{selectedPool.protocol === "Morpho" && (
|
|
352
|
-
<img
|
|
353
|
-
src={morphoLogo}
|
|
354
|
-
alt="Morpho"
|
|
355
|
-
className="w-3 h-3 mr-1"
|
|
356
|
-
/>
|
|
357
|
-
)}
|
|
358
|
-
{selectedPool.protocolUrl ? (
|
|
359
|
-
<a
|
|
360
|
-
href={selectedPool.protocolUrl}
|
|
361
|
-
target="_blank"
|
|
362
|
-
rel="noopener noreferrer"
|
|
363
|
-
className="hover:underline cursor-pointer"
|
|
364
|
-
>
|
|
365
|
-
{selectedPool.protocol}
|
|
366
|
-
</a>
|
|
367
|
-
) : (
|
|
368
|
-
selectedPool.protocol
|
|
369
|
-
)}
|
|
370
|
-
</span>
|
|
371
|
-
<span
|
|
372
|
-
className={`px-2 py-0.5 rounded-full text-xs font-medium ${getChainColor(selectedPool.chainId)}`}
|
|
373
|
-
>
|
|
374
|
-
{getChainInfo(selectedPool.chainId)?.name ||
|
|
375
|
-
`Chain ${selectedPool.chainId}`}
|
|
376
|
-
</span>
|
|
377
|
-
</div>
|
|
378
|
-
</div>
|
|
379
|
-
</div>
|
|
380
|
-
<div className="text-right">
|
|
381
|
-
<div className="flex items-center space-x-1 text-green-600 dark:text-green-400">
|
|
382
|
-
<TrendingUp className="w-3 h-3" />
|
|
383
|
-
<span className="font-semibold text-sm">
|
|
384
|
-
{selectedPool.apy.toFixed(1)}%
|
|
385
|
-
</span>
|
|
386
|
-
</div>
|
|
387
|
-
<p className="text-xs text-gray-500 dark:text-gray-400">APY</p>
|
|
388
|
-
</div>
|
|
389
|
-
</div>
|
|
390
|
-
<div className="flex items-center justify-between text-sm">
|
|
391
|
-
<div className="flex items-center space-x-1 text-gray-600 dark:text-gray-400">
|
|
392
|
-
<span className="text-xs">
|
|
393
|
-
TVL: {formatTvl(selectedPool.tvl)}
|
|
394
|
-
</span>
|
|
395
|
-
</div>
|
|
396
|
-
<div className="flex items-center space-x-1">
|
|
397
|
-
<span
|
|
398
|
-
className={`w-2 h-2 rounded-full ${selectedPool.isActive ? "bg-green-500" : "bg-red-500"}`}
|
|
399
|
-
/>
|
|
400
|
-
<span className="text-xs text-gray-600 dark:text-gray-400">
|
|
401
|
-
{selectedPool.isActive ? "Active" : "Inactive"}
|
|
402
|
-
</span>
|
|
403
|
-
</div>
|
|
404
|
-
</div>
|
|
405
|
-
</div>
|
|
406
|
-
)}
|
|
407
|
-
|
|
408
|
-
<form onSubmit={handleSubmit} className="space-y-2">
|
|
409
|
-
{/* Chain Selection - More Compact */}
|
|
410
|
-
{!toChainId && (
|
|
411
|
-
<div className="mb-4">
|
|
412
|
-
<label
|
|
413
|
-
htmlFor="destination-chain"
|
|
414
|
-
className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300 text-left"
|
|
415
|
-
>
|
|
416
|
-
Destination Chain
|
|
417
|
-
</label>
|
|
418
|
-
<div className="relative" ref={chainDropdownRef}>
|
|
419
|
-
<button
|
|
420
|
-
type="button"
|
|
421
|
-
onClick={() => setIsChainDropdownOpen(!isChainDropdownOpen)}
|
|
422
|
-
className="w-full flex items-center px-4 py-3 border border-solid trails-border-radius-dropdown hover:border-gray-400 cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 trails-dropdown"
|
|
423
|
-
>
|
|
424
|
-
<ChainImage chainId={selectedDestinationChain.id} size={24} />
|
|
425
|
-
<span className="ml-2 flex-1 text-left">
|
|
426
|
-
{selectedDestinationChain.name}
|
|
427
|
-
</span>
|
|
428
|
-
<ChevronDown
|
|
429
|
-
className={`h-5 w-5 ${"text-gray-400"} transition-transform ${
|
|
430
|
-
isChainDropdownOpen ? "transform rotate-180" : ""
|
|
431
|
-
}`}
|
|
432
|
-
/>
|
|
433
|
-
</button>
|
|
434
|
-
|
|
435
|
-
{isChainDropdownOpen && (
|
|
436
|
-
<div className="absolute z-10 w-full mt-1 border border-solid trails-border-radius-dropdown shadow-lg max-h-60 overflow-y-auto custom-scrollbar trails-dropdown">
|
|
437
|
-
{supportedChains.map((chain) => (
|
|
438
|
-
<button
|
|
439
|
-
key={chain.id}
|
|
440
|
-
type="button"
|
|
441
|
-
onClick={(e) => {
|
|
442
|
-
e.preventDefault()
|
|
443
|
-
e.stopPropagation()
|
|
444
|
-
setSelectedDestinationChain(chain)
|
|
445
|
-
setIsChainDropdownOpen(false)
|
|
446
|
-
}}
|
|
447
|
-
onMouseDown={(e) => {
|
|
448
|
-
e.preventDefault()
|
|
449
|
-
e.stopPropagation()
|
|
450
|
-
}}
|
|
451
|
-
className={`w-full flex items-center px-4 py-3 trails-dropdown-item cursor-pointer ${
|
|
452
|
-
selectedDestinationChain.id === chain.id
|
|
453
|
-
? "trails-dropdown-item-selected"
|
|
454
|
-
: "hover:trails-dropdown-item"
|
|
455
|
-
}`}
|
|
456
|
-
>
|
|
457
|
-
<ChainImage chainId={chain.id} size={24} />
|
|
458
|
-
<span className="ml-2">{chain.name}</span>
|
|
459
|
-
{selectedDestinationChain.id === chain.id && (
|
|
460
|
-
<span className="ml-auto text-gray-900 dark:text-white">
|
|
461
|
-
•
|
|
462
|
-
</span>
|
|
463
|
-
)}
|
|
464
|
-
</button>
|
|
465
|
-
))}
|
|
466
|
-
</div>
|
|
467
|
-
)}
|
|
468
|
-
</div>
|
|
469
|
-
</div>
|
|
470
|
-
)}
|
|
471
|
-
|
|
472
|
-
{/* Token Selection - More Compact */}
|
|
473
|
-
{!toToken && (
|
|
474
|
-
<div className="mb-4">
|
|
475
|
-
<label
|
|
476
|
-
htmlFor="token"
|
|
477
|
-
className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300 text-left"
|
|
478
|
-
>
|
|
479
|
-
Receive Token
|
|
480
|
-
</label>
|
|
481
|
-
<div className="relative" ref={tokenDropdownRef}>
|
|
482
|
-
<button
|
|
483
|
-
type="button"
|
|
484
|
-
onClick={() => setIsTokenDropdownOpen(!isTokenDropdownOpen)}
|
|
485
|
-
className="w-full flex items-center px-4 py-3 border border-solid trails-border-radius-dropdown hover:border-gray-400 cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 trails-dropdown"
|
|
486
|
-
>
|
|
487
|
-
<div className="w-5 h-5 rounded-full flex items-center justify-center text-sm bg-gray-100 dark:bg-gray-700">
|
|
488
|
-
<TokenImage
|
|
489
|
-
symbol={selectedDestToken?.symbol}
|
|
490
|
-
imageUrl={selectedDestToken?.imageUrl}
|
|
491
|
-
size={24}
|
|
492
|
-
/>
|
|
493
|
-
</div>
|
|
494
|
-
<span className="ml-2 flex-1 text-left">
|
|
495
|
-
{selectedDestToken?.name} ({selectedDestToken?.symbol})
|
|
496
|
-
</span>
|
|
497
|
-
<ChevronDown
|
|
498
|
-
className={`h-5 w-5 text-gray-400 transition-transform ${
|
|
499
|
-
isTokenDropdownOpen ? "transform rotate-180" : ""
|
|
500
|
-
}`}
|
|
501
|
-
/>
|
|
502
|
-
</button>
|
|
503
|
-
|
|
504
|
-
{isTokenDropdownOpen && (
|
|
505
|
-
<div className="absolute z-10 w-full mt-1 border border-solid trails-border-radius-dropdown shadow-lg max-h-60 overflow-y-auto custom-scrollbar trails-dropdown">
|
|
506
|
-
{supportedTokens.map((token) => (
|
|
507
|
-
<button
|
|
508
|
-
key={`${token.contractAddress}-${token.chainId}`}
|
|
509
|
-
type="button"
|
|
510
|
-
onClick={() => {
|
|
511
|
-
setSelectedDestToken(token as TokenInfo)
|
|
512
|
-
setIsTokenDropdownOpen(false)
|
|
513
|
-
}}
|
|
514
|
-
className={`w-full flex items-center px-4 py-3 cursor-pointer trails-dropdown-item ${
|
|
515
|
-
selectedDestToken?.symbol === token.symbol
|
|
516
|
-
? "trails-dropdown-item-selected"
|
|
517
|
-
: "hover:trails-dropdown-item"
|
|
518
|
-
}`}
|
|
519
|
-
>
|
|
520
|
-
<TokenImage
|
|
521
|
-
symbol={token.symbol}
|
|
522
|
-
imageUrl={token.imageUrl}
|
|
523
|
-
size={24}
|
|
524
|
-
/>
|
|
525
|
-
<span className="ml-2">
|
|
526
|
-
{token.name} ({token.symbol})
|
|
527
|
-
</span>
|
|
528
|
-
{selectedDestToken?.symbol === token.symbol && (
|
|
529
|
-
<span className="ml-auto text-gray-900 dark:text-white">
|
|
530
|
-
•
|
|
531
|
-
</span>
|
|
532
|
-
)}
|
|
533
|
-
</button>
|
|
534
|
-
))}
|
|
535
|
-
</div>
|
|
536
|
-
)}
|
|
537
|
-
</div>
|
|
538
|
-
</div>
|
|
539
|
-
)}
|
|
540
|
-
|
|
541
|
-
{/* Amount Input - More Compact */}
|
|
542
|
-
{!toAmount && (
|
|
543
|
-
<div className="mb-2">
|
|
544
|
-
<label
|
|
545
|
-
htmlFor="amount"
|
|
546
|
-
className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300 text-left"
|
|
547
|
-
>
|
|
548
|
-
Amount to {mode === "earn" ? "Deposit" : "Receive"}
|
|
549
|
-
</label>
|
|
550
|
-
<div className="relative trails-border-radius-container">
|
|
551
|
-
<input
|
|
552
|
-
id="amount"
|
|
553
|
-
type="text"
|
|
554
|
-
value={amount}
|
|
555
|
-
onChange={(e) => handleAmountChange(e.target.value)}
|
|
556
|
-
placeholder="0.00"
|
|
557
|
-
className="block w-full pl-4 pr-12 py-3 border border-solid trails-border-radius-input focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg trails-input"
|
|
558
|
-
/>
|
|
559
|
-
<div className="absolute inset-y-0 right-0 flex items-center pr-4">
|
|
560
|
-
<span className="text-gray-400">
|
|
561
|
-
{selectedDestToken?.symbol}
|
|
562
|
-
</span>
|
|
563
|
-
</div>
|
|
564
|
-
</div>
|
|
565
|
-
{amountUsdDisplay && selectedDestToken?.symbol && (
|
|
566
|
-
<div className="h-6 mt-1">
|
|
567
|
-
<div className="text-sm text-gray-400 text-left">
|
|
568
|
-
≈ {amountUsdDisplay}
|
|
569
|
-
</div>
|
|
570
|
-
</div>
|
|
571
|
-
)}
|
|
572
|
-
</div>
|
|
573
|
-
)}
|
|
574
|
-
|
|
575
|
-
{/* Receive Section - Similar to FundSendForm */}
|
|
576
|
-
{(toAmount || toChainId || toToken) && (
|
|
577
|
-
<div className="space-y-1">
|
|
578
|
-
<div className="flex items-center justify-between">
|
|
579
|
-
<div
|
|
580
|
-
className={`text-lg font-semibold text-left ${"text-gray-900 dark:text-white"}`}
|
|
581
|
-
>
|
|
582
|
-
{mode === "earn" ? "Deposit" : "Receive"}
|
|
583
|
-
</div>
|
|
584
|
-
<button
|
|
585
|
-
type="button"
|
|
586
|
-
onClick={handleRefetchQuote}
|
|
587
|
-
disabled={
|
|
588
|
-
isLoadingQuote ||
|
|
589
|
-
!amount ||
|
|
590
|
-
!selectedDestToken ||
|
|
591
|
-
!selectedDestinationChain ||
|
|
592
|
-
!isValidRecipient
|
|
593
|
-
}
|
|
594
|
-
className={`p-2 rounded-md transition-colors cursor-pointer ${
|
|
595
|
-
isLoadingQuote ||
|
|
596
|
-
!amount ||
|
|
597
|
-
!selectedDestToken ||
|
|
598
|
-
!selectedDestinationChain ||
|
|
599
|
-
!isValidRecipient
|
|
600
|
-
? "opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-500"
|
|
601
|
-
: "text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200"
|
|
602
|
-
}`}
|
|
603
|
-
title="Refetch quote"
|
|
604
|
-
>
|
|
605
|
-
<RefreshCcw
|
|
606
|
-
className={`h-4 w-4 ${isLoadingQuote ? "animate-spin" : ""}`}
|
|
607
|
-
/>
|
|
608
|
-
</button>
|
|
609
|
-
</div>
|
|
610
|
-
|
|
611
|
-
<div className="p-2">
|
|
612
|
-
<div className="flex items-center space-x-3">
|
|
613
|
-
<a
|
|
614
|
-
href={getExplorerUrlForAddress({
|
|
615
|
-
address: destinationTokenAddress || "",
|
|
616
|
-
chainId: selectedDestinationChain.id,
|
|
617
|
-
})}
|
|
618
|
-
target="_blank"
|
|
619
|
-
rel="noopener noreferrer"
|
|
620
|
-
className="cursor-pointer"
|
|
621
|
-
>
|
|
622
|
-
<TokenImage
|
|
623
|
-
symbol={selectedDestToken?.symbol}
|
|
624
|
-
imageUrl={selectedDestToken?.imageUrl}
|
|
625
|
-
chainId={selectedDestinationChain.id}
|
|
626
|
-
size={32}
|
|
627
|
-
/>
|
|
628
|
-
</a>
|
|
629
|
-
<div>
|
|
630
|
-
<div className="flex items-center space-x-2">
|
|
631
|
-
<div
|
|
632
|
-
className={`text-lg font-semibold ${"text-gray-900 dark:text-white"} ${isLoadingQuote ? "animate-pulse" : ""}`}
|
|
633
|
-
>
|
|
634
|
-
{toAmountDisplay} {selectedDestToken?.symbol}
|
|
635
|
-
</div>
|
|
636
|
-
{isLoadingQuote && (
|
|
637
|
-
<div
|
|
638
|
-
className={`animate-spin rounded-full h-4 w-4 border-solid border-b-2 ${"border-blue-400"}`}
|
|
639
|
-
/>
|
|
640
|
-
)}
|
|
641
|
-
</div>
|
|
642
|
-
<div
|
|
643
|
-
className={`text-xs ${"text-gray-500 dark:text-gray-400"} ${isLoadingQuote ? "animate-pulse" : ""}`}
|
|
644
|
-
>
|
|
645
|
-
≈ {amountUsdDisplay}{" "}
|
|
646
|
-
{selectedDestinationChain
|
|
647
|
-
? `on ${selectedDestinationChain.name}`
|
|
648
|
-
: ""}
|
|
649
|
-
</div>
|
|
650
|
-
</div>
|
|
651
|
-
</div>
|
|
652
|
-
</div>
|
|
653
|
-
|
|
654
|
-
{/* Show recipient address if different from sender */}
|
|
655
|
-
{recipient &&
|
|
656
|
-
recipient.toLowerCase() !== account.address.toLowerCase() && (
|
|
657
|
-
<div className="px-2 pb-1">
|
|
658
|
-
<div className={`text-xs text-left ${"text-gray-400"}`}>
|
|
659
|
-
{mode === "earn" ? "Pool" : "Recipient"}:{" "}
|
|
660
|
-
<TruncatedAddress
|
|
661
|
-
address={recipient}
|
|
662
|
-
chainId={selectedDestinationChain.id}
|
|
663
|
-
/>
|
|
664
|
-
</div>
|
|
665
|
-
</div>
|
|
666
|
-
)}
|
|
667
|
-
</div>
|
|
668
|
-
)}
|
|
669
|
-
|
|
670
|
-
{/* Recipient Input - More Compact */}
|
|
671
|
-
{!toRecipient && (
|
|
672
|
-
<div className="mb-4">
|
|
673
|
-
<div className="flex justify-between items-center mb-1">
|
|
674
|
-
<div>
|
|
675
|
-
<label
|
|
676
|
-
htmlFor="recipient"
|
|
677
|
-
className="text-sm font-medium text-gray-700 dark:text-gray-300"
|
|
678
|
-
>
|
|
679
|
-
{toCalldata
|
|
680
|
-
? "Destination Address"
|
|
681
|
-
: mode === "earn"
|
|
682
|
-
? "Pool Address"
|
|
683
|
-
: "Recipient Address"}
|
|
684
|
-
</label>
|
|
685
|
-
{recipient &&
|
|
686
|
-
isAddress(recipient) &&
|
|
687
|
-
recipient.toLowerCase() === account.address.toLowerCase() && (
|
|
688
|
-
<div className="text-xs mt-0.5 text-left text-gray-400">
|
|
689
|
-
Same as sender
|
|
690
|
-
</div>
|
|
691
|
-
)}
|
|
692
|
-
</div>
|
|
693
|
-
<div className="h-7 flex items-center">
|
|
694
|
-
{recipient !== account.address ? (
|
|
695
|
-
<button
|
|
696
|
-
type="button"
|
|
697
|
-
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
|
|
698
|
-
event.preventDefault()
|
|
699
|
-
setRecipientInput(account.address)
|
|
700
|
-
setRecipient(account.address)
|
|
701
|
-
}}
|
|
702
|
-
className={`px-2 py-1 text-xs cursor-pointer trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 text-white`}
|
|
703
|
-
>
|
|
704
|
-
Use Account
|
|
705
|
-
</button>
|
|
706
|
-
) : null}
|
|
707
|
-
</div>
|
|
708
|
-
</div>
|
|
709
|
-
<input
|
|
710
|
-
id="recipient"
|
|
711
|
-
type="text"
|
|
712
|
-
value={recipientInput}
|
|
713
|
-
onChange={handleRecipientInputChange}
|
|
714
|
-
placeholder="0x... or name.eth"
|
|
715
|
-
className="block w-full px-4 py-3 border border-solid trails-border-radius-input focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm trails-input"
|
|
716
|
-
/>
|
|
717
|
-
{ensAddress && <p className="text-sm text-gray-400">{recipient}</p>}
|
|
718
|
-
</div>
|
|
719
|
-
)}
|
|
720
|
-
|
|
721
|
-
{/* Custom Calldata - More Compact */}
|
|
722
|
-
{toCalldata && (
|
|
723
|
-
<div className="px-2 py-1">
|
|
724
|
-
<p className={`text-[10px] text-left ${"text-gray-400"}`}>
|
|
725
|
-
This transaction includes custom calldata for contract interaction
|
|
726
|
-
at the destination address
|
|
727
|
-
</p>
|
|
728
|
-
</div>
|
|
729
|
-
)}
|
|
730
|
-
|
|
731
|
-
{/* Refund Address Input */}
|
|
732
|
-
{/* <RefundAddressInput
|
|
733
|
-
account={account}
|
|
734
|
-
isOpen={isRefundAddressOpen}
|
|
735
|
-
onToggle={() => setIsRefundAddressOpen(!isRefundAddressOpen)}
|
|
736
|
-
refundAddress={refundAddress}
|
|
737
|
-
onRefundAddressChange={setRefundAddress}
|
|
738
|
-
chainId={selectedDestinationChain.id}
|
|
739
|
-
/> */}
|
|
740
|
-
|
|
741
|
-
{/* Warning Messages - Show only one at a time */}
|
|
742
|
-
{isSameTokenWithoutCustomCalldata ? (
|
|
743
|
-
<ErrorDisplay
|
|
744
|
-
errorPrettified="Cannot swap to the same token on the same chain without custom calldata. Please select a different origin token."
|
|
745
|
-
severity="error"
|
|
746
|
-
/>
|
|
747
|
-
) : (
|
|
748
|
-
<ErrorDisplay
|
|
749
|
-
errorPrettified={quoteErrorPrettified}
|
|
750
|
-
error={quoteError}
|
|
751
|
-
severity="warning"
|
|
752
|
-
/>
|
|
753
|
-
)}
|
|
754
|
-
{prepareSendQuote?.noSufficientBalance ? (
|
|
755
|
-
<div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
|
|
756
|
-
<div className="flex items-center space-x-2">
|
|
757
|
-
<svg
|
|
758
|
-
className="w-4 h-4 text-amber-500 flex-shrink-0"
|
|
759
|
-
fill="none"
|
|
760
|
-
stroke="currentColor"
|
|
761
|
-
viewBox="0 0 24 24"
|
|
762
|
-
aria-hidden="true"
|
|
763
|
-
>
|
|
764
|
-
<path
|
|
765
|
-
strokeLinecap="round"
|
|
766
|
-
strokeLinejoin="round"
|
|
767
|
-
strokeWidth={2}
|
|
768
|
-
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"
|
|
769
|
-
/>
|
|
770
|
-
</svg>
|
|
771
|
-
<p className="text-sm text-amber-600 dark:text-amber-400">
|
|
772
|
-
Insufficient balance to complete this transaction
|
|
773
|
-
</p>
|
|
774
|
-
</div>
|
|
775
|
-
</div>
|
|
776
|
-
) : null}
|
|
777
|
-
|
|
778
|
-
<button
|
|
779
|
-
type="submit"
|
|
780
|
-
disabled={
|
|
781
|
-
!amount ||
|
|
782
|
-
!isValidRecipient ||
|
|
783
|
-
isSubmitting ||
|
|
784
|
-
!destinationTokenAddress ||
|
|
785
|
-
!isValidCustomToken ||
|
|
786
|
-
isLoadingQuote ||
|
|
787
|
-
!prepareSendQuote ||
|
|
788
|
-
prepareSendQuote?.noSufficientBalance ||
|
|
789
|
-
isSameTokenWithoutCustomCalldata
|
|
790
|
-
}
|
|
791
|
-
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`}
|
|
792
|
-
>
|
|
793
|
-
{isSubmitting ? (
|
|
794
|
-
<div className="flex items-center justify-center">
|
|
795
|
-
<Loader2
|
|
796
|
-
className={`w-5 h-5 animate-spin mr-2 ${"text-gray-400"}`}
|
|
797
|
-
/>
|
|
798
|
-
<span>{buttonText}</span>
|
|
799
|
-
</div>
|
|
800
|
-
) : isSameTokenWithoutCustomCalldata ? (
|
|
801
|
-
"Select Different Tokens"
|
|
802
|
-
) : prepareSendQuote?.noSufficientBalance ? (
|
|
803
|
-
"Insufficient Balance"
|
|
804
|
-
) : (
|
|
805
|
-
buttonText
|
|
806
|
-
)}
|
|
807
|
-
</button>
|
|
808
|
-
|
|
809
|
-
{/* Quote Details */}
|
|
810
|
-
{prepareSendQuote && (
|
|
811
|
-
<div className="space-y-2">
|
|
812
|
-
<QuoteDetails quote={prepareSendQuote} showContent={true} />
|
|
813
|
-
</div>
|
|
814
|
-
)}
|
|
815
|
-
</form>
|
|
816
|
-
</div>
|
|
817
|
-
)
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
const styles = `
|
|
821
|
-
select {
|
|
822
|
-
appearance: none;
|
|
823
|
-
border: 1px solid #e5e7eb;
|
|
824
|
-
outline: none;
|
|
825
|
-
font-size: 1rem;
|
|
826
|
-
width: 100%;
|
|
827
|
-
background-color: #fff;
|
|
828
|
-
border-radius: 0.5rem;
|
|
829
|
-
padding: 0.75rem 1rem;
|
|
830
|
-
padding-right: 2rem;
|
|
831
|
-
|
|
832
|
-
cursor: pointer;
|
|
833
|
-
transition: all 0.2s;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
select:hover {
|
|
837
|
-
border-color: #d1d5db;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
select:focus {
|
|
841
|
-
border-color: #3b82f6;
|
|
842
|
-
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
select option {
|
|
846
|
-
padding: 0.75rem 1rem;
|
|
847
|
-
min-height: 3rem;
|
|
848
|
-
display: flex;
|
|
849
|
-
align-items: center;
|
|
850
|
-
padding-left: 2.75rem;
|
|
851
|
-
position: relative;
|
|
852
|
-
cursor: pointer;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
select option:hover {
|
|
856
|
-
background-color: #f3f4f6;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
select option:checked {
|
|
860
|
-
background-color: #eff6ff;
|
|
861
|
-
color: #1d4ed8;
|
|
862
|
-
}
|
|
863
|
-
`
|
|
864
|
-
|
|
865
|
-
if (typeof document !== "undefined") {
|
|
866
|
-
const styleTag = document.createElement("style")
|
|
867
|
-
styleTag.textContent = styles
|
|
868
|
-
document.head.appendChild(styleTag)
|
|
869
|
-
}
|