0xtrails 0.1.3 → 0.1.4
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/address.d.ts.map +1 -1
- package/dist/analytics.d.ts +18 -0
- package/dist/analytics.d.ts.map +1 -1
- package/dist/apiClient.d.ts +1 -1
- package/dist/apiClient.d.ts.map +1 -1
- package/dist/{ccip-CWd4g9uZ.js → ccip-dLSEJjCf.js} +55 -55
- package/dist/cctpqueue.d.ts +1 -1
- package/dist/cctpqueue.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/decoders.d.ts +58 -0
- package/dist/decoders.d.ts.map +1 -0
- package/dist/ens.d.ts +6 -0
- package/dist/ens.d.ts.map +1 -1
- package/dist/error.d.ts +7 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/{index-BTUBzx4R.js → index-BXbaLmtt.js} +25694 -24507
- package/dist/index.js +2 -2
- package/dist/intents.d.ts +4 -4
- package/dist/intents.d.ts.map +1 -1
- package/dist/metaTxns.d.ts +1 -1
- package/dist/metaTxns.d.ts.map +1 -1
- package/dist/mode.d.ts +1 -1
- package/dist/mode.d.ts.map +1 -1
- package/dist/preconditions.d.ts +1 -1
- package/dist/preconditions.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +30 -24
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/prices.d.ts +1 -1
- package/dist/prices.d.ts.map +1 -1
- package/dist/proxyCaller.d.ts +0 -1
- package/dist/proxyCaller.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts +1 -1
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/trails.d.ts +1 -1
- package/dist/trails.d.ts.map +1 -1
- package/dist/transactions.d.ts +4 -0
- package/dist/transactions.d.ts.map +1 -1
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/widget/components/DebugScreensDropdown.d.ts.map +1 -1
- package/dist/widget/components/ErrorDisplay.d.ts +9 -0
- package/dist/widget/components/ErrorDisplay.d.ts.map +1 -0
- package/dist/widget/components/FundSendForm.d.ts +1 -1
- package/dist/widget/components/FundSendForm.d.ts.map +1 -1
- package/dist/widget/components/OriginTransferInformation.d.ts +10 -0
- package/dist/widget/components/OriginTransferInformation.d.ts.map +1 -0
- package/dist/widget/components/PaySendForm.d.ts +1 -1
- package/dist/widget/components/PaySendForm.d.ts.map +1 -1
- 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 +12 -0
- package/dist/widget/components/Receive.d.ts.map +1 -0
- package/dist/widget/components/Swap.d.ts +5 -1
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapDisplay.d.ts +9 -0
- package/dist/widget/components/SwapDisplay.d.ts.map +1 -0
- package/dist/widget/components/TransferPendingVertical.d.ts +2 -0
- package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
- package/dist/widget/components/YellowWarningAnimation.d.ts +2 -0
- package/dist/widget/components/YellowWarningAnimation.d.ts.map +1 -0
- package/dist/widget/hooks/useDebugScreens.d.ts +22 -0
- package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +7 -3
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +16 -15
- package/src/address.ts +3 -0
- package/src/analytics.ts +105 -4
- package/src/apiClient.ts +1 -1
- package/src/cctpqueue.ts +1 -1
- package/src/constants.ts +3 -0
- package/src/decoders.ts +310 -0
- package/src/ens.ts +16 -1
- package/src/error.ts +86 -1
- package/src/intents.ts +10 -2
- package/src/metaTxns.ts +1 -1
- package/src/mode.ts +1 -1
- package/src/preconditions.ts +1 -1
- package/src/prepareSend.ts +432 -114
- package/src/prices.ts +5 -1
- package/src/proxyCaller.ts +2 -14
- package/src/tokenBalances.ts +21 -17
- package/src/tokens.ts +62 -3
- package/src/trails.ts +2 -2
- package/src/transactions.ts +35 -18
- package/src/utils.ts +28 -0
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/DebugScreensDropdown.tsx +3 -0
- package/src/widget/components/ErrorDisplay.tsx +150 -0
- package/src/widget/components/FundSendForm.tsx +62 -9
- package/src/widget/components/OriginTransferInformation.tsx +59 -0
- package/src/widget/components/PaySendForm.tsx +65 -12
- package/src/widget/components/QRCodeDeposit.tsx +5 -5
- package/src/widget/components/QrCode.tsx +1 -1
- package/src/widget/components/QuoteDetails.tsx +93 -25
- package/src/widget/components/Receipt.tsx +296 -103
- package/src/widget/components/Receive.tsx +146 -0
- package/src/widget/components/RecentTokens.tsx +1 -1
- package/src/widget/components/Swap.tsx +206 -85
- package/src/widget/components/SwapDisplay.tsx +68 -0
- package/src/widget/components/TokenSelector.tsx +1 -1
- package/src/widget/components/TransferPendingVertical.tsx +162 -112
- package/src/widget/components/YellowWarningAnimation.tsx +146 -0
- package/src/widget/hooks/useDebugScreens.ts +583 -0
- package/src/widget/hooks/useSendForm.ts +46 -4
- package/src/widget/hooks/useTokenList.ts +8 -27
- package/src/widget/widget.tsx +201 -484
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query"
|
|
2
2
|
import type React from "react"
|
|
3
|
-
import { useEffect, useState } from "react"
|
|
3
|
+
import { useEffect, useState, useCallback, useMemo } from "react"
|
|
4
|
+
import { ChevronRight } from "lucide-react"
|
|
4
5
|
import type { TransactionState } from "../../transactions.js"
|
|
5
6
|
import { GreenCheckAnimation } from "./GreenCheckAnimation.js"
|
|
7
|
+
import { YellowWarningAnimation } from "./YellowWarningAnimation.js"
|
|
6
8
|
import { getTxTimeDiff } from "../../transactions.js"
|
|
7
9
|
import { QuoteDetails } from "./QuoteDetails.js"
|
|
8
10
|
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
9
11
|
import { truncateAddress } from "../../address.js"
|
|
10
12
|
import { formatElapsed } from "../../utils.js"
|
|
13
|
+
import { ChainImage } from "./ChainImage.js"
|
|
11
14
|
|
|
12
15
|
interface ReceiptProps {
|
|
13
16
|
onSendAnother: () => void
|
|
@@ -55,8 +58,9 @@ function useTxTimeDiff(firstTx?: TransactionState, lastTx?: TransactionState) {
|
|
|
55
58
|
|
|
56
59
|
// Custom hook to compute finalExplorerUrl and completionTimeSeconds
|
|
57
60
|
function useReceipt(transactionStates?: TransactionState[]) {
|
|
58
|
-
const
|
|
59
|
-
|
|
61
|
+
const lastTx = transactionStates?.[transactionStates.length - 1]
|
|
62
|
+
const finalExplorerUrl = lastTx?.explorerUrl
|
|
63
|
+
const finalChainId = lastTx?.chainId
|
|
60
64
|
|
|
61
65
|
// Only consider confirmed transactions
|
|
62
66
|
const confirmedTxs = (transactionStates || []).filter(
|
|
@@ -67,10 +71,11 @@ function useReceipt(transactionStates?: TransactionState[]) {
|
|
|
67
71
|
const last = confirmedTxs[confirmedTxs.length - 1]
|
|
68
72
|
|
|
69
73
|
const completionTimeSeconds = useTxTimeDiff(first, last)
|
|
70
|
-
return { finalExplorerUrl, completionTimeSeconds }
|
|
74
|
+
return { finalExplorerUrl, completionTimeSeconds, finalChainId }
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
export const Receipt: React.FC<ReceiptProps> = ({
|
|
78
|
+
onSendAnother,
|
|
74
79
|
onClose,
|
|
75
80
|
renderInline = false,
|
|
76
81
|
transactionStates = [],
|
|
@@ -78,6 +83,8 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
78
83
|
quote,
|
|
79
84
|
}) => {
|
|
80
85
|
const [showContent, setShowContent] = useState(false)
|
|
86
|
+
const [showRefundInfo, setShowRefundInfo] = useState(false)
|
|
87
|
+
const [refundMessage, setRefundMessage] = useState<string | null>(null)
|
|
81
88
|
|
|
82
89
|
useEffect(() => {
|
|
83
90
|
const timer = setTimeout(() => {
|
|
@@ -87,13 +94,155 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
87
94
|
return () => clearTimeout(timer)
|
|
88
95
|
}, [])
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
// Helper function to check if a specific transaction has meta tx errors
|
|
98
|
+
const hasMetaTxError = useCallback((tx: TransactionState) => {
|
|
99
|
+
return tx?.decodedGuestModuleEvents?.some(
|
|
100
|
+
(event) => event.type === "CallFailed",
|
|
101
|
+
)
|
|
102
|
+
}, [])
|
|
103
|
+
|
|
104
|
+
const showMetaTxError = useMemo(() => {
|
|
105
|
+
return transactionStates.some((tx) => hasMetaTxError(tx))
|
|
106
|
+
}, [transactionStates, hasMetaTxError])
|
|
107
|
+
|
|
108
|
+
const {
|
|
109
|
+
finalExplorerUrl,
|
|
110
|
+
finalChainId,
|
|
111
|
+
completionTimeSeconds: calculatedCompletionTime,
|
|
112
|
+
} = useReceipt(transactionStates)
|
|
92
113
|
|
|
93
114
|
// Use provided totalCompletionSeconds if available, otherwise use calculated time
|
|
94
115
|
const completionTimeSeconds =
|
|
95
116
|
totalCompletionSeconds ?? calculatedCompletionTime
|
|
96
117
|
|
|
118
|
+
// Detect successful refund events on origin or sweep on destination
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!transactionStates || transactionStates.length === 0) return
|
|
121
|
+
|
|
122
|
+
const originTx = transactionStates[0]
|
|
123
|
+
const destinationTx = transactionStates[transactionStates.length - 1]
|
|
124
|
+
|
|
125
|
+
// Check if this is a same-chain transaction (all transactions on same chain)
|
|
126
|
+
const isSameChain =
|
|
127
|
+
transactionStates.length <= 2 &&
|
|
128
|
+
transactionStates.every((tx) => tx.chainId === originTx?.chainId)
|
|
129
|
+
|
|
130
|
+
const originRefund = originTx?.decodedTrailsTokenSweeperEvents?.find(
|
|
131
|
+
(e) => e.type === "Refund",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
// Only check destination sweep for cross-chain transactions
|
|
135
|
+
const destinationSweep = !isSameChain
|
|
136
|
+
? destinationTx?.decodedTrailsTokenSweeperEvents?.find(
|
|
137
|
+
(e) => e.type === "Sweep",
|
|
138
|
+
)
|
|
139
|
+
: null
|
|
140
|
+
|
|
141
|
+
if (originRefund) {
|
|
142
|
+
setRefundMessage(
|
|
143
|
+
"The origin call failed, but your funds were successfully refunded on the origin chain.",
|
|
144
|
+
)
|
|
145
|
+
setShowRefundInfo(true)
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (destinationSweep) {
|
|
150
|
+
setRefundMessage(
|
|
151
|
+
"The destination call failed, but a refund was successfully handled on the destination chain.",
|
|
152
|
+
)
|
|
153
|
+
setShowRefundInfo(true)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
setShowRefundInfo(false)
|
|
158
|
+
setRefundMessage(null)
|
|
159
|
+
}, [transactionStates])
|
|
160
|
+
|
|
161
|
+
// Extract QuoteDetails section to reuse in both success and failure states
|
|
162
|
+
const quoteDetailsSection = quote && (
|
|
163
|
+
<div className="mt-2">
|
|
164
|
+
<QuoteDetails quote={quote} showContent={true}>
|
|
165
|
+
{transactionStates.length > 0 && (
|
|
166
|
+
<>
|
|
167
|
+
<div className="font-medium text-gray-700 dark:text-gray-300">
|
|
168
|
+
Transactions:
|
|
169
|
+
</div>
|
|
170
|
+
<div className="space-y-2">
|
|
171
|
+
{transactionStates.map((state, i) => (
|
|
172
|
+
<div
|
|
173
|
+
key={`${state.transactionHash}-${i}`}
|
|
174
|
+
className="p-2 rounded bg-gray-100 dark:bg-gray-700/50"
|
|
175
|
+
>
|
|
176
|
+
<div className="flex justify-between items-center">
|
|
177
|
+
<span className="text-gray-600 dark:text-gray-400">
|
|
178
|
+
{state.label}:
|
|
179
|
+
</span>
|
|
180
|
+
<span
|
|
181
|
+
className={`px-2 py-0.5 rounded-full text-xs ${
|
|
182
|
+
state.state === "confirmed"
|
|
183
|
+
? "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-400"
|
|
184
|
+
: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-400"
|
|
185
|
+
}`}
|
|
186
|
+
>
|
|
187
|
+
{state.state.charAt(0).toUpperCase() +
|
|
188
|
+
state.state.slice(1)}
|
|
189
|
+
</span>
|
|
190
|
+
</div>
|
|
191
|
+
<div className="mt-1 flex justify-between items-center">
|
|
192
|
+
<span className="text-gray-600 dark:text-gray-400">
|
|
193
|
+
Hash:
|
|
194
|
+
</span>
|
|
195
|
+
<a
|
|
196
|
+
href={state.explorerUrl}
|
|
197
|
+
target="_blank"
|
|
198
|
+
rel="noopener noreferrer"
|
|
199
|
+
className="flex items-center gap-1 hover:underline text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
|
200
|
+
>
|
|
201
|
+
{hasMetaTxError(state) && (
|
|
202
|
+
<svg
|
|
203
|
+
className="w-4 h-4 text-orange-500"
|
|
204
|
+
fill="none"
|
|
205
|
+
viewBox="0 0 24 24"
|
|
206
|
+
stroke="currentColor"
|
|
207
|
+
>
|
|
208
|
+
<title>
|
|
209
|
+
An internal meta transaction failure occurred
|
|
210
|
+
</title>
|
|
211
|
+
<path
|
|
212
|
+
strokeLinecap="round"
|
|
213
|
+
strokeLinejoin="round"
|
|
214
|
+
strokeWidth={2}
|
|
215
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
216
|
+
/>
|
|
217
|
+
</svg>
|
|
218
|
+
)}
|
|
219
|
+
<ChainImage chainId={state.chainId} size={16} />
|
|
220
|
+
<span>{truncateAddress(state.transactionHash)}</span>
|
|
221
|
+
<svg
|
|
222
|
+
className="w-3 h-3"
|
|
223
|
+
fill="none"
|
|
224
|
+
viewBox="0 0 24 24"
|
|
225
|
+
stroke="currentColor"
|
|
226
|
+
>
|
|
227
|
+
<title>External Link</title>
|
|
228
|
+
<path
|
|
229
|
+
strokeLinecap="round"
|
|
230
|
+
strokeLinejoin="round"
|
|
231
|
+
strokeWidth={2}
|
|
232
|
+
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
233
|
+
/>
|
|
234
|
+
</svg>
|
|
235
|
+
</a>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
))}
|
|
239
|
+
</div>
|
|
240
|
+
</>
|
|
241
|
+
)}
|
|
242
|
+
</QuoteDetails>
|
|
243
|
+
</div>
|
|
244
|
+
)
|
|
245
|
+
|
|
97
246
|
if (!finalExplorerUrl) {
|
|
98
247
|
return (
|
|
99
248
|
<div className="flex flex-col justify-center min-h-full space-y-6 pt-8">
|
|
@@ -126,6 +275,21 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
126
275
|
</p>
|
|
127
276
|
</div>
|
|
128
277
|
|
|
278
|
+
{onSendAnother && (
|
|
279
|
+
<div className="flex justify-center">
|
|
280
|
+
<button
|
|
281
|
+
type="button"
|
|
282
|
+
onClick={onSendAnother}
|
|
283
|
+
className="inline-flex items-center gap-1 px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 trails-border-radius-button transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 cursor-pointer font-medium"
|
|
284
|
+
>
|
|
285
|
+
Try Again
|
|
286
|
+
</button>
|
|
287
|
+
</div>
|
|
288
|
+
)}
|
|
289
|
+
|
|
290
|
+
{/* Quote Details - Show even in failed state */}
|
|
291
|
+
{quoteDetailsSection}
|
|
292
|
+
|
|
129
293
|
{!renderInline && (
|
|
130
294
|
<div className="text-center">
|
|
131
295
|
<button
|
|
@@ -145,15 +309,24 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
145
309
|
<div className="flex flex-col justify-center min-h-full space-y-6 pt-8">
|
|
146
310
|
<div className="text-center mb-2">
|
|
147
311
|
<div className={`mx-auto flex items-center justify-center`}>
|
|
148
|
-
|
|
312
|
+
{showRefundInfo || showMetaTxError ? (
|
|
313
|
+
<YellowWarningAnimation />
|
|
314
|
+
) : (
|
|
315
|
+
<GreenCheckAnimation />
|
|
316
|
+
)}
|
|
149
317
|
</div>
|
|
150
318
|
|
|
151
319
|
<div
|
|
152
320
|
className={`transition-all duration-500 ease-out ${showContent ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
|
|
153
321
|
>
|
|
154
322
|
<h2 className="mt-4 text-2xl font-bold text-gray-900 dark:text-white">
|
|
155
|
-
Completed
|
|
323
|
+
{showRefundInfo ? "Unable to process." : "Completed"}
|
|
156
324
|
</h2>
|
|
325
|
+
{showRefundInfo && (
|
|
326
|
+
<div className="mt-1 text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-1 justify-center animate-fade-in-up">
|
|
327
|
+
Refunded.
|
|
328
|
+
</div>
|
|
329
|
+
)}
|
|
157
330
|
{completionTimeSeconds > 0 && (
|
|
158
331
|
<div
|
|
159
332
|
className="mt-1 text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1 justify-center animate-fade-in-up"
|
|
@@ -162,28 +335,37 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
162
335
|
animationFillMode: "both",
|
|
163
336
|
}}
|
|
164
337
|
>
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
338
|
+
<div className="inline-block animate-fade-in-up">
|
|
339
|
+
{showRefundInfo ? (
|
|
340
|
+
<span>Transaction confirmed</span>
|
|
341
|
+
) : (
|
|
342
|
+
<span>
|
|
343
|
+
Completed in{" "}
|
|
344
|
+
<strong>{formatElapsed(completionTimeSeconds)}</strong>
|
|
345
|
+
</span>
|
|
346
|
+
)}
|
|
347
|
+
</div>
|
|
348
|
+
{totalCompletionSeconds &&
|
|
349
|
+
totalCompletionSeconds < 15 &&
|
|
350
|
+
!showMetaTxError &&
|
|
351
|
+
!showRefundInfo && (
|
|
352
|
+
<svg
|
|
353
|
+
className="w-4 h-4 ml-1 text-yellow-400 inline"
|
|
354
|
+
fill="none"
|
|
355
|
+
viewBox="0 0 24 24"
|
|
356
|
+
stroke="currentColor"
|
|
357
|
+
aria-hidden="true"
|
|
358
|
+
>
|
|
359
|
+
<title>Lightning Fast</title>
|
|
360
|
+
<path
|
|
361
|
+
strokeLinecap="round"
|
|
362
|
+
strokeLinejoin="round"
|
|
363
|
+
strokeWidth={2}
|
|
364
|
+
d="M13 10V3L4 14h7v7l9-11h-7z"
|
|
365
|
+
fill="currentColor"
|
|
366
|
+
/>
|
|
367
|
+
</svg>
|
|
368
|
+
)}
|
|
187
369
|
<style>{`
|
|
188
370
|
@keyframes fadeInUp {
|
|
189
371
|
0% { opacity: 0; transform: translateY(16px); }
|
|
@@ -192,6 +374,33 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
192
374
|
`}</style>
|
|
193
375
|
</div>
|
|
194
376
|
)}
|
|
377
|
+
|
|
378
|
+
{(showMetaTxError || showRefundInfo) && (
|
|
379
|
+
<div
|
|
380
|
+
className="mt-2 text-sm text-orange-600 dark:text-orange-400 flex items-center gap-2 justify-center animate-fade-in-up"
|
|
381
|
+
style={{
|
|
382
|
+
animation: "fadeInUp 0.7s cubic-bezier(0.23, 1, 0.32, 1)",
|
|
383
|
+
animationFillMode: "both",
|
|
384
|
+
}}
|
|
385
|
+
>
|
|
386
|
+
<svg
|
|
387
|
+
className="w-4 h-4 text-orange-500"
|
|
388
|
+
fill="none"
|
|
389
|
+
viewBox="0 0 24 24"
|
|
390
|
+
stroke="currentColor"
|
|
391
|
+
aria-hidden="true"
|
|
392
|
+
>
|
|
393
|
+
<title>Internal Meta Transaction Error</title>
|
|
394
|
+
<path
|
|
395
|
+
strokeLinecap="round"
|
|
396
|
+
strokeLinejoin="round"
|
|
397
|
+
strokeWidth={2}
|
|
398
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
399
|
+
/>
|
|
400
|
+
</svg>
|
|
401
|
+
<span>Although one or more errors occurred</span>
|
|
402
|
+
</div>
|
|
403
|
+
)}
|
|
195
404
|
</div>
|
|
196
405
|
</div>
|
|
197
406
|
|
|
@@ -204,6 +413,7 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
204
413
|
rel="noopener noreferrer"
|
|
205
414
|
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"
|
|
206
415
|
>
|
|
416
|
+
{finalChainId && <ChainImage chainId={finalChainId} size={16} />}
|
|
207
417
|
View on Explorer
|
|
208
418
|
<svg
|
|
209
419
|
className="w-4 h-4 ml-1 text-black dark:text-blue-300"
|
|
@@ -222,9 +432,64 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
222
432
|
</a>
|
|
223
433
|
</div>
|
|
224
434
|
|
|
435
|
+
{showRefundInfo && refundMessage && (
|
|
436
|
+
<div
|
|
437
|
+
className="mt-2 text-sm text-yellow-700 dark:text-yellow-400 flex items-center gap-2 justify-center animate-fade-in-up"
|
|
438
|
+
style={{
|
|
439
|
+
animation: "fadeInUp 0.7s cubic-bezier(0.23, 1, 0.32, 1)",
|
|
440
|
+
animationFillMode: "both",
|
|
441
|
+
}}
|
|
442
|
+
>
|
|
443
|
+
<div className="rounded-xl bg-warning">
|
|
444
|
+
<div className="flex bg-background-overlay rounded-xl p-4 w-full flex-col gap-3">
|
|
445
|
+
<div className="flex w-full gap-2 justify-between">
|
|
446
|
+
<div className="flex flex-col gap-1">
|
|
447
|
+
<div className="text-sm font-medium text-gray-900 dark:text-white text-left">
|
|
448
|
+
Refund Information
|
|
449
|
+
</div>
|
|
450
|
+
<div className="text-sm text-gray-700 dark:text-gray-300 text-left">
|
|
451
|
+
{refundMessage}
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
<div className="flex items-center">
|
|
455
|
+
<svg
|
|
456
|
+
className="w-5 h-5 text-yellow-600 dark:text-yellow-400"
|
|
457
|
+
fill="none"
|
|
458
|
+
viewBox="0 0 24 24"
|
|
459
|
+
stroke="currentColor"
|
|
460
|
+
aria-hidden="true"
|
|
461
|
+
>
|
|
462
|
+
<title>Information</title>
|
|
463
|
+
<path
|
|
464
|
+
strokeLinecap="round"
|
|
465
|
+
strokeLinejoin="round"
|
|
466
|
+
strokeWidth={2}
|
|
467
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
468
|
+
/>
|
|
469
|
+
</svg>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
</div>
|
|
474
|
+
</div>
|
|
475
|
+
)}
|
|
476
|
+
|
|
225
477
|
<div
|
|
226
478
|
className={`space-y-3 transition-all duration-500 ease-out delay-200 ${showContent ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
|
|
227
479
|
>
|
|
480
|
+
{onSendAnother && (
|
|
481
|
+
<div className="flex justify-center">
|
|
482
|
+
<button
|
|
483
|
+
type="button"
|
|
484
|
+
onClick={onSendAnother}
|
|
485
|
+
className="inline-flex items-center gap-1 px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 trails-border-radius-button transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 cursor-pointer font-medium"
|
|
486
|
+
>
|
|
487
|
+
Send Again
|
|
488
|
+
<ChevronRight className="w-4 h-4" />
|
|
489
|
+
</button>
|
|
490
|
+
</div>
|
|
491
|
+
)}
|
|
492
|
+
|
|
228
493
|
{!renderInline && (
|
|
229
494
|
<button
|
|
230
495
|
type="button"
|
|
@@ -236,79 +501,7 @@ export const Receipt: React.FC<ReceiptProps> = ({
|
|
|
236
501
|
)}
|
|
237
502
|
|
|
238
503
|
{/* Quote Details */}
|
|
239
|
-
{
|
|
240
|
-
<div className="mt-2">
|
|
241
|
-
<QuoteDetails quote={quote} showContent={true}>
|
|
242
|
-
{transactionStates.length > 0 && (
|
|
243
|
-
<>
|
|
244
|
-
<div className="font-medium text-gray-700 dark:text-gray-300">
|
|
245
|
-
Transactions:
|
|
246
|
-
</div>
|
|
247
|
-
<div className="space-y-2">
|
|
248
|
-
{transactionStates.map((state) => (
|
|
249
|
-
<div
|
|
250
|
-
key={state.transactionHash}
|
|
251
|
-
className="p-2 rounded bg-gray-100 dark:bg-gray-700/50"
|
|
252
|
-
>
|
|
253
|
-
<div className="flex justify-between items-center">
|
|
254
|
-
<span className="text-gray-600 dark:text-gray-400">
|
|
255
|
-
{state.label}:
|
|
256
|
-
</span>
|
|
257
|
-
<span
|
|
258
|
-
className={`px-2 py-0.5 rounded-full text-xs ${
|
|
259
|
-
state.state === "confirmed"
|
|
260
|
-
? "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-400"
|
|
261
|
-
: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-400"
|
|
262
|
-
}`}
|
|
263
|
-
>
|
|
264
|
-
{state.state}
|
|
265
|
-
</span>
|
|
266
|
-
</div>
|
|
267
|
-
<div className="mt-1 flex justify-between items-center">
|
|
268
|
-
<span className="text-gray-600 dark:text-gray-400">
|
|
269
|
-
Chain ID:
|
|
270
|
-
</span>
|
|
271
|
-
<span className="text-gray-900 dark:text-white">
|
|
272
|
-
{state.chainId}
|
|
273
|
-
</span>
|
|
274
|
-
</div>
|
|
275
|
-
<div className="mt-1 flex justify-between items-center">
|
|
276
|
-
<span className="text-gray-600 dark:text-gray-400">
|
|
277
|
-
Hash:
|
|
278
|
-
</span>
|
|
279
|
-
<a
|
|
280
|
-
href={state.explorerUrl}
|
|
281
|
-
target="_blank"
|
|
282
|
-
rel="noopener noreferrer"
|
|
283
|
-
className="flex items-center gap-1 hover:underline text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
|
284
|
-
>
|
|
285
|
-
<span>
|
|
286
|
-
{truncateAddress(state.transactionHash)}
|
|
287
|
-
</span>
|
|
288
|
-
<svg
|
|
289
|
-
className="w-3 h-3"
|
|
290
|
-
fill="none"
|
|
291
|
-
viewBox="0 0 24 24"
|
|
292
|
-
stroke="currentColor"
|
|
293
|
-
>
|
|
294
|
-
<title>External Link</title>
|
|
295
|
-
<path
|
|
296
|
-
strokeLinecap="round"
|
|
297
|
-
strokeLinejoin="round"
|
|
298
|
-
strokeWidth={2}
|
|
299
|
-
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
300
|
-
/>
|
|
301
|
-
</svg>
|
|
302
|
-
</a>
|
|
303
|
-
</div>
|
|
304
|
-
</div>
|
|
305
|
-
))}
|
|
306
|
-
</div>
|
|
307
|
-
</>
|
|
308
|
-
)}
|
|
309
|
-
</QuoteDetails>
|
|
310
|
-
</div>
|
|
311
|
-
)}
|
|
504
|
+
{quoteDetailsSection}
|
|
312
505
|
</div>
|
|
313
506
|
</div>
|
|
314
507
|
)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type React from "react"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
|
+
import { QrCode } from "./QrCode.js"
|
|
4
|
+
import { ScreenHeader } from "./ScreenHeader.js"
|
|
5
|
+
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
6
|
+
import { ExternalLink } from "lucide-react"
|
|
7
|
+
import { truncateAddress } from "../../address.js"
|
|
8
|
+
import { useResolveEnsName } from "../../ens.js"
|
|
9
|
+
|
|
10
|
+
interface ReceiveProps {
|
|
11
|
+
accountAddress: string
|
|
12
|
+
onBack: () => void
|
|
13
|
+
isConnected?: boolean
|
|
14
|
+
onConnectWallet?: () => void
|
|
15
|
+
onPay?: () => void
|
|
16
|
+
toChainId?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const Receive: React.FC<ReceiveProps> = ({
|
|
20
|
+
accountAddress,
|
|
21
|
+
onBack,
|
|
22
|
+
isConnected = false,
|
|
23
|
+
onConnectWallet,
|
|
24
|
+
onPay,
|
|
25
|
+
toChainId,
|
|
26
|
+
}) => {
|
|
27
|
+
// Use the provided address directly
|
|
28
|
+
const resolvedAddress = accountAddress
|
|
29
|
+
|
|
30
|
+
// Resolve ENS name from the address
|
|
31
|
+
const { ensName } = useResolveEnsName({
|
|
32
|
+
address: accountAddress,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Generate QR code URL for the address
|
|
36
|
+
const qrCodeUrl = useMemo(() => {
|
|
37
|
+
if (!resolvedAddress) return ""
|
|
38
|
+
return `ethereum:${resolvedAddress}`
|
|
39
|
+
}, [resolvedAddress])
|
|
40
|
+
|
|
41
|
+
// Check if accountAddress is provided
|
|
42
|
+
if (!accountAddress) {
|
|
43
|
+
return (
|
|
44
|
+
<div className="space-y-6">
|
|
45
|
+
<ScreenHeader
|
|
46
|
+
onBack={onBack}
|
|
47
|
+
headerContent="Receive"
|
|
48
|
+
headerContentAlign="center"
|
|
49
|
+
/>
|
|
50
|
+
|
|
51
|
+
<div className="flex flex-col justify-center min-h-full space-y-6 pt-8">
|
|
52
|
+
<div className="text-center p-6 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-700/50 rounded-lg">
|
|
53
|
+
<div className="flex items-center justify-center space-x-2 text-amber-600 dark:text-amber-400">
|
|
54
|
+
<svg
|
|
55
|
+
className="w-5 h-5"
|
|
56
|
+
fill="none"
|
|
57
|
+
viewBox="0 0 24 24"
|
|
58
|
+
stroke="currentColor"
|
|
59
|
+
>
|
|
60
|
+
<path
|
|
61
|
+
strokeLinecap="round"
|
|
62
|
+
strokeLinejoin="round"
|
|
63
|
+
strokeWidth={2}
|
|
64
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
65
|
+
/>
|
|
66
|
+
</svg>
|
|
67
|
+
<span className="font-medium">Account address is required</span>
|
|
68
|
+
</div>
|
|
69
|
+
<p className="mt-2 text-sm text-amber-600 dark:text-amber-400">
|
|
70
|
+
Please provide an account address as <code>toAddress</code> to
|
|
71
|
+
generate the receive QR code.
|
|
72
|
+
</p>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div className="space-y-2">
|
|
81
|
+
<ScreenHeader
|
|
82
|
+
onBack={onBack}
|
|
83
|
+
headerContent={`Pay ${ensName ? ensName : truncateAddress(resolvedAddress)}`}
|
|
84
|
+
headerContentAlign="center"
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<div className="flex flex-col justify-center min-h-full space-y-6 pt-2">
|
|
88
|
+
{/* QR Code Section */}
|
|
89
|
+
<div className="space-y-3 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg">
|
|
90
|
+
<div className="flex justify-center">
|
|
91
|
+
<div className="flex flex-col items-center">
|
|
92
|
+
<QrCode url={qrCodeUrl} size={300} />
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
{/* Address Display */}
|
|
97
|
+
<div className="flex flex-col items-center justify-center gap-1 pt-2">
|
|
98
|
+
<div className="flex items-center gap-1">
|
|
99
|
+
<span className="text-xs text-gray-500 dark:text-gray-400">
|
|
100
|
+
Address:
|
|
101
|
+
</span>
|
|
102
|
+
<a
|
|
103
|
+
href={getExplorerUrlForAddress({
|
|
104
|
+
address: resolvedAddress,
|
|
105
|
+
chainId: toChainId || 1,
|
|
106
|
+
})}
|
|
107
|
+
target="_blank"
|
|
108
|
+
rel="noopener noreferrer"
|
|
109
|
+
className="flex items-center gap-1 text-xs text-gray-500 dark:text-gray-400 hover:underline transition-all"
|
|
110
|
+
>
|
|
111
|
+
<span>{truncateAddress(resolvedAddress)}</span>
|
|
112
|
+
<ExternalLink className="w-3 h-3" />
|
|
113
|
+
</a>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
{/* Connect Wallet Button - Only show when not connected */}
|
|
119
|
+
{!isConnected && onConnectWallet && (
|
|
120
|
+
<div className="flex justify-center">
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
onClick={onConnectWallet}
|
|
124
|
+
className="px-6 py-3 font-medium rounded-lg transition-colors duration-200 cursor-pointer bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-900 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-300 dark:hover:text-white"
|
|
125
|
+
>
|
|
126
|
+
Connect Wallet
|
|
127
|
+
</button>
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{/* Pay Button - Only show when connected */}
|
|
132
|
+
{isConnected && onPay && (
|
|
133
|
+
<div className="flex justify-center">
|
|
134
|
+
<button
|
|
135
|
+
type="button"
|
|
136
|
+
onClick={onPay}
|
|
137
|
+
className="px-6 py-3 font-medium rounded-lg transition-colors duration-200 cursor-pointer bg-blue-500 hover:bg-blue-600 text-white"
|
|
138
|
+
>
|
|
139
|
+
Pay
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
@@ -27,7 +27,7 @@ export const RecentTokens: React.FC<RecentTokensProps> = ({
|
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<div className="mb-0">
|
|
30
|
-
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-500">
|
|
30
|
+
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-500 text-left">
|
|
31
31
|
Recently Used
|
|
32
32
|
</h3>
|
|
33
33
|
<div className="flex gap-2 overflow-x-auto pb-1 trails-scrollbar">
|