0xtrails 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aave.d.ts +8 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/{ccip-ConT1gDe.js → ccip-CXlshvBY.js} +1 -1
- package/dist/chains.d.ts +5 -1
- package/dist/chains.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +5 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/estimate.d.ts +52 -0
- package/dist/estimate.d.ts.map +1 -1
- package/dist/{index-CMh8uEbV.js → index-_QuyGrjU.js} +86304 -83380
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/intentEntrypoint.d.ts +0 -8
- package/dist/intentEntrypoint.d.ts.map +1 -1
- package/dist/intents.d.ts +40 -0
- package/dist/intents.d.ts.map +1 -1
- package/dist/metaTxnMonitor.d.ts +5 -4
- package/dist/metaTxnMonitor.d.ts.map +1 -1
- package/dist/metaTxns.d.ts +3 -3
- package/dist/metaTxns.d.ts.map +1 -1
- package/dist/morpho.d.ts +8 -0
- package/dist/morpho.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +16 -6
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/queryParams.d.ts.map +1 -1
- package/dist/relayer.d.ts +10 -7
- package/dist/relayer.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +3 -2
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts +7 -0
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/tokens.d.ts +2 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/trails.d.ts +2 -2
- package/dist/trails.d.ts.map +1 -1
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -0
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts +4 -0
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/EarnPools.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts +1 -0
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/{FundSendForm.d.ts → FundSwap.d.ts} +11 -5
- package/dist/widget/components/FundSwap.d.ts.map +1 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts +4 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts +1 -0
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PercentageMaxButtons.d.ts +12 -0
- package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -0
- package/dist/widget/components/{PaySendForm.d.ts → PoolDeposit.d.ts} +11 -34
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
- package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +16 -8
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receive.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts +4 -0
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Recipients.d.ts.map +1 -1
- package/dist/widget/components/RefundWarning.d.ts +1 -0
- package/dist/widget/components/RefundWarning.d.ts.map +1 -1
- package/dist/widget/components/RequiredPropsError.d.ts +8 -0
- package/dist/widget/components/RequiredPropsError.d.ts.map +1 -0
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +1 -0
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapSettings.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts +1 -0
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/TokenList.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts +16 -0
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +8 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -0
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletList.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -0
- package/dist/widget/css/index.css +554 -0
- package/dist/widget/hooks/useBack.d.ts +6 -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/useInitialRedirect.d.ts +7 -0
- package/dist/widget/hooks/useInitialRedirect.d.ts.map +1 -0
- package/dist/widget/hooks/usePayMessage.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFundMethod.d.ts +12 -0
- package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts +4 -4
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +30 -23
- package/src/aave.ts +32 -0
- package/src/chains.ts +23 -3
- package/src/config.ts +12 -4
- package/src/constants.ts +11 -16
- package/src/error.ts +20 -2
- package/src/estimate.ts +416 -5
- package/src/index.ts +8 -3
- package/src/intentEntrypoint.ts +0 -15
- package/src/intents.ts +161 -11
- package/src/metaTxnMonitor.ts +28 -22
- package/src/metaTxns.ts +3 -3
- package/src/morpho.ts +32 -0
- package/src/prepareSend.ts +710 -458
- package/src/queryParams.ts +2 -1
- package/src/relayer.ts +15 -16
- package/src/sequenceWallet.ts +7 -3
- package/src/tokenBalances.ts +47 -0
- package/src/tokens.ts +17 -1
- package/src/trails.ts +2 -2
- package/src/wallets.ts +8 -0
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountActionsDropdown.tsx +9 -15
- package/src/widget/components/AccountIntentTransactionHistory.tsx +1 -1
- package/src/widget/components/AccountSettings.tsx +10 -27
- package/src/widget/components/ChainFilterDropdown.tsx +1 -1
- package/src/widget/components/ChainList.tsx +1 -1
- package/src/widget/components/ClassicSwap.tsx +111 -155
- package/src/widget/components/ConnectWallet.tsx +10 -39
- package/src/widget/components/ConnectedWallets.tsx +113 -58
- package/src/widget/components/Earn.tsx +73 -589
- package/src/widget/components/EarnPools.tsx +2 -1
- package/src/widget/components/Fund.tsx +81 -109
- package/src/widget/components/FundMethods.tsx +82 -159
- package/src/widget/components/FundSwap.tsx +52 -0
- package/src/widget/components/FundingMethodSelectorButton.tsx +60 -0
- package/src/widget/components/Modal.tsx +6 -2
- package/src/widget/components/Pay.tsx +198 -200
- package/src/widget/components/PercentageMaxButtons.tsx +77 -0
- package/src/widget/components/PoolDeposit.tsx +593 -0
- package/src/widget/components/PoolWithdraw.tsx +903 -0
- package/src/widget/components/QuoteDetails.tsx +22 -8
- package/src/widget/components/Receive.tsx +1 -3
- package/src/widget/components/RecipientSelectorButton.tsx +42 -0
- package/src/widget/components/Recipients.tsx +64 -156
- package/src/widget/components/RefundWarning.tsx +5 -1
- package/src/widget/components/RequiredPropsError.tsx +33 -0
- package/src/widget/components/ScreenHeader.tsx +5 -1
- package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
- package/src/widget/components/Swap.tsx +2 -43
- package/src/widget/components/SwapSettings.tsx +3 -15
- package/src/widget/components/TokenImage.tsx +21 -4
- package/src/widget/components/TokenList.tsx +0 -1
- package/src/widget/components/TokenSelector.tsx +2 -1
- package/src/widget/components/TokenSelectorButton.tsx +75 -0
- package/src/widget/components/UserPreferences.tsx +6 -24
- package/src/widget/components/WaasFeeOptions.tsx +331 -0
- package/src/widget/components/WalletConfirmation.tsx +55 -3
- package/src/widget/components/WalletList.tsx +7 -5
- package/src/widget/hooks/useBack.tsx +113 -9
- 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/useInitialRedirect.tsx +70 -0
- package/src/widget/hooks/usePayMessage.tsx +86 -11
- package/src/widget/hooks/useSelectedFeeToken.tsx +10 -16
- package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
- package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
- package/src/widget/hooks/useSendForm.ts +34 -12
- package/src/widget/hooks/useTokenList.ts +1 -1
- package/src/widget/index.css +27 -0
- package/src/widget/widget.tsx +245 -208
- 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
- /package/dist/{style.css → 0xtrails.css} +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Settings } from "lucide-react"
|
|
2
2
|
import type React from "react"
|
|
3
3
|
import { useEffect, useRef, useState } from "react"
|
|
4
|
-
import { SwapDisplayMode } from "./SwapDisplayMode.js"
|
|
4
|
+
// import { SwapDisplayMode } from "./SwapDisplayMode.js"
|
|
5
5
|
import { SlippageToleranceSettings } from "./SlippageToleranceSettings.js"
|
|
6
|
-
import { useSwapSettings } from "../hooks/useSwapSettings.js"
|
|
7
6
|
|
|
8
7
|
export const SwapSettings: React.FC = () => {
|
|
9
|
-
const { isSimpleSwapMode, setIsSimpleSwapModeWithStorage } = useSwapSettings()
|
|
10
8
|
const [isSettingsDropdownOpen, setIsSettingsDropdownOpen] = useState(false)
|
|
11
9
|
const settingsDropdownRef = useRef<HTMLDivElement>(null)
|
|
12
10
|
|
|
@@ -27,13 +25,8 @@ export const SwapSettings: React.FC = () => {
|
|
|
27
25
|
}
|
|
28
26
|
}, [isSettingsDropdownOpen])
|
|
29
27
|
|
|
30
|
-
const handleModeSelect = (isSimple: boolean) => {
|
|
31
|
-
setIsSimpleSwapModeWithStorage(isSimple)
|
|
32
|
-
setIsSettingsDropdownOpen(false)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
28
|
return (
|
|
36
|
-
<div
|
|
29
|
+
<div ref={settingsDropdownRef}>
|
|
37
30
|
<button
|
|
38
31
|
type="button"
|
|
39
32
|
onClick={() => setIsSettingsDropdownOpen(!isSettingsDropdownOpen)}
|
|
@@ -47,12 +40,7 @@ export const SwapSettings: React.FC = () => {
|
|
|
47
40
|
{isSettingsDropdownOpen && (
|
|
48
41
|
<div className="absolute right-0 top-full mt-2 w-80 trails-bg-card rounded-lg shadow-lg border trails-border-primary z-20">
|
|
49
42
|
<div className="p-4 space-y-4">
|
|
50
|
-
<
|
|
51
|
-
isSimpleMode={isSimpleSwapMode}
|
|
52
|
-
onModeChange={handleModeSelect}
|
|
53
|
-
/>
|
|
54
|
-
|
|
55
|
-
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
|
|
43
|
+
<div>
|
|
56
44
|
<SlippageToleranceSettings />
|
|
57
45
|
</div>
|
|
58
46
|
</div>
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import React, { useMemo } from "react"
|
|
2
2
|
import { ChainImage } from "./ChainImage.js"
|
|
3
3
|
import { getCommonTokenImageUrl } from "../../tokens.js"
|
|
4
|
+
import { logger } from "../../logger.js"
|
|
4
5
|
|
|
5
6
|
function normalizeImageUrl(
|
|
6
7
|
imageUrl?: string | null,
|
|
7
8
|
symbol?: string | null,
|
|
8
9
|
chainId?: number | null,
|
|
10
|
+
contractAddress?: string | null,
|
|
9
11
|
) {
|
|
10
12
|
if (symbol === "ETH") {
|
|
11
13
|
return "https://assets.sequence.info/images/tokens/large/1/0x0000000000000000000000000000000000000000.webp"
|
|
12
14
|
}
|
|
15
|
+
const commonImageUrl = getCommonTokenImageUrl({
|
|
16
|
+
symbol,
|
|
17
|
+
chainId,
|
|
18
|
+
contractAddress,
|
|
19
|
+
})
|
|
20
|
+
if (commonImageUrl) {
|
|
21
|
+
return commonImageUrl
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
if (imageUrl) {
|
|
14
25
|
return imageUrl.replace("/small/", "/large/")
|
|
15
|
-
} else if (symbol) {
|
|
16
|
-
return getCommonTokenImageUrl({ symbol, chainId })
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
return null
|
|
@@ -23,6 +32,7 @@ interface TokenImageProps {
|
|
|
23
32
|
imageUrl?: string | null
|
|
24
33
|
symbol?: string | null
|
|
25
34
|
chainId?: number | null
|
|
35
|
+
contractAddress?: string | null
|
|
26
36
|
size?: number
|
|
27
37
|
}
|
|
28
38
|
|
|
@@ -30,12 +40,19 @@ export const TokenImage: React.FC<TokenImageProps> = ({
|
|
|
30
40
|
imageUrl,
|
|
31
41
|
symbol,
|
|
32
42
|
chainId,
|
|
43
|
+
contractAddress,
|
|
33
44
|
size = 24,
|
|
34
45
|
}) => {
|
|
35
46
|
const [imageError, setImageError] = React.useState(false)
|
|
36
47
|
const effectiveImageUrl = useMemo(() => {
|
|
37
|
-
|
|
38
|
-
|
|
48
|
+
logger.console.log("[TokenImage] normalizeImageUrl", {
|
|
49
|
+
imageUrl,
|
|
50
|
+
symbol,
|
|
51
|
+
chainId,
|
|
52
|
+
contractAddress,
|
|
53
|
+
})
|
|
54
|
+
return normalizeImageUrl(imageUrl, symbol, chainId, contractAddress)
|
|
55
|
+
}, [imageUrl, symbol, chainId, contractAddress])
|
|
39
56
|
|
|
40
57
|
const displaySymbol = symbol?.[0]?.toUpperCase() || "?"
|
|
41
58
|
|
|
@@ -120,7 +120,7 @@ export const TokenSelector: React.FC<TokenSelectorProps> = ({
|
|
|
120
120
|
// Then apply search filtering
|
|
121
121
|
if (!searchQuery.trim()) return true
|
|
122
122
|
|
|
123
|
-
const query = searchQuery.toLowerCase()
|
|
123
|
+
const query = searchQuery.trim().toLowerCase()
|
|
124
124
|
return (
|
|
125
125
|
recentToken.symbol.toLowerCase().includes(query) ||
|
|
126
126
|
recentToken.name.toLowerCase().includes(query) ||
|
|
@@ -295,6 +295,7 @@ export const TokenSelector: React.FC<TokenSelectorProps> = ({
|
|
|
295
295
|
symbol={symbol}
|
|
296
296
|
imageUrl={imageUrl}
|
|
297
297
|
chainId={chainId}
|
|
298
|
+
contractAddress={contractAddress}
|
|
298
299
|
size={32}
|
|
299
300
|
/>
|
|
300
301
|
) : (
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ChevronRight } from "lucide-react"
|
|
2
|
+
import type React from "react"
|
|
3
|
+
import { useMemo } from "react"
|
|
4
|
+
import { TokenImage } from "./TokenImage.js"
|
|
5
|
+
import { getChainInfo } from "../../chains.js"
|
|
6
|
+
|
|
7
|
+
interface TokenSelectorButtonProps {
|
|
8
|
+
token?: {
|
|
9
|
+
symbol: string
|
|
10
|
+
imageUrl?: string
|
|
11
|
+
contractAddress?: string
|
|
12
|
+
chainId?: number | null
|
|
13
|
+
} | null
|
|
14
|
+
chainId?: number | null
|
|
15
|
+
onSelect: () => void
|
|
16
|
+
className?: string
|
|
17
|
+
unselectable?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const TokenSelectorButton: React.FC<TokenSelectorButtonProps> = ({
|
|
21
|
+
token,
|
|
22
|
+
chainId,
|
|
23
|
+
onSelect,
|
|
24
|
+
className = "flex items-center space-x-2 trails-border-radius-input px-2.5 py-1.5 border transition-colors",
|
|
25
|
+
unselectable = false,
|
|
26
|
+
}) => {
|
|
27
|
+
const displayChainId = token?.chainId || chainId
|
|
28
|
+
|
|
29
|
+
const chainInfo = useMemo(() => {
|
|
30
|
+
return displayChainId ? getChainInfo(displayChainId) : null
|
|
31
|
+
}, [displayChainId])
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<button
|
|
35
|
+
type="button"
|
|
36
|
+
onClick={unselectable ? undefined : onSelect}
|
|
37
|
+
disabled={unselectable}
|
|
38
|
+
className={`${className} ${
|
|
39
|
+
token
|
|
40
|
+
? "trails-bg-card hover:trails-hover-bg trails-border-primary"
|
|
41
|
+
: "bg-blue-500 hover:bg-blue-600 border-blue-500 text-white"
|
|
42
|
+
} ${unselectable ? "cursor-default" : "cursor-pointer"}`}
|
|
43
|
+
>
|
|
44
|
+
{token ? (
|
|
45
|
+
<>
|
|
46
|
+
<TokenImage
|
|
47
|
+
symbol={token.symbol}
|
|
48
|
+
imageUrl={token.imageUrl}
|
|
49
|
+
chainId={displayChainId}
|
|
50
|
+
contractAddress={token.contractAddress}
|
|
51
|
+
size={28}
|
|
52
|
+
/>
|
|
53
|
+
<div className="flex flex-col items-start">
|
|
54
|
+
<span className="font-bold trails-text-primary text-sm">
|
|
55
|
+
{token.symbol}
|
|
56
|
+
</span>
|
|
57
|
+
{chainInfo && (
|
|
58
|
+
<span className="text-xs trails-text-muted">
|
|
59
|
+
{chainInfo.name}
|
|
60
|
+
</span>
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
{!unselectable && (
|
|
64
|
+
<ChevronRight className="w-3.5 h-3.5 trails-text-muted" />
|
|
65
|
+
)}
|
|
66
|
+
</>
|
|
67
|
+
) : (
|
|
68
|
+
<>
|
|
69
|
+
<span className="font-medium text-sm text-white">Select Token</span>
|
|
70
|
+
{!unselectable && <ChevronRight className="w-3.5 h-3.5 text-white" />}
|
|
71
|
+
</>
|
|
72
|
+
)}
|
|
73
|
+
</button>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ChevronDown, RotateCcw } from "lucide-react"
|
|
2
2
|
import type React from "react"
|
|
3
3
|
import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
|
|
4
|
-
import { useSwapSettings } from "../hooks/useSwapSettings.js"
|
|
5
4
|
import { useThemePreference } from "../hooks/useTheme.js"
|
|
6
5
|
import { useWidgetProps } from "../hooks/useWidgetProps.js"
|
|
7
6
|
import { ScreenHeader } from "./ScreenHeader.js"
|
|
7
|
+
import { SlippageToleranceSettings } from "./SlippageToleranceSettings.js"
|
|
8
8
|
import { logger } from "../../logger.js"
|
|
9
9
|
|
|
10
10
|
interface UserPreferencesProps {
|
|
@@ -14,7 +14,6 @@ interface UserPreferencesProps {
|
|
|
14
14
|
export const UserPreferences: React.FC<UserPreferencesProps> = ({ onBack }) => {
|
|
15
15
|
const { isBalanceVisible, toggleBalanceVisible, resetBalanceVisible } =
|
|
16
16
|
useBalanceVisible()
|
|
17
|
-
const { resetSwapSettings } = useSwapSettings()
|
|
18
17
|
const { selectedTheme, setSelectedTheme, resetThemePreference } =
|
|
19
18
|
useThemePreference()
|
|
20
19
|
const { customCss, theme: widgetTheme } = useWidgetProps()
|
|
@@ -31,7 +30,6 @@ export const UserPreferences: React.FC<UserPreferencesProps> = ({ onBack }) => {
|
|
|
31
30
|
try {
|
|
32
31
|
// Reset all preferences using their respective hook methods
|
|
33
32
|
resetBalanceVisible()
|
|
34
|
-
resetSwapSettings()
|
|
35
33
|
resetThemePreference()
|
|
36
34
|
|
|
37
35
|
logger.console.log(
|
|
@@ -51,7 +49,6 @@ export const UserPreferences: React.FC<UserPreferencesProps> = ({ onBack }) => {
|
|
|
51
49
|
headerContent="User Preferences"
|
|
52
50
|
headerContentAlign="left"
|
|
53
51
|
onBack={onBack}
|
|
54
|
-
showAccountActions={false}
|
|
55
52
|
/>
|
|
56
53
|
|
|
57
54
|
<div className="space-y-6">
|
|
@@ -75,26 +72,6 @@ export const UserPreferences: React.FC<UserPreferencesProps> = ({ onBack }) => {
|
|
|
75
72
|
</button>
|
|
76
73
|
</div>
|
|
77
74
|
|
|
78
|
-
{/* Simple Swap UI Setting */}
|
|
79
|
-
{/* <div className="flex items-center justify-between">
|
|
80
|
-
<span className="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
81
|
-
Simple Swap UI
|
|
82
|
-
</span>
|
|
83
|
-
<button
|
|
84
|
-
type="button"
|
|
85
|
-
onClick={toggleSimpleSwapMode}
|
|
86
|
-
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
|
|
87
|
-
isSimpleSwapMode ? "bg-blue-600" : "bg-gray-200 dark:bg-gray-700"
|
|
88
|
-
}`}
|
|
89
|
-
>
|
|
90
|
-
<span
|
|
91
|
-
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
|
|
92
|
-
isSimpleSwapMode ? "translate-x-6" : "translate-x-1"
|
|
93
|
-
}`}
|
|
94
|
-
/>
|
|
95
|
-
</button>
|
|
96
|
-
</div> */}
|
|
97
|
-
|
|
98
75
|
{/* Theme Setting */}
|
|
99
76
|
<div className="flex items-center justify-between">
|
|
100
77
|
<span
|
|
@@ -136,6 +113,11 @@ export const UserPreferences: React.FC<UserPreferencesProps> = ({ onBack }) => {
|
|
|
136
113
|
</div>
|
|
137
114
|
</div>
|
|
138
115
|
|
|
116
|
+
{/* Slippage Tolerance Settings */}
|
|
117
|
+
<div className="pt-2">
|
|
118
|
+
<SlippageToleranceSettings />
|
|
119
|
+
</div>
|
|
120
|
+
|
|
139
121
|
{/* Reset Preferences Button */}
|
|
140
122
|
<div className="pt-4 dark:border-gray-700">
|
|
141
123
|
<button
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
import { useWaasFeeOptions } from "@0xsequence/connect"
|
|
3
|
+
import { TokenImage } from "./TokenImage.js"
|
|
4
|
+
import { ChevronDown, ChevronUp } from "lucide-react"
|
|
5
|
+
import { formatUnits } from "viem"
|
|
6
|
+
|
|
7
|
+
// Define types based on the @0xsequence/connect documentation
|
|
8
|
+
interface FeeToken {
|
|
9
|
+
symbol: string
|
|
10
|
+
contractAddress?: string
|
|
11
|
+
name?: string
|
|
12
|
+
decimals?: number
|
|
13
|
+
imageUrl?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface FeeOption {
|
|
17
|
+
token: FeeToken
|
|
18
|
+
amount?: string
|
|
19
|
+
amountUSD?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface FeeOptionExtended extends FeeOption {
|
|
23
|
+
balance: string
|
|
24
|
+
balanceFormatted: string
|
|
25
|
+
hasEnoughBalanceForFee: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface WaasFeeOptionsProps {
|
|
29
|
+
chainId?: number
|
|
30
|
+
setIsFeeOptionConfirmed: (isFeeOptionConfirmed: boolean) => void
|
|
31
|
+
onFeeOptionsLoaded?: () => void
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
|
|
35
|
+
chainId,
|
|
36
|
+
setIsFeeOptionConfirmed,
|
|
37
|
+
onFeeOptionsLoaded,
|
|
38
|
+
}) => {
|
|
39
|
+
const [
|
|
40
|
+
pendingFeeOptionConfirmation,
|
|
41
|
+
confirmPendingFeeOption,
|
|
42
|
+
rejectPendingFeeOption,
|
|
43
|
+
] = useWaasFeeOptions({ chainIdOverride: chainId })
|
|
44
|
+
|
|
45
|
+
const [selectedFeeOptionTokenName, setSelectedFeeOptionTokenName] =
|
|
46
|
+
useState<string>()
|
|
47
|
+
const [isExpanded, setIsExpanded] = useState(false)
|
|
48
|
+
const [isProcessing, setIsProcessing] = useState(false)
|
|
49
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
50
|
+
|
|
51
|
+
// Debug logging
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
console.log("[trails-sdk] WaasFeeOptions component mounted/updated:", {
|
|
54
|
+
chainId,
|
|
55
|
+
pendingFeeOptionConfirmation: !!pendingFeeOptionConfirmation,
|
|
56
|
+
optionsCount: pendingFeeOptionConfirmation?.options?.length || 0,
|
|
57
|
+
hasOptions: !!pendingFeeOptionConfirmation?.options,
|
|
58
|
+
confirmationId: pendingFeeOptionConfirmation?.id,
|
|
59
|
+
isLoading,
|
|
60
|
+
isProcessing,
|
|
61
|
+
})
|
|
62
|
+
}, [chainId, pendingFeeOptionConfirmation, isLoading, isProcessing])
|
|
63
|
+
|
|
64
|
+
// Log when component renders but has no pending confirmation
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!pendingFeeOptionConfirmation) {
|
|
67
|
+
console.log(
|
|
68
|
+
"[trails-sdk] WaasFeeOptions: No pending fee confirmation - this is normal until a transaction requires fee payment",
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}, [pendingFeeOptionConfirmation])
|
|
72
|
+
|
|
73
|
+
// Manage loading state
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (
|
|
76
|
+
pendingFeeOptionConfirmation &&
|
|
77
|
+
pendingFeeOptionConfirmation.options?.length > 0
|
|
78
|
+
) {
|
|
79
|
+
setIsLoading(false)
|
|
80
|
+
} else if (
|
|
81
|
+
pendingFeeOptionConfirmation &&
|
|
82
|
+
(!pendingFeeOptionConfirmation.options ||
|
|
83
|
+
pendingFeeOptionConfirmation.options.length === 0)
|
|
84
|
+
) {
|
|
85
|
+
setIsLoading(true)
|
|
86
|
+
}
|
|
87
|
+
}, [pendingFeeOptionConfirmation])
|
|
88
|
+
|
|
89
|
+
// Initialize with first option when fee options become available
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (pendingFeeOptionConfirmation) {
|
|
92
|
+
console.log(
|
|
93
|
+
"[trails-sdk] Pending fee options: ",
|
|
94
|
+
pendingFeeOptionConfirmation.options,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
// Notify parent that fee options are loaded
|
|
98
|
+
if (
|
|
99
|
+
onFeeOptionsLoaded &&
|
|
100
|
+
pendingFeeOptionConfirmation.options?.length > 0
|
|
101
|
+
) {
|
|
102
|
+
onFeeOptionsLoaded()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Select the first fee option by default
|
|
106
|
+
if (pendingFeeOptionConfirmation.options.length > 0) {
|
|
107
|
+
const firstOption = pendingFeeOptionConfirmation.options.filter(
|
|
108
|
+
(option: any) => option.hasEnoughBalanceForFee,
|
|
109
|
+
)[0]
|
|
110
|
+
if (firstOption?.token?.symbol) {
|
|
111
|
+
setSelectedFeeOptionTokenName(firstOption.token.symbol)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}, [pendingFeeOptionConfirmation, onFeeOptionsLoaded])
|
|
116
|
+
|
|
117
|
+
// Handle fee option selection and confirmation
|
|
118
|
+
const handleConfirmFee = async (tokenAddress: string | null) => {
|
|
119
|
+
if (pendingFeeOptionConfirmation && !isProcessing) {
|
|
120
|
+
setIsProcessing(true)
|
|
121
|
+
try {
|
|
122
|
+
confirmPendingFeeOption(pendingFeeOptionConfirmation.id, tokenAddress)
|
|
123
|
+
setIsFeeOptionConfirmed(true)
|
|
124
|
+
} finally {
|
|
125
|
+
setIsProcessing(false)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Handle fee option rejection
|
|
131
|
+
const handleRejectFee = async () => {
|
|
132
|
+
if (pendingFeeOptionConfirmation && !isProcessing) {
|
|
133
|
+
setIsProcessing(true)
|
|
134
|
+
try {
|
|
135
|
+
rejectPendingFeeOption(pendingFeeOptionConfirmation.id)
|
|
136
|
+
} finally {
|
|
137
|
+
setIsProcessing(false)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Don't render if no pending fee confirmation
|
|
143
|
+
if (!pendingFeeOptionConfirmation) {
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Show loading when we have confirmation but no options yet
|
|
148
|
+
if (isLoading) {
|
|
149
|
+
return (
|
|
150
|
+
<div className="flex items-center justify-center py-8">
|
|
151
|
+
<div className="flex flex-col items-center space-y-3">
|
|
152
|
+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-trails-primary"></div>
|
|
153
|
+
<p className="text-sm trails-text-muted">Loading fee options...</p>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const selectedOption = pendingFeeOptionConfirmation.options
|
|
160
|
+
.filter((option: any) => option.hasEnoughBalanceForFee)
|
|
161
|
+
.find((option) => option.token.symbol === selectedFeeOptionTokenName) as
|
|
162
|
+
| FeeOptionExtended
|
|
163
|
+
| undefined
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<div className="space-y-2">
|
|
167
|
+
{/* Header */}
|
|
168
|
+
<div className="flex items-center justify-between">
|
|
169
|
+
<div className="text-sm font-medium trails-text-primary">
|
|
170
|
+
Select Fee Payment Token
|
|
171
|
+
</div>
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
175
|
+
className="flex items-center space-x-1 text-xs trails-text-muted hover:trails-text-primary transition-colors cursor-pointer"
|
|
176
|
+
>
|
|
177
|
+
<span>{isExpanded ? "Hide" : "Show"} options</span>
|
|
178
|
+
{isExpanded ? (
|
|
179
|
+
<ChevronUp className="w-3 h-3" />
|
|
180
|
+
) : (
|
|
181
|
+
<ChevronDown className="w-3 h-3" />
|
|
182
|
+
)}
|
|
183
|
+
</button>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
{/* Selected Option Display */}
|
|
187
|
+
{selectedOption?.hasEnoughBalanceForFee && (
|
|
188
|
+
<div className="trails-bg-secondary trails-border-radius-container p-3">
|
|
189
|
+
<div className="flex items-center justify-between">
|
|
190
|
+
<div className="flex items-center space-x-2">
|
|
191
|
+
<TokenImage
|
|
192
|
+
symbol={selectedOption.token.symbol}
|
|
193
|
+
imageUrl={(selectedOption.token as any).logoURL}
|
|
194
|
+
chainId={chainId}
|
|
195
|
+
size={20}
|
|
196
|
+
/>
|
|
197
|
+
<div className="text-left">
|
|
198
|
+
<div className="font-medium trails-text-primary text-sm">
|
|
199
|
+
{selectedOption.token.symbol}
|
|
200
|
+
</div>
|
|
201
|
+
<div className="text-xs trails-text-muted">
|
|
202
|
+
{selectedOption.token.contractAddress
|
|
203
|
+
? `${selectedOption.token.contractAddress.slice(0, 6)}...${selectedOption.token.contractAddress.slice(-4)}`
|
|
204
|
+
: "Native Token"}
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
{/* Display balance info if available */}
|
|
209
|
+
{selectedOption && "balanceFormatted" in selectedOption && (
|
|
210
|
+
<div className="text-right">
|
|
211
|
+
<div className="text-xs trails-text-muted">
|
|
212
|
+
Balance: {String(selectedOption.balanceFormatted)}
|
|
213
|
+
</div>
|
|
214
|
+
{!selectedOption.hasEnoughBalanceForFee && (
|
|
215
|
+
<div className="text-xs text-red-500">
|
|
216
|
+
Insufficient balance
|
|
217
|
+
</div>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
|
|
225
|
+
{/* Expanded Options */}
|
|
226
|
+
{isExpanded && (
|
|
227
|
+
<div className="space-y-2">
|
|
228
|
+
{pendingFeeOptionConfirmation.options
|
|
229
|
+
.filter((option: any) => option.hasEnoughBalanceForFee)
|
|
230
|
+
.map((option) => (
|
|
231
|
+
<label
|
|
232
|
+
key={option.token.symbol || option.token.contractAddress}
|
|
233
|
+
className={`flex items-center space-x-3 p-3 rounded-lg border cursor-pointer transition-colors ${
|
|
234
|
+
selectedFeeOptionTokenName === option.token.symbol
|
|
235
|
+
? "trails-bg-primary/10 border-trails-primary"
|
|
236
|
+
: "trails-bg-secondary hover:trails-hover-bg border-transparent"
|
|
237
|
+
}`}
|
|
238
|
+
>
|
|
239
|
+
<input
|
|
240
|
+
type="radio"
|
|
241
|
+
name="feeOption"
|
|
242
|
+
checked={selectedFeeOptionTokenName === option.token.symbol}
|
|
243
|
+
onChange={() =>
|
|
244
|
+
setSelectedFeeOptionTokenName(option.token.symbol)
|
|
245
|
+
}
|
|
246
|
+
className="w-4 h-4 text-trails-primary focus:ring-trails-primary"
|
|
247
|
+
/>
|
|
248
|
+
<div className="flex items-center space-x-2 flex-1">
|
|
249
|
+
<TokenImage
|
|
250
|
+
symbol={option.token.symbol}
|
|
251
|
+
imageUrl={(option.token as any).logoURL}
|
|
252
|
+
chainId={chainId}
|
|
253
|
+
size={20}
|
|
254
|
+
/>
|
|
255
|
+
<div className="flex-1 text-left">
|
|
256
|
+
<div className="font-medium trails-text-primary text-sm">
|
|
257
|
+
{option.token.symbol}
|
|
258
|
+
</div>
|
|
259
|
+
<div className="text-xs trails-text-muted">
|
|
260
|
+
{option.token.contractAddress
|
|
261
|
+
? `${option.token.contractAddress.slice(0, 6)}...${option.token.contractAddress.slice(-4)}`
|
|
262
|
+
: "Native Token"}
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
{/* Display balance info if available */}
|
|
267
|
+
{"balanceFormatted" in option && (
|
|
268
|
+
<div className="text-right">
|
|
269
|
+
<div className="text-xs trails-text-muted">
|
|
270
|
+
Balance: {String(option.balanceFormatted)}
|
|
271
|
+
</div>
|
|
272
|
+
<div className="text-xs trails-text-muted">
|
|
273
|
+
Cost:{" "}
|
|
274
|
+
{String(
|
|
275
|
+
formatUnits(
|
|
276
|
+
BigInt(option.value),
|
|
277
|
+
option.token.decimals || 18,
|
|
278
|
+
),
|
|
279
|
+
)}
|
|
280
|
+
</div>
|
|
281
|
+
{!("hasEnoughBalanceForFee" in option) ||
|
|
282
|
+
!option.hasEnoughBalanceForFee ? (
|
|
283
|
+
<div className="text-xs text-red-500">Insufficient</div>
|
|
284
|
+
) : null}
|
|
285
|
+
</div>
|
|
286
|
+
)}
|
|
287
|
+
</label>
|
|
288
|
+
))}
|
|
289
|
+
</div>
|
|
290
|
+
)}
|
|
291
|
+
|
|
292
|
+
{/* Action Buttons */}
|
|
293
|
+
<div className="flex space-x-3">
|
|
294
|
+
<button
|
|
295
|
+
type="button"
|
|
296
|
+
onClick={() =>
|
|
297
|
+
handleConfirmFee(selectedOption?.token.contractAddress || null)
|
|
298
|
+
}
|
|
299
|
+
disabled={!selectedOption || isProcessing}
|
|
300
|
+
className="flex-1 py-3 px-6 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:text-gray-500 text-white font-semibold rounded-lg transition-all duration-200 cursor-pointer disabled:cursor-not-allowed shadow-sm hover:shadow-md disabled:shadow-none flex items-center justify-center"
|
|
301
|
+
>
|
|
302
|
+
{isProcessing ? (
|
|
303
|
+
<>
|
|
304
|
+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
|
305
|
+
Processing...
|
|
306
|
+
</>
|
|
307
|
+
) : (
|
|
308
|
+
"Confirm Fee"
|
|
309
|
+
)}
|
|
310
|
+
</button>
|
|
311
|
+
<button
|
|
312
|
+
type="button"
|
|
313
|
+
onClick={handleRejectFee}
|
|
314
|
+
disabled={isProcessing}
|
|
315
|
+
className="px-6 py-3 bg-gray-100 hover:bg-gray-200 disabled:bg-gray-50 text-gray-700 font-semibold rounded-lg transition-all duration-200 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 flex items-center justify-center border border-gray-300"
|
|
316
|
+
>
|
|
317
|
+
{isProcessing ? (
|
|
318
|
+
<>
|
|
319
|
+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-500 mr-2"></div>
|
|
320
|
+
Processing...
|
|
321
|
+
</>
|
|
322
|
+
) : (
|
|
323
|
+
"Cancel"
|
|
324
|
+
)}
|
|
325
|
+
</button>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export default WaasFeeOptions
|