Dria

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

Phase Transition Vulnerability in SwanManager::setMarketParameters()

Summary

A critical flaw in the SwanManager::setMarketParameters() function allows unintended phase transitions in the Swan protocol. Changing market parameters can inadvertently skip critical trading phases, such as moving directly from the SELL phase to the WITHDRAW phase without allowing for a BUY phase.

Vulnerability Details

The vulnerability stems from the immediate application of updated parameters in the getRoundPhase() function within the BuyerAgent contract. If setMarketParameters updates the market intervals mid-cycle, the function might interpret the current time as part of a new cycle based on the updated parameters, potentially skipping phases.

// SwanManager.sol
function setMarketParameters(uint256 sellInterval, uint256 buyInterval, uint256 withdrawInterval) public onlyOwner {
currentMarketParameters.sellInterval = sellInterval;
currentMarketParameters.buyInterval = buyInterval;
currentMarketParameters.withdrawInterval = withdrawInterval;
emit MarketParametersUpdated(sellInterval, buyInterval, withdrawInterval);
}
// BuyerAgent.sol
function getRoundPhase() public view returns (uint256, Phase, uint256) {
SwanMarketParameters[] memory marketParams = swan.getMarketParameters();
if (marketParams.length == marketParameterIdx + 1) {
// Case 1: If there is only one set of parameters, calculate the phase based on it.
return _computePhase(marketParams[marketParameterIdx], block.timestamp - createdAt);
} else {
// Case 2: Multiple parameter updates - Accumulate rounds and calculate the current phase.
uint256 idx = marketParameterIdx;
uint256 round;
// Calculate initial rounds from contract creation time up to the first update.
(uint256 initialRound,,) = _computePhase(marketParams[idx], marketParams[idx + 1].timestamp - createdAt);
round = initialRound;
idx++;
// Process all intermediate parameter sets.
while (idx < marketParams.length - 1) {
(uint256 innerRound,,) =
_computePhase(marketParams[idx], marketParams[idx + 1].timestamp - marketParams[idx].timestamp);
round += innerRound + 1;
idx++;
}
// Calculate the phase for the latest parameter set based on the current time.
(uint256 lastRound, Phase phase, uint256 timeRemaining) =
_computePhase(marketParams[idx], block.timestamp - marketParams[idx].timestamp);
round += lastRound + 1;
return (round, phase, timeRemaining);
}
}

Impact

When market parameters are altered mid-cycle and durations are reduced, it can disrupt the protocol's standard operational flow. This may skip Buy Phase which does not only impacts the trading cycle but also skips crucial transactions that are integral to the protocol's system.

Tools Used

Manual review

Recommendations

Implement a mechanism where parameter updates take effect only at the start of the next cycle rather than immediately.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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