# resolveQueuedTrades() ERC777 re-enter to steal funds

Buffer's _openQueuedTrade refunds fees to the user before clearing isQueued, letting an ERC777 token re-enter cancelQueuedTrade and double-withdraw funds.

- Payout: Contest reward
- Severity: medium
- Program: Buffer
- Credited: HonorLt
- Disclosed: 2022-11-11
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2022-11-buffer-judging/issues/130
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-11-buffer%3AM-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:reentrancy

**Target:** BufferRouter.sol _openQueuedTrade / resolveQueuedTrades
**Root cause:** _openQueuedTrade performs tokenX.transfer to the user (refund of totalFee - revisedFee) before setting queuedTrade.isQueued = false, violating checks-effects-interactions.
**Steps:**
1. Deploy/queue a trade where tokenX is an ERC777 token (e.g. sushi) and revisedFee < queuedTrade.totalFee so a refund transfer occurs.
2. Call resolveQueuedTrades() so it invokes _openQueuedTrade().
3. During tokenX.transfer(queuedTrade.user) the ERC777 tokensToSend hook fires; re-enter cancelQueuedTrade() for the same queueId.
4. cancelQueuedTrade() sees isQueued still true, closes the trade and refunds tokenX again.
5. Return to _openQueuedTrade(), which sets isQueued = false; attacker has received tokenX twice.
**How found:** Manual review of _openQueuedTrade noticed the external tokenX.transfer call placed before the isQueued state update, and reasoned that an ERC777 hook could re-enter cancelQueuedTrade while isQueued was still true.
**Exploitation:** Attacker queues a trade with an ERC777 tokenX, waits for resolution to trigger the refund transfer, and uses the ERC777 hook to re-enter cancelQueuedTrade before isQueued is cleared, extracting the fee refund twice.
**Insight:** When auditing queue-resolution flows, check whether refund/fee transfers to the user happen before the queue-entry flag is cleared; ERC777 (or any hook-bearing token) turns that ordering into a double-spend of the refund via cancelQueuedTrade.
