Skip to content

Commit e32af44

Browse files
Merge pull request #16 from StabilityNexus/Frontend
Changes for Individual page.
2 parents 9ac434b + 331686c commit e32af44

1 file changed

Lines changed: 100 additions & 68 deletions

File tree

app/[oracleId]/InteractionClient.tsx

Lines changed: 100 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import {
2727
Database,
2828
CheckCircle,
2929
} from "lucide-react"
30-
import { useAccount, useWriteContract, useReadContract, useWaitForTransactionReceipt } from "wagmi"
31-
import { parseUnits, formatUnits, erc20Abi } from "viem"
30+
import { useAccount, useWriteContract, useReadContract, useWaitForTransactionReceipt, usePublicClient } from "wagmi"
31+
import { parseUnits, formatUnits, erc20Abi, BaseError } from "viem"
3232

3333
function isHexAddress(value: string | null): value is `0x${string}` {
3434
return !!value && /^0x[a-fA-F0-9]{40}$/.test(value)
@@ -80,7 +80,6 @@ export default function OracleInteractionPage() {
8080
const [tokenAllowance, setTokenAllowance] = useState<string>("0")
8181

8282
const [priceHistoryPoints, setPriceHistoryPoints] = useState<PriceChartPoint[]>([])
83-
const [pendingRead, setPendingRead] = useState<"aggregated" | "latest" | null>(null)
8483

8584
// Oracle configuration display values
8685
const [rewardRate, setRewardRate] = useState<string>("Loading...")
@@ -137,6 +136,7 @@ export default function OracleInteractionPage() {
137136
const oracleAddress = isHexAddress(oracleParam) ? (oracleParam as `0x${string}`) : null
138137
const chainId = chainIdParam ? Number(chainIdParam) : undefined
139138
const chainIdValid = chainId !== undefined && Number.isFinite(chainId) && chainId > 0
139+
const publicClient = usePublicClient({ chainId })
140140

141141
// Contract write hook
142142
const { writeContract, writeContractAsync, data: hash, error: contractError, isPending } = useWriteContract()
@@ -355,6 +355,16 @@ export default function OracleInteractionPage() {
355355
[userTokenBalance]
356356
)
357357

358+
const lockedTokensRaw = lockedTokensData ? BigInt(lockedTokensData as bigint) : BigInt(0)
359+
const unlockedTokensRaw = unlockedTokensData ? BigInt(unlockedTokensData as bigint) : BigInt(0)
360+
const totalDepositedTokensRaw = lockedTokensRaw + unlockedTokensRaw
361+
const userTokenBalanceRaw = userTokenBalanceData ? BigInt(userTokenBalanceData as bigint) : BigInt(0)
362+
363+
const isTokenHolder = userTokenBalanceRaw > BigInt(0)
364+
const isActiveOperator = totalDepositedTokensRaw > BigInt(0)
365+
const hasUnlockedTokens = unlockedTokensRaw > BigInt(0)
366+
const operatorActionsDisabled = isActiveOperator && !hasUnlockedTokens
367+
358368
// Update real-time data when contract data changes
359369
useEffect(() => {
360370
// Calculate total deposited tokens (sum of locked and unlocked tokens)
@@ -476,31 +486,12 @@ export default function OracleInteractionPage() {
476486
const refreshValues = async () => {
477487
try {
478488
const result = await refetchPriceHistory()
479-
if (pendingRead && result?.data) {
489+
if (result?.data) {
480490
const data = result.data as PriceHistoryResult
481491
updatePriceDisplays(data)
482-
483-
const points = buildPriceHistoryPoints(data)
484-
if (points.length > 0) {
485-
const latestPoint = points[points.length - 1]
486-
if (pendingRead === "aggregated") {
487-
toast({
488-
title: "Aggregated Value",
489-
description: `Current aggregated value: ${latestPoint.aggregated.toFixed(DISPLAY_PRECISION)}`,
490-
})
491-
}
492-
if (pendingRead === "latest") {
493-
toast({
494-
title: "Latest Submission",
495-
description: `Latest submitted value: ${latestPoint.latest.toFixed(DISPLAY_PRECISION)}`,
496-
})
497-
}
498-
}
499492
}
500493
} catch (err) {
501494
console.error('Error updating price data after confirmation:', err)
502-
} finally {
503-
setPendingRead(null)
504495
}
505496
}
506497

@@ -520,7 +511,7 @@ export default function OracleInteractionPage() {
520511
setDepositAmount("")
521512
setWithdrawAmount("")
522513
setVoteTarget("")
523-
}, [isConfirmed, pendingRead, refetchPriceHistory, updatePriceDisplays, buildPriceHistoryPoints, toast])
514+
}, [isConfirmed, refetchPriceHistory, updatePriceDisplays, toast])
524515

525516
// Handle transaction errors
526517
useEffect(() => {
@@ -893,77 +884,118 @@ export default function OracleInteractionPage() {
893884
}
894885
}
895886

896-
const handleReadValue = async () => {
897-
if (!isConnected || !userAddress) {
898-
toast({
899-
title: "Wallet Not Connected",
900-
description: "Please connect your wallet to read values.",
901-
variant: "destructive",
902-
})
903-
return
904-
}
887+
const simulateRead = useCallback(
888+
async (fnName: "readValue" | "readLatestValue") => {
889+
if (!oracleAddress || !publicClient) {
890+
throw new Error("Oracle client not ready")
891+
}
892+
893+
const attempt = async (account?: `0x${string}`) => {
894+
const { result } = await publicClient.simulateContract({
895+
address: oracleAddress,
896+
abi: OracleAbi,
897+
functionName: fnName,
898+
args: [],
899+
account,
900+
})
901+
return result as bigint
902+
}
903+
904+
let lastError: unknown
905+
906+
if (userAddress) {
907+
try {
908+
const result = await attempt(userAddress as `0x${string}`)
909+
return { result, usedFallback: false }
910+
} catch (err) {
911+
lastError = err
912+
}
913+
}
914+
915+
try {
916+
const result = await attempt(undefined)
917+
if (userAddress) {
918+
console.warn(`[OracleInteraction] Falling back to neutral account for ${fnName} due to address restrictions.`)
919+
}
920+
return { result, usedFallback: !!userAddress }
921+
} catch (err) {
922+
if (err instanceof Error) {
923+
throw err
924+
}
925+
if (lastError instanceof Error) {
926+
throw lastError
927+
}
928+
throw new Error("Failed to simulate read call")
929+
}
930+
},
931+
[oracleAddress, publicClient, userAddress]
932+
)
905933

934+
const handleReadValue = async () => {
906935
try {
907936
setIsReadingValue(true)
908-
setPendingRead("aggregated")
909937

910-
await writeContractAsync({
911-
address: oracleAddress!,
912-
abi: OracleAbi,
913-
functionName: 'readValue',
914-
args: [],
915-
})
938+
const { result, usedFallback } = await simulateRead("readValue")
939+
const formatted = formatPriceFromWei(result)
940+
941+
setAggregatedValue(formatted)
942+
setLastUpdated("Just now")
916943

917944
toast({
918-
title: "Transaction Submitted",
919-
description: "Awaiting confirmation to retrieve the aggregated value.",
945+
title: "Aggregated Value",
946+
description: usedFallback
947+
? `Current aggregated value: ${formatted}. Retrieved via neutral simulation.`
948+
: `Current aggregated value: ${formatted}`,
920949
})
921-
} catch (err: any) {
922-
console.error('Error reading value:', err)
950+
} catch (err: unknown) {
951+
console.error('Error reading aggregated value:', err)
952+
const description =
953+
err instanceof BaseError
954+
? err.shortMessage
955+
: err instanceof Error
956+
? err.message
957+
: "Failed to read aggregated value. Please try again."
958+
923959
toast({
924960
title: "Read Failed",
925-
description: err?.message || "Failed to read aggregated value. Please try again.",
961+
description,
926962
variant: "destructive",
927963
})
928-
setPendingRead(null)
929964
} finally {
930965
setIsReadingValue(false)
931966
}
932967
}
933968

934969
const handleReadLatestValue = async () => {
935-
if (!isConnected || !userAddress) {
936-
toast({
937-
title: "Wallet Not Connected",
938-
description: "Please connect your wallet to read values.",
939-
variant: "destructive",
940-
})
941-
return
942-
}
943-
944970
try {
945971
setIsReadingLatestValue(true)
946-
setPendingRead("latest")
947972

948-
await writeContractAsync({
949-
address: oracleAddress!,
950-
abi: OracleAbi,
951-
functionName: 'readLatestValue',
952-
args: [],
953-
})
973+
const { result, usedFallback } = await simulateRead("readLatestValue")
974+
const formatted = formatPriceFromWei(result)
975+
976+
setLatestValue(formatted)
977+
setLastUpdated("Just now")
954978

955979
toast({
956-
title: "Transaction Submitted",
957-
description: "Awaiting confirmation to retrieve the latest value.",
980+
title: "Latest Submission",
981+
description: usedFallback
982+
? `Latest submitted value: ${formatted}. Retrieved via neutral simulation.`
983+
: `Latest submitted value: ${formatted}`,
958984
})
959-
} catch (err: any) {
985+
} catch (err: unknown) {
960986
console.error('Error reading latest value:', err)
987+
const description =
988+
err instanceof BaseError
989+
? err.shortMessage
990+
: err instanceof Error
991+
? err.message
992+
: "Failed to read latest value. Please try again."
993+
961994
toast({
962995
title: "Read Failed",
963-
description: err?.message || "Failed to read latest value. Please try again.",
996+
description,
964997
variant: "destructive",
965998
})
966-
setPendingRead(null)
967999
} finally {
9681000
setIsReadingLatestValue(false)
9691001
}
@@ -1088,7 +1120,7 @@ export default function OracleInteractionPage() {
10881120
</CardTitle>
10891121
</CardHeader>
10901122
<CardContent className="p-6">
1091-
<PriceChart data={priceHistoryPoints} loading={pendingRead !== null || isFetchingPriceHistory} />
1123+
<PriceChart data={priceHistoryPoints} loading={isFetchingPriceHistory || isReadingValue || isReadingLatestValue} />
10921124
</CardContent>
10931125
</Card>
10941126

0 commit comments

Comments
 (0)