0xtrails 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aave.d.ts +8 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/{ccip-BlV1Mry3.js → ccip-CXlshvBY.js} +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/estimate.d.ts +52 -0
- package/dist/estimate.d.ts.map +1 -1
- package/dist/{index-BNWCIGfQ.js → index-_QuyGrjU.js} +72332 -72246
- package/dist/index.js +2 -2
- package/dist/intents.d.ts +40 -0
- package/dist/intents.d.ts.map +1 -1
- package/dist/metaTxnMonitor.d.ts +3 -3
- package/dist/metaTxnMonitor.d.ts.map +1 -1
- package/dist/metaTxns.d.ts +3 -3
- package/dist/metaTxns.d.ts.map +1 -1
- package/dist/morpho.d.ts +8 -0
- package/dist/morpho.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +16 -6
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/queryParams.d.ts.map +1 -1
- package/dist/relayer.d.ts +6 -6
- package/dist/relayer.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +2 -2
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -0
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts +4 -0
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/{FundSendForm.d.ts → FundSwap.d.ts} +11 -5
- package/dist/widget/components/FundSwap.d.ts.map +1 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts +4 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PercentageMaxButtons.d.ts +12 -0
- package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -0
- package/dist/widget/components/{PaySendForm.d.ts → PoolDeposit.d.ts} +11 -34
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
- package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +16 -8
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receive.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts +4 -0
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Recipients.d.ts.map +1 -1
- package/dist/widget/components/RequiredPropsError.d.ts +8 -0
- package/dist/widget/components/RequiredPropsError.d.ts.map +1 -0
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +1 -0
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapSettings.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts +1 -0
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/TokenList.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts +16 -0
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +8 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -0
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletList.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -0
- package/dist/widget/css/index.css +554 -0
- package/dist/widget/hooks/useBack.d.ts +1 -0
- package/dist/widget/hooks/useBack.d.ts.map +1 -1
- package/dist/widget/hooks/useCheckout.d.ts +1 -1
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts +3 -3
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/usePayMessage.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFundMethod.d.ts +12 -0
- package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts +4 -4
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +18 -12
- package/src/aave.ts +32 -0
- package/src/config.ts +12 -4
- package/src/constants.ts +2 -0
- package/src/error.ts +19 -1
- package/src/estimate.ts +416 -5
- package/src/intents.ts +161 -11
- package/src/metaTxnMonitor.ts +3 -3
- package/src/metaTxns.ts +3 -5
- package/src/morpho.ts +32 -0
- package/src/prepareSend.ts +503 -166
- package/src/queryParams.ts +2 -1
- package/src/relayer.ts +11 -11
- package/src/sequenceWallet.ts +2 -2
- package/src/tokens.ts +7 -1
- package/src/wallets.ts +8 -0
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountActionsDropdown.tsx +3 -13
- package/src/widget/components/AccountSettings.tsx +6 -24
- package/src/widget/components/ClassicSwap.tsx +111 -155
- package/src/widget/components/ConnectWallet.tsx +4 -37
- package/src/widget/components/ConnectedWallets.tsx +113 -58
- package/src/widget/components/Earn.tsx +73 -589
- package/src/widget/components/Fund.tsx +31 -82
- package/src/widget/components/FundMethods.tsx +82 -159
- package/src/widget/components/FundSwap.tsx +52 -0
- package/src/widget/components/FundingMethodSelectorButton.tsx +60 -0
- package/src/widget/components/Modal.tsx +6 -2
- package/src/widget/components/Pay.tsx +183 -208
- package/src/widget/components/PercentageMaxButtons.tsx +77 -0
- package/src/widget/components/PoolDeposit.tsx +593 -0
- package/src/widget/components/PoolWithdraw.tsx +903 -0
- package/src/widget/components/QuoteDetails.tsx +22 -8
- package/src/widget/components/Receive.tsx +0 -2
- package/src/widget/components/RecipientSelectorButton.tsx +42 -0
- package/src/widget/components/Recipients.tsx +62 -156
- package/src/widget/components/RequiredPropsError.tsx +33 -0
- package/src/widget/components/ScreenHeader.tsx +5 -1
- package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
- package/src/widget/components/Swap.tsx +2 -43
- package/src/widget/components/SwapSettings.tsx +2 -14
- package/src/widget/components/TokenImage.tsx +21 -4
- package/src/widget/components/TokenList.tsx +0 -1
- package/src/widget/components/TokenSelector.tsx +1 -0
- package/src/widget/components/TokenSelectorButton.tsx +75 -0
- package/src/widget/components/UserPreferences.tsx +6 -24
- package/src/widget/components/WaasFeeOptions.tsx +331 -0
- package/src/widget/components/WalletConfirmation.tsx +55 -3
- package/src/widget/components/WalletList.tsx +4 -2
- package/src/widget/hooks/useBack.tsx +2 -0
- package/src/widget/hooks/useCheckout.ts +36 -20
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDefaultTokenSelection.tsx +104 -28
- package/src/widget/hooks/usePayMessage.tsx +86 -11
- package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
- package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
- package/src/widget/hooks/useSendForm.ts +24 -2
- package/src/widget/index.css +27 -0
- package/src/widget/widget.tsx +169 -111
- package/dist/widget/components/FundSendForm.d.ts.map +0 -1
- package/dist/widget/components/PaySendForm.d.ts.map +0 -1
- package/dist/widget/components/SimpleSwap.d.ts.map +0 -1
- package/dist/widget/hooks/useSwapSettings.d.ts +0 -16
- package/dist/widget/hooks/useSwapSettings.d.ts.map +0 -1
- package/src/widget/components/FundSendForm.tsx +0 -903
- package/src/widget/components/PaySendForm.tsx +0 -869
- package/src/widget/components/SimpleSwap.tsx +0 -983
- package/src/widget/hooks/useSwapSettings.tsx +0 -100
|
@@ -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
|
|
|
@@ -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
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { TokenImage } from "./TokenImage.js"
|
|
2
2
|
import { ChevronLeft } from "lucide-react"
|
|
3
3
|
import type React from "react"
|
|
4
|
-
import { useEffect, useState } from "react"
|
|
4
|
+
import { useEffect, useMemo, useState } from "react"
|
|
5
5
|
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
6
6
|
import { QuoteDetails } from "./QuoteDetails.js"
|
|
7
|
+
import { WaasFeeOptions } from "./WaasFeeOptions.js"
|
|
8
|
+
import { useAccount } from "wagmi"
|
|
7
9
|
|
|
8
10
|
interface WalletConfirmationProps {
|
|
9
11
|
onBack?: () => void
|
|
@@ -21,6 +23,9 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
|
|
|
21
23
|
}) => {
|
|
22
24
|
const [showContent, setShowContent] = useState(false)
|
|
23
25
|
const [showTimeoutWarning, setShowTimeoutWarning] = useState(false)
|
|
26
|
+
const [isFeeOptionConfirmed, setIsFeeOptionConfirmed] = useState(false)
|
|
27
|
+
const [areFeeOptionsLoaded, setAreFeeOptionsLoaded] = useState(false)
|
|
28
|
+
const { connector } = useAccount()
|
|
24
29
|
|
|
25
30
|
useEffect(() => {
|
|
26
31
|
setShowContent(true)
|
|
@@ -39,6 +44,25 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
|
|
|
39
44
|
return () => clearTimeout(timer)
|
|
40
45
|
}, [retryEnabled])
|
|
41
46
|
|
|
47
|
+
const isSequenceWaas = useMemo(() => {
|
|
48
|
+
if (!connector) return false
|
|
49
|
+
const connectorName = connector.name?.toLowerCase() || ""
|
|
50
|
+
const connectorId = connector.id?.toLowerCase() || ""
|
|
51
|
+
const isSequenceWaas =
|
|
52
|
+
connectorName.includes("waas") ||
|
|
53
|
+
connectorId.includes("waas") ||
|
|
54
|
+
connectorId === "sequence-waas"
|
|
55
|
+
|
|
56
|
+
console.log("[trails-sdk] Sequence WaaS detection:", {
|
|
57
|
+
connectorName,
|
|
58
|
+
connectorId,
|
|
59
|
+
isSequenceWaas,
|
|
60
|
+
connector: connector.name,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return isSequenceWaas
|
|
64
|
+
}, [connector])
|
|
65
|
+
|
|
42
66
|
return (
|
|
43
67
|
<div className="space-y-6">
|
|
44
68
|
<div className="flex items-center relative">
|
|
@@ -67,6 +91,7 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
|
|
|
67
91
|
imageUrl={quote?.originToken.imageUrl}
|
|
68
92
|
symbol={quote?.originToken.symbol}
|
|
69
93
|
chainId={quote?.originChain.id}
|
|
94
|
+
contractAddress={quote?.originToken.contractAddress}
|
|
70
95
|
size={64}
|
|
71
96
|
/>
|
|
72
97
|
</div>
|
|
@@ -76,12 +101,39 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
|
|
|
76
101
|
className={`mb-2 transition-all duration-500 ease-out ${showContent ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
|
|
77
102
|
>
|
|
78
103
|
<h2 className="text-xl font-bold text-gray-900 dark:text-white">
|
|
79
|
-
{retryEnabled
|
|
104
|
+
{retryEnabled
|
|
105
|
+
? "Try again"
|
|
106
|
+
: !isSequenceWaas
|
|
107
|
+
? "Waiting for wallet…"
|
|
108
|
+
: isFeeOptionConfirmed
|
|
109
|
+
? "Waiting for wallet…"
|
|
110
|
+
: areFeeOptionsLoaded
|
|
111
|
+
? "Waiting for fee selection…"
|
|
112
|
+
: "Waiting for fee options…"}
|
|
80
113
|
</h2>
|
|
81
114
|
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
|
|
82
|
-
|
|
115
|
+
{!isSequenceWaas
|
|
116
|
+
? "Please approve the request in your wallet"
|
|
117
|
+
: isFeeOptionConfirmed
|
|
118
|
+
? "Please approve the request in your wallet"
|
|
119
|
+
: ""}
|
|
83
120
|
</p>
|
|
84
121
|
</div>
|
|
122
|
+
|
|
123
|
+
{isSequenceWaas && (
|
|
124
|
+
<div
|
|
125
|
+
className={`mb-2 mt-4 transition-all duration-500 ease-out ${showContent ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
|
|
126
|
+
>
|
|
127
|
+
<WaasFeeOptions
|
|
128
|
+
chainId={quote?.originChain.id}
|
|
129
|
+
setIsFeeOptionConfirmed={setIsFeeOptionConfirmed}
|
|
130
|
+
onFeeOptionsLoaded={() => {
|
|
131
|
+
console.log("[trails-sdk] Fee options loaded callback called")
|
|
132
|
+
setAreFeeOptionsLoaded(true)
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
85
137
|
</div>
|
|
86
138
|
|
|
87
139
|
{/* Timeout Warning */}
|
|
@@ -21,7 +21,9 @@ export const WalletList: React.FC<WalletListProps> = ({
|
|
|
21
21
|
|
|
22
22
|
const prefilteredWalletOptions = useMemo(() => {
|
|
23
23
|
return walletOptions
|
|
24
|
-
.filter(
|
|
24
|
+
.filter(
|
|
25
|
+
(wallet) => wallet.id !== "injected" && wallet.id !== "sequence-waas",
|
|
26
|
+
)
|
|
25
27
|
.sort((a, b) => {
|
|
26
28
|
const aIndex = topShownWallets.indexOf(a.id)
|
|
27
29
|
const bIndex = topShownWallets.indexOf(b.id)
|
|
@@ -61,7 +63,7 @@ export const WalletList: React.FC<WalletListProps> = ({
|
|
|
61
63
|
return (
|
|
62
64
|
<div className="space-y-6">
|
|
63
65
|
<ScreenHeader
|
|
64
|
-
headerContent="
|
|
66
|
+
headerContent="Connect a Wallet"
|
|
65
67
|
headerContentAlign="left"
|
|
66
68
|
onBack={onBack}
|
|
67
69
|
/>
|
|
@@ -20,6 +20,7 @@ interface BackContextType {
|
|
|
20
20
|
setAccountSettingsSource: (screen: Screen) => void
|
|
21
21
|
getAccountSettingsSource: () => Screen | null
|
|
22
22
|
setCurrentScreenWithBack: (screen: Screen, backTo?: Screen) => void
|
|
23
|
+
getPreviousScreen: () => Screen | null
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const BackContext = createContext<BackContextType | null>(null)
|
|
@@ -194,6 +195,7 @@ export function BackProvider({ children }: BackProviderProps) {
|
|
|
194
195
|
setAccountSettingsSource: () => {}, // Deprecated, kept for compatibility
|
|
195
196
|
getAccountSettingsSource: () => null, // Deprecated, kept for compatibility
|
|
196
197
|
setCurrentScreenWithBack,
|
|
198
|
+
getPreviousScreen,
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
return <BackContext.Provider value={value}>{children}</BackContext.Provider>
|