Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

Round Synchronization Vulnerability in Swan.sol Relisting Mechanism

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:

// Check old round
(uint256 oldRound,,) = BuyerAgent(asset.buyer).getRoundPhase();
if (oldRound <= asset.round) {
revert RoundNotFinished(_asset, asset.round);
}
// Check new buyer's round separately
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];
// Get both rounds atomically at the start
(uint256 oldRound,,) = BuyerAgent(asset.buyer).getRoundPhase();
(uint256 newRound, BuyerAgent.Phase phase,) = BuyerAgent(_buyer).getRoundPhase();
// Validate round sequence
if (oldRound <= asset.round) {
revert RoundNotFinished(_asset, asset.round);
}
// Ensure new round is valid relative to old round
if (newRound <= oldRound) {
revert InvalidRoundSequence(oldRound, newRound);
}
// Continue with existing checks...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.