Summary
The `relist` function in Swan.sol contains a potential race condition in its round management logic where the sequential checking of old and new buyer rounds could lead to inconsistent states if round transitions occur during execution. This vulnerability could allow assets to be relisted in incorrect rounds, potentially impacting market fairness and asset availability.
Vulnerability Details
The vulnerability exists in the round validation logic of the `relist` function:
(uint256 oldRound,,) = BuyerAgent(asset.buyer).getRoundPhase();
if (oldRound <= asset.round) {
revert RoundNotFinished(_asset, asset.round);
}
BuyerAgent buyer = BuyerAgent(_buyer);
(uint256 round, BuyerAgent.Phase phase,) = buyer.getRoundPhase();
The issue arises because:
-
Round checks are performed sequentially, not atomically
-
No validation exists between old and new round relationships
-
Round transitions can occur between checks
Attack Scenario
1. Asset is listed in round N with Buyer A
2. Seller attempts to relist to Buyer B who is in round N+1
3. During transaction execution:
- Old round check passes (N <= N)
- Buyer B transitions to round N+2
- Asset gets relisted in an inconsistent state
Impact
- **Market Manipulation**: Assets could be relisted in advantageous rounds
- **Economic Impact**: Round transitions may affect pricing and availability
- **Fairness**: Could give certain buyers unfair advantages in asset acquisition
- **Protocol Integrity**: Undermines the round-based market structure
Tools Used
manual review
Recommendations
Consider Atomic Round Validation
function relist(address _asset, address _buyer, uint256 _price) external {
AssetListing storage asset = listings[_asset];
(uint256 oldRound,,) = BuyerAgent(asset.buyer).getRoundPhase();
(uint256 newRound, BuyerAgent.Phase phase,) = BuyerAgent(_buyer).getRoundPhase();
if (oldRound <= asset.round) {
revert RoundNotFinished(_asset, asset.round);
}
if (newRound <= oldRound) {
revert InvalidRoundSequence(oldRound, newRound);
}
}