The normal behavior should ensure that order state changes only occur after all token transfers have been successfully completed to maintain data consistency.
The buyOrder
function modifies the order's active state before completing token transfers, which can result in orders being marked as inactive while tokens remain locked in the contract if any transfer fails.
Likelihood:
When buyer has insufficient USDC allowance or balance for the protocol fee transfer
When seller's address is a contract that rejects token transfers
When the token being sold has transfer restrictions or is paused
Impact:
Seller's tokens remain permanently locked in the contract with no way to retrieve them
Order becomes unfillable and uncancellable since it's marked as inactive
Protocol loses user trust due to funds being stuck
Attack Scenario: This demonstrates how a failed buyOrder
transaction can permanently lock seller's tokens due to premature state changes.
Explanation:
Alice creates a valid sell order, transferring her wBTC to the contract
Dan attempts to buy but only approves insufficient USDC (1000 vs 50000 needed)
The buyOrder
function sets order.isActive = false
before transfers
The first USDC transfer succeeds (protocol fee), but the second fails due to insufficient allowance
The transaction reverts, but the order state remains isActive = false
Alice cannot cancel the order because it's marked inactive, but she also didn't receive payment
Her wBTC remains permanently locked in the contract with no recovery mechanism
Solution: Apply the Checks-Effects-Interactions pattern by moving state changes after all external calls.
Why this works:
State changes (order.isActive = false
) only occur after all external calls succeed
If any transfer fails, the entire transaction reverts and state remains unchanged
Sellers retain the ability to cancel orders that haven't been successfully purchased
Follows the secure Checks-Effects-Interactions pattern to prevent state inconsistencies
Additionally consider adding nonReentrant
modifier for extra protection
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.