Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Valid

Disruption of market timing and potential manipulation of asset availability

Summary

The list() function does not check if an asset has already been listed before creating a new listing. The only checks performed are:

  1. Buyer must be in sell phase

  2. Asset count must not exceed maxAssetCount

This means an asset can be listed multiple times if:

  1. The first listing is created successfully

  2. The same asset is listed again with different parameters while still in sell phase

  3. The asset count hasn't reached the limit

The bug can be reproduced by

// First listing
list("Asset1", "AST1", "desc", 100, buyer);
// Second listing with same asset but different params
list("Asset1", "AST1", "new desc", 200, buyer); // Should revert but doesn't

Vulnerability Details

  1. Race Condition in Round Checking:

  • The vulnerability allows a potential race condition where the round state could change between check and execution

  • This could lead to assets being relisted in incorrect rounds, breaking the protocol's round-based logic

  • Impact: Disruption of market timing and potential manipulation of asset availability

  1. Insufficient Buyer Validation:

  • The code assumes the new buyer address is valid without proper verification

  • A malicious actor could provide an invalid buyer address or manipulate the buyer state

  • Impact: Potential asset lockup or manipulation of market dynamics

These vulnerabilities could be exploited to:

  • Manipulate market timing

  • Create inconsistent asset states

  • Bypass intended round restrictions

  • Lock assets in invalid states

The combination of these issues makes the relist function particularly dangerous for the protocol's integrity and user assets.

[Swan.sol#L197-L224](https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L197-L224)

function relist(address _asset, address _buyer, uint256 _price) external {
AssetListing storage asset = listings[_asset];
// only the seller can relist the asset
if (asset.seller != msg.sender) {
revert Unauthorized(msg.sender);
}
// asset must be listed
if (asset.status != AssetStatus.Listed) {
revert InvalidStatus(asset.status, AssetStatus.Listed);
}
// @bug detected: Race condition in round checking
// The check only verifies oldRound <= asset.round but doesn't account for
// the time between this check and the actual relisting
(uint256 oldRound,,) = BuyerAgent(asset.buyer).getRoundPhase();
if (oldRound <= asset.round) {
revert RoundNotFinished(_asset, asset.round);
}
// @bug detected: Missing validation of new buyer state
// The new buyer could be in an invalid state or non-existent
BuyerAgent buyer = BuyerAgent(_buyer);
(uint256 round, BuyerAgent.Phase phase,) = buyer.getRoundPhase();

This issue connects to multiple critical paths:

  • SwanManager.sol: Round management

  • BuyerAgent.sol: Phase transitions

  • Swan.sol: Asset listing logic

This creates a systemic risk to the entire protocol's market mechanics and user funds.

Impact

  • Assets can be relisted in incorrect rounds

  • Potential double-spending of royalties

  • Market manipulation through timing attacks

  • Asset state inconsistencies

Causes

  1. External state dependency (BuyerAgent round state)

  2. Non-atomic operations in critical path

  3. Missing synchronization between round transitions

Tools Used

Manual Review

Recommendations

Implement a round-based state machine that ensures atomic transitions and synchronized validation of asset states and rounds.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Duplicate assets in `Swan::list` function

Appeal created

ljj Auditor
6 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Duplicate assets in `Swan::list` function

Support

FAQs

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