0xtrails 0.7.0 → 0.8.0
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-fConRNoG.js → ccip-uMWNlvmJ.js} +34 -34
- package/dist/fees.d.ts.map +1 -1
- package/dist/{index-BbajxCG_.js → index-BiPwqVkZ.js} +31527 -28874
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +478 -456
- package/dist/intents.d.ts +10 -4
- package/dist/intents.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +1 -1
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/prices.d.ts +2 -2
- package/dist/prices.d.ts.map +1 -1
- package/dist/refund.d.ts +116 -0
- package/dist/refund.d.ts.map +1 -0
- package/dist/tokenBalances.d.ts +1 -1
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts +4 -3
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +3 -3
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
- package/dist/transactionIntent/quote/normalizeQuote.d.ts +1 -2
- package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +3 -3
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
- package/dist/transactionIntent/types.d.ts +5 -4
- package/dist/transactionIntent/types.d.ts.map +1 -1
- package/dist/transactions.d.ts +4 -0
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -1
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts +2 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/ErrorDisplay.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts +2 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundSwap.d.ts +2 -1
- package/dist/widget/components/FundSwap.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts +2 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts +2 -1
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts +1 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +2 -1
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +1 -1
- package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/useGetIntent.d.ts +18 -0
- package/dist/widget/hooks/useGetIntent.d.ts.map +1 -0
- package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/hooks/useQuote.d.ts +10 -7
- package/dist/widget/hooks/useQuote.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +3 -2
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/hooks/useTrailsSendTransaction.d.ts.map +1 -1
- package/dist/widget/index.js +3 -3
- package/dist/widget/widget.d.ts +2 -1
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +5 -12
- package/src/fees.ts +8 -2
- package/src/index.ts +33 -1
- package/src/intents.ts +34 -7
- package/src/prepareSend.ts +6 -4
- package/src/prices.ts +6 -6
- package/src/refund.ts +914 -0
- package/src/tokenBalances.ts +4 -14
- package/src/transactionIntent/handlers/crossChain.ts +21 -10
- package/src/transactionIntent/handlers/sameChainSameToken.ts +12 -8
- package/src/transactionIntent/quote/normalizeQuote.ts +29 -27
- package/src/transactionIntent/quote/quoteHelpers.ts +5 -9
- package/src/transactionIntent/types.ts +5 -3
- package/src/transactions.ts +5 -0
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountIntentTransactionHistory.tsx +197 -5
- package/src/widget/components/ClassicSwap.tsx +6 -3
- package/src/widget/components/Earn.tsx +6 -3
- package/src/widget/components/ErrorDisplay.tsx +6 -4
- package/src/widget/components/Fund.tsx +6 -3
- package/src/widget/components/FundSwap.tsx +2 -1
- package/src/widget/components/Pay.tsx +15 -7
- package/src/widget/components/PoolDeposit.tsx +6 -3
- package/src/widget/components/QuoteDetails.tsx +34 -38
- package/src/widget/components/Swap.tsx +2 -1
- package/src/widget/components/TokenImage.tsx +3 -1
- package/src/widget/components/TransactionDetails.tsx +108 -0
- package/src/widget/hooks/useAmountUsd.ts +0 -3
- package/src/widget/hooks/useDefaultTokenSelection.tsx +0 -3
- package/src/widget/hooks/useGetIntent.ts +53 -0
- package/src/widget/hooks/useIntentTransactionHistory.ts +85 -3
- package/src/widget/hooks/useQuote.ts +16 -10
- package/src/widget/hooks/useSendForm.ts +30 -15
- package/src/widget/hooks/useTokenList.ts +2 -4
- package/src/widget/hooks/useTrailsSendTransaction.ts +2 -1
- package/src/widget/widget.tsx +12 -6
- package/dist/sequenceWallet.d.ts +0 -67
- package/dist/sequenceWallet.d.ts.map +0 -1
- package/src/sequenceWallet.ts +0 -532
|
@@ -10,10 +10,13 @@ import { formatRelativeDate } from "../../time.js"
|
|
|
10
10
|
import { SearchInputField } from "./SearchInputField.js"
|
|
11
11
|
import { Identicon } from "./Identicon.js"
|
|
12
12
|
import { truncateAddress } from "../../utils.js"
|
|
13
|
-
import { useConnections, useAccount } from "wagmi"
|
|
13
|
+
import { useConnections, useAccount, useWalletClient } from "wagmi"
|
|
14
14
|
import { ChevronDown } from "lucide-react"
|
|
15
15
|
import { getExplorerUrl } from "../../explorer.js"
|
|
16
|
+
import { ErrorDisplay } from "./ErrorDisplay.js"
|
|
17
|
+
import { attemptSwitchChain } from "../../chainSwitch.js"
|
|
16
18
|
import { logger } from "../../logger.js"
|
|
19
|
+
import { useTrailsRefund } from "../../refund.js"
|
|
17
20
|
|
|
18
21
|
interface AccountIntentTransactionHistoryProps {
|
|
19
22
|
accountAddress?: string
|
|
@@ -35,6 +38,8 @@ const ExecutionStatusBadge: React.FC<{ status?: string }> = ({ status }) => {
|
|
|
35
38
|
return "bg-yellow-100 text-gray-800 dark:bg-yellow-900 dark:text-gray-200"
|
|
36
39
|
case "refunded":
|
|
37
40
|
return "bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200"
|
|
41
|
+
case "aborted":
|
|
42
|
+
return "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"
|
|
38
43
|
case "created":
|
|
39
44
|
return "bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
|
|
40
45
|
default:
|
|
@@ -56,10 +61,136 @@ const ExecutionStatusBadge: React.FC<{ status?: string }> = ({ status }) => {
|
|
|
56
61
|
const TransactionItem: React.FC<{
|
|
57
62
|
transaction: IntentTransaction
|
|
58
63
|
index: number
|
|
59
|
-
|
|
64
|
+
onRefetch?: () => void
|
|
65
|
+
}> = ({ transaction, index, onRefetch }) => {
|
|
60
66
|
const [isExpanded, setIsExpanded] = useState(false)
|
|
61
67
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
62
68
|
const dateInfo = formatRelativeDate(transaction.createdAt)
|
|
69
|
+
const { data: walletClient } = useWalletClient()
|
|
70
|
+
|
|
71
|
+
// Track refund transaction hash per intent
|
|
72
|
+
const [refundTxHash, setRefundTxHash] = useState<`0x${string}` | null>(null)
|
|
73
|
+
|
|
74
|
+
// Check if intent is not completed
|
|
75
|
+
const isCompleted =
|
|
76
|
+
transaction.executionStatus === "executed" ||
|
|
77
|
+
transaction.executionStatus === "completed" ||
|
|
78
|
+
transaction.executionStatus === "succeeded"
|
|
79
|
+
|
|
80
|
+
// Hook for refunding intents (recover) - call early to get hasIntentBalance
|
|
81
|
+
const {
|
|
82
|
+
signPayload,
|
|
83
|
+
getRefundTx,
|
|
84
|
+
isLoadingIntent,
|
|
85
|
+
isLoadingBalances,
|
|
86
|
+
intentError,
|
|
87
|
+
balancesError,
|
|
88
|
+
hasIntentBalance,
|
|
89
|
+
refetchIntent,
|
|
90
|
+
} = useTrailsRefund({
|
|
91
|
+
intentId:
|
|
92
|
+
!isCompleted && transaction.intentId && !refundTxHash
|
|
93
|
+
? transaction.intentId
|
|
94
|
+
: "",
|
|
95
|
+
walletClient: walletClient || undefined,
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// Create a wrapper for onRefetch that also refetches intent data and balances
|
|
99
|
+
// This ensures the recover button state is updated when the refresh button is clicked
|
|
100
|
+
const enhancedOnRefetch = useMemo(() => {
|
|
101
|
+
if (!onRefetch) return undefined
|
|
102
|
+
return () => {
|
|
103
|
+
onRefetch()
|
|
104
|
+
// Refetch intent data and balances to update recover button state
|
|
105
|
+
if (!isCompleted && transaction.intentId && !refundTxHash) {
|
|
106
|
+
refetchIntent()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}, [
|
|
110
|
+
onRefetch,
|
|
111
|
+
isCompleted,
|
|
112
|
+
transaction.intentId,
|
|
113
|
+
refundTxHash,
|
|
114
|
+
refetchIntent,
|
|
115
|
+
])
|
|
116
|
+
|
|
117
|
+
const canRecover =
|
|
118
|
+
!isCompleted &&
|
|
119
|
+
transaction.intentId &&
|
|
120
|
+
walletClient &&
|
|
121
|
+
!refundTxHash &&
|
|
122
|
+
hasIntentBalance
|
|
123
|
+
|
|
124
|
+
const [isRecovering, setIsRecovering] = useState(false)
|
|
125
|
+
const [recoverError, setRecoverError] = useState<string | null>(null)
|
|
126
|
+
|
|
127
|
+
const handleRecover = async () => {
|
|
128
|
+
if (!transaction.intentId || !walletClient) {
|
|
129
|
+
logger.console.error(
|
|
130
|
+
"[AccountIntentTransactionHistory] Cannot recover: missing intentId or walletClient",
|
|
131
|
+
)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
setIsRecovering(true)
|
|
137
|
+
setRecoverError(null)
|
|
138
|
+
|
|
139
|
+
// Sign the payload
|
|
140
|
+
const { signature, payload } = await signPayload()
|
|
141
|
+
|
|
142
|
+
// Get the refund transaction
|
|
143
|
+
const refundTx = await getRefundTx({
|
|
144
|
+
signedHash: signature,
|
|
145
|
+
payload,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// Ensure we're on the correct chain before sending
|
|
149
|
+
// attemptSwitchChain already checks if we're on the correct chain
|
|
150
|
+
await attemptSwitchChain({
|
|
151
|
+
walletClient,
|
|
152
|
+
desiredChainId: refundTx.chainId,
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// Send the refund transaction with explicit chain
|
|
156
|
+
const hash = await walletClient.sendTransaction({
|
|
157
|
+
to: refundTx.to,
|
|
158
|
+
data: refundTx.data,
|
|
159
|
+
chain: refundTx.chain,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
logger.console.log(
|
|
163
|
+
"[AccountIntentTransactionHistory] Refund transaction sent",
|
|
164
|
+
{ intentId: transaction.intentId, hash },
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
// Store the transaction hash to show explorer link
|
|
168
|
+
setRefundTxHash(hash)
|
|
169
|
+
setRecoverError(null)
|
|
170
|
+
|
|
171
|
+
// Refetch history after recovery
|
|
172
|
+
if (enhancedOnRefetch) {
|
|
173
|
+
setTimeout(() => {
|
|
174
|
+
enhancedOnRefetch()
|
|
175
|
+
}, 2000)
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
logger.console.error(
|
|
179
|
+
"[AccountIntentTransactionHistory] Failed to recover intent",
|
|
180
|
+
{ intentId: transaction.intentId, error },
|
|
181
|
+
)
|
|
182
|
+
// Set error message for display
|
|
183
|
+
const errorMessage =
|
|
184
|
+
error instanceof Error
|
|
185
|
+
? error.message
|
|
186
|
+
: typeof error === "string"
|
|
187
|
+
? error
|
|
188
|
+
: "Failed to recover intent. Please try again."
|
|
189
|
+
setRecoverError(errorMessage)
|
|
190
|
+
} finally {
|
|
191
|
+
setIsRecovering(false)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
63
194
|
|
|
64
195
|
// Determine the last known intent transaction hash and chain ID
|
|
65
196
|
// Priority: destinationTransactionHash > destinationIntentTxHash > originTransactionHash > originIntentTxHash > txnHash
|
|
@@ -119,11 +250,22 @@ const TransactionItem: React.FC<{
|
|
|
119
250
|
})
|
|
120
251
|
}, [lastKnownTxHash])
|
|
121
252
|
|
|
253
|
+
// Get explorer URL for refund transaction if available
|
|
254
|
+
const refundExplorerUrl = useMemo(() => {
|
|
255
|
+
if (!refundTxHash || !transaction.originChainId) {
|
|
256
|
+
return null
|
|
257
|
+
}
|
|
258
|
+
return getExplorerUrl({
|
|
259
|
+
txHash: refundTxHash,
|
|
260
|
+
chainId: transaction.originChainId,
|
|
261
|
+
})
|
|
262
|
+
}, [refundTxHash, transaction.originChainId])
|
|
263
|
+
|
|
122
264
|
return (
|
|
123
265
|
<div className="border border-gray-200 dark:border-gray-700 rounded-lg p-3 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
124
266
|
{/* Header with status and metadata */}
|
|
125
267
|
<div className="flex items-center justify-between mb-2">
|
|
126
|
-
<div className="flex items-center gap-2">
|
|
268
|
+
<div className="flex items-center gap-2 flex-wrap">
|
|
127
269
|
<span className="text-xs font-medium text-gray-600 dark:text-gray-400">
|
|
128
270
|
#{index + 1}
|
|
129
271
|
</span>
|
|
@@ -209,9 +351,58 @@ const TransactionItem: React.FC<{
|
|
|
209
351
|
</div>
|
|
210
352
|
</div>
|
|
211
353
|
|
|
212
|
-
{/*
|
|
354
|
+
{/* Action Buttons - only visible when collapsed */}
|
|
213
355
|
{!isExpanded && (
|
|
214
|
-
<div className="flex
|
|
356
|
+
<div className="flex flex-col items-center gap-2">
|
|
357
|
+
{refundTxHash && refundExplorerUrl ? (
|
|
358
|
+
<a
|
|
359
|
+
href={refundExplorerUrl}
|
|
360
|
+
target="_blank"
|
|
361
|
+
rel="noopener noreferrer"
|
|
362
|
+
className="inline-flex items-center gap-1 px-3 py-1.5 rounded-md font-medium transition-colors border border-solid text-sm bg-white border-gray-200 text-black hover:bg-gray-50 hover:text-gray-900 dark:bg-gray-900 dark:border-gray-700 dark:text-blue-300 dark:hover:bg-gray-800 dark:hover:text-blue-200"
|
|
363
|
+
aria-label="View refund transaction on explorer"
|
|
364
|
+
>
|
|
365
|
+
View on Explorer
|
|
366
|
+
<svg
|
|
367
|
+
className="w-4 h-4 ml-1 text-black dark:text-blue-300"
|
|
368
|
+
fill="none"
|
|
369
|
+
viewBox="0 0 24 24"
|
|
370
|
+
stroke="currentColor"
|
|
371
|
+
aria-hidden="true"
|
|
372
|
+
>
|
|
373
|
+
<title>External Link</title>
|
|
374
|
+
<path
|
|
375
|
+
strokeLinecap="round"
|
|
376
|
+
strokeLinejoin="round"
|
|
377
|
+
strokeWidth={2}
|
|
378
|
+
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
379
|
+
/>
|
|
380
|
+
</svg>
|
|
381
|
+
</a>
|
|
382
|
+
) : canRecover ? (
|
|
383
|
+
<button
|
|
384
|
+
type="button"
|
|
385
|
+
onClick={handleRecover}
|
|
386
|
+
disabled={
|
|
387
|
+
isRecovering ||
|
|
388
|
+
isLoadingIntent ||
|
|
389
|
+
isLoadingBalances ||
|
|
390
|
+
!!intentError ||
|
|
391
|
+
!!balancesError
|
|
392
|
+
}
|
|
393
|
+
className="flex items-center justify-center gap-1 py-1 px-3 rounded-md transition-colors cursor-pointer text-xs font-medium text-white bg-orange-600 hover:bg-orange-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
|
|
394
|
+
aria-label="Recover intent"
|
|
395
|
+
>
|
|
396
|
+
{isRecovering || isLoadingIntent || isLoadingBalances
|
|
397
|
+
? "Recovering..."
|
|
398
|
+
: "Recover"}
|
|
399
|
+
</button>
|
|
400
|
+
) : null}
|
|
401
|
+
{recoverError && (
|
|
402
|
+
<div className="w-full">
|
|
403
|
+
<ErrorDisplay error={recoverError} severity="error" />
|
|
404
|
+
</div>
|
|
405
|
+
)}
|
|
215
406
|
<button
|
|
216
407
|
type="button"
|
|
217
408
|
onClick={() => setIsExpanded(true)}
|
|
@@ -731,6 +922,7 @@ export const AccountIntentTransactionHistory: React.FC<
|
|
|
731
922
|
key={`${transaction.originIntentAddress}-${transaction.destinationIntentAddress}-${index}`}
|
|
732
923
|
transaction={transaction}
|
|
733
924
|
index={page * ITEMS_PER_PAGE + index}
|
|
925
|
+
onRefetch={refetch}
|
|
734
926
|
/>
|
|
735
927
|
))}
|
|
736
928
|
</div>
|
|
@@ -51,7 +51,8 @@ interface ClassicSwapProps {
|
|
|
51
51
|
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
52
52
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
53
53
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
54
|
-
|
|
54
|
+
swapProvider?: string
|
|
55
|
+
bridgeProvider?: string
|
|
55
56
|
fundMethod?: string
|
|
56
57
|
onNavigateToOnramp?: (
|
|
57
58
|
props: {
|
|
@@ -90,7 +91,8 @@ export const ClassicSwap: React.FC<ClassicSwapProps> = ({
|
|
|
90
91
|
onWaitingForWalletConfirm,
|
|
91
92
|
paymasterUrls,
|
|
92
93
|
setWalletConfirmRetryHandler,
|
|
93
|
-
|
|
94
|
+
swapProvider,
|
|
95
|
+
bridgeProvider,
|
|
94
96
|
fundMethod,
|
|
95
97
|
onNavigateToOnramp,
|
|
96
98
|
onAmountUpdate,
|
|
@@ -201,7 +203,8 @@ export const ClassicSwap: React.FC<ClassicSwapProps> = ({
|
|
|
201
203
|
selectedToken: originToken as any,
|
|
202
204
|
setWalletConfirmRetryHandler,
|
|
203
205
|
tradeType: tradeType,
|
|
204
|
-
|
|
206
|
+
swapProvider,
|
|
207
|
+
bridgeProvider,
|
|
205
208
|
fundMethod,
|
|
206
209
|
mode,
|
|
207
210
|
onNavigateToOnramp,
|
|
@@ -24,7 +24,8 @@ interface EarnProps {
|
|
|
24
24
|
onSend: (amount: string, recipient: string) => void
|
|
25
25
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
26
26
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
27
|
-
|
|
27
|
+
swapProvider?: string
|
|
28
|
+
bridgeProvider?: string
|
|
28
29
|
fundMethod?: string
|
|
29
30
|
onNavigateToOnramp?: (
|
|
30
31
|
props: {
|
|
@@ -54,7 +55,8 @@ export const Earn: React.FC<EarnProps> = ({
|
|
|
54
55
|
onSend,
|
|
55
56
|
paymasterUrls,
|
|
56
57
|
setWalletConfirmRetryHandler,
|
|
57
|
-
|
|
58
|
+
swapProvider,
|
|
59
|
+
bridgeProvider,
|
|
58
60
|
fundMethod,
|
|
59
61
|
onNavigateToOnramp,
|
|
60
62
|
checkoutOnHandlers,
|
|
@@ -117,7 +119,8 @@ export const Earn: React.FC<EarnProps> = ({
|
|
|
117
119
|
onSend={onSend}
|
|
118
120
|
paymasterUrls={paymasterUrls}
|
|
119
121
|
setWalletConfirmRetryHandler={setWalletConfirmRetryHandler}
|
|
120
|
-
|
|
122
|
+
swapProvider={swapProvider}
|
|
123
|
+
bridgeProvider={bridgeProvider}
|
|
121
124
|
fundMethod={fundMethod}
|
|
122
125
|
onNavigateToOnramp={onNavigateToOnramp}
|
|
123
126
|
checkoutOnHandlers={checkoutOnHandlers}
|
|
@@ -82,8 +82,10 @@ export const ErrorDisplay: React.FC<ErrorDisplayProps> = ({
|
|
|
82
82
|
|
|
83
83
|
const colors = getSeverityColors()
|
|
84
84
|
|
|
85
|
-
//
|
|
86
|
-
|
|
85
|
+
// Show error if we have a prettified error or a raw error message
|
|
86
|
+
// If we can't prettify it, show the raw error
|
|
87
|
+
const displayError = computedErrorPrettified || error
|
|
88
|
+
if (!displayError) {
|
|
87
89
|
return null
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -107,8 +109,8 @@ export const ErrorDisplay: React.FC<ErrorDisplayProps> = ({
|
|
|
107
109
|
/>
|
|
108
110
|
</svg>
|
|
109
111
|
<div className="flex-1 min-w-0">
|
|
110
|
-
<p className={`text-sm ${colors.text}`}>{
|
|
111
|
-
{error && error !==
|
|
112
|
+
<p className={`text-sm ${colors.text}`}>{displayError}</p>
|
|
113
|
+
{error && error !== displayError && (
|
|
112
114
|
<div className="mt-2">
|
|
113
115
|
<button
|
|
114
116
|
type="button"
|
|
@@ -46,7 +46,8 @@ interface FundProps {
|
|
|
46
46
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
47
47
|
isSequenceWallet?: boolean
|
|
48
48
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
49
|
-
|
|
49
|
+
swapProvider?: string
|
|
50
|
+
bridgeProvider?: string
|
|
50
51
|
fundMethod?: string
|
|
51
52
|
onNavigateToOnramp?: (
|
|
52
53
|
props: {
|
|
@@ -82,7 +83,8 @@ export const Fund: React.FC<FundProps> = ({
|
|
|
82
83
|
paymasterUrls,
|
|
83
84
|
isSequenceWallet = false,
|
|
84
85
|
setWalletConfirmRetryHandler,
|
|
85
|
-
|
|
86
|
+
swapProvider,
|
|
87
|
+
bridgeProvider,
|
|
86
88
|
fundMethod,
|
|
87
89
|
onNavigateToOnramp,
|
|
88
90
|
checkoutOnHandlers,
|
|
@@ -164,7 +166,8 @@ export const Fund: React.FC<FundProps> = ({
|
|
|
164
166
|
selectedToken: originToken as any,
|
|
165
167
|
setWalletConfirmRetryHandler,
|
|
166
168
|
tradeType: TradeType.EXACT_INPUT,
|
|
167
|
-
|
|
169
|
+
swapProvider,
|
|
170
|
+
bridgeProvider,
|
|
168
171
|
fundMethod,
|
|
169
172
|
mode,
|
|
170
173
|
onNavigateToOnramp,
|
|
@@ -25,7 +25,8 @@ interface FundProps {
|
|
|
25
25
|
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
26
26
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
27
27
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
28
|
-
|
|
28
|
+
swapProvider?: string
|
|
29
|
+
bridgeProvider?: string
|
|
29
30
|
fundMethod?: string
|
|
30
31
|
onNavigateToOnramp?: (
|
|
31
32
|
props: {
|
|
@@ -54,7 +54,8 @@ interface PayProps {
|
|
|
54
54
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
55
55
|
isSequenceWallet?: boolean
|
|
56
56
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
57
|
-
|
|
57
|
+
swapProvider?: string
|
|
58
|
+
bridgeProvider?: string
|
|
58
59
|
fundMethod?: string
|
|
59
60
|
onNavigateToOnramp?: (
|
|
60
61
|
props: {
|
|
@@ -92,7 +93,8 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
92
93
|
paymasterUrls,
|
|
93
94
|
isSequenceWallet = false,
|
|
94
95
|
setWalletConfirmRetryHandler,
|
|
95
|
-
|
|
96
|
+
swapProvider,
|
|
97
|
+
bridgeProvider,
|
|
96
98
|
fundMethod,
|
|
97
99
|
onNavigateToOnramp,
|
|
98
100
|
checkoutOnHandlers,
|
|
@@ -140,6 +142,7 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
140
142
|
useState(false)
|
|
141
143
|
const [showDestinationChainList, setShowDestinationChainList] =
|
|
142
144
|
useState(false)
|
|
145
|
+
const [showQuoteDetails, setShowQuoteDetails] = useState(false)
|
|
143
146
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
144
147
|
const paymentRequestInputRef = useRef<HTMLInputElement>(null)
|
|
145
148
|
const lastAutoSelectedRef = useRef<string | null>(null)
|
|
@@ -217,7 +220,8 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
217
220
|
selectedToken: originToken as any,
|
|
218
221
|
setWalletConfirmRetryHandler,
|
|
219
222
|
tradeType: TradeType.EXACT_OUTPUT, // Key difference: using EXACT_OUTPUT
|
|
220
|
-
|
|
223
|
+
swapProvider,
|
|
224
|
+
bridgeProvider,
|
|
221
225
|
fundMethod,
|
|
222
226
|
mode,
|
|
223
227
|
onNavigateToOnramp,
|
|
@@ -682,16 +686,19 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
682
686
|
</>
|
|
683
687
|
) : (
|
|
684
688
|
<>
|
|
685
|
-
≈ {prepareSendQuote?.originAmountUsdDisplay || "$0.00"}
|
|
689
|
+
≈ {prepareSendQuote?.originAmountUsdDisplay || "$0.00"}{" "}
|
|
686
690
|
{prepareSendQuote?.fees?.totalFeeAmountUsd &&
|
|
687
691
|
parseFloat(prepareSendQuote.fees.totalFeeAmountUsd) >
|
|
688
692
|
0 ? (
|
|
689
|
-
<
|
|
690
|
-
|
|
693
|
+
<button
|
|
694
|
+
type="button"
|
|
695
|
+
onClick={() => setShowQuoteDetails(true)}
|
|
696
|
+
className="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 cursor-pointer transition-colors"
|
|
697
|
+
>
|
|
691
698
|
(incl.{" "}
|
|
692
699
|
{prepareSendQuote.fees.totalFeeAmountUsdDisplay}{" "}
|
|
693
700
|
fees)
|
|
694
|
-
</
|
|
701
|
+
</button>
|
|
695
702
|
) : null}
|
|
696
703
|
</>
|
|
697
704
|
)
|
|
@@ -993,6 +1000,7 @@ export const Pay: React.FC<PayProps> = ({
|
|
|
993
1000
|
quote={prepareSendQuote}
|
|
994
1001
|
showContent={true}
|
|
995
1002
|
isRefetching={isLoadingQuote}
|
|
1003
|
+
initialExpanded={showQuoteDetails}
|
|
996
1004
|
/>
|
|
997
1005
|
</div>
|
|
998
1006
|
)}
|
|
@@ -54,7 +54,8 @@ interface PoolDepositProps {
|
|
|
54
54
|
onSend: (amount: string, recipient: string) => void
|
|
55
55
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
56
56
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
57
|
-
|
|
57
|
+
swapProvider?: string
|
|
58
|
+
bridgeProvider?: string
|
|
58
59
|
fundMethod?: string
|
|
59
60
|
onNavigateToOnramp?: (
|
|
60
61
|
props: {
|
|
@@ -84,7 +85,8 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
|
|
|
84
85
|
onSend,
|
|
85
86
|
paymasterUrls,
|
|
86
87
|
setWalletConfirmRetryHandler,
|
|
87
|
-
|
|
88
|
+
swapProvider,
|
|
89
|
+
bridgeProvider,
|
|
88
90
|
fundMethod,
|
|
89
91
|
onNavigateToOnramp,
|
|
90
92
|
checkoutOnHandlers,
|
|
@@ -205,7 +207,8 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
|
|
|
205
207
|
selectedToken: originToken as any,
|
|
206
208
|
setWalletConfirmRetryHandler,
|
|
207
209
|
tradeType: TradeType.EXACT_INPUT,
|
|
208
|
-
|
|
210
|
+
swapProvider,
|
|
211
|
+
bridgeProvider,
|
|
209
212
|
fundMethod,
|
|
210
213
|
mode,
|
|
211
214
|
onNavigateToOnramp,
|
|
@@ -26,6 +26,7 @@ interface QuoteDetailsProps {
|
|
|
26
26
|
swapMode?: boolean
|
|
27
27
|
compact?: boolean
|
|
28
28
|
isRefetching?: boolean
|
|
29
|
+
initialExpanded?: boolean
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
@@ -36,10 +37,11 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
36
37
|
swapMode,
|
|
37
38
|
compact = false,
|
|
38
39
|
isRefetching = false,
|
|
40
|
+
initialExpanded = false,
|
|
39
41
|
}) => {
|
|
40
42
|
const [showCalldata, setShowCalldata] = useState(false)
|
|
41
43
|
const [showOriginRate, setShowOriginRate] = useState(true)
|
|
42
|
-
const [isExpanded, setIsExpanded] = useState(
|
|
44
|
+
const [isExpanded, setIsExpanded] = useState(initialExpanded)
|
|
43
45
|
const [intentIdCopied, setIntentIdCopied] = useState(false)
|
|
44
46
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
45
47
|
const calldataRef = useRef<HTMLDivElement>(null)
|
|
@@ -57,6 +59,13 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
57
59
|
}
|
|
58
60
|
}, [showContent])
|
|
59
61
|
|
|
62
|
+
// Sync with initialExpanded prop changes
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (initialExpanded !== undefined) {
|
|
65
|
+
setIsExpanded(initialExpanded)
|
|
66
|
+
}
|
|
67
|
+
}, [initialExpanded])
|
|
68
|
+
|
|
60
69
|
// Notify parent when expansion state changes
|
|
61
70
|
useEffect(() => {
|
|
62
71
|
onExpand?.(isExpanded)
|
|
@@ -80,9 +89,11 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
80
89
|
|
|
81
90
|
if (!showContent) return null
|
|
82
91
|
|
|
83
|
-
// Use
|
|
84
|
-
const
|
|
85
|
-
|
|
92
|
+
// Use totalFeeAmountUsd from fees prop (this is the total fee from the API)
|
|
93
|
+
const totalFeeUsd = quote?.fees?.totalFeeAmountUsd
|
|
94
|
+
? parseFloat(quote.fees.totalFeeAmountUsd)
|
|
95
|
+
: 0
|
|
96
|
+
const totalFeeUsdDisplay = quote?.fees?.totalFeeAmountUsdDisplay ?? "$0.00"
|
|
86
97
|
|
|
87
98
|
return (
|
|
88
99
|
<div
|
|
@@ -136,7 +147,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
136
147
|
</span>
|
|
137
148
|
</div>
|
|
138
149
|
)}
|
|
139
|
-
{
|
|
150
|
+
{totalFeeUsd > 0 && (
|
|
140
151
|
<div className="flex items-center gap-1">
|
|
141
152
|
<svg
|
|
142
153
|
aria-hidden="true"
|
|
@@ -154,7 +165,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
154
165
|
d="M32 64C32 28.7 60.7 0 96 0H256c35.3 0 64 28.7 64 64V256h8c48.6 0 88 39.4 88 88v32c0 13.3 10.7 24 24 24s24-10.7 24-24V222c-27.6-7.1-48-32.2-48-62V96L384 64c-8.8-8.8-8.8-23.2 0-32s23.2-8.8 32 0l77.3 77.3c12 12 18.7 28.3 18.7 45.3V168v24 32V376c0 39.8-32.2 72-72 72s-72-32.2-72-72V344c0-22.1-17.9-40-40-40h-8V448c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32V64zM96 80v96c0 8.8 7.2 16 16 16H240c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16H112c-8.8 0-16 7.2-16 16z"
|
|
155
166
|
/>
|
|
156
167
|
</svg>
|
|
157
|
-
<span className="font-medium">{
|
|
168
|
+
<span className="font-medium">{totalFeeUsdDisplay}</span>
|
|
158
169
|
</div>
|
|
159
170
|
)}
|
|
160
171
|
<ChevronDown
|
|
@@ -214,15 +225,15 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
214
225
|
{quote?.trailsFeeBreakdown &&
|
|
215
226
|
(quote?.trailsFeeBreakdown.originRelayFee ||
|
|
216
227
|
quote?.trailsFeeBreakdown.destinationRelayFee) &&
|
|
217
|
-
|
|
228
|
+
totalFeeUsd > 0 && (
|
|
218
229
|
<>
|
|
219
230
|
<Row variant="bold">
|
|
220
231
|
<RowLabel tooltip="The total fees for this transaction, including gas costs and all provider fees">
|
|
221
232
|
Fees total
|
|
222
233
|
</RowLabel>
|
|
223
234
|
<RowValue>
|
|
224
|
-
<span title={`$${
|
|
225
|
-
≈ {
|
|
235
|
+
<span title={`$${totalFeeUsd}`}>
|
|
236
|
+
≈ {totalFeeUsdDisplay}
|
|
226
237
|
</span>
|
|
227
238
|
</RowValue>
|
|
228
239
|
</Row>
|
|
@@ -328,24 +339,31 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
328
339
|
const providerFee = quote.trailsFeeBreakdown.providerFee
|
|
329
340
|
const isCrossChain =
|
|
330
341
|
quote.originChain.id !== quote.destinationChain.id
|
|
331
|
-
|
|
342
|
+
|
|
343
|
+
const routeProviders = quote.routeProviders || []
|
|
344
|
+
|
|
345
|
+
// Filter out providers with empty names and get the first one
|
|
346
|
+
const validProviders = routeProviders.filter(
|
|
347
|
+
(p) => p.name,
|
|
348
|
+
)
|
|
349
|
+
const firstProvider = validProviders[0]
|
|
332
350
|
|
|
333
351
|
return (
|
|
334
352
|
<Row variant="light">
|
|
335
353
|
<RowLabel tooltip="Fee charged by the bridge/swap provider for executing the transaction">
|
|
336
354
|
{isCrossChain ? (
|
|
337
|
-
|
|
355
|
+
firstProvider ? (
|
|
338
356
|
<>
|
|
339
357
|
Bridge
|
|
340
358
|
<span>
|
|
341
359
|
(
|
|
342
360
|
<a
|
|
343
|
-
href={
|
|
361
|
+
href={firstProvider.url}
|
|
344
362
|
target="_blank"
|
|
345
363
|
rel="noopener noreferrer"
|
|
346
364
|
className="hover:underline inline-flex items-center gap-0.5 text-blue-500"
|
|
347
365
|
>
|
|
348
|
-
{
|
|
366
|
+
{firstProvider.name}
|
|
349
367
|
<ExternalLink className="size-3" />
|
|
350
368
|
</a>
|
|
351
369
|
)
|
|
@@ -354,18 +372,18 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
354
372
|
) : (
|
|
355
373
|
<>Bridge:</>
|
|
356
374
|
)
|
|
357
|
-
) :
|
|
375
|
+
) : firstProvider ? (
|
|
358
376
|
<>
|
|
359
377
|
Liquidity Provider{" "}
|
|
360
378
|
<span>
|
|
361
379
|
(
|
|
362
380
|
<a
|
|
363
|
-
href={
|
|
381
|
+
href={firstProvider.url}
|
|
364
382
|
target="_blank"
|
|
365
383
|
rel="noopener noreferrer"
|
|
366
384
|
className="hover:underline inline-flex items-center gap-0.5 text-blue-500"
|
|
367
385
|
>
|
|
368
|
-
{
|
|
386
|
+
{firstProvider.name}
|
|
369
387
|
<ExternalLink className="size-3" />
|
|
370
388
|
</a>
|
|
371
389
|
)
|
|
@@ -384,28 +402,6 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
384
402
|
)
|
|
385
403
|
})()}
|
|
386
404
|
|
|
387
|
-
{/* Swap Fees (implicit costs) */}
|
|
388
|
-
{quote.swapFeesUsdDisplay &&
|
|
389
|
-
(() => {
|
|
390
|
-
const swapFeesUsd = quote.swapFeesUsd ?? 0
|
|
391
|
-
|
|
392
|
-
// Only show if swap fees > 0
|
|
393
|
-
if (swapFeesUsd <= 0) return null
|
|
394
|
-
|
|
395
|
-
return (
|
|
396
|
-
<Row variant="light">
|
|
397
|
-
<RowLabel tooltip="Implicit costs including DEX fees, liquidity provider fees, and routing costs">
|
|
398
|
-
Swap
|
|
399
|
-
</RowLabel>
|
|
400
|
-
<RowValue>
|
|
401
|
-
<span title={`$${swapFeesUsd}`}>
|
|
402
|
-
{quote.swapFeesUsdDisplay}
|
|
403
|
-
</span>
|
|
404
|
-
</RowValue>
|
|
405
|
-
</Row>
|
|
406
|
-
)
|
|
407
|
-
})()}
|
|
408
|
-
|
|
409
405
|
{/* Trails Platform Fee */}
|
|
410
406
|
{hasTrailsFee &&
|
|
411
407
|
quote.trailsFeeBreakdown.trailsFee &&
|
|
@@ -25,7 +25,8 @@ interface SwapProps {
|
|
|
25
25
|
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
26
26
|
paymasterUrls?: Array<{ chainId: number; url: string }>
|
|
27
27
|
setWalletConfirmRetryHandler: (handler: () => Promise<void>) => void
|
|
28
|
-
|
|
28
|
+
swapProvider?: string
|
|
29
|
+
bridgeProvider?: string
|
|
29
30
|
fundMethod?: string
|
|
30
31
|
onNavigateToOnramp?: (
|
|
31
32
|
props: {
|