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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type React from "react"
|
|
2
|
+
import { TooltipPrimitive } from "@0xsequence/design-system"
|
|
3
|
+
import { useTheme } from "./ThemeProvider.js"
|
|
4
|
+
|
|
5
|
+
interface TooltipProps {
|
|
6
|
+
message: string
|
|
7
|
+
children: React.ReactNode
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Tooltip: React.FC<TooltipProps> = ({
|
|
12
|
+
message,
|
|
13
|
+
children,
|
|
14
|
+
className = "",
|
|
15
|
+
}) => {
|
|
16
|
+
const { isDark } = useTheme()
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<TooltipPrimitive.Provider>
|
|
20
|
+
<TooltipPrimitive.Root delayDuration={0}>
|
|
21
|
+
<TooltipPrimitive.Trigger asChild>
|
|
22
|
+
<div className={className}>{children}</div>
|
|
23
|
+
</TooltipPrimitive.Trigger>
|
|
24
|
+
<TooltipPrimitive.Portal>
|
|
25
|
+
<TooltipPrimitive.Content
|
|
26
|
+
className="trails-border-radius-container px-3 py-2 text-xs font-medium shadow-lg z-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
|
|
27
|
+
style={{
|
|
28
|
+
maxWidth: "400px",
|
|
29
|
+
wordWrap: "break-word",
|
|
30
|
+
whiteSpace: "normal",
|
|
31
|
+
overflowWrap: "break-word",
|
|
32
|
+
backgroundColor: isDark ? "#111827" : "#ffffff", // gray-900 or white
|
|
33
|
+
color: isDark ? "#ffffff" : "#000000", // white or black
|
|
34
|
+
}}
|
|
35
|
+
side="top"
|
|
36
|
+
align="center"
|
|
37
|
+
sideOffset={4}
|
|
38
|
+
alignOffset={0}
|
|
39
|
+
>
|
|
40
|
+
{message}
|
|
41
|
+
<TooltipPrimitive.Arrow
|
|
42
|
+
style={{ fill: isDark ? "#111827" : "#ffffff" }} // gray-900 or white
|
|
43
|
+
/>
|
|
44
|
+
</TooltipPrimitive.Content>
|
|
45
|
+
</TooltipPrimitive.Portal>
|
|
46
|
+
</TooltipPrimitive.Root>
|
|
47
|
+
</TooltipPrimitive.Provider>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default Tooltip
|
|
@@ -483,7 +483,7 @@ export const TransferPending: React.FC<TransferPendingProps> = ({
|
|
|
483
483
|
}`}
|
|
484
484
|
>
|
|
485
485
|
<div className="mt-4">
|
|
486
|
-
<QuoteDetails quote={quote} showContent={true} />
|
|
486
|
+
<QuoteDetails quote={quote} showContent={true} compact={true} />
|
|
487
487
|
</div>
|
|
488
488
|
</div>
|
|
489
489
|
|
|
@@ -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,450 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
import { useWaasFeeOptions } from "@0xsequence/connect"
|
|
3
|
+
import { TokenImage } from "./TokenImage.js"
|
|
4
|
+
import { ChevronDown, ChevronUp, Copy } 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
|
+
setIsError?: (isError: boolean) => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
|
|
36
|
+
chainId,
|
|
37
|
+
setIsFeeOptionConfirmed,
|
|
38
|
+
onFeeOptionsLoaded,
|
|
39
|
+
setIsError,
|
|
40
|
+
}) => {
|
|
41
|
+
const [
|
|
42
|
+
pendingFeeOptionConfirmation,
|
|
43
|
+
confirmPendingFeeOption,
|
|
44
|
+
rejectPendingFeeOption,
|
|
45
|
+
] = useWaasFeeOptions({ chainIdOverride: chainId })
|
|
46
|
+
|
|
47
|
+
const [selectedFeeOptionTokenName, setSelectedFeeOptionTokenName] =
|
|
48
|
+
useState<string>()
|
|
49
|
+
const [isExpanded, setIsExpanded] = useState(false)
|
|
50
|
+
const [isProcessing, setIsProcessing] = useState(false)
|
|
51
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
52
|
+
const [copiedAddress, setCopiedAddress] = useState<string | null>(null)
|
|
53
|
+
|
|
54
|
+
// Debug logging
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
console.log("[trails-sdk] WaasFeeOptions component mounted/updated:", {
|
|
57
|
+
chainId,
|
|
58
|
+
pendingFeeOptionConfirmation: !!pendingFeeOptionConfirmation,
|
|
59
|
+
optionsCount: pendingFeeOptionConfirmation?.options?.length || 0,
|
|
60
|
+
hasOptions: !!pendingFeeOptionConfirmation?.options,
|
|
61
|
+
confirmationId: pendingFeeOptionConfirmation?.id,
|
|
62
|
+
isLoading,
|
|
63
|
+
isProcessing,
|
|
64
|
+
})
|
|
65
|
+
}, [chainId, pendingFeeOptionConfirmation, isLoading, isProcessing])
|
|
66
|
+
|
|
67
|
+
// Log when component renders but has no pending confirmation
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!pendingFeeOptionConfirmation) {
|
|
70
|
+
console.log(
|
|
71
|
+
"[trails-sdk] WaasFeeOptions: No pending fee confirmation - this is normal until a transaction requires fee payment",
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}, [pendingFeeOptionConfirmation])
|
|
75
|
+
|
|
76
|
+
// Manage loading state
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (
|
|
79
|
+
pendingFeeOptionConfirmation &&
|
|
80
|
+
pendingFeeOptionConfirmation.options?.length > 0
|
|
81
|
+
) {
|
|
82
|
+
setIsLoading(false)
|
|
83
|
+
} else if (
|
|
84
|
+
pendingFeeOptionConfirmation &&
|
|
85
|
+
(!pendingFeeOptionConfirmation.options ||
|
|
86
|
+
pendingFeeOptionConfirmation.options.length === 0)
|
|
87
|
+
) {
|
|
88
|
+
setIsLoading(true)
|
|
89
|
+
}
|
|
90
|
+
}, [pendingFeeOptionConfirmation])
|
|
91
|
+
|
|
92
|
+
// Initialize with first option when fee options become available
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
setIsError?.(false)
|
|
95
|
+
if (pendingFeeOptionConfirmation) {
|
|
96
|
+
console.log(
|
|
97
|
+
"[trails-sdk] Pending fee options: ",
|
|
98
|
+
pendingFeeOptionConfirmation.options,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
// Notify parent that fee options are loaded
|
|
102
|
+
if (
|
|
103
|
+
onFeeOptionsLoaded &&
|
|
104
|
+
pendingFeeOptionConfirmation.options?.length > 0 &&
|
|
105
|
+
pendingFeeOptionConfirmation.options.find(
|
|
106
|
+
(option: any) => option.hasEnoughBalanceForFee,
|
|
107
|
+
)
|
|
108
|
+
) {
|
|
109
|
+
onFeeOptionsLoaded()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Select the first fee option by default
|
|
113
|
+
if (pendingFeeOptionConfirmation.options.length > 0) {
|
|
114
|
+
const firstOption = pendingFeeOptionConfirmation.options.filter(
|
|
115
|
+
(option: any) => option.hasEnoughBalanceForFee,
|
|
116
|
+
)[0]
|
|
117
|
+
if (firstOption?.token?.symbol) {
|
|
118
|
+
setSelectedFeeOptionTokenName(firstOption.token.symbol)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}, [pendingFeeOptionConfirmation, onFeeOptionsLoaded, setIsError])
|
|
123
|
+
|
|
124
|
+
// Handle fee option selection and confirmation
|
|
125
|
+
const handleConfirmFee = async (tokenAddress: string | null) => {
|
|
126
|
+
if (pendingFeeOptionConfirmation && !isProcessing) {
|
|
127
|
+
setIsProcessing(true)
|
|
128
|
+
try {
|
|
129
|
+
confirmPendingFeeOption(pendingFeeOptionConfirmation.id, tokenAddress)
|
|
130
|
+
setIsFeeOptionConfirmed(true)
|
|
131
|
+
} finally {
|
|
132
|
+
setIsProcessing(false)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Handle fee option rejection
|
|
138
|
+
const handleRejectFee = async () => {
|
|
139
|
+
if (pendingFeeOptionConfirmation && !isProcessing) {
|
|
140
|
+
setIsProcessing(true)
|
|
141
|
+
try {
|
|
142
|
+
rejectPendingFeeOption(pendingFeeOptionConfirmation.id)
|
|
143
|
+
} finally {
|
|
144
|
+
setIsProcessing(false)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Handle copy address to clipboard
|
|
150
|
+
const handleCopyAddress = async (address: string, e: React.MouseEvent) => {
|
|
151
|
+
e.preventDefault()
|
|
152
|
+
e.stopPropagation()
|
|
153
|
+
try {
|
|
154
|
+
await navigator.clipboard.writeText(address)
|
|
155
|
+
setCopiedAddress(address)
|
|
156
|
+
setTimeout(() => setCopiedAddress(null), 2000)
|
|
157
|
+
} catch (error) {
|
|
158
|
+
try {
|
|
159
|
+
const textArea = document.createElement("textarea")
|
|
160
|
+
textArea.value = address
|
|
161
|
+
document.body.appendChild(textArea)
|
|
162
|
+
textArea.select()
|
|
163
|
+
document.execCommand("copy")
|
|
164
|
+
document.body.removeChild(textArea)
|
|
165
|
+
setCopiedAddress(address)
|
|
166
|
+
setTimeout(() => setCopiedAddress(null), 2000)
|
|
167
|
+
} catch (fallbackError) {
|
|
168
|
+
console.error("Fallback copy failed:", fallbackError)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Don't render if no pending fee confirmation
|
|
174
|
+
if (!pendingFeeOptionConfirmation) {
|
|
175
|
+
return null
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Show loading when we have confirmation but no options yet
|
|
179
|
+
if (isLoading) {
|
|
180
|
+
return (
|
|
181
|
+
<div className="flex items-center justify-center py-8">
|
|
182
|
+
<div className="flex flex-col items-center space-y-3">
|
|
183
|
+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-trails-primary"></div>
|
|
184
|
+
<p className="text-sm trails-text-muted">Loading fee options...</p>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const selectedOption = pendingFeeOptionConfirmation.options
|
|
191
|
+
.filter((option: any) => option.hasEnoughBalanceForFee)
|
|
192
|
+
.find((option) => option.token.symbol === selectedFeeOptionTokenName) as
|
|
193
|
+
| FeeOptionExtended
|
|
194
|
+
| undefined
|
|
195
|
+
|
|
196
|
+
const hasTokenForFee = pendingFeeOptionConfirmation.options.find(
|
|
197
|
+
(option: any) => option.hasEnoughBalanceForFee,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if (!hasTokenForFee) {
|
|
201
|
+
setIsError?.(true)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!hasTokenForFee) {
|
|
205
|
+
return (
|
|
206
|
+
<div className="space-y-4 py-6">
|
|
207
|
+
<div className="text-center space-y-1">
|
|
208
|
+
<p className="text-xs trails-text-muted">
|
|
209
|
+
Fund your wallet with one of the following tokens
|
|
210
|
+
</p>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div className="flex flex-col space-y-2">
|
|
214
|
+
{pendingFeeOptionConfirmation.options.map((option: any) => {
|
|
215
|
+
const contractAddress = option.token.contractAddress
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<div
|
|
219
|
+
key={option.token.symbol || contractAddress}
|
|
220
|
+
className="flex items-center space-x-3 p-3 trails-bg-secondary trails-border-radius-container border border-transparent"
|
|
221
|
+
>
|
|
222
|
+
<div className="flex items-center shrink-0">
|
|
223
|
+
<TokenImage
|
|
224
|
+
symbol={option.token.symbol}
|
|
225
|
+
imageUrl={(option.token as any).logoURL}
|
|
226
|
+
chainId={chainId}
|
|
227
|
+
size={32}
|
|
228
|
+
/>
|
|
229
|
+
</div>
|
|
230
|
+
<div className="flex-1 min-w-0 flex flex-col items-start">
|
|
231
|
+
<span className="text-sm font-bold trails-text-primary leading-tight">
|
|
232
|
+
{option.token.symbol}
|
|
233
|
+
</span>
|
|
234
|
+
{contractAddress ? (
|
|
235
|
+
<div className="flex items-center space-x-1.5 mt-0.5">
|
|
236
|
+
<span className="text-xs trails-text-muted leading-tight">
|
|
237
|
+
{contractAddress.slice(0, 4)}...
|
|
238
|
+
{contractAddress.slice(-4)}
|
|
239
|
+
</span>
|
|
240
|
+
<button
|
|
241
|
+
type="button"
|
|
242
|
+
onClick={(e) => handleCopyAddress(contractAddress, e)}
|
|
243
|
+
className="shrink-0 p-0.5 rounded transition-colors cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 flex items-center justify-center"
|
|
244
|
+
title={
|
|
245
|
+
copiedAddress === contractAddress
|
|
246
|
+
? "Copied!"
|
|
247
|
+
: "Copy address"
|
|
248
|
+
}
|
|
249
|
+
>
|
|
250
|
+
{copiedAddress === contractAddress ? (
|
|
251
|
+
<svg
|
|
252
|
+
className="w-3 h-3 text-green-600 dark:text-green-400"
|
|
253
|
+
fill="none"
|
|
254
|
+
viewBox="0 0 24 24"
|
|
255
|
+
stroke="currentColor"
|
|
256
|
+
aria-label="Copied"
|
|
257
|
+
>
|
|
258
|
+
<path
|
|
259
|
+
strokeLinecap="round"
|
|
260
|
+
strokeLinejoin="round"
|
|
261
|
+
strokeWidth={2}
|
|
262
|
+
d="M5 13l4 4L19 7"
|
|
263
|
+
/>
|
|
264
|
+
</svg>
|
|
265
|
+
) : (
|
|
266
|
+
<Copy className="w-3 h-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" />
|
|
267
|
+
)}
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
) : (
|
|
271
|
+
<span className="text-xs trails-text-muted mt-0.5 leading-tight">
|
|
272
|
+
Native Token
|
|
273
|
+
</span>
|
|
274
|
+
)}
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
)
|
|
278
|
+
})}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<div className="space-y-2">
|
|
286
|
+
{/* Header */}
|
|
287
|
+
<div className="flex items-center justify-between">
|
|
288
|
+
<div className="text-sm font-medium trails-text-primary">
|
|
289
|
+
Select Fee Payment Token
|
|
290
|
+
</div>
|
|
291
|
+
<button
|
|
292
|
+
type="button"
|
|
293
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
294
|
+
className="flex items-center space-x-1 text-xs trails-text-muted hover:trails-text-primary transition-colors cursor-pointer"
|
|
295
|
+
>
|
|
296
|
+
<span>{isExpanded ? "Hide" : "Show"} options</span>
|
|
297
|
+
{isExpanded ? (
|
|
298
|
+
<ChevronUp className="w-3 h-3" />
|
|
299
|
+
) : (
|
|
300
|
+
<ChevronDown className="w-3 h-3" />
|
|
301
|
+
)}
|
|
302
|
+
</button>
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
{/* Selected Option Display */}
|
|
306
|
+
{selectedOption?.hasEnoughBalanceForFee && (
|
|
307
|
+
<div className="trails-bg-secondary trails-border-radius-container p-3">
|
|
308
|
+
<div className="flex items-center justify-between">
|
|
309
|
+
<div className="flex items-center space-x-2">
|
|
310
|
+
<TokenImage
|
|
311
|
+
symbol={selectedOption.token.symbol}
|
|
312
|
+
imageUrl={(selectedOption.token as any).logoURL}
|
|
313
|
+
chainId={chainId}
|
|
314
|
+
size={20}
|
|
315
|
+
/>
|
|
316
|
+
<div className="text-left">
|
|
317
|
+
<div className="font-medium trails-text-primary text-sm">
|
|
318
|
+
{selectedOption.token.symbol}
|
|
319
|
+
</div>
|
|
320
|
+
<div className="text-xs trails-text-muted">
|
|
321
|
+
{selectedOption.token.contractAddress
|
|
322
|
+
? `${selectedOption.token.contractAddress.slice(0, 6)}...${selectedOption.token.contractAddress.slice(-4)}`
|
|
323
|
+
: "Native Token"}
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
{/* Display balance info if available */}
|
|
328
|
+
{selectedOption && "balanceFormatted" in selectedOption && (
|
|
329
|
+
<div className="text-right">
|
|
330
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
331
|
+
Balance: {String(selectedOption.balanceFormatted)}
|
|
332
|
+
</div>
|
|
333
|
+
{!selectedOption.hasEnoughBalanceForFee && (
|
|
334
|
+
<div className="text-xs text-red-500">
|
|
335
|
+
Insufficient balance
|
|
336
|
+
</div>
|
|
337
|
+
)}
|
|
338
|
+
</div>
|
|
339
|
+
)}
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
)}
|
|
343
|
+
|
|
344
|
+
{/* Expanded Options */}
|
|
345
|
+
{isExpanded && (
|
|
346
|
+
<div className="space-y-2">
|
|
347
|
+
{pendingFeeOptionConfirmation.options
|
|
348
|
+
.filter((option: any) => option.hasEnoughBalanceForFee)
|
|
349
|
+
.map((option) => (
|
|
350
|
+
<label
|
|
351
|
+
key={option.token.symbol || option.token.contractAddress}
|
|
352
|
+
className={`flex items-center space-x-3 p-3 rounded-lg border cursor-pointer transition-colors ${
|
|
353
|
+
selectedFeeOptionTokenName === option.token.symbol
|
|
354
|
+
? "trails-bg-primary/10 border-trails-primary"
|
|
355
|
+
: "trails-bg-secondary hover:trails-hover-bg border-transparent"
|
|
356
|
+
}`}
|
|
357
|
+
>
|
|
358
|
+
<input
|
|
359
|
+
type="radio"
|
|
360
|
+
name="feeOption"
|
|
361
|
+
checked={selectedFeeOptionTokenName === option.token.symbol}
|
|
362
|
+
onChange={() =>
|
|
363
|
+
setSelectedFeeOptionTokenName(option.token.symbol)
|
|
364
|
+
}
|
|
365
|
+
className="w-4 h-4 text-trails-primary focus:ring-trails-primary"
|
|
366
|
+
/>
|
|
367
|
+
<div className="flex items-center space-x-2 flex-1">
|
|
368
|
+
<TokenImage
|
|
369
|
+
symbol={option.token.symbol}
|
|
370
|
+
imageUrl={(option.token as any).logoURL}
|
|
371
|
+
chainId={chainId}
|
|
372
|
+
size={20}
|
|
373
|
+
/>
|
|
374
|
+
<div className="flex-1 text-left">
|
|
375
|
+
<div className="font-medium trails-text-primary text-sm">
|
|
376
|
+
{option.token.symbol}
|
|
377
|
+
</div>
|
|
378
|
+
<div className="text-xs trails-text-muted">
|
|
379
|
+
{option.token.contractAddress
|
|
380
|
+
? `${option.token.contractAddress.slice(0, 6)}...${option.token.contractAddress.slice(-4)}`
|
|
381
|
+
: "Native Token"}
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
{/* Display balance info if available */}
|
|
386
|
+
{"balanceFormatted" in option && (
|
|
387
|
+
<div className="text-right">
|
|
388
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
389
|
+
Balance: {String(option.balanceFormatted)}
|
|
390
|
+
</div>
|
|
391
|
+
<div className="text-xs trails-text-muted">
|
|
392
|
+
Cost:{" "}
|
|
393
|
+
{String(
|
|
394
|
+
formatUnits(
|
|
395
|
+
BigInt(option.value),
|
|
396
|
+
option.token.decimals || 18,
|
|
397
|
+
),
|
|
398
|
+
)}
|
|
399
|
+
</div>
|
|
400
|
+
{!("hasEnoughBalanceForFee" in option) ||
|
|
401
|
+
!option.hasEnoughBalanceForFee ? (
|
|
402
|
+
<div className="text-xs text-red-500">Insufficient</div>
|
|
403
|
+
) : null}
|
|
404
|
+
</div>
|
|
405
|
+
)}
|
|
406
|
+
</label>
|
|
407
|
+
))}
|
|
408
|
+
</div>
|
|
409
|
+
)}
|
|
410
|
+
|
|
411
|
+
{/* Action Buttons */}
|
|
412
|
+
<div className="flex space-x-3">
|
|
413
|
+
<button
|
|
414
|
+
type="button"
|
|
415
|
+
onClick={() =>
|
|
416
|
+
handleConfirmFee(selectedOption?.token.contractAddress || null)
|
|
417
|
+
}
|
|
418
|
+
disabled={!selectedOption || isProcessing}
|
|
419
|
+
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"
|
|
420
|
+
>
|
|
421
|
+
{isProcessing ? (
|
|
422
|
+
<>
|
|
423
|
+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
|
424
|
+
Processing...
|
|
425
|
+
</>
|
|
426
|
+
) : (
|
|
427
|
+
"Confirm Fee"
|
|
428
|
+
)}
|
|
429
|
+
</button>
|
|
430
|
+
<button
|
|
431
|
+
type="button"
|
|
432
|
+
onClick={handleRejectFee}
|
|
433
|
+
disabled={isProcessing}
|
|
434
|
+
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"
|
|
435
|
+
>
|
|
436
|
+
{isProcessing ? (
|
|
437
|
+
<>
|
|
438
|
+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-500 mr-2"></div>
|
|
439
|
+
Processing...
|
|
440
|
+
</>
|
|
441
|
+
) : (
|
|
442
|
+
"Cancel"
|
|
443
|
+
)}
|
|
444
|
+
</button>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export default WaasFeeOptions
|