Shell Protocol - d3e4's results

A set of EVM-based smart contracts on Arbitrum One. In a nutshell it is DeFi made simple.

General Information

Platform: Code4rena

Start Date: 21/08/2023

Pot Size: $36,500 USDC

Total HM: 1

Participants: 43

Period: 7 days

Judge: Dravee

Id: 277

League: ETH

Shell Protocol

Findings Distribution

Researcher Performance

Rank: 7/43

Findings: 1

Award: $1,933.59

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: Mirror

Also found by: ItsNio, T1MOH, Testerbot, Udsen, d3e4, ktg, markus_ether, mert_eren, oakcobalt, pontifex, prapandey031, skodi

Labels

bug
3 (High Risk)
disagree with severity
satisfactory
sponsor confirmed
sufficient quality report
duplicate-57

Awards

1933.5938 USDC - $1,933.59

External Links

Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L563-L595 https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L701-L724 https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L716

Vulnerability details

Impact

There is a missing balance check in _reserveTokenSpecified(), which allows reserve tokens to be withdrawn or deposited into illegal balances, which may cause subsequent transactions to revert. It also allows the pool to be killed by withdrawing all balances which prevents any further deposit.

Proof of Concept

The allowed region of possible reserve token balances is constrained by _checkBalances(), which requires that each balance be at least MIN_BALANCE and that the ratio of balances be in the interval [MIN_M, MAX_M).

The functions available for swapping are swapGivenInputAmount() and swapGivenOutputAmount(), both of which make use of _swap() for calculating the unknown value (output and input amounts) which in turn checks the resulting balance after the swap with _checkBalances(). Thus it is impossible to swap out of the allowed region.

The functions depositGivenOutputAmount() and withdrawGivenInputAmount() both make use of _lpTokenSpecified() for the calculation which likewise checks the resulting balance after the deposit or withdrawal with _checkBalances(). Thus it is impossible to deposit or withdraw, using these functions, out of the allowed region.

However, the remaining functions depositGivenInputAmount() and withdrawGivenOutputAmount() instead make use of _reserveTokenSpecified() which fails to perform the balance checks. The balances may therefore end up outside of the allowed region when using these functions. Specifically, one may withdraw too much such that MIN_BALANCE is violated or one may deposit too much such that the ratio of balances is violated.

By entering this forbidden region, some transactions will be reverted if they fail to leave the forbidden region. It also makes it possible to kill the pool by withdrawing all of both reserve tokens. Then all deposits will revert due to division by zero in _reserveTokenSpecified() at L589 and in _getUtilityFinalLp() at L660 (called by _lpTokenSpecified()).

Also note that _getUtility() accepts negative balances as parameters. This means (depending on the integration of EvolvingProteus) that one can withdraw into a negative balance. Further note the unsafe casting of an integer into an uint256 at L716 in the calculation of disc. This is an issue precisely when we have this freedom with the balances. The utility may thus underflow into an invalid and much higher value, breaking an important invariant.

Add balance checks in _reserveTokenSpecified(), as in _swap() and _lpTokenSpecified().

Consider also checking that x and y in _getUtility() are non-negative and that the uint256 casting in the calculation of disc doesn't underflow.

Assessed type

Invalid Validation

#0 - c4-pre-sort

2023-08-28T20:41:09Z

0xRobocop marked the issue as primary issue

#1 - c4-pre-sort

2023-08-28T20:41:33Z

0xRobocop marked the issue as sufficient quality report

#2 - c4-sponsor

2023-09-04T04:57:35Z

viraj124 marked the issue as disagree with severity

#3 - viraj124

2023-09-04T04:57:55Z

this should be low/med at best IMO we're adding the balance check but note _getUtility is a internal method and there are input check of the reserve balances values passed so that is a invalid argument

#4 - c4-sponsor

2023-09-04T04:58:01Z

viraj124 (sponsor) acknowledged

#5 - viraj124

2023-09-11T05:52:53Z

we checked this further with some other members of the team and agreed this is a high and we've fixed this in a pr

#6 - c4-sponsor

2023-09-11T05:52:58Z

viraj124 (sponsor) confirmed

#7 - c4-judge

2023-09-11T19:20:32Z

JustDravee marked the issue as satisfactory

#8 - c4-judge

2023-09-11T19:20:57Z

JustDravee marked issue #57 as primary and marked this issue as a duplicate of 57

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