@@ -28,7 +28,7 @@ import {
2828 CheckCircle ,
2929} from "lucide-react"
3030import { useAccount , useWriteContract , useReadContract , useWaitForTransactionReceipt } from "wagmi"
31- import { parseEther , formatEther , formatUnits , erc20Abi } from "viem"
31+ import { parseUnits , formatUnits , erc20Abi } from "viem"
3232
3333function isHexAddress ( value : string | null ) : value is `0x${string } ` {
3434 return ! ! value && / ^ 0 x [ a - f A - F 0 - 9 ] { 40 } $ / . test ( value )
@@ -152,6 +152,20 @@ export default function OracleInteractionPage() {
152152 query : { enabled : ! ! oracleAddress }
153153 } )
154154
155+ const { data : weightTokenSymbolData } = useReadContract ( {
156+ address : ( weightTokenAddress as `0x${string } `) || undefined ,
157+ abi : erc20Abi ,
158+ functionName : 'symbol' ,
159+ query : { enabled : ! ! weightTokenAddress }
160+ } )
161+
162+ const { data : weightTokenDecimalsData } = useReadContract ( {
163+ address : ( weightTokenAddress as `0x${string } `) || undefined ,
164+ abi : erc20Abi ,
165+ functionName : 'decimals' ,
166+ query : { enabled : ! ! weightTokenAddress }
167+ } )
168+
155169 // Read user's locked tokens (for governance operations)
156170 const { data : lockedTokensData } = useReadContract ( {
157171 address : oracleAddress || undefined ,
@@ -305,20 +319,56 @@ export default function OracleInteractionPage() {
305319 query : { enabled : ! ! weightTokenAddress && ! ! userAddress && ! ! oracleAddress }
306320 } )
307321
322+ const weightTokenSymbol = useMemo ( ( ) => ( weightTokenSymbolData ? String ( weightTokenSymbolData ) : "WEIGHT" ) , [ weightTokenSymbolData ] )
323+ const weightTokenDecimals = useMemo ( ( ) => {
324+ if ( weightTokenDecimalsData === undefined || weightTokenDecimalsData === null ) {
325+ return 18
326+ }
327+ const value = Number ( weightTokenDecimalsData )
328+ return Number . isFinite ( value ) ? value : 18
329+ } , [ weightTokenDecimalsData ] )
330+ const weightTokenAddressString = useMemo ( ( ) => ( weightTokenAddress ? String ( weightTokenAddress ) : "—" ) , [ weightTokenAddress ] )
331+ const canCopyWeightTokenAddress = useMemo (
332+ ( ) => weightTokenAddressString . startsWith ( "0x" ) && weightTokenAddressString . length === 42 ,
333+ [ weightTokenAddressString ]
334+ )
335+ const formatTokenAmount = useCallback (
336+ ( value ?: bigint | null , fractionDigits = 2 ) => {
337+ try {
338+ const normalized = formatUnits ( value ?? BigInt ( 0 ) , weightTokenDecimals )
339+ const numeric = Number . parseFloat ( normalized )
340+ if ( ! Number . isFinite ( numeric ) ) {
341+ return "0.00"
342+ }
343+ return numeric . toFixed ( fractionDigits )
344+ } catch {
345+ return "0.00"
346+ }
347+ } ,
348+ [ weightTokenDecimals ]
349+ )
350+ const walletTokenBalanceDisplay = useMemo (
351+ ( ) => {
352+ const numeric = Number . parseFloat ( userTokenBalance || "0" )
353+ return Number . isFinite ( numeric ) ? numeric . toFixed ( 2 ) : "0.00"
354+ } ,
355+ [ userTokenBalance ]
356+ )
357+
308358 // Update real-time data when contract data changes
309359 useEffect ( ( ) => {
310360 // Calculate total deposited tokens (sum of locked and unlocked tokens)
311361 if ( lockedTokensData !== undefined || unlockedTokensData !== undefined ) {
312362 const locked = lockedTokensData ? BigInt ( lockedTokensData as bigint ) : BigInt ( 0 )
313363 const unlocked = unlockedTokensData ? BigInt ( unlockedTokensData as bigint ) : BigInt ( 0 )
314364 const total = locked + unlocked
315- setUserDepositedTokens ( formatEther ( total ) )
365+ setUserDepositedTokens ( formatTokenAmount ( total , 4 ) )
316366 }
317- if ( userTokenBalanceData ) {
318- setUserTokenBalance ( formatEther ( userTokenBalanceData as bigint ) )
367+ if ( userTokenBalanceData !== undefined ) {
368+ setUserTokenBalance ( formatTokenAmount ( userTokenBalanceData as bigint , 4 ) )
319369 }
320- if ( tokenAllowanceData ) {
321- setTokenAllowance ( formatEther ( tokenAllowanceData as bigint ) )
370+ if ( tokenAllowanceData !== undefined ) {
371+ setTokenAllowance ( formatTokenAmount ( tokenAllowanceData as bigint , 4 ) )
322372 }
323373 if ( lastSubmissionTimeData ) {
324374 const timestamp = Number ( lastSubmissionTimeData as bigint )
@@ -379,7 +429,7 @@ export default function OracleInteractionPage() {
379429 }
380430 }
381431
382- } , [ lockedTokensData , unlockedTokensData , userTokenBalanceData , tokenAllowanceData , lastSubmissionTimeData , rewardData , halfLifeSecondsData , quorumData , operationLockingPeriodData , withdrawalLockingPeriodData , alphaData , depositTimestampData , lastOperationTimestampData ] )
432+ } , [ lockedTokensData , unlockedTokensData , userTokenBalanceData , tokenAllowanceData , formatTokenAmount , weightTokenDecimals , lastSubmissionTimeData , rewardData , halfLifeSecondsData , quorumData , operationLockingPeriodData , withdrawalLockingPeriodData , alphaData , depositTimestampData , lastOperationTimestampData ] )
383433
384434 // Early validation before calling the hook
385435 if ( ! oracleAddress || ! chainIdValid ) {
@@ -568,7 +618,7 @@ export default function OracleInteractionPage() {
568618
569619 try {
570620 setIsApproving ( true )
571- const amount = parseEther ( depositAmount )
621+ const amount = parseUnits ( depositAmount , weightTokenDecimals )
572622
573623 writeContract ( {
574624 address : weightTokenAddress as `0x${string } `,
@@ -611,8 +661,8 @@ export default function OracleInteractionPage() {
611661 return
612662 }
613663
614- const amount = parseEther ( depositAmount )
615- const allowance = parseEther ( tokenAllowance )
664+ const amount = parseUnits ( depositAmount , weightTokenDecimals )
665+ const allowance = tokenAllowanceData ? BigInt ( tokenAllowanceData as bigint ) : BigInt ( 0 )
616666
617667 if ( allowance < amount ) {
618668 toast ( {
@@ -669,7 +719,7 @@ export default function OracleInteractionPage() {
669719
670720 try {
671721 setIsWithdrawing ( true )
672- const amount = parseEther ( withdrawAmount )
722+ const amount = parseUnits ( withdrawAmount , weightTokenDecimals )
673723
674724 console . log ( 'Withdrawing tokens:' , {
675725 amount : amount . toString ( ) ,
@@ -984,18 +1034,45 @@ export default function OracleInteractionPage() {
9841034 < p className = "text-lg text-muted-foreground mb-6 max-w-3xl mx-auto font-light" > { oracle . description } </ p >
9851035 ) }
9861036
987- { /* Oracle Address */ }
988- < div className = "flex items-center gap-2 justify-center mb-8" >
989- < code className = "text-sm bg-card/50 border border-primary/30 px-4 py-2 rounded-xl text-primary font-mono" >
990- { oracle . address }
991- </ code >
992- < button
993- onClick = { ( ) => navigator . clipboard . writeText ( oracle . address ) }
994- className = "text-muted-foreground hover:text-primary transition-colors p-2 hover:bg-card/50 rounded-lg border border-transparent hover:border-primary/30"
995- title = "Copy address"
996- >
997- < Copy className = "h-4 w-4" />
998- </ button >
1037+ { /* Addresses */ }
1038+ < div className = "grid gap-4 md:grid-cols-2 mb-8" >
1039+ < div className = "bg-card/40 border border-primary/25 rounded-xl p-4 text-left" >
1040+ < div className = "text-xs uppercase tracking-wide text-muted-foreground/70 mb-2" > Oracle Address</ div >
1041+ < div className = "flex items-center justify-between gap-3" >
1042+ < code className = "flex-1 text-xs sm:text-sm bg-card/60 border border-primary/30 px-3 py-2 rounded-lg text-primary font-mono break-all" >
1043+ { oracle . address }
1044+ </ code >
1045+ < button
1046+ onClick = { ( ) => navigator . clipboard . writeText ( oracle . address ) }
1047+ className = "text-muted-foreground hover:text-primary transition-colors p-2 hover:bg-card/50 rounded-lg border border-transparent hover:border-primary/30"
1048+ title = "Copy oracle address"
1049+ >
1050+ < Copy className = "h-4 w-4" />
1051+ </ button >
1052+ </ div >
1053+ </ div >
1054+
1055+ < div className = "bg-card/40 border border-primary/25 rounded-xl p-4 text-left" >
1056+ < div className = "flex items-center justify-between mb-2" >
1057+ < div className = "text-xs uppercase tracking-wide text-muted-foreground/70" > Weight Token</ div >
1058+ < span className = "text-xs font-medium text-primary/80" > { weightTokenSymbol } </ span >
1059+ </ div >
1060+ < div className = "flex items-center justify-between gap-3" >
1061+ < code className = "flex-1 text-xs sm:text-sm bg-card/60 border border-primary/30 px-3 py-2 rounded-lg text-primary font-mono break-all" >
1062+ { weightTokenAddressString }
1063+ </ code >
1064+ < button
1065+ onClick = { ( ) =>
1066+ canCopyWeightTokenAddress && navigator . clipboard . writeText ( weightTokenAddressString )
1067+ }
1068+ disabled = { ! canCopyWeightTokenAddress }
1069+ className = "text-muted-foreground hover:text-primary transition-colors p-2 hover:bg-card/50 rounded-lg border border-transparent hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed"
1070+ title = "Copy weight token address"
1071+ >
1072+ < Copy className = "h-4 w-4" />
1073+ </ button >
1074+ </ div >
1075+ </ div >
9991076 </ div >
10001077 </ div >
10011078
@@ -1124,17 +1201,25 @@ export default function OracleInteractionPage() {
11241201 < div className = "space-y-3 mb-4" >
11251202
11261203 { /* Detailed Token State Breakdown */ }
1127- < div className = "grid grid-cols-2 gap-2 p-2 bg-card/30 border border-primary/20 rounded-lg text-xs" >
1128- < div className = "text-center" >
1129- < div className = "text-muted-foreground/80 mb-0.5" > 🔒 Locked</ div >
1130- < div className = "text-foreground/90 font-light" > { lockedTokensData ? parseFloat ( formatEther ( lockedTokensData as bigint ) ) . toFixed ( 2 ) : '0.00' } </ div >
1131- </ div >
1132- < div className = "text-center" >
1133- < div className = "text-muted-foreground/80 mb-0.5" > 📅 Deposit Time</ div >
1134- < div className = "text-foreground/90 font-light text-xs" > { depositTimestamp } </ div >
1135- </ div >
1204+ < div className = "grid grid-cols-1 sm:grid-cols-3 gap-2 p-2 bg-card/30 border border-primary/20 rounded-lg text-xs" >
1205+ < div className = "text-center" >
1206+ < div className = "text-muted-foreground/80 mb-0.5" > 🔒 Locked</ div >
1207+ < div className = "text-foreground/90 font-light" >
1208+ { formatTokenAmount ( lockedTokensData ? ( lockedTokensData as bigint ) : undefined ) } { weightTokenSymbol }
11361209 </ div >
11371210 </ div >
1211+ < div className = "text-center" >
1212+ < div className = "text-muted-foreground/80 mb-0.5" > 📅 Deposit Time</ div >
1213+ < div className = "text-foreground/90 font-light text-xs" > { depositTimestamp } </ div >
1214+ </ div >
1215+ < div className = "text-center" >
1216+ < div className = "text-muted-foreground/80 mb-0.5" > 💼 Wallet Balance</ div >
1217+ < div className = "text-foreground/90 font-light" >
1218+ { walletTokenBalanceDisplay } { weightTokenSymbol }
1219+ </ div >
1220+ </ div >
1221+ </ div >
1222+ </ div >
11381223 ) }
11391224
11401225 < div className = "space-y-2" >
@@ -1151,8 +1236,8 @@ export default function OracleInteractionPage() {
11511236
11521237 { /* Conditional Buttons based on allowance */ }
11531238 { ( ( ) => {
1154- const amount = depositAmount ? parseEther ( depositAmount ) : BigInt ( 0 )
1155- const allowance = tokenAllowance ? parseEther ( tokenAllowance ) : BigInt ( 0 )
1239+ const amount = depositAmount ? parseUnits ( depositAmount , weightTokenDecimals ) : BigInt ( 0 )
1240+ const allowance = tokenAllowanceData ? BigInt ( tokenAllowanceData as bigint ) : BigInt ( 0 )
11561241 const needsApproval = amount > allowance
11571242
11581243 if ( needsApproval ) {
@@ -1203,7 +1288,9 @@ export default function OracleInteractionPage() {
12031288 </ div >
12041289 < div className = "text-center" >
12051290 < div className = "text-muted-foreground/80 mb-0.5" > ✓ Unlocked</ div >
1206- < div className = "text-foreground/90 font-light" > { unlockedTokensData ? parseFloat ( formatEther ( unlockedTokensData as bigint ) ) . toFixed ( 2 ) : '0.00' } </ div >
1291+ < div className = "text-foreground/90 font-light" >
1292+ { formatTokenAmount ( unlockedTokensData ? ( unlockedTokensData as bigint ) : undefined ) } { weightTokenSymbol }
1293+ </ div >
12071294 </ div >
12081295 </ div >
12091296 ) }
0 commit comments