Dria

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

Calling `Swan::getMarketParameters()` copies the full array into memory leading to permanent DoS for the Protocol in the future

Description

When changing market parameters, we push the new parameters into an array, and the last element in the array is the current market parameters.

swan/SwanManager.sol#L80-L84

function setMarketParameters(SwanMarketParameters memory _marketParameters) external onlyOwner {
require(_marketParameters.platformFee <= 100, "Platform fee cannot exceed 100%");
_marketParameters.timestamp = block.timestamp;
marketParameters.push(_marketParameters);
}

There is a function that returns all that array into memory, that can be used to return all the Array.

swan/SwanManager.sol#L68-L70

function getMarketParameters() external view returns (SwanMarketParameters[] memory) {
return marketParameters;
}

This function returns the hole array. It is a view function so ir will not cost gas when calling it alone, but calling it in another function will make the calling contract coppies all that array into its memory which consums gas.

The problem is that this function is used in critical functions. it is used in BuyerAgent::getRoundPhase() and in the constructor when deploying new BuyerAgent.

swan/BuyerAgent.sol#L335 | swan/BuyerAgent.sol#L138

function getRoundPhase() public view returns (uint256, Phase, uint256) {
>> SwanMarketParameters[] memory marketParams = swan.getMarketParameters();
...
}
...
constructor( ... ) Ownable(_owner) {
...
>> marketParameterIdx = swan.getMarketParameters().length - 1;
...
}

Function getRoundPhase() is getting called in different parts:

  • When BuyerAgent Owner withdraws his tokens BuyerAgent::withdraw()

  • _checkRoundPhase() internal function which is used in different parts
    This function is called getRoundPhase(), which loops through all parameters to compute the Round, leading to a High likelihood of a DoS scenario.

  • When the seller lists items Swan::list()

  • When the seller relists his item (getting called two times) Swan::relist()

This will make this function subjected to DoS in the long term when changing market parameters many times, and it will make all of the protocol insolvable, as Copying a huge array into memory, besides doing some calculations, can make the TX go OOG.

And in a function like relist() it is getting called twice, not only once, which increases the likelihood of it going OOG before other functions.

Impact

Permanent DoS for the protocol

Recommendations

Make two new functions in Swan. The first will get the length of the marketParameters array, and the other will fetch a single element in that array using the index as a parameter by the caller.

So when doing our calculations we will use fetch the length, and elements we need in that array, and not the whole array. This will allow us to copy only the necessary elements, not the full array, and do our calculations normally.

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.