Dria

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

The `AssetStatus` enum using 0 as Unlisted creates ambiguity between new assets and expired listings

Summary

state management vulnerability in Swan.sol creates risks for the asset listing system:

  1. State Manipulation Risk:

  • The AssetStatus enum using 0 as Unlisted creates ambiguity between new assets and expired listings

  • Attackers could exploit this to bypass listing restrictions

  • Impact: Potential market manipulation and broken invariants

  1. Relisting Vulnerability:

  • The relist function overwrites listings without proper state cleanup

  • Missing validation of state transitions

  • Impact: Could lead to assets existing in invalid states, breaking core market functionality

  1. Economic Impact:

  • Broken state management affects asset trading

  • Could disrupt fee collection and royalty distributions

  • Impacts market participants: buyers, sellers and protocol revenue

The combination of these issues creates systemic risk for the Swan protocol's core marketplace functionality.

Vulnerability Details

Swan's asset state management system allows invalid state transitions and breaks core protocol invariants through the relisting mechanism.

https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L66-L70

// @bug detected: AssetStatus enum allows state manipulation since Unlisted=0 is default
// This means assets can be relisted without proper state validation
enum AssetStatus {
Unlisted, // 0 as default creates ambiguity between new assets and expired listings
Listed, // 1
Sold // 2
}

https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L197-L246

function relist(address _asset, address _buyer, uint256 _price) external {
AssetListing storage asset = listings[_asset];
// @bug detected: Insufficient state validation
// Only checks if Listed but doesn't validate transition from previous states
if (asset.status != AssetStatus.Listed) {
revert InvalidStatus(asset.status, AssetStatus.Listed);
}
// @bug detected: State overwrite without cleanup
// Creates new listing without properly clearing old state
listings[_asset] = AssetListing({
status: AssetStatus.Listed,
// ...
});
}

The bug is the state management of assets, specifically in the relist() function. Here's why:

  1. The relist() function allows an asset to be relisted if it was previously listed but not sold

  2. However, there's no check to ensure the asset's state is properly reset when relisting

  3. This function creates a new listing with AssetStatus.Listed without first verifying or resetting the previous state

This could lead to a scenario where:

  1. Asset is initially listed (state = 1)

  2. Round passes without sale

  3. Asset is relisted but previous state remains

  4. New listing state is set without clearing old one

  5. Could potentially result in invalid state values

1. Create asset A with status Unlisted (0)
2. List asset A -> status = Listed (1)
3. Round passes without sale
4. Relist asset A:
- Previous state remains
- New listing created
- State invariant broken
5. Asset now in invalid state affecting:
- Purchase operations
- Fee calculations
- Market parameters

Impact

  • Breaks core invariant: assetStates[asset] <= 2

  • Disrupts market operations and fee collection

  • Allows manipulation of asset states

  • Affects all market participants

Tools Used

Manual Review

Recommendations

Implement a proper state machine with explicit transitions and cleanup mechanisms.

Alternative

enum AssetStatus {
- Unlisted,
+ Invalid,
Listed,
Sold
}
function relist(...) external {
+ require(validateStateTransition(asset.status, AssetStatus.Listed), "Invalid transition");
+ cleanupOldListing(asset);
listings[_asset] = AssetListing({...});
}
+ function validateStateTransition(AssetStatus current, AssetStatus next) internal pure returns (bool) {
+ // state transition validation logic
+ }
Updates

Lead Judging Commences

inallhonesty Lead Judge
7 months ago
inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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