0xtrails 0.6.3 → 0.6.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/{ccip-Ct6RMeeG.js → ccip-BlQRn0i5.js} +1 -1
- package/dist/{index-27ebsG0R.js → index-BsEaWwhF.js} +21694 -21333
- package/dist/index.js +118 -115
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/relaySdk.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts +2 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +2 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
- package/dist/transactionIntent/types.d.ts +1 -0
- package/dist/transactionIntent/types.d.ts.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/FeeOption.d.ts +6 -1
- package/dist/widget/components/FeeOption.d.ts.map +1 -1
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +1 -1
- package/dist/widget/hooks/useQuote.d.ts +2 -1
- package/dist/widget/hooks/useQuote.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +0 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts +1 -0
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/prepareSend.ts +23 -5
- package/src/relaySdk.ts +2 -0
- package/src/tokens.ts +52 -4
- package/src/transactionIntent/deposits/gaslessDeposit.ts +2 -2
- package/src/transactionIntent/handlers/crossChain.ts +3 -0
- package/src/transactionIntent/handlers/sameChainSameToken.ts +315 -1
- package/src/transactionIntent/quote/quoteHelpers.ts +7 -2
- package/src/transactionIntent/types.ts +1 -0
- package/src/utils.ts +15 -0
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/ClassicSwap.tsx +51 -6
- package/src/widget/components/FeeOption.tsx +55 -38
- package/src/widget/components/FeeOptions.tsx +57 -10
- package/src/widget/components/Fund.tsx +0 -4
- package/src/widget/components/Pay.tsx +23 -8
- package/src/widget/components/PoolDeposit.tsx +10 -1
- package/src/widget/hooks/useQuote.ts +4 -0
- package/src/widget/hooks/useSendForm.ts +71 -36
- package/src/widget/widget.tsx +1 -0
|
@@ -6,7 +6,10 @@ import { useSelectedFundMethod } from "../hooks/useSelectedFundMethod.js"
|
|
|
6
6
|
import type { ProcessedFeeOption } from "../hooks/useSelectedFeeOption.js"
|
|
7
7
|
import { logger } from "../../logger.js"
|
|
8
8
|
import type { FeeOption } from "@0xsequence/trails-api"
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
FeeOption as FeeOptionComponent,
|
|
11
|
+
isFeeOptionDisabled,
|
|
12
|
+
} from "./FeeOption.js"
|
|
10
13
|
import { isNativeToken, normalizeAddress } from "../../utils.js"
|
|
11
14
|
import type { Token } from "../hooks/useOriginSelectedToken.js"
|
|
12
15
|
|
|
@@ -90,7 +93,11 @@ export const FeeOptions: React.FC<FeeOptionsProps> = ({
|
|
|
90
93
|
const selectedOption = getSelectedOption()
|
|
91
94
|
|
|
92
95
|
// Use nativeGasOption as fallback when selectedOption is null/undefined
|
|
93
|
-
const displayOption = selectedOption
|
|
96
|
+
const displayOption = selectedOption
|
|
97
|
+
? isFeeOptionDisabled(selectedOption as ProcessedFeeOption, originTokenInfo)
|
|
98
|
+
? nativeGasOption
|
|
99
|
+
: selectedOption
|
|
100
|
+
: nativeGasOption
|
|
94
101
|
|
|
95
102
|
const handleFeeOptionSelect = (option: FeeOption) => {
|
|
96
103
|
// For native gas (zero/ETH address), set to null to trigger non-gasless flow
|
|
@@ -111,6 +118,35 @@ export const FeeOptions: React.FC<FeeOptionsProps> = ({
|
|
|
111
118
|
setIsOpen(false)
|
|
112
119
|
}
|
|
113
120
|
|
|
121
|
+
if (processedFeeOptions.length === 1 && selectedOption) {
|
|
122
|
+
return (
|
|
123
|
+
<div className="space-y-1" ref={accordionRef}>
|
|
124
|
+
<div className="p-2">
|
|
125
|
+
<div className="flex justify-between items-center mb-2">
|
|
126
|
+
<div className="text-xs font-medium trails-text-primary">
|
|
127
|
+
Gas Fee Option
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div className="mt-2 space-y-1">
|
|
131
|
+
<FeeOptionComponent
|
|
132
|
+
key={`${selectedOption?.tokenAddress}-0`}
|
|
133
|
+
option={selectedOption as ProcessedFeeOption}
|
|
134
|
+
isSelected={
|
|
135
|
+
isNativeToken(selectedOption?.tokenAddress)
|
|
136
|
+
? selectedFeeOption === null ||
|
|
137
|
+
isNativeToken(selectedFeeOption?.tokenAddress)
|
|
138
|
+
: normalizeAddress(selectedFeeOption?.tokenAddress) ===
|
|
139
|
+
normalizeAddress(selectedOption?.tokenAddress)
|
|
140
|
+
}
|
|
141
|
+
chainId={selectedOption?.chainId || chainId}
|
|
142
|
+
originTokenInfo={originTokenInfo}
|
|
143
|
+
/>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
114
150
|
return (
|
|
115
151
|
<div className="space-y-1" ref={accordionRef}>
|
|
116
152
|
<div className="p-2">
|
|
@@ -126,8 +162,17 @@ export const FeeOptions: React.FC<FeeOptionsProps> = ({
|
|
|
126
162
|
{/* Accordion Header */}
|
|
127
163
|
<button
|
|
128
164
|
type="button"
|
|
129
|
-
onClick={
|
|
130
|
-
|
|
165
|
+
onClick={
|
|
166
|
+
processedFeeOptions.length === 1
|
|
167
|
+
? undefined
|
|
168
|
+
: () => setIsOpen(!isOpen)
|
|
169
|
+
}
|
|
170
|
+
disabled={processedFeeOptions.length === 1}
|
|
171
|
+
className={`w-full flex items-center justify-between p-1.5 trails-border-radius-input border trails-border-primary transition-colors ${
|
|
172
|
+
processedFeeOptions.length === 1
|
|
173
|
+
? "cursor-default"
|
|
174
|
+
: "hover:trails-hover-bg cursor-pointer"
|
|
175
|
+
}`}
|
|
131
176
|
>
|
|
132
177
|
<div className="flex items-center space-x-2">
|
|
133
178
|
{displayOption && (
|
|
@@ -154,16 +199,18 @@ export const FeeOptions: React.FC<FeeOptionsProps> = ({
|
|
|
154
199
|
</div>
|
|
155
200
|
</div>
|
|
156
201
|
)}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
202
|
+
{processedFeeOptions.length > 1 && (
|
|
203
|
+
<ChevronDown
|
|
204
|
+
className={`w-3 h-3 trails-text-muted transition-transform ${
|
|
205
|
+
isOpen ? "transform rotate-180" : ""
|
|
206
|
+
}`}
|
|
207
|
+
/>
|
|
208
|
+
)}
|
|
162
209
|
</div>
|
|
163
210
|
</button>
|
|
164
211
|
|
|
165
212
|
{/* Accordion Content */}
|
|
166
|
-
{isOpen && (
|
|
213
|
+
{isOpen && processedFeeOptions.length > 1 && (
|
|
167
214
|
<div className="mt-2 space-y-1">
|
|
168
215
|
{/* All Fee Options (including native gas) */}
|
|
169
216
|
{processedFeeOptions.map((option, index) => (
|
|
@@ -142,7 +142,6 @@ export const Fund: React.FC<FundProps> = ({
|
|
|
142
142
|
setSelectedDestinationChain,
|
|
143
143
|
quoteError,
|
|
144
144
|
quoteErrorPrettified,
|
|
145
|
-
isSameTokenWithoutCustomCalldata,
|
|
146
145
|
destinationTokenAddress,
|
|
147
146
|
isValidCustomToken,
|
|
148
147
|
isSenderContractOnOrigin,
|
|
@@ -1149,7 +1148,6 @@ export const Fund: React.FC<FundProps> = ({
|
|
|
1149
1148
|
!destinationTokenAddress ||
|
|
1150
1149
|
!isValidCustomToken ||
|
|
1151
1150
|
prepareSendQuote?.noSufficientBalance ||
|
|
1152
|
-
isSameTokenWithoutCustomCalldata ||
|
|
1153
1151
|
!prepareSendQuote
|
|
1154
1152
|
}
|
|
1155
1153
|
className="w-full font-semibold py-4 px-4 trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white disabled:text-gray-500 disabled:cursor-not-allowed cursor-pointer relative"
|
|
@@ -1159,8 +1157,6 @@ export const Fund: React.FC<FundProps> = ({
|
|
|
1159
1157
|
<Loader2 className="w-5 h-5 animate-spin mr-2" />
|
|
1160
1158
|
<span>{buttonText}</span>
|
|
1161
1159
|
</div>
|
|
1162
|
-
) : isSameTokenWithoutCustomCalldata ? (
|
|
1163
|
-
"Select Different Tokens"
|
|
1164
1160
|
) : prepareSendQuote?.noSufficientBalance ? (
|
|
1165
1161
|
"Insufficient Balance"
|
|
1166
1162
|
) : !selectedRecipient ? (
|
|
@@ -38,6 +38,8 @@ import { FundingMethodSelectorButton } from "./FundingMethodSelectorButton.js"
|
|
|
38
38
|
import { PercentageMaxButtons } from "./PercentageMaxButtons.js"
|
|
39
39
|
import { useDynamicInputStyles } from "./DynamicInputStyles.js"
|
|
40
40
|
import { DynamicSizeInputField } from "./DynamicSizeInputField.js"
|
|
41
|
+
import { isFeeOptionDisabled } from "./FeeOption.js"
|
|
42
|
+
import type { ProcessedFeeOption } from "../hooks/useSelectedFeeOption.js"
|
|
41
43
|
|
|
42
44
|
interface PayProps {
|
|
43
45
|
selectedToken?: any // Origin token (optional - user can select)
|
|
@@ -1019,18 +1021,23 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
1019
1021
|
) : null}
|
|
1020
1022
|
|
|
1021
1023
|
{/* Fee Options */}
|
|
1022
|
-
{fundMethod !== "qr-code" && fundMethod !== "exchange" && (
|
|
1024
|
+
{fundMethod !== "qr-code" && fundMethod !== "exchange" && originToken && (
|
|
1023
1025
|
<FeeOptions
|
|
1024
1026
|
processedFeeOptions={processedFeeOptions}
|
|
1025
1027
|
selectedFeeOption={selectedFeeOption}
|
|
1026
1028
|
setSelectedFeeOption={(feeOption) => setSelectedFeeOption(feeOption)}
|
|
1027
|
-
chainId={originToken
|
|
1029
|
+
chainId={originToken.chainId}
|
|
1028
1030
|
isRefetching={isLoadingQuote}
|
|
1029
|
-
originTokenInfo={
|
|
1030
|
-
originToken
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1031
|
+
originTokenInfo={
|
|
1032
|
+
originToken
|
|
1033
|
+
? {
|
|
1034
|
+
originToken,
|
|
1035
|
+
originTokenBalance: originToken.balance ?? "0",
|
|
1036
|
+
originTokenAmount:
|
|
1037
|
+
prepareSendQuote?.originAmountFormatted ?? "0",
|
|
1038
|
+
}
|
|
1039
|
+
: undefined
|
|
1040
|
+
}
|
|
1034
1041
|
/>
|
|
1035
1042
|
)}
|
|
1036
1043
|
|
|
@@ -1058,7 +1065,15 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
1058
1065
|
!destinationTokenAddress ||
|
|
1059
1066
|
!isValidCustomToken ||
|
|
1060
1067
|
prepareSendQuote?.noSufficientBalance ||
|
|
1061
|
-
!prepareSendQuote
|
|
1068
|
+
!prepareSendQuote ||
|
|
1069
|
+
selectedFeeOption
|
|
1070
|
+
? isFeeOptionDisabled(selectedFeeOption as ProcessedFeeOption, {
|
|
1071
|
+
originToken: originToken,
|
|
1072
|
+
originTokenBalance: originToken?.balance ?? "0",
|
|
1073
|
+
originTokenAmount:
|
|
1074
|
+
prepareSendQuote?.originAmountFormatted ?? "0",
|
|
1075
|
+
})
|
|
1076
|
+
: false
|
|
1062
1077
|
}
|
|
1063
1078
|
className="w-full font-semibold py-4 px-4 trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white disabled:text-gray-500 disabled:cursor-not-allowed cursor-pointer relative"
|
|
1064
1079
|
>
|
|
@@ -40,6 +40,8 @@ import { generateAaveDepositCalldata } from "../../aave.js"
|
|
|
40
40
|
import { generateMorphoDepositCalldata } from "../../morpho.js"
|
|
41
41
|
import { TRAILS_ROUTER_PLACEHOLDER_AMOUNT } from "../../trailsRouter.js"
|
|
42
42
|
import { ScreenHeader } from "./ScreenHeader.js"
|
|
43
|
+
import type { ProcessedFeeOption } from "../hooks/useSelectedFeeOption.js"
|
|
44
|
+
import { isFeeOptionDisabled } from "./FeeOption.js"
|
|
43
45
|
|
|
44
46
|
interface PoolDepositProps {
|
|
45
47
|
account?: Account
|
|
@@ -626,7 +628,14 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
|
|
|
626
628
|
!selectedPool ||
|
|
627
629
|
isLoadingQuote ||
|
|
628
630
|
!prepareSendQuote ||
|
|
629
|
-
prepareSendQuote?.noSufficientBalance
|
|
631
|
+
prepareSendQuote?.noSufficientBalance ||
|
|
632
|
+
selectedFeeOption
|
|
633
|
+
? isFeeOptionDisabled(selectedFeeOption as ProcessedFeeOption, {
|
|
634
|
+
originToken: originToken!,
|
|
635
|
+
originTokenBalance: originToken?.balance ?? "0",
|
|
636
|
+
originTokenAmount: amount ?? "0",
|
|
637
|
+
})
|
|
638
|
+
: false
|
|
630
639
|
}
|
|
631
640
|
className={`w-full font-semibold py-4 px-4 trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white disabled:text-gray-500 disabled:cursor-not-allowed cursor-pointer relative`}
|
|
632
641
|
>
|
|
@@ -72,6 +72,7 @@ export type UseQuoteProps = {
|
|
|
72
72
|
abortSignal?: AbortSignal
|
|
73
73
|
apiKey?: string | null
|
|
74
74
|
nodeGatewayEnv?: "prod" | "dev" | "local" | "cors-anywhere"
|
|
75
|
+
isSmartWallet?: boolean | null
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export type SwapReturn = {
|
|
@@ -149,6 +150,7 @@ export function useQuote({
|
|
|
149
150
|
nodeGatewayEnv,
|
|
150
151
|
abortSignal: externalAbortSignal,
|
|
151
152
|
apiKey,
|
|
153
|
+
isSmartWallet,
|
|
152
154
|
}: Partial<UseQuoteProps> = {}): UseQuoteReturn {
|
|
153
155
|
// Set node gateway environment override for this quote session
|
|
154
156
|
if (nodeGatewayEnv) {
|
|
@@ -212,6 +214,7 @@ export function useQuote({
|
|
|
212
214
|
slippageTolerance,
|
|
213
215
|
quoteProvider,
|
|
214
216
|
apiKey,
|
|
217
|
+
isSmartWallet,
|
|
215
218
|
],
|
|
216
219
|
queryFn: async () => {
|
|
217
220
|
try {
|
|
@@ -467,6 +470,7 @@ export function useQuote({
|
|
|
467
470
|
sequenceProjectAccessKey,
|
|
468
471
|
originPublicClient: originPublicClient ?? undefined,
|
|
469
472
|
destinationPublicClient: destinationPublicClient ?? undefined,
|
|
473
|
+
isSmartWallet: isSmartWallet ?? undefined,
|
|
470
474
|
}
|
|
471
475
|
|
|
472
476
|
logger.console.log("[trails-sdk] options", options)
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
useSelectedFeeOption,
|
|
51
51
|
type ProcessedFeeOption,
|
|
52
52
|
} from "./useSelectedFeeOption.js"
|
|
53
|
+
import { useWidgetProps } from "./useWidgetProps.js"
|
|
53
54
|
|
|
54
55
|
export interface Token {
|
|
55
56
|
id: number
|
|
@@ -170,7 +171,6 @@ export type UseSendReturn = {
|
|
|
170
171
|
toAmountDisplay: string
|
|
171
172
|
quoteError: string | null
|
|
172
173
|
quoteErrorPrettified: string | null
|
|
173
|
-
isSameTokenWithoutCustomCalldata: boolean
|
|
174
174
|
isRecipientContract: boolean
|
|
175
175
|
isSenderContractOnOrigin: boolean
|
|
176
176
|
isSenderContractOnDestination: boolean
|
|
@@ -206,6 +206,9 @@ export function useSendForm({
|
|
|
206
206
|
const { connector } = useAccount()
|
|
207
207
|
const walletId = connector?.id
|
|
208
208
|
|
|
209
|
+
// Read isSmartWallet from widget props
|
|
210
|
+
const { isSmartWallet } = useWidgetProps()
|
|
211
|
+
|
|
209
212
|
// Auto-set quoteProvider to "lifi" if either from or to chain is etherlink
|
|
210
213
|
const effectiveQuoteProvider = useMemo(() => {
|
|
211
214
|
if (!quoteProvider || quoteProvider === "auto") {
|
|
@@ -742,6 +745,67 @@ export function useSendForm({
|
|
|
742
745
|
|
|
743
746
|
// Get quote automatically when inputs change
|
|
744
747
|
const getQuote = useCallback(async () => {
|
|
748
|
+
// Debug log: comprehensive state check
|
|
749
|
+
const debugState = {
|
|
750
|
+
account: account ? { address: account.address } : null,
|
|
751
|
+
amount,
|
|
752
|
+
amountRaw,
|
|
753
|
+
destinationTokenAddress,
|
|
754
|
+
destinationTokenAddressFromTokenSymbol,
|
|
755
|
+
isValidRecipient,
|
|
756
|
+
selectedDestToken: selectedDestToken
|
|
757
|
+
? {
|
|
758
|
+
symbol: selectedDestToken.symbol,
|
|
759
|
+
name: selectedDestToken.name,
|
|
760
|
+
decimals: selectedDestToken.decimals,
|
|
761
|
+
}
|
|
762
|
+
: null,
|
|
763
|
+
selectedDestinationChain: selectedDestinationChain
|
|
764
|
+
? {
|
|
765
|
+
id: selectedDestinationChain.id,
|
|
766
|
+
name: selectedDestinationChain.name,
|
|
767
|
+
}
|
|
768
|
+
: null,
|
|
769
|
+
selectedToken: selectedToken
|
|
770
|
+
? {
|
|
771
|
+
symbol: selectedToken.symbol,
|
|
772
|
+
contractAddress: selectedToken.contractAddress,
|
|
773
|
+
chainId: selectedToken.chainId,
|
|
774
|
+
contractInfo: selectedToken.contractInfo,
|
|
775
|
+
}
|
|
776
|
+
: null,
|
|
777
|
+
isCustomToken,
|
|
778
|
+
toToken,
|
|
779
|
+
recipient,
|
|
780
|
+
conditions: {
|
|
781
|
+
hasAccount: !!account,
|
|
782
|
+
hasAmount: !!amount,
|
|
783
|
+
hasAmountRaw: !!amountRaw,
|
|
784
|
+
amountNotZero: amount !== "0",
|
|
785
|
+
amountRawNotZero: amountRaw !== "0",
|
|
786
|
+
hasDestinationTokenAddress: !!destinationTokenAddress,
|
|
787
|
+
hasDestinationTokenAddressFromSymbol:
|
|
788
|
+
!!destinationTokenAddressFromTokenSymbol,
|
|
789
|
+
isValidRecipientValue: isValidRecipient,
|
|
790
|
+
hasSelectedDestToken: !!selectedDestToken,
|
|
791
|
+
hasSelectedDestinationChain: !!selectedDestinationChain,
|
|
792
|
+
hasSelectedToken: !!selectedToken,
|
|
793
|
+
},
|
|
794
|
+
allConditionsMet:
|
|
795
|
+
!!account &&
|
|
796
|
+
!!amount &&
|
|
797
|
+
!!destinationTokenAddress &&
|
|
798
|
+
isValidRecipient &&
|
|
799
|
+
!!selectedDestToken &&
|
|
800
|
+
!!selectedDestinationChain &&
|
|
801
|
+
amount !== "0" &&
|
|
802
|
+
!!amountRaw &&
|
|
803
|
+
amountRaw !== "0" &&
|
|
804
|
+
!!selectedToken,
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
logger.console.log("[trails-sdk] [DEBUG] getQuote state check", debugState)
|
|
808
|
+
|
|
745
809
|
// Only get quote if all required inputs are present
|
|
746
810
|
if (
|
|
747
811
|
!account ||
|
|
@@ -765,6 +829,7 @@ export function useSendForm({
|
|
|
765
829
|
selectedDestinationChain,
|
|
766
830
|
amountRaw,
|
|
767
831
|
selectedToken,
|
|
832
|
+
debugState,
|
|
768
833
|
},
|
|
769
834
|
)
|
|
770
835
|
setQuoteError(null)
|
|
@@ -918,6 +983,7 @@ export function useSendForm({
|
|
|
918
983
|
sequenceProjectAccessKey: trailsApiKey,
|
|
919
984
|
originPublicClient: originChainPublicClient ?? undefined,
|
|
920
985
|
destinationPublicClient: destinationChainPublicClient ?? undefined,
|
|
986
|
+
isSmartWallet,
|
|
921
987
|
}
|
|
922
988
|
|
|
923
989
|
logger.console.log(
|
|
@@ -982,6 +1048,9 @@ export function useSendForm({
|
|
|
982
1048
|
selectedDestToken?.decimals,
|
|
983
1049
|
recipient,
|
|
984
1050
|
destinationTokenAddress,
|
|
1051
|
+
destinationTokenAddressFromTokenSymbol,
|
|
1052
|
+
isCustomToken,
|
|
1053
|
+
toToken,
|
|
985
1054
|
sequenceIndexerUrl,
|
|
986
1055
|
selectedDestToken?.symbol,
|
|
987
1056
|
selectedDestinationChain?.id,
|
|
@@ -1009,6 +1078,7 @@ export function useSendForm({
|
|
|
1009
1078
|
buildQuoteInputsFingerprint,
|
|
1010
1079
|
originChainPublicClient,
|
|
1011
1080
|
destinationChainPublicClient,
|
|
1081
|
+
isSmartWallet,
|
|
1012
1082
|
])
|
|
1013
1083
|
|
|
1014
1084
|
// Auto-fetch quotes when inputs change (debounced)
|
|
@@ -1432,40 +1502,6 @@ export function useSendForm({
|
|
|
1432
1502
|
}
|
|
1433
1503
|
}, [quoteError])
|
|
1434
1504
|
|
|
1435
|
-
// Check if origin and destination tokens are the same (same contract address on same chain)
|
|
1436
|
-
// Only block same-token transactions when there's no custom calldata AND recipient is the same as sender
|
|
1437
|
-
const isSameTokenWithoutCustomCalldata = useMemo(() => {
|
|
1438
|
-
if (
|
|
1439
|
-
!selectedToken ||
|
|
1440
|
-
!selectedToken.contractAddress ||
|
|
1441
|
-
!destinationTokenAddress ||
|
|
1442
|
-
!selectedToken?.chainId ||
|
|
1443
|
-
!selectedDestinationChain?.id
|
|
1444
|
-
) {
|
|
1445
|
-
return false
|
|
1446
|
-
}
|
|
1447
|
-
const isSameChainAndToken =
|
|
1448
|
-
selectedToken.contractAddress.toLowerCase() ===
|
|
1449
|
-
destinationTokenAddress.toLowerCase() &&
|
|
1450
|
-
selectedToken.chainId === selectedDestinationChain?.id
|
|
1451
|
-
|
|
1452
|
-
// Allow same-token transactions if:
|
|
1453
|
-
// 1. There's custom calldata (e.g., NFT minting)
|
|
1454
|
-
// 2. Recipient is different from sender (simple transfer to another address)
|
|
1455
|
-
const recipientIsSameAsSender =
|
|
1456
|
-
recipient?.toLowerCase() === account?.address?.toLowerCase()
|
|
1457
|
-
|
|
1458
|
-
return isSameChainAndToken && !toCalldata && recipientIsSameAsSender
|
|
1459
|
-
}, [
|
|
1460
|
-
selectedToken,
|
|
1461
|
-
destinationTokenAddress,
|
|
1462
|
-
selectedDestinationChain,
|
|
1463
|
-
toCalldata,
|
|
1464
|
-
selectedToken?.chainId,
|
|
1465
|
-
recipient,
|
|
1466
|
-
account?.address,
|
|
1467
|
-
])
|
|
1468
|
-
|
|
1469
1505
|
return {
|
|
1470
1506
|
amount,
|
|
1471
1507
|
amountRaw,
|
|
@@ -1511,7 +1547,6 @@ export function useSendForm({
|
|
|
1511
1547
|
prepareSendQuote: prepareSendResult?.quote ?? null,
|
|
1512
1548
|
quoteError,
|
|
1513
1549
|
quoteErrorPrettified,
|
|
1514
|
-
isSameTokenWithoutCustomCalldata,
|
|
1515
1550
|
isRecipientContract,
|
|
1516
1551
|
isSenderContractOnOrigin,
|
|
1517
1552
|
isSenderContractOnDestination,
|