# Function _execBuyNftFromMarket() fails to check the actual ETH Balance in the contract after executing the trade

_execBuyNftFromMarket approves WETH but only checks ETH balance delta, leaving leftover WETH allowance that another borrower can spend to buy an NFT for free.

- Payout: Contest reward
- Severity: medium
- Program: Particle Protocol
- Credited: minhquanym
- Disclosed: 2023-08-07
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-05-particle-findings/issues/7
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-particle%3AM-04
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** NFT market-buy function _execBuyNftFromMarket in lending protocol
**Root cause:** When useToken==1 the contract deposits and approves `amount` WETH to the marketplace, but the post-trade validation only compares ETH balance delta (balanceBefore - address(this).balance != amount), ignoring WETH. Any unused WETH allowance remains on the marketplace.
**Steps:**
1. Alice calls `buyNftFromMarket()` with useToken=1, amount=105 WETH for a 100 WETH NFT; contract deposits 105 WETH and approves marketplace for 105 WETH.
2. Marketplace pulls only 100 WETH; 5 WETH allowance remains to the marketplace.
3. Bob calls `buyNftFromMarket()` with useToken=0, amount=0 for a 5 WETH NFT.
4. Marketplace pulls the 5 WETH from the leftover allowance; Bob's ETH balance check passes since amount=0.
5. Bob acquires the NFT using Alice's locked WETH.
**How found:** Code review of the WETH branch: noticed the balance check only reads address(this).balance (ETH) while the trade path uses WETH allowance, so the invariant doesn't cover the WETH actually spent.
**Exploitation:** Attacker monitors for a prior buyNftFromMarket call that over-approved WETH to the marketplace, then submits their own buy with amount=0/useToken=0 so the marketplace draws on the residual allowance, acquiring an NFT at the victim's expense.
**Insight:** When a contract swaps between native ETH and a wrapped token, verify the post-condition against the token actually approved/spent, not the native balance; residual allowances to external marketplaces are spendable by any later caller.
