Bug Description
Description
purchaseItem() in the HubCoin shop deducts coins and grants the item immediately on click, with no guard against the function being invoked twice before the first Firestore write resolves (e.g. via rapid double-click or a slow network causing the user to click again).
Steps to Reproduce
- Open the Mascot/HubCoin shop with a balance just above an item's price
- Rapidly double-click "Purchase" on an item
- Observe the item may be purchased twice, or coins go negative
Expected Behavior
A purchase should be atomic and idempotent per click — the button should disable immediately on click and only re-enable after the transaction resolves (success or failure).
Actual Behavior
Both clicks fire purchaseItem() before the UI or state updates, resulting in a double deduction/grant race.
Impact
Economy integrity issue — users can exploit this to acquire items they can't afford, or coin balances can go negative.
Suggested Fix
Disable the purchase button on click until the Firestore transaction resolves, and/or use a Firestore transaction with a server-side balance check so a second concurrent write fails cleanly instead of double-applying.
Bug Description
Description
purchaseItem()in the HubCoin shop deducts coins and grants the item immediately on click, with no guard against the function being invoked twice before the first Firestore write resolves (e.g. via rapid double-click or a slow network causing the user to click again).Steps to Reproduce
Expected Behavior
A purchase should be atomic and idempotent per click — the button should disable immediately on click and only re-enable after the transaction resolves (success or failure).
Actual Behavior
Both clicks fire
purchaseItem()before the UI or state updates, resulting in a double deduction/grant race.Impact
Economy integrity issue — users can exploit this to acquire items they can't afford, or coin balances can go negative.
Suggested Fix
Disable the purchase button on click until the Firestore transaction resolves, and/or use a Firestore transaction with a server-side balance check so a second concurrent write fails cleanly instead of double-applying.