Yieldy contest - csanuragjain's results

A protocol for gaining single side yields on various tokens.

General Information

Platform: Code4rena

Start Date: 21/06/2022

Pot Size: $50,000 USDC

Total HM: 31

Participants: 99

Period: 5 days

Judges: moose-code, JasoonS, denhampreen

Total Solo HM: 17

Id: 139

League: ETH

Yieldy

Findings Distribution

Researcher Performance

Rank: 8/99

Findings: 6

Award: $2,209.08

🌟 Selected for report: 3

🚀 Solo Findings: 2

Findings Information

🌟 Selected for report: 0x1f8b

Also found by: BowTiedWardens, Lambda, StErMi, berndartmueller, csanuragjain, neumo, rfa

Labels

bug
duplicate
2 (Med Risk)

Awards

119.2495 USDC - $119.25

External Links

Lines of code

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/BatchRequests.sol#L89

Vulnerability details

Impact

Deleted contract address index are not moved on removeAddress function at BatchRequests.sol#L89.

All deleted index will become 0 so contract address will start having 0 address values. This becomes problem at canBatchContracts which will now fail since IStaking(contracts[i]).canBatchTransactions() will fail on 0 address

Proof of Concept

  1. Assume 10 address are present in contracts

  2. Admin decides to remove address X which is present at index contracts[2]

  3. Admin calls removeAddress for same which makes contracts[2] = address(0)

  4. User calls canBatchContracts which fails since IStaking(contracts[i]).canBatchTransactions() will fail on 0 address

Ideally deleted index should be replaced by last index and a pop should be done

#0 - toshiSat

2022-06-28T00:23:48Z

duplicate #82

Findings Information

🌟 Selected for report: pashov

Also found by: csanuragjain, hake, kenta, m_Rassska, oyc_109

Labels

bug
duplicate
2 (Med Risk)

Awards

119.2495 USDC - $119.25

External Links

Lines of code

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Migration.sol#L48

Vulnerability details

Impact

It is not checked whether call to transferFrom has succeded or not in moveFundsToUpgradedContract function. This becomes a problem and could lead to contract losing funds

Proof of Concept

  1. User A calls moveFundsToUpgradedContract
  2. Unfortunately due to some reasons, call to IYieldy(OLD_YIELDY_TOKEN).transferFrom(...) fails so no user fund are transferred to contract
  3. IStaking(NEW_CONTRACT).stake(userWalletBalance, msg.sender); will stake userWalletBalance for User A even though User A paid nothing

Check return value of transferFrom. If it is false then revert

bool success = IYieldy(OLD_YIELDY_TOKEN).transferFrom( msg.sender, address(this), userWalletBalance ); require(success, "transfer failed");

#0 - toshiSat

2022-06-28T16:16:34Z

duplicate #99

Findings Information

🌟 Selected for report: csanuragjain

Labels

bug
2 (Med Risk)
sponsor acknowledged

Awards

158.9994 USDC - $159.00

External Links

Lines of code

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Yieldy.sol#L91

Vulnerability details

Impact

It was observed that if updatedTotalSupply > MAX_SUPPLY then updatedTotalSupply becomes MAX_SUPPLY. This means _profit amount is not fully used. But _storeRebase function is still called with _profit amount

This becomes a problem since _storeRebase function caluclates rebasePercent using this incorrect _profit amount

Proof of Concept

  1. REBASE_ROLE calls rebase function with say profit 10. Assume currentTotalSupply is 90

  2. updatedTotalSupply is calculated as updatedTotalSupply = currentTotalSupply + _profit. Thus updatedTotalSupply becomes 90+10=100

  3. Assume MAX_SUPPLY is 91. Since updatedTotalSupply>MAX_SUPPLY so updatedTotalSupply is updated to be 91

  4. Now _storeRebase function is called with updatedTotalSupply (91), _profit(10)

  5. This is incorrect since 10 amount from _profit is not utilized and only 1 amount is utilized. This becomes a problem in rebasePercent calculation where it is calculated on full 10 amount instead of 1

Use below:

if (updatedTotalSupply > MAX_SUPPLY) { _profit=_profit - (updatedTotalSupply-MAX_SUPPLY); updatedTotalSupply = MAX_SUPPLY; }

#0 - toshiSat

2022-06-28T00:35:35Z

Max Supply is nearly the max amount in uint256. The protection is there, but will most likely never hit.

#1 - JasoonS

2022-07-30T15:19:22Z

Potentially, this should be a medium issue.

#2 - JasoonS

2022-08-29T16:41:37Z

Downgrading to medium

Findings Information

🌟 Selected for report: csanuragjain

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

1211.7009 USDC - $1,211.70

External Links

Lines of code

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/LiquidityReserve.sol#L161

Vulnerability details

Impact

Whale who provided most liquidity to the contract can simply use removeLiquidity function and can remove all of his liquidity. This can leave the residual liquidity to be less than MINIMUM_LIQUIDITY which is incorrect

Proof of Concept

  1. Whale A provided initial liquidity plus more liquidity using enableLiquidityReserve and addLiquidity function

  2. There are other small liquidity providers as well

  3. Now Whale A decides to remove all the liquidity provided

  4. This means after liquidity removal the balance liquidity will even drop below MINIMUM_LIQUIDITY which is incorrect

Add below check

require( IERC20Upgradeable(stakingToken).balanceOf(address(this)) - MINIMUM_LIQUIDITY >= amountToWithdraw, "Not enough funds" );

Findings Information

🌟 Selected for report: csanuragjain

Also found by: MiloTruck

Labels

bug
2 (Med Risk)

Awards

545.2654 USDC - $545.27

External Links

Lines of code

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Staking.sol#L319

Vulnerability details

Impact

_requestWithdrawalFromTokemak function :: Instead of sending amountToRequest for requestWithdrawal, contract is asking _amount for requestWithdrawal. This becomes a problem when balance < _amount and only balance could be withdrawn

Proof of Concept

  1. In _requestWithdrawalFromTokemak function, amountToRequest is calculated as
// the only way balance < _amount is when using unstakeAllFromTokemak uint256 amountToRequest = balance < _amount ? balance : _amount;
  1. Now assuming balance < _amount then amountToRequest becomes balance

  2. But tokePoolContract.requestWithdrawal is called over _amount instead of amountToRequest which means withdrawal is requested over an extra amount

Modify Staking.sol#L326 to

if (amountToRequest > 0) tokePoolContract.requestWithdrawal(amountToRequest);

#0 - toshiSat

2022-06-28T00:30:10Z

duplicate #143

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/BatchRequests.sol#L19

Function sendWithdrawalRequests: No need to check IStaking(contracts[i]).canBatchTransactions() as this is already done in IStaking(contracts[i]).sendWithdrawalRequests();

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/LiquidityReserve.sol#L161

Function removeLiquidity: require(isReserveEnabled, "Not enabled yet"); should be added otherwise there is no liquidity to remove

https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Staking.sol#L88

Function initialize: L88-L91 is complete duplicate of L84-L87 . Remove either one of them

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