Review a pull request: coupons and withdrawals

Not solved

Money-moving code that is correct one request at a time. Find what breaks when requests arrive together.

Level
Advanced
Estimated time
~25 min
Points
0/75 pts
Questions
0/0 answered
OWASP
A06:2025
CWE
CWE-362
CWE
CWE-367
src/services/wallet.ts0/2 found
import { db } from '../db'
+export async function redeemCoupon(userId: string, code: string) {
+ const coupon = await db.one('SELECT * FROM coupons WHERE code = $1', [code])
+ if (!coupon) throw new HttpError(404, 'Unknown coupon')
+ if (coupon.redeemed_at) throw new HttpError(409, 'Coupon already used')
+ await credit(userId, coupon.amount)
+ await db.query('UPDATE coupons SET redeemed_at = now(), redeemed_by = $2 WHERE id = $1', [coupon.id, userId])
+}
+
+export async function withdraw(userId: string, amount: number) {
+ if (!Number.isInteger(amount) || amount <= 0) throw new HttpError(400, 'Invalid amount')
+ const wallet = await db.one('SELECT balance FROM wallets WHERE user_id = $1', [userId])
+ if (wallet.balance < amount) throw new HttpError(402, 'Insufficient funds')
+ await db.query('UPDATE wallets SET balance = $2 WHERE user_id = $1', [userId, wallet.balance - amount])
+ await payouts.send(userId, amount)
+}
async function credit(userId: string, amount: number) {
await db.query('UPDATE wallets SET balance = balance + $2 WHERE user_id = $1', [userId, amount])
}

Click a line number to flag a defect. The review code appears when every defect is flagged with no false positives.