Problem
The Earned column in each farm row shows a static credit value fetched from the contract. Credits accrue continuously at dailyRate × lockedAmount / 86400 per second, but the UI only updates when the React Query cache refreshes (every 5 seconds per useUserCredits). This makes the earned display feel stale and disconnected from reality, especially given that SmartDrop's core value proposition is watching credits accumulate.
Expected Behaviour
After the initial credit snapshot is fetched from the contract, the row interpolates the earned value client-side at 1-second granularity using the known rate, without issuing additional RPC calls. When the cache refreshes, the interpolated value snaps to the authoritative on-chain figure.
Acceptance Criteria
Relevant Files
src/app/farm/page.tsx — EarningRow, the earned display field
src/hooks/useSorobanQuery.ts — useUserCredits provides baseCredits and dataUpdatedAt
src/types/farm.ts — FarmPosition.earned is currently a static string; may need to become numeric
Problem
The Earned column in each farm row shows a static credit value fetched from the contract. Credits accrue continuously at
dailyRate × lockedAmount / 86400per second, but the UI only updates when the React Query cache refreshes (every 5 seconds peruseUserCredits). This makes the earned display feel stale and disconnected from reality, especially given that SmartDrop's core value proposition is watching credits accumulate.Expected Behaviour
After the initial credit snapshot is fetched from the contract, the row interpolates the earned value client-side at 1-second granularity using the known rate, without issuing additional RPC calls. When the cache refreshes, the interpolated value snaps to the authoritative on-chain figure.
Acceptance Criteria
useLiveCredits(baseCredits, dailyRate, lockedAmount, lastFetchedAt)hook is added tosrc/hooks/that ticks every second:displayed = baseCredits + (dailyRate / 86400) × lockedAmount × (Date.now() - lastFetchedAt) / 1000baseCreditsorlastFetchedAtchange (i.e. when React Query delivers a fresh value from the contract)useLiveCreditsand formats the output to 4 decimal placesdailyRate / 86400 × lockedAmountwith ±0.001 toleranceRelevant Files
src/app/farm/page.tsx—EarningRow, theearneddisplay fieldsrc/hooks/useSorobanQuery.ts—useUserCreditsprovidesbaseCreditsanddataUpdatedAtsrc/types/farm.ts—FarmPosition.earnedis currently a static string; may need to become numeric