0xtrails 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abortController.d.ts +8 -0
- package/dist/abortController.d.ts.map +1 -0
- package/dist/{ccip-CXlshvBY.js → ccip-Xjh9d1gb.js} +7 -7
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/fees.d.ts +19 -0
- package/dist/fees.d.ts.map +1 -0
- package/dist/{index-_QuyGrjU.js → index-BnhdZ8Ho.js} +34769 -34247
- package/dist/index.js +726 -520
- package/dist/prepareSend.d.ts +11 -77
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/transactions.d.ts +4 -2
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts +4 -0
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts.map +1 -0
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -2
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/DynamicInputStyles.d.ts +18 -0
- package/dist/widget/components/DynamicInputStyles.d.ts.map +1 -0
- package/dist/widget/components/Earn.d.ts +2 -2
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/ErrorAnimationIcon.d.ts +2 -0
- package/dist/widget/components/ErrorAnimationIcon.d.ts.map +1 -0
- package/dist/widget/components/FeeBreakdown.d.ts +9 -0
- package/dist/widget/components/FeeBreakdown.d.ts.map +1 -0
- package/dist/widget/components/Fund.d.ts +2 -2
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundSwap.d.ts +2 -2
- package/dist/widget/components/FundSwap.d.ts.map +1 -1
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Identicon.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectExchanges.d.ts +0 -3
- package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts +2 -2
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts +3 -2
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/PoolWithdraw.d.ts +3 -2
- package/dist/widget/components/PoolWithdraw.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/Receipt.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +2 -2
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts +11 -0
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts.map +1 -0
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Tooltip.d.ts +9 -0
- package/dist/widget/components/Tooltip.d.ts.map +1 -0
- package/dist/widget/components/WaasFeeOptions.d.ts +1 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +1 -1
- package/dist/widget/hooks/useQuote.d.ts +83 -0
- package/dist/widget/hooks/useQuote.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +2 -2
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +2 -2
- package/dist/widget/widget.d.ts +5 -0
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/abortController.ts +35 -0
- package/src/constants.ts +3 -0
- package/src/fees.ts +199 -0
- package/src/prepareSend.ts +225 -398
- package/src/trails.ts +3 -3
- package/src/transactions.ts +62 -18
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountIntentTransactionHistoryButton.tsx +22 -0
- package/src/widget/components/AccountSettings.tsx +48 -36
- package/src/widget/components/ChainFilterDropdown.tsx +24 -3
- package/src/widget/components/ClassicSwap.tsx +24 -62
- package/src/widget/components/ConnectWallet.tsx +4 -1
- package/src/widget/components/ConnectedWallets.tsx +21 -21
- package/src/widget/components/DynamicInputStyles.tsx +76 -0
- package/src/widget/components/Earn.tsx +34 -29
- package/src/widget/components/ErrorAnimationIcon.tsx +130 -0
- package/src/widget/components/FeeBreakdown.tsx +155 -0
- package/src/widget/components/Fund.tsx +10 -26
- package/src/widget/components/FundSwap.tsx +2 -2
- package/src/widget/components/FundingMethodSelectorButton.tsx +24 -14
- package/src/widget/components/Identicon.tsx +164 -95
- package/src/widget/components/MeshConnectExchanges.tsx +2 -15
- package/src/widget/components/Modal.tsx +0 -12
- package/src/widget/components/Pay.tsx +65 -63
- package/src/widget/components/PoolDeposit.tsx +206 -230
- package/src/widget/components/PoolWithdraw.tsx +219 -238
- package/src/widget/components/PriceImpactWarning.tsx +1 -1
- package/src/widget/components/QuoteDetails.tsx +25 -8
- package/src/widget/components/Receipt.tsx +16 -2
- package/src/widget/components/RecipientSelectorButton.tsx +7 -5
- package/src/widget/components/Recipients.tsx +1 -1
- package/src/widget/components/ScreenHeader.tsx +60 -36
- package/src/widget/components/Swap.tsx +2 -2
- package/src/widget/components/ThemeProvider.tsx +2 -1
- package/src/widget/components/TokenDisplayNonSelectable.tsx +40 -0
- package/src/widget/components/TokenImage.tsx +1 -1
- package/src/widget/components/TokenSelector.tsx +62 -53
- package/src/widget/components/TokenSelectorButton.tsx +38 -15
- package/src/widget/components/Tooltip.tsx +51 -0
- package/src/widget/components/TransferPendingVertical.tsx +1 -1
- package/src/widget/components/WaasFeeOptions.tsx +124 -5
- package/src/widget/components/WalletConfirmation.tsx +23 -13
- package/src/widget/components/WalletConnect.tsx +93 -29
- package/src/widget/hooks/useQuote.ts +413 -0
- package/src/widget/hooks/useSendForm.ts +8 -4
- package/src/widget/widget.tsx +175 -190
|
@@ -27,10 +27,12 @@ import { logger } from "../../logger.js"
|
|
|
27
27
|
import { generateAaveWithdrawCalldata } from "../../aave.js"
|
|
28
28
|
import { generateMorphoWithdrawCalldata } from "../../morpho.js"
|
|
29
29
|
import { formatAmount } from "../../tokenBalances.js"
|
|
30
|
+
import { useDynamicInputStyles } from "./DynamicInputStyles.js"
|
|
31
|
+
import { TokenDisplayNonSelectable } from "./TokenDisplayNonSelectable.js"
|
|
30
32
|
|
|
31
33
|
interface PoolWithdrawProps {
|
|
32
|
-
account
|
|
33
|
-
walletClient
|
|
34
|
+
account?: Account
|
|
35
|
+
walletClient?: WalletClient
|
|
34
36
|
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
35
37
|
onError: (error: Error | string | null) => void
|
|
36
38
|
onWaitingForWalletConfirm: (props: PrepareSendQuote) => void
|
|
@@ -55,6 +57,7 @@ interface PoolWithdrawProps {
|
|
|
55
57
|
recentTokens?: SupportedToken[]
|
|
56
58
|
onRecentTokenSelect?: (token: SupportedToken) => void
|
|
57
59
|
onTrackToken?: (token: any) => void
|
|
60
|
+
onPoolSelectorStateChange?: (isShowing: boolean) => void
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
@@ -73,6 +76,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
73
76
|
fundMethod,
|
|
74
77
|
onNavigateToMeshConnect,
|
|
75
78
|
checkoutOnHandlers,
|
|
79
|
+
onPoolSelectorStateChange,
|
|
76
80
|
}) => {
|
|
77
81
|
const { mode } = useMode()
|
|
78
82
|
const { isBalanceVisible } = useBalanceVisible()
|
|
@@ -301,6 +305,13 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
301
305
|
|
|
302
306
|
// Generate withdraw calldata dynamically based on user's entered amount
|
|
303
307
|
const withdrawCalldata = useMemo(() => {
|
|
308
|
+
if (!account?.address) {
|
|
309
|
+
logger.console.log(
|
|
310
|
+
"[pool-withdraw] No account found, skipping calldata generation",
|
|
311
|
+
)
|
|
312
|
+
return undefined
|
|
313
|
+
}
|
|
314
|
+
|
|
304
315
|
const isAave = selectedPool?.protocol === "Aave"
|
|
305
316
|
const isMorpho = selectedPool?.protocol === "Morpho"
|
|
306
317
|
|
|
@@ -356,7 +367,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
356
367
|
)
|
|
357
368
|
return undefined
|
|
358
369
|
}
|
|
359
|
-
}, [selectedPool, amount, account
|
|
370
|
+
}, [selectedPool, amount, account?.address])
|
|
360
371
|
|
|
361
372
|
// Convert pool to token format for useSendForm
|
|
362
373
|
// For Aave, use the aToken address
|
|
@@ -539,6 +550,14 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
539
550
|
}
|
|
540
551
|
}, [])
|
|
541
552
|
|
|
553
|
+
// Notify parent component about pool selector visibility
|
|
554
|
+
useEffect(() => {
|
|
555
|
+
if (onPoolSelectorStateChange) {
|
|
556
|
+
// Only hide tabs when showing EarnPools selector
|
|
557
|
+
onPoolSelectorStateChange(showEarnPools)
|
|
558
|
+
}
|
|
559
|
+
}, [showEarnPools, onPoolSelectorStateChange])
|
|
560
|
+
|
|
542
561
|
const handleAmountChange = (value: string) => {
|
|
543
562
|
// Validate decimal places (max 8 decimals)
|
|
544
563
|
const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
|
|
@@ -561,6 +580,17 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
561
580
|
setSendFormAmount(selectedAmount)
|
|
562
581
|
}
|
|
563
582
|
|
|
583
|
+
// Dynamic font size based on input length
|
|
584
|
+
const inputStyles = useDynamicInputStyles({
|
|
585
|
+
inputValue: amount,
|
|
586
|
+
variant: "default",
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
// Get chain info for selected pool
|
|
590
|
+
const chainInfo = useMemo(() => {
|
|
591
|
+
return selectedPool ? getChainInfo(selectedPool.chainId) : null
|
|
592
|
+
}, [selectedPool])
|
|
593
|
+
|
|
564
594
|
if (showEarnPools) {
|
|
565
595
|
return (
|
|
566
596
|
<EarnPools
|
|
@@ -572,271 +602,222 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
572
602
|
|
|
573
603
|
return (
|
|
574
604
|
<div className="space-y-2">
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
<div className="
|
|
582
|
-
|
|
583
|
-
Withdraw From
|
|
584
|
-
</div>
|
|
605
|
+
{/* Pool Selection (Primary Section) */}
|
|
606
|
+
<div className="trails-bg-secondary trails-border-radius-container transition-all duration-200 border border-transparent hover:!bg-white dark:hover:!bg-white hover:border-gray-400 dark:hover:border-gray-500">
|
|
607
|
+
{selectedPool ? (
|
|
608
|
+
<div className="p-3 trails-border-radius-container trails-bg-secondary transition-all overflow-hidden">
|
|
609
|
+
{/* Vault Label */}
|
|
610
|
+
<div className="flex justify-between items-center mb-2">
|
|
611
|
+
<div className="text-sm font-semibold trails-text-secondary text-left">
|
|
612
|
+
From
|
|
585
613
|
</div>
|
|
614
|
+
</div>
|
|
586
615
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
616
|
+
<div className="px-1">
|
|
617
|
+
<div className="flex items-center justify-between">
|
|
618
|
+
<div className="flex items-center space-x-3">
|
|
619
|
+
<div style={{ width: "32px", height: "32px" }}>
|
|
620
|
+
<a
|
|
621
|
+
href={getExplorerUrlForAddress({
|
|
622
|
+
address: selectedPool.token.address,
|
|
623
|
+
chainId: selectedPool.chainId,
|
|
624
|
+
})}
|
|
625
|
+
target="_blank"
|
|
626
|
+
rel="noopener noreferrer"
|
|
627
|
+
className="cursor-pointer"
|
|
628
|
+
>
|
|
629
|
+
<TokenImage
|
|
630
|
+
symbol={selectedPool.token.symbol}
|
|
631
|
+
imageUrl={selectedPool.token.logoUrl}
|
|
632
|
+
chainId={selectedPool.chainId}
|
|
633
|
+
contractAddress={selectedPool.token.address}
|
|
634
|
+
size={32}
|
|
635
|
+
/>
|
|
636
|
+
</a>
|
|
637
|
+
</div>
|
|
638
|
+
<div>
|
|
639
|
+
<h3 className="font-medium text-gray-900 dark:text-white text-sm">
|
|
640
|
+
{selectedPool.poolUrl ? (
|
|
641
|
+
<a
|
|
642
|
+
href={selectedPool.poolUrl}
|
|
643
|
+
target="_blank"
|
|
644
|
+
rel="noopener noreferrer"
|
|
645
|
+
className="hover:underline cursor-pointer"
|
|
646
|
+
>
|
|
647
|
+
{selectedPool.name}
|
|
648
|
+
</a>
|
|
649
|
+
) : (
|
|
650
|
+
selectedPool.name
|
|
651
|
+
)}
|
|
652
|
+
</h3>
|
|
653
|
+
<div className="flex items-center space-x-2">
|
|
654
|
+
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
655
|
+
{selectedPool.protocol === "Aave" && (
|
|
656
|
+
<img
|
|
657
|
+
src={aaveLogo}
|
|
658
|
+
alt="Aave"
|
|
659
|
+
className="w-3 h-3 mr-1"
|
|
660
|
+
/>
|
|
661
|
+
)}
|
|
662
|
+
{selectedPool.protocol === "Morpho" && (
|
|
663
|
+
<img
|
|
664
|
+
src={morphoLogo}
|
|
665
|
+
alt="Morpho"
|
|
666
|
+
className="w-3 h-3 mr-1"
|
|
667
|
+
/>
|
|
668
|
+
)}
|
|
669
|
+
{selectedPool.protocolUrl ? (
|
|
612
670
|
<a
|
|
613
|
-
href={selectedPool.
|
|
671
|
+
href={selectedPool.protocolUrl}
|
|
614
672
|
target="_blank"
|
|
615
673
|
rel="noopener noreferrer"
|
|
616
674
|
className="hover:underline cursor-pointer"
|
|
617
675
|
>
|
|
618
|
-
{selectedPool.
|
|
676
|
+
{selectedPool.protocol}
|
|
619
677
|
</a>
|
|
620
678
|
) : (
|
|
621
|
-
selectedPool.
|
|
679
|
+
selectedPool.protocol
|
|
622
680
|
)}
|
|
623
|
-
</
|
|
624
|
-
<div className="flex items-center space-x-2">
|
|
625
|
-
<span className="text-xs text-gray-500 dark:text-gray-400 flex items-center">
|
|
626
|
-
{selectedPool.protocol === "Aave" && (
|
|
627
|
-
<img
|
|
628
|
-
src={aaveLogo}
|
|
629
|
-
alt="Aave"
|
|
630
|
-
className="w-3 h-3 mr-1"
|
|
631
|
-
/>
|
|
632
|
-
)}
|
|
633
|
-
{selectedPool.protocol === "Morpho" && (
|
|
634
|
-
<img
|
|
635
|
-
src={morphoLogo}
|
|
636
|
-
alt="Morpho"
|
|
637
|
-
className="w-3 h-3 mr-1"
|
|
638
|
-
/>
|
|
639
|
-
)}
|
|
640
|
-
{selectedPool.protocolUrl ? (
|
|
641
|
-
<a
|
|
642
|
-
href={selectedPool.protocolUrl}
|
|
643
|
-
target="_blank"
|
|
644
|
-
rel="noopener noreferrer"
|
|
645
|
-
className="hover:underline cursor-pointer"
|
|
646
|
-
>
|
|
647
|
-
{selectedPool.protocol}
|
|
648
|
-
</a>
|
|
649
|
-
) : (
|
|
650
|
-
selectedPool.protocol
|
|
651
|
-
)}
|
|
652
|
-
</span>
|
|
653
|
-
</div>
|
|
681
|
+
</span>
|
|
654
682
|
</div>
|
|
655
683
|
</div>
|
|
656
|
-
<button
|
|
657
|
-
type="button"
|
|
658
|
-
title="Select Vault"
|
|
659
|
-
onClick={() => setShowEarnPools(true)}
|
|
660
|
-
className="text-right flex items-center space-x-3 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 rounded p-2 transition-colors"
|
|
661
|
-
>
|
|
662
|
-
<div>
|
|
663
|
-
<div className="flex items-center justify-end space-x-1 text-green-600 dark:text-green-400 mb-1 whitespace-nowrap">
|
|
664
|
-
<TrendingUp className="w-3 h-3" />
|
|
665
|
-
<span className="font-semibold text-sm">
|
|
666
|
-
{selectedPool.apy.toFixed(1)}% APY
|
|
667
|
-
</span>
|
|
668
|
-
</div>
|
|
669
|
-
<p className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
670
|
-
TVL: {formatTvl(selectedPool.tvl)}
|
|
671
|
-
</p>
|
|
672
|
-
</div>
|
|
673
|
-
<ChevronRight className="w-4 h-4 text-gray-400" />
|
|
674
|
-
</button>
|
|
675
684
|
</div>
|
|
685
|
+
<button
|
|
686
|
+
type="button"
|
|
687
|
+
title="Select Vault"
|
|
688
|
+
onClick={() => setShowEarnPools(true)}
|
|
689
|
+
className="text-right flex items-center space-x-3 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 rounded p-2 transition-colors"
|
|
690
|
+
>
|
|
691
|
+
<div>
|
|
692
|
+
<div className="flex items-center justify-end space-x-1 text-green-600 dark:text-green-400 mb-1 whitespace-nowrap">
|
|
693
|
+
<TrendingUp className="w-3 h-3" />
|
|
694
|
+
<span className="font-semibold text-sm">
|
|
695
|
+
{selectedPool.apy.toFixed(1)}% APY
|
|
696
|
+
</span>
|
|
697
|
+
</div>
|
|
698
|
+
<p className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
699
|
+
TVL: {formatTvl(selectedPool.tvl)}
|
|
700
|
+
</p>
|
|
701
|
+
</div>
|
|
702
|
+
<ChevronRight className="w-4 h-4 text-gray-400" />
|
|
703
|
+
</button>
|
|
676
704
|
</div>
|
|
677
705
|
</div>
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
706
|
+
</div>
|
|
707
|
+
) : (
|
|
708
|
+
<button
|
|
709
|
+
type="button"
|
|
710
|
+
onClick={() => setShowEarnPools(true)}
|
|
711
|
+
className="w-full py-6 px-4 trails-list-item trails-border-radius-container transition-all duration-200 cursor-pointer"
|
|
712
|
+
>
|
|
713
|
+
<div className="flex items-center justify-between">
|
|
714
|
+
<div className="flex items-center space-x-3 flex-1">
|
|
715
|
+
<div className="w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center">
|
|
716
|
+
<Search className="w-4 h-4 text-gray-400" />
|
|
717
|
+
</div>
|
|
718
|
+
<div className="text-left flex-1">
|
|
719
|
+
<div className="font-semibold text-gray-900 dark:text-white text-sm">
|
|
720
|
+
Select vault to withdraw from
|
|
693
721
|
</div>
|
|
694
722
|
</div>
|
|
695
|
-
<ChevronRight className="w-4 h-4 trails-text-muted flex-shrink-0" />
|
|
696
723
|
</div>
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
724
|
+
<ChevronRight className="w-4 h-4 trails-text-muted flex-shrink-0" />
|
|
725
|
+
</div>
|
|
726
|
+
</button>
|
|
727
|
+
)}
|
|
728
|
+
</div>
|
|
700
729
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
730
|
+
{/* Amount Input Section */}
|
|
731
|
+
{selectedPool && (
|
|
732
|
+
<div className="pt-4 pb-4 mb-4 trails-bg-secondary trails-bg-secondary-hover trails-border-radius-container p-3 group transition-all duration-200 border border-transparent focus-within:!bg-white dark:focus-within:!bg-gray-800 trails-focus-border-secondary min-h-[120px] flex flex-col">
|
|
733
|
+
{/* Withdraw Label */}
|
|
734
|
+
<div className="mb-4 flex justify-between items-center">
|
|
735
|
+
<div className="text-sm font-medium trails-text-secondary text-left m-0">
|
|
736
|
+
Amount
|
|
737
|
+
</div>
|
|
738
|
+
</div>
|
|
739
|
+
|
|
740
|
+
<div className="flex items-center space-x-2 flex-1">
|
|
741
|
+
{/* Amount Input */}
|
|
742
|
+
<div className="flex-1">
|
|
743
|
+
<div className="flex items-center space-x-2">
|
|
744
|
+
<input
|
|
745
|
+
ref={inputRef}
|
|
746
|
+
id="amount"
|
|
747
|
+
type="text"
|
|
748
|
+
value={amount}
|
|
749
|
+
onChange={(e) => handleAmountChange(e.target.value)}
|
|
750
|
+
placeholder={"0"}
|
|
751
|
+
className={`w-full bg-transparent font-bold trails-text-primary placeholder:trails-text-muted border-none outline-none ${
|
|
752
|
+
isLoadingQuote ? "animate-pulse" : ""
|
|
753
|
+
}`}
|
|
754
|
+
style={inputStyles}
|
|
755
|
+
inputMode="decimal"
|
|
756
|
+
/>
|
|
757
|
+
{isLoadingQuote && (
|
|
758
|
+
<div className="animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
|
|
759
|
+
)}
|
|
708
760
|
</div>
|
|
709
761
|
</div>
|
|
710
762
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
763
|
+
{/* Token Display (Not Selectable) */}
|
|
764
|
+
<TokenDisplayNonSelectable
|
|
765
|
+
symbol={selectedPool.token.symbol}
|
|
766
|
+
imageUrl={selectedPool.token.logoUrl}
|
|
767
|
+
chainId={selectedPool.chainId}
|
|
768
|
+
contractAddress={selectedPool.token.address}
|
|
769
|
+
chainName={chainInfo?.name}
|
|
770
|
+
/>
|
|
771
|
+
</div>
|
|
772
|
+
|
|
773
|
+
{/* Bottom Info Row */}
|
|
774
|
+
<div className="mt-4 flex justify-between items-center">
|
|
775
|
+
{/* USD Amount */}
|
|
776
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
777
|
+
{selectedPool && amount ? (
|
|
778
|
+
<>≈ {underlyingTokenUsdDisplay || "$0.00"}</>
|
|
779
|
+
) : (
|
|
780
|
+
<span> </span>
|
|
781
|
+
)}
|
|
782
|
+
</div>
|
|
783
|
+
|
|
784
|
+
{/* Pool Balance and Percentage Buttons */}
|
|
785
|
+
{poolBalance && (
|
|
786
|
+
<div className="flex items-center space-x-2">
|
|
714
787
|
<button
|
|
715
788
|
type="button"
|
|
716
|
-
className="
|
|
717
|
-
onClick={() =>
|
|
789
|
+
className="text-xs text-gray-500 dark:text-gray-400 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 transition-colors bg-transparent border-none p-0"
|
|
790
|
+
onClick={() => handleAmountSelect(poolBalance || "0")}
|
|
791
|
+
onKeyDown={(e) => {
|
|
792
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
793
|
+
e.preventDefault()
|
|
794
|
+
handleAmountSelect(poolBalance || "0")
|
|
795
|
+
}
|
|
796
|
+
}}
|
|
797
|
+
title="Click to withdraw full balance"
|
|
718
798
|
>
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
placeholder="0"
|
|
726
|
-
className={`bg-transparent border-none outline-none font-bold text-left trails-text-primary placeholder-trails-text-primary ${
|
|
727
|
-
isLoadingQuote ? "animate-pulse" : ""
|
|
728
|
-
}`}
|
|
729
|
-
style={{
|
|
730
|
-
fontSize:
|
|
731
|
-
amount.length > 12
|
|
732
|
-
? "0.875rem"
|
|
733
|
-
: amount.length > 9
|
|
734
|
-
? "1rem"
|
|
735
|
-
: amount.length > 6
|
|
736
|
-
? "1.125rem"
|
|
737
|
-
: amount.length > 3
|
|
738
|
-
? "1.25rem"
|
|
739
|
-
: "1.5rem",
|
|
740
|
-
width: `${Math.max((amount || "0").length, 1)}ch`,
|
|
741
|
-
minWidth: "1ch",
|
|
742
|
-
maxWidth: "270px",
|
|
743
|
-
padding: "0",
|
|
744
|
-
margin: "0",
|
|
745
|
-
transition: "all 0.1s ease-in-out",
|
|
746
|
-
}}
|
|
747
|
-
inputMode="decimal"
|
|
748
|
-
/>
|
|
749
|
-
<span
|
|
750
|
-
className="font-bold text-gray-400 dark:text-gray-500"
|
|
751
|
-
style={{
|
|
752
|
-
fontSize:
|
|
753
|
-
amount.length > 12
|
|
754
|
-
? "0.875rem"
|
|
755
|
-
: amount.length > 9
|
|
756
|
-
? "1rem"
|
|
757
|
-
: amount.length > 6
|
|
758
|
-
? "1.125rem"
|
|
759
|
-
: amount.length > 3
|
|
760
|
-
? "1.25rem"
|
|
761
|
-
: "1.5rem",
|
|
762
|
-
marginLeft: "0.1em",
|
|
763
|
-
padding: "0",
|
|
764
|
-
transition: "all 0.2s ease-in-out",
|
|
765
|
-
}}
|
|
766
|
-
>
|
|
767
|
-
{selectedPool?.token.symbol.slice(0, 4) || ""}
|
|
768
|
-
</span>
|
|
769
|
-
{isLoadingQuote && (
|
|
770
|
-
<div className="ml-2 animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
|
|
771
|
-
)}
|
|
772
|
-
</div>
|
|
799
|
+
Pool Balance:{" "}
|
|
800
|
+
{isBalanceVisible
|
|
801
|
+
? isLoadingBalance
|
|
802
|
+
? "Loading..."
|
|
803
|
+
: poolBalance || "0.00"
|
|
804
|
+
: "••••••"}
|
|
773
805
|
</button>
|
|
774
|
-
</div>
|
|
775
806
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
807
|
+
{/* Percentage Buttons */}
|
|
808
|
+
<PercentageMaxButtons
|
|
809
|
+
userBalance={poolBalance || undefined}
|
|
810
|
+
isNativeToken={false} // Pool tokens are never native tokens
|
|
811
|
+
gasCostFormatted={prepareSendQuote?.gasCostFormatted}
|
|
781
812
|
chainId={selectedPool.chainId}
|
|
782
|
-
|
|
783
|
-
|
|
813
|
+
onAmountSelect={handleAmountSelect}
|
|
814
|
+
className="opacity-100"
|
|
784
815
|
/>
|
|
785
|
-
<span className="font-medium trails-text-primary text-sm">
|
|
786
|
-
{selectedPool.token.symbol}
|
|
787
|
-
</span>
|
|
788
816
|
</div>
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
{/* Bottom Info Row */}
|
|
792
|
-
<div className="mt-2 flex justify-between items-center">
|
|
793
|
-
{/* USD Amount */}
|
|
794
|
-
<div className="text-xs trails-text-muted">
|
|
795
|
-
{selectedPool && amount ? (
|
|
796
|
-
<>≈ {underlyingTokenUsdDisplay || "$0.00"}</>
|
|
797
|
-
) : (
|
|
798
|
-
<span> </span>
|
|
799
|
-
)}
|
|
800
|
-
</div>
|
|
801
|
-
|
|
802
|
-
{/* Pool Balance and Percentage Buttons */}
|
|
803
|
-
{poolBalance && (
|
|
804
|
-
<div className="flex items-center space-x-2">
|
|
805
|
-
<button
|
|
806
|
-
type="button"
|
|
807
|
-
className="text-xs trails-text-muted cursor-pointer hover:trails-hover-text transition-colors bg-transparent border-none p-0"
|
|
808
|
-
onClick={() => handleAmountSelect(poolBalance || "0")}
|
|
809
|
-
onKeyDown={(e) => {
|
|
810
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
811
|
-
e.preventDefault()
|
|
812
|
-
handleAmountSelect(poolBalance || "0")
|
|
813
|
-
}
|
|
814
|
-
}}
|
|
815
|
-
title="Click to withdraw full balance"
|
|
816
|
-
>
|
|
817
|
-
Pool Balance:{" "}
|
|
818
|
-
{isBalanceVisible
|
|
819
|
-
? isLoadingBalance
|
|
820
|
-
? "Loading..."
|
|
821
|
-
: poolBalance || "0.00"
|
|
822
|
-
: "••••••"}
|
|
823
|
-
</button>
|
|
824
|
-
|
|
825
|
-
{/* Percentage Buttons */}
|
|
826
|
-
<PercentageMaxButtons
|
|
827
|
-
userBalance={poolBalance || undefined}
|
|
828
|
-
isNativeToken={false} // Pool tokens are never native tokens
|
|
829
|
-
gasCostFormatted={prepareSendQuote?.gasCostFormatted}
|
|
830
|
-
chainId={selectedPool.chainId}
|
|
831
|
-
onAmountSelect={handleAmountSelect}
|
|
832
|
-
className="opacity-100"
|
|
833
|
-
/>
|
|
834
|
-
</div>
|
|
835
|
-
)}
|
|
836
|
-
</div>
|
|
817
|
+
)}
|
|
837
818
|
</div>
|
|
838
|
-
|
|
839
|
-
|
|
819
|
+
</div>
|
|
820
|
+
)}
|
|
840
821
|
|
|
841
822
|
{prepareSendQuote?.noSufficientBalance ? (
|
|
842
823
|
<div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
|
|
@@ -864,7 +845,7 @@ export const PoolWithdraw: React.FC<PoolWithdrawProps> = ({
|
|
|
864
845
|
|
|
865
846
|
{/* Quote Details */}
|
|
866
847
|
{prepareSendQuote && (
|
|
867
|
-
<div className="
|
|
848
|
+
<div className="mb-4">
|
|
868
849
|
<QuoteDetails quote={prepareSendQuote} showContent={true} />
|
|
869
850
|
</div>
|
|
870
851
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TokenImage } from "./TokenImage.js"
|
|
2
|
-
import { InfoIcon
|
|
2
|
+
import { InfoIcon } from "@0xsequence/design-system"
|
|
3
|
+
import { Tooltip } from "./Tooltip.js"
|
|
3
4
|
import type React from "react"
|
|
4
5
|
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
5
6
|
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
@@ -7,6 +8,7 @@ import { useState, useEffect, useRef } from "react"
|
|
|
7
8
|
import { truncateAddress } from "../../utils.js"
|
|
8
9
|
import { PriceImpactWarning } from "./PriceImpactWarning.js"
|
|
9
10
|
import { usePriceImpactWarning } from "../hooks/usePriceImpactWarning.js"
|
|
11
|
+
import { FeeBreakdown } from "./FeeBreakdown.js"
|
|
10
12
|
|
|
11
13
|
interface QuoteDetailsProps {
|
|
12
14
|
quote?: PrepareSendQuote | null
|
|
@@ -14,6 +16,7 @@ interface QuoteDetailsProps {
|
|
|
14
16
|
children?: React.ReactNode
|
|
15
17
|
onExpand?: (isExpanded: boolean) => void
|
|
16
18
|
swapMode?: boolean
|
|
19
|
+
compact?: boolean
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
// Helper function to format completion time
|
|
@@ -44,6 +47,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
44
47
|
children,
|
|
45
48
|
onExpand,
|
|
46
49
|
swapMode,
|
|
50
|
+
compact = false,
|
|
47
51
|
}) => {
|
|
48
52
|
const [showCalldata, setShowCalldata] = useState(false)
|
|
49
53
|
const [showOriginRate, setShowOriginRate] = useState(true)
|
|
@@ -88,7 +92,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
88
92
|
<button
|
|
89
93
|
type="button"
|
|
90
94
|
onClick={() => setIsExpanded(true)}
|
|
91
|
-
className="w-full flex items-center justify-between py-2 px-4 trails-border-radius-button transition-colors cursor-pointer text-xs
|
|
95
|
+
className="w-full flex items-center justify-between py-2 px-4 trails-border-radius-button transition-colors cursor-pointer text-xs"
|
|
92
96
|
aria-label="Show more details"
|
|
93
97
|
>
|
|
94
98
|
<div className="flex items-center gap-2 text-gray-600 dark:text-gray-400 whitespace-nowrap max-w-48 truncate">
|
|
@@ -161,7 +165,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
161
165
|
<button
|
|
162
166
|
type="button"
|
|
163
167
|
onClick={() => setIsExpanded(true)}
|
|
164
|
-
className=
|
|
168
|
+
className={`w-full max-w-md flex items-center ${compact ? "justify-center" : "justify-between"} gap-2 py-1 px-1 trails-border-radius-button transition-colors cursor-pointer text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300`}
|
|
165
169
|
aria-label="Show transaction details"
|
|
166
170
|
>
|
|
167
171
|
<span>Transaction details</span>
|
|
@@ -195,9 +199,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
195
199
|
className={`text-sm ${swapMode ? "p-2 space-y-2" : "p-4 rounded-lg space-y-4 trails-bg-secondary"}`}
|
|
196
200
|
>
|
|
197
201
|
{/* Close Button - only visible when expanded, at top center */}
|
|
198
|
-
<div
|
|
199
|
-
className={`flex justify-center ${swapMode ? "mb-2 -mt-1" : "mb-4 -mt-2"}`}
|
|
200
|
-
>
|
|
202
|
+
<div className={`flex justify-center mb-4 -mt-2`}>
|
|
201
203
|
{swapMode ? (
|
|
202
204
|
<button
|
|
203
205
|
type="button"
|
|
@@ -665,7 +667,22 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
665
667
|
)
|
|
666
668
|
})()}
|
|
667
669
|
|
|
668
|
-
{
|
|
670
|
+
{/* Total Fees with optional breakdown */}
|
|
671
|
+
{quote?.trailsFeeBreakdown ? (
|
|
672
|
+
<FeeBreakdown feeBreakdown={quote.trailsFeeBreakdown}>
|
|
673
|
+
<div className="flex justify-between items-center w-full">
|
|
674
|
+
<span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 w-full">
|
|
675
|
+
Total Fees:
|
|
676
|
+
<Tooltip message="The total fees charged for this transaction, including gas fees, bridge fees, and any platform fees. These fees are deducted from your transaction.">
|
|
677
|
+
<InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
|
|
678
|
+
</Tooltip>
|
|
679
|
+
</span>
|
|
680
|
+
<span className="font-medium text-xs text-gray-900 dark:text-white">
|
|
681
|
+
{quote.fees.totalFeeAmountUsdDisplay}
|
|
682
|
+
</span>
|
|
683
|
+
</div>
|
|
684
|
+
</FeeBreakdown>
|
|
685
|
+
) : quote?.fees?.totalFeeAmountUsd != null ? (
|
|
669
686
|
<div className="flex justify-between items-center">
|
|
670
687
|
<span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
|
|
671
688
|
Total Fees:
|
|
@@ -677,7 +694,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
|
|
|
677
694
|
{quote.fees.totalFeeAmountUsdDisplay}
|
|
678
695
|
</span>
|
|
679
696
|
</div>
|
|
680
|
-
)}
|
|
697
|
+
) : null}
|
|
681
698
|
|
|
682
699
|
{quote?.quoteProvider?.name && (
|
|
683
700
|
<div className="flex justify-between items-center">
|