Swan's purchase mechanism where state changes occur before external interactions, potentially leading to asset theft and locked funds.
Looking at the purchase()
function in Swan.sol
, there are multiple external calls:
Token transfers via transferFrom()
NFT transfers via transferFrom()
The key issue is in the token transfer sequence:
The bug is that the contract updates the asset status to "Sold" before performing the transfers:
This violates the CEI (Checks-Effects-Interactions) pattern since the state is updated before external calls.
The purchase()
function in Swan.sol
: https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L276-L302
This is dangerous for the protocol because:
State changes occur before external interactions, violating CEI pattern
Multiple dependent transfers create points of failure
Asset ownership could change without payment completing
Failed transfers would leave the contract in an inconsistent state
No way to revert the status change if transfers fail
The sequence of operations should be:
Execute all transfers
Verify success
Update state
Emit event
This vulnerability could lead to asset theft or locked assets if exploited.
Any failed transfer will trigger this vulnerability
Multiple external calls increase failure probability
Assets can be marked as sold without payment completing
Seller loses NFT without receiving payment if token transfer fails
Contract state becomes inconsistent with actual ownership
No way to revert the status change
Manual Review
Consider implementing atomic swaps or escrow mechanism to ensure asset and payment transfers occur atomically.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.