Skip to content

Commit 67cb023

Browse files
feat: update user balance in every bet
1 parent e2b2ae0 commit 67cb023

File tree

7 files changed

+88
-25
lines changed

7 files changed

+88
-25
lines changed

app/page.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,14 @@ export default function Home() {
173173
try {
174174
const result = await claimBalance(amount, selectedToken, contractId, tokenUid);
175175
toast.success(`Balance withdrawn successfully! TX: ${result.response.hash?.slice(0, 10)}...`);
176-
// Refresh claimable balance
177-
const claimable = await coreAPI.getClaimableBalance(contractId, address!);
178-
setContractBalance(claimable);
176+
177+
// Update balances locally after successful withdraw
178+
const withdrawAmountCents = Math.round(amount * 100);
179+
// Increase wallet balance
180+
setBalance(balance + BigInt(withdrawAmountCents));
181+
// Decrease contract balance
182+
setContractBalance(contractBalance - BigInt(withdrawAmountCents));
183+
179184
setShowWithdrawModal(false);
180185
setWithdrawAmount('');
181186
} catch (error: any) {

components/AddLiquidityCard.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface AddLiquidityCardProps {
1414
}
1515

1616
export default function AddLiquidityCard({ selectedToken, isExpanded, onToggle }: AddLiquidityCardProps) {
17-
const { walletBalance, contractBalance, addLiquidity } = useWallet();
17+
const { walletBalance, contractBalance, addLiquidity, balance, setBalance } = useWallet();
1818
const { isConnected, getContractStateForToken, getContractIdForToken } = useHathor();
1919
const contractBalanceInTokens = Number(contractBalance) / 100;
2020
const totalBalance = walletBalance + contractBalanceInTokens;
@@ -55,6 +55,11 @@ export default function AddLiquidityCard({ selectedToken, isExpanded, onToggle }
5555
try {
5656
const result = await addLiquidity(amount, selectedToken, contractId, tokenUid);
5757
toast.success(`Liquidity added successfully! TX: ${result.response.hash?.slice(0, 10)}...`);
58+
59+
// Update wallet balance locally after successful add liquidity
60+
const amountCents = Math.round(amount * 100);
61+
setBalance(balance - BigInt(amountCents));
62+
5863
setAmount(0);
5964
} catch (error: any) {
6065
toast.error(error.message || 'Failed to add liquidity');

components/BetResultNotification.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export default function BetResultNotification({ bet, onComplete }: BetResultNoti
105105
CHICKEN DINNER! 🍗
106106
</h3>
107107
<div className="text-5xl font-bold text-slate-900 mb-2">
108-
+{bet.payout.toFixed(2)} {bet.token}
108+
+{(bet.payout / 100).toFixed(2)} {bet.token}
109109
</div>
110110
<div className="text-sm text-slate-800 mt-4">
111111
You won with lucky number {bet.luckyNumber}{bet.threshold}!
@@ -121,7 +121,7 @@ export default function BetResultNotification({ bet, onComplete }: BetResultNoti
121121
Lucky number {bet.luckyNumber} {'>'} {bet.threshold}
122122
</div>
123123
<div className="text-lg text-slate-400 mb-4">
124-
Lost {bet.amount.toFixed(2)} {bet.token}
124+
Lost {(bet.amount / 100).toFixed(2)} {bet.token}
125125
</div>
126126
<div className="bg-slate-700 rounded-lg p-4 mt-4">
127127
<p className="text-yellow-400 font-semibold mb-2">

components/FortuneTigerBetCard.tsx

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useHathor } from '@/contexts/HathorContext';
77
import {
88
calculatePayout,
99
formatTokenAmount,
10+
formatBalanceWithCommas,
1011
multiplierToThreshold,
1112
thresholdToWinChance,
1213
calculateMaxMultiplier,
@@ -60,12 +61,22 @@ export default function FortuneTigerBetCard({
6061
onLoadBalance,
6162
walletType,
6263
}: FortuneTigerBetCardProps) {
63-
const { walletBalance, contractBalance, placeBet, connectWallet, balance, refreshBalance, isLoadingBalance, balanceVerified } = useWallet();
64+
const { walletBalance, contractBalance, placeBet, connectWallet, balance, refreshBalance, isLoadingBalance, balanceVerified, setBalance, setContractBalance } = useWallet();
6465
const { isConnected, getContractStateForToken, getContractIdForToken, allBets, address } = useHathor();
6566
const [showMobileDisconnect, setShowMobileDisconnect] = useState(false);
6667
const contractBalanceInTokens = Number(contractBalance) / 100;
6768
const totalBalance = walletBalance + contractBalanceInTokens;
6869

70+
// Compute displayed balance locally from context values (instead of prop)
71+
// This ensures immediate updates when we modify balance/contractBalance
72+
const computedTotalBalance = balance + contractBalance;
73+
const localFormattedBalance = isConnected && balanceVerified && computedTotalBalance > 0n
74+
? `${formatBalanceWithCommas(computedTotalBalance)} ${selectedToken}`
75+
: formattedBalance; // Fallback to prop if conditions not met
76+
77+
// Track pending bet info for local balance updates
78+
const pendingBetInfoRef = useRef<{ betAmountCents: number; depositAmountCents: number } | null>(null);
79+
6980
const [betAmount, setBetAmount] = useState(1);
7081
const [selectedMultiplier, setSelectedMultiplier] = useState(1.5);
7182
const [showBetInput, setShowBetInput] = useState(false);
@@ -109,6 +120,12 @@ export default function FortuneTigerBetCard({
109120
setPotentialPayout(payout);
110121
}, [betAmount, selectedMultiplier, randomBitLength, houseEdgeBasisPoints, contractMaxMultiplierTenths]);
111122

123+
// Keep a ref to the latest contract balance for use in the bet result effect
124+
const contractBalanceRef = useRef(contractBalance);
125+
useEffect(() => {
126+
contractBalanceRef.current = contractBalance;
127+
}, [contractBalance]);
128+
112129
// Watch for bet results
113130
useEffect(() => {
114131
if (!pendingBetTxId) return;
@@ -121,6 +138,14 @@ export default function FortuneTigerBetCard({
121138
setBetResult(bet.result as 'win' | 'lose');
122139
setPendingBetTxId(null);
123140

141+
// Update contract balance based on result
142+
if (bet.result === 'win' && bet.payout > 0) {
143+
// Add payout to contract balance (payout is in cents)
144+
setContractBalance(contractBalanceRef.current + BigInt(Math.round(bet.payout)));
145+
}
146+
// Clear pending bet info
147+
pendingBetInfoRef.current = null;
148+
124149
// Randomly select an animation based on result
125150
const winAnimations: AnimationType[] = [
126151
'winner-chicken-dinner',
@@ -144,6 +169,7 @@ export default function FortuneTigerBetCard({
144169
// Show animation immediately - no delay
145170
setActiveAnimation(selectedAnimation);
146171
}
172+
// eslint-disable-next-line react-hooks/exhaustive-deps
147173
}, [allBets, pendingBetTxId]);
148174

149175
// Trigger balance request when auth popup shows, and close popup when balance is loaded
@@ -280,9 +306,27 @@ export default function FortuneTigerBetCard({
280306
setIsPlacingBet(true);
281307

282308
try {
309+
// Calculate deposit and bet amounts in cents for local balance tracking
310+
const betAmountCents = Math.round(betAmount * 100);
311+
const contractBalanceCents = Number(contractBalance);
312+
const depositAmountCents = Math.max(0, betAmountCents - contractBalanceCents);
313+
283314
const result = await placeBet(betAmount, threshold, selectedToken, contractId, tokenUid, contractBalance);
284315
setPendingBetTxId(result.response.hash);
285316

317+
// Store pending bet info for balance update on result
318+
pendingBetInfoRef.current = { betAmountCents, depositAmountCents };
319+
320+
// Update balances locally after successful bet submission
321+
// Wallet balance decreases by deposit amount
322+
if (depositAmountCents > 0) {
323+
setBalance(balance - BigInt(depositAmountCents));
324+
}
325+
// Contract balance: receives deposit, then bet is deducted
326+
// New contract balance = old + deposit - bet
327+
const newContractBalance = BigInt(contractBalanceCents) + BigInt(depositAmountCents) - BigInt(betAmountCents);
328+
setContractBalance(newContractBalance >= 0n ? newContractBalance : 0n);
329+
286330
// Start spinning AFTER wallet confirmation
287331
setIsSpinning(true);
288332
toast.success('🎰 Transaction confirmed! Spinning...');
@@ -604,7 +648,7 @@ export default function FortuneTigerBetCard({
604648
{/* Content */}
605649
<div className="relative z-10">
606650
{isPlacingBet ? (
607-
<div className="flex items-center justify-center gap-2">
651+
<div className="flex items-center justify-center gap-4">
608652
<GoddessSpinner size={48} interval={500} />
609653
<span className="text-xl md:text-2xl">SENDING...</span>
610654
</div>
@@ -619,12 +663,12 @@ export default function FortuneTigerBetCard({
619663

620664
{/* Mobile Balance & Statistics - Below SPIN button on mobile only */}
621665
<div className="flex md:hidden items-stretch justify-center gap-3 mt-2 w-full">
622-
{formattedBalance ? (
666+
{localFormattedBalance ? (
623667
<div className="flex-1 px-4 py-2 rounded-full border-2 border-yellow-500/60 bg-gradient-to-br from-yellow-900/30 via-black/50 to-yellow-900/30 backdrop-blur-sm flex items-center justify-center">
624668
<div className="flex items-center justify-center gap-2">
625669
<div className="text-base">💰</div>
626670
<span className="text-xs font-bold text-transparent bg-clip-text bg-gradient-to-r from-yellow-200 via-yellow-400 to-yellow-200 font-mono">
627-
{formattedBalance}
671+
{localFormattedBalance}
628672
</span>
629673
</div>
630674
</div>

components/RemoveLiquidityCard.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface RemoveLiquidityCardProps {
1414
}
1515

1616
export default function RemoveLiquidityCard({ selectedToken, isExpanded, onToggle }: RemoveLiquidityCardProps) {
17-
const { address, removeLiquidity } = useWallet();
17+
const { address, removeLiquidity, balance, setBalance } = useWallet();
1818
const { isConnected, getContractStateForToken, getContractIdForToken, coreAPI } = useHathor();
1919
const [amount, setAmount] = useState(0);
2020
const [maxLiquidity, setMaxLiquidity] = useState<bigint>(0n);
@@ -85,10 +85,15 @@ export default function RemoveLiquidityCard({ selectedToken, isExpanded, onToggl
8585
try {
8686
const result = await removeLiquidity(amount, selectedToken, contractId, tokenUid);
8787
toast.success(`Liquidity removed successfully! TX: ${result.response.hash?.slice(0, 10)}...`);
88+
89+
// Update balances locally after successful remove liquidity
90+
const amountCents = Math.round(amount * 100);
91+
// Increase wallet balance
92+
setBalance(balance + BigInt(amountCents));
93+
// Decrease max liquidity locally
94+
setMaxLiquidity(maxLiquidity - BigInt(amountCents));
95+
8896
setAmount(0);
89-
// Refresh max liquidity after successful removal
90-
const max = await coreAPI.getMaximumLiquidityRemoval(contractId, address!);
91-
setMaxLiquidity(max);
9297
} catch (error: any) {
9398
toast.error(error.message || 'Failed to remove liquidity');
9499
} finally {

components/WithdrawCard.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface WithdrawCardProps {
1313
}
1414

1515
export default function WithdrawCard({ selectedToken, isExpanded, onToggle }: WithdrawCardProps) {
16-
const { address, claimBalance } = useWallet();
16+
const { address, claimBalance, balance, setBalance } = useWallet();
1717
const { isConnected, getContractStateForToken, getContractIdForToken, coreAPI } = useHathor();
1818
const [claimableBalance, setClaimableBalance] = useState<bigint>(0n);
1919
const [isLoadingClaimable, setIsLoadingClaimable] = useState(false);
@@ -76,9 +76,13 @@ export default function WithdrawCard({ selectedToken, isExpanded, onToggle }: Wi
7676
try {
7777
const result = await claimBalance(amountToWithdraw, selectedToken, contractId, tokenUid);
7878
toast.success(`Balance withdrawn successfully! TX: ${result.response.hash?.slice(0, 10)}...`);
79-
// Refresh claimable balance
80-
const claimable = await coreAPI.getClaimableBalance(contractId, address!);
81-
setClaimableBalance(claimable);
79+
80+
// Update balances locally after successful withdraw
81+
const withdrawAmountCents = Math.round(amountToWithdraw * 100);
82+
// Increase wallet balance
83+
setBalance(balance + BigInt(withdrawAmountCents));
84+
// Decrease claimable balance locally
85+
setClaimableBalance(claimableBalance - BigInt(withdrawAmountCents));
8286
} catch (error: any) {
8387
toast.error(error.message || 'Failed to withdraw balance');
8488
} finally {

contexts/HathorContext.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
3+
import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
44
import { HathorCoreAPI } from '@/lib/hathorCoreAPI';
55
import { ContractState, ContractTransaction } from '@/types/hathor';
66
import { config, Network } from '@/lib/config';
@@ -142,22 +142,22 @@ export function HathorProvider({ children }: { children: ReactNode }) {
142142
}
143143
};
144144

145-
const getContractStateForToken = (token: string): ContractState | null => {
145+
const getContractStateForToken = useCallback((token: string): ContractState | null => {
146146
return contractStates[token] || null;
147-
};
147+
}, [contractStates]);
148148

149-
const getContractIdForToken = (token: string): string | null => {
149+
const getContractIdForToken = useCallback((token: string): string | null => {
150150
return tokenContractMap[token] || null;
151-
};
151+
}, [tokenContractMap]);
152152

153-
const getTokenForContractId = (contractId: string): string => {
153+
const getTokenForContractId = useCallback((contractId: string): string => {
154154
for (const [token, id] of Object.entries(tokenContractMap)) {
155155
if (id === contractId) {
156156
return token;
157157
}
158158
}
159159
return 'HTR'; // fallback
160-
};
160+
}, [tokenContractMap]);
161161

162162
const refreshContractStates = async () => {
163163
if (config.useMockWallet) {

0 commit comments

Comments
 (0)