@@ -6,6 +6,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
66import { AlertCircle , ArrowRightLeft , Info , Settings , Share2 , Vote , Waves } from "lucide-react" ;
77
88import { Badge , Button , Card , CardContent , CardFooter , CardHeader , ChainAssetSelector , Input } from "@/components/ui" ;
9+ import { cn } from "@/lib/utils" ;
910import type { Chain as SelectorChain } from "@/components/ui" ;
1011
1112const QuotePreviewCard = dynamic ( ( ) =>
@@ -119,7 +120,7 @@ function buildSigningLifecycle(
119120}
120121
121122export default function SwapPage ( ) {
122- const { isConnected } = useUnifiedWallet ( ) ;
123+ const { isConnected, activeChain , balance } = useUnifiedWallet ( ) ;
123124 const { localizePath } = useI18n ( ) ;
124125 const [ amount , setAmount ] = useState ( "" ) ;
125126 const [ orderType , setOrderType ] = useState < "market" | "limit" | "twap" > ( "limit" ) ;
@@ -164,6 +165,33 @@ export default function SwapPage() {
164165 const isAmountValid = Number . isFinite ( Number ( amount ) ) && Number ( amount ) > 0 ;
165166 const canSubmit = isConnected && isAmountValid && ! quoteLoading && ! quoteError && ! isSameChain ;
166167
168+ // Inject wallet balance into the from-chain asset so ChainAssetSelector can display it (#383)
169+ const fromChainData = useMemo ( ( ) => {
170+ if ( ! balance || activeChain !== sourceChain ) return CHAIN_SELECTOR_DATA ;
171+ return CHAIN_SELECTOR_DATA . map ( ( chain ) =>
172+ chain . id !== activeChain
173+ ? chain
174+ : {
175+ ...chain ,
176+ assets : chain . assets . map ( ( asset ) => ( {
177+ ...asset ,
178+ balance : asset . symbol === fromAsset ? balance : undefined ,
179+ } ) ) ,
180+ }
181+ ) ;
182+ } , [ balance , activeChain , sourceChain , fromAsset ] ) ;
183+
184+ // Balance available for quick-amount shortcuts — only when wallet chain matches source chain
185+ const walletBalance = activeChain === sourceChain ? ( balance ?? null ) : null ;
186+
187+ const applyQuickAmount = ( label : string ) => {
188+ const bal = parseFloat ( walletBalance ?? "0" ) ;
189+ if ( ! bal || bal <= 0 ) return ;
190+ const multiplier = label === "Max" ? 1 : parseFloat ( label ) / 100 ;
191+ const raw = ( bal * multiplier ) . toFixed ( 8 ) . replace ( / \. ? 0 + $ / , "" ) ;
192+ setAmount ( raw ) ;
193+ } ;
194+
167195 const submitLabel = ! isConnected
168196 ? "Connect Wallet to Swap"
169197 : ! isAmountValid
@@ -278,7 +306,7 @@ export default function SwapPage() {
278306 : "" ;
279307
280308 return (
281- < div className = "container mx-auto max-w-3xl px-4 py-12 " >
309+ < div className = "mx-auto max-w-3xl" >
282310 < FeeWarningBanner chains = { [ sourceChain , destChain ] } />
283311
284312 < Card >
@@ -289,12 +317,12 @@ export default function SwapPage() {
289317 < CardContent className = "space-y-4" >
290318 < div className = "grid grid-cols-2 gap-3" >
291319 < ChainAssetSelector
292- chains = { CHAIN_SELECTOR_DATA }
320+ chains = { fromChainData }
293321 selectedChain = { sourceChain }
294322 selectedAsset = { fromAsset }
295323 onSelect = { handleSourceSelect }
296324 label = "From"
297- showBalance = { false }
325+ showBalance = { ! ! walletBalance }
298326 />
299327 < ChainAssetSelector
300328 chains = { CHAIN_SELECTOR_DATA }
@@ -313,12 +341,32 @@ export default function SwapPage() {
313341 </ p >
314342 ) }
315343
316- < Input
317- placeholder = "0.00"
318- type = "number"
319- value = { amount }
320- onChange = { ( e ) => setAmount ( e . target . value ) }
321- />
344+ < div className = "space-y-2" >
345+ < Input
346+ placeholder = "0.00"
347+ type = "number"
348+ value = { amount }
349+ onChange = { ( e ) => setAmount ( e . target . value ) }
350+ />
351+ < div className = "flex gap-1.5" >
352+ { ( [ "25%" , "50%" , "75%" , "Max" ] as const ) . map ( ( label ) => (
353+ < button
354+ key = { label }
355+ type = "button"
356+ disabled = { ! walletBalance }
357+ onClick = { ( ) => applyQuickAmount ( label ) }
358+ className = { cn (
359+ "flex-1 rounded-md py-1 text-xs font-medium transition-colors" ,
360+ walletBalance
361+ ? "bg-surface-raised text-text-secondary hover:bg-brand-500/10 hover:text-brand-500 cursor-pointer"
362+ : "bg-surface text-text-muted opacity-40 cursor-not-allowed"
363+ ) }
364+ >
365+ { label }
366+ </ button >
367+ ) ) }
368+ </ div >
369+ </ div >
322370
323371 < QuotePreviewCard
324372 quote = { quote }
0 commit comments