Skip to content

Commit 7604e3b

Browse files
Copilot0xrinegade
andcommitted
Fix critical bugs: division by zero, infinite re-renders, mock data, and memory leaks
Co-authored-by: 0xrinegade <[email protected]>
1 parent 70ebd6b commit 7604e3b

File tree

4 files changed

+67
-20
lines changed

4 files changed

+67
-20
lines changed

src/components/UserProfile.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,20 @@ const UserProfile = ({ wallet: walletProp, network, initialTab = 'overview', onT
173173
}
174174
}, [isWalletConnected, reputationLoading, historyLoading]);
175175

176-
// Only fetch data when wallet or network changes
176+
// Only fetch data when wallet connection status changes (not when loading states change)
177177
useEffect(() => {
178178
// Extra protection in case fetchProfileData changes between renders
179179
try {
180-
fetchProfileData();
180+
if (isWalletConnected) {
181+
// Call fetchProfileData directly to avoid dependency warning
182+
fetchProfileData();
183+
}
181184
} catch (err) {
182185
console.error('[UserProfile] Error in fetchProfileData effect:', err);
183186
setError('An error occurred while loading your profile');
184187
setLoading(false);
185188
}
186-
}, [fetchProfileData]);
189+
}, [isWalletConnected, fetchProfileData]); // Include fetchProfileData to fix lint warning
187190

188191
// Handle settings update - optimized with useCallback
189192
const handleSaveSettings = useCallback((newSettings) => {

src/components/UserStatistics.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ const UserStatistics = () => {
216216
{renderStatCard(
217217
'Completed Trades',
218218
completedTrades.length,
219-
`${completedTrades.length > 0 ? ((completedTrades.length / safeHistory.length) * 100).toFixed(1) : 0}% completion rate`,
219+
`${completedTrades.length > 0 && safeHistory.length > 0 ? ((completedTrades.length / safeHistory.length) * 100).toFixed(1) : 0}% completion rate`,
220220
'Successfully completed trades',
221221
'green'
222222
)}

src/hooks/useOnChainData.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const useOffers = (program, filters = {}) => {
1313
const [loading, setLoading] = useState(true);
1414
const [error, setError] = useState(null);
1515

16-
const fetchOffers = useCallback(async () => {
16+
const fetchOffers = useCallback(async (abortSignal) => {
1717
if (!program) {
1818
setOffers([]);
1919
setLoading(false);
@@ -26,9 +26,21 @@ export const useOffers = (program, filters = {}) => {
2626
try {
2727
logger.info('Fetching offers from blockchain...');
2828

29+
// Check if operation was aborted
30+
if (abortSignal?.aborted) {
31+
logger.info('Fetch offers operation aborted');
32+
return;
33+
}
34+
2935
// Fetch all offer accounts
3036
const offerAccounts = await program.account.offer.all();
3137

38+
// Check again after async operation
39+
if (abortSignal?.aborted) {
40+
logger.info('Fetch offers operation aborted after blockchain query');
41+
return;
42+
}
43+
3244
const processedOffers = offerAccounts.map(({ account, publicKey }) => ({
3345
id: publicKey.toString(),
3446
seller: account.seller.toString(),
@@ -72,26 +84,48 @@ export const useOffers = (program, filters = {}) => {
7284
filteredOffers = filteredOffers.filter(offer => offer.solAmount <= filters.maxAmount);
7385
}
7486

87+
// Final abort check before setting state
88+
if (abortSignal?.aborted) {
89+
logger.info('Fetch offers operation aborted before setting state');
90+
return;
91+
}
92+
7593
logger.info(`Fetched ${filteredOffers.length} offers from blockchain`, {
7694
total: offerAccounts.length,
7795
filtered: filteredOffers.length
7896
});
7997

8098
setOffers(filteredOffers);
8199
} catch (err) {
100+
if (abortSignal?.aborted) {
101+
logger.info('Fetch offers operation aborted due to error:', err.message);
102+
return;
103+
}
82104
logger.error('Error fetching offers:', err);
83105
setError(`Failed to fetch offers: ${err.message}`);
84106
setOffers([]);
85107
} finally {
86-
setLoading(false);
108+
if (!abortSignal?.aborted) {
109+
setLoading(false);
110+
}
87111
}
88112
}, [program, filters]);
89113

90114
useEffect(() => {
115+
const abortController = new AbortController();
116+
fetchOffers(abortController.signal);
117+
118+
// Cleanup function
119+
return () => {
120+
abortController.abort();
121+
};
122+
}, [fetchOffers]);
123+
124+
const refetchOffers = useCallback(() => {
91125
fetchOffers();
92126
}, [fetchOffers]);
93127

94-
return { offers, loading, error, refetch: fetchOffers };
128+
return { offers, loading, error, refetch: refetchOffers };
95129
};
96130

97131
/**
@@ -175,10 +209,20 @@ export const useUserReputation = (program, userPublicKey) => {
175209
}, [program, userPublicKey]);
176210

177211
useEffect(() => {
212+
const abortController = new AbortController();
213+
fetchReputation(abortController.signal);
214+
215+
// Cleanup function
216+
return () => {
217+
abortController.abort();
218+
};
219+
}, [fetchReputation]);
220+
221+
const refetchReputation = useCallback(() => {
178222
fetchReputation();
179223
}, [fetchReputation]);
180224

181-
return { reputation, loading, error, refetch: fetchReputation };
225+
return { reputation, loading, error, refetch: refetchReputation };
182226
};
183227

184228
/**

src/utils/rewardQueries.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,18 @@ export const fetchUserRewards = async (userPublicKey) => {
143143
}
144144

145145
// Parse the account data (simplified - in reality would use Anchor IDL)
146-
// For now, return mock data that represents realistic values with proper Date objects
147-
const mockData = {
148-
totalEarned: Math.floor(Math.random() * 2000) + 500,
149-
totalClaimed: Math.floor(Math.random() * 1000) + 200,
150-
unclaimedBalance: Math.floor(Math.random() * 500) + 50,
151-
tradingVolume: Math.floor((Math.random() * 20 + 5) * CONVERSION_HELPERS.solToLamports(1)), // SOL to lamports
152-
governanceVotes: Math.floor(Math.random() * 10) + 1,
153-
lastTradeReward: new Date(Date.now() - Math.random() * 86400000 * 7), // Last week
154-
lastVoteReward: new Date(Date.now() - Math.random() * 86400000 * 14), // Last 2 weeks
146+
// Return default values instead of random mock data
147+
const defaultRewardData = {
148+
totalEarned: 0, // Start with 0 for new users
149+
totalClaimed: 0,
150+
unclaimedBalance: 0,
151+
tradingVolume: 0,
152+
governanceVotes: 0,
153+
lastTradeReward: null, // No rewards initially
154+
lastVoteReward: null,
155155
};
156156

157-
return mockData;
157+
return defaultRewardData;
158158
} catch (error) {
159159
console.error('Error fetching user rewards:', error);
160160
throw new Error(`Failed to fetch user rewards: ${error.message}`);
@@ -170,8 +170,8 @@ export const fetchUserRewards = async (userPublicKey) => {
170170
export const fetchUserTokenBalance = async (userPublicKey, mintAddress) => {
171171
try {
172172
if (!getConnection) {
173-
// Mock balance for test environment
174-
return Math.floor(Math.random() * 1000);
173+
// Return 0 balance for test environment instead of random
174+
return 0;
175175
}
176176

177177
const connection = getConnection();

0 commit comments

Comments
 (0)