Asymmetry contest - Phantasmagoria's results

A protocol to help diversify and decentralize liquid staking derivatives.

General Information

Platform: Code4rena

Start Date: 24/03/2023

Pot Size: $49,200 USDC

Total HM: 20

Participants: 246

Period: 6 days

Judge: Picodes

Total Solo HM: 1

Id: 226

League: ETH

Asymmetry Finance

Findings Distribution

Researcher Performance

Rank: 217/246

Findings: 1

Award: $8.84

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

8.8405 USDC - $8.84

Labels

bug
2 (Med Risk)
downgraded by judge
partial-50
edited-by-warden
duplicate-152

External Links

Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L115-L116

Vulnerability details

Impact

Divisions in EVM are rounded down, which means when the fraction price is close to 1 (e.g. 0.999) it would effectively be zero, when it's close to 2 (1.999) it would be rounded to 1 - loosing close to 50% of the intended price. unstake function divides result of multiplying (derivatives[i].balance() * _safEthAmount) by safEthTotalSupply to get derivativeAmount. This can lead to loss of funds if the result of multiplying will be a floating-point number

115: uint256 derivativeAmount = (derivatives[i].balance() * 116: _safEthAmount) / safEthTotalSupply;

Example: User has 3.5 safEth and he wants to exchange them on ETH. Let's say that safEthTotalSupply is equals to 600 and every derivative balance is equal to 200 ETH. Then (200 * 3.5) / 600 = 1.16 But due to rounding it will be equal to 1 ETH

Additionally, it's worth noting that users who deposited less than 1 ETH may lose their funds. derivativeAmount will always be zero, and funds will not be withdrawn due to the following check:

117: if (derivativeAmount == 0) continue; // if derivative empty ignore

And users safEth will be burned here:

120: _burn(msg.sender, _safEthAmount);

Proof of Concept

function unstake(uint256 _safEthAmount) external { require(pauseUnstaking == false, "unstaking is paused"); uint256 safEthTotalSupply = totalSupply(); uint256 ethAmountBefore = address(this).balance; for (uint256 i = 0; i < derivativeCount; i++) { // withdraw a percentage of each asset based on the amount of safETH uint256 derivativeAmount = (derivatives[i].balance() * _safEthAmount) / safEthTotalSupply; if (derivativeAmount == 0) continue; // if derivative empty ignore derivatives[i].withdraw(derivativeAmount); } _burn(msg.sender, _safEthAmount); uint256 ethAmountAfter = address(this).balance; uint256 ethAmountToWithdraw = ethAmountAfter - ethAmountBefore; // solhint-disable-next-line (bool sent, ) = address(msg.sender).call{value: ethAmountToWithdraw}( "" ); require(sent, "Failed to send Ether"); emit Unstaked(msg.sender, ethAmountToWithdraw, _safEthAmount); }

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L108-L129

Tools Used

Manual review

One way to implement rounding in Solidity is to multiply and divide by a power of 10 to shift the decimal point. For example, to round a value to two decimal places, you could multiply the value by 100, round the result using integer division, and then divide the result by 100. Here's an example:

function round(uint256 value, uint256 precision) internal pure returns (uint256) { uint256 factor = 10 ** precision; uint256 roundedValue = (value * factor) / factor; return roundedValue; }

In this function, the value parameter represents the value to be rounded, and the precision parameter represents the number of decimal places to round to. The function first calculates a factor variable based on the desired precision, then multiplies the value by the factor to shift the decimal point, rounds the result using integer division, and then divides the result by the factor to shift the decimal point back.

#0 - c4-pre-sort

2023-04-04T16:20:12Z

0xSorryNotSorry marked the issue as duplicate of #455

#1 - c4-judge

2023-04-24T20:57:44Z

Picodes marked the issue as partial-50

#2 - c4-judge

2023-04-24T21:10:02Z

Picodes changed the severity to 2 (Med Risk)

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter