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
Rank: 8/99
Findings: 6
Award: $2,209.08
🌟 Selected for report: 3
🚀 Solo Findings: 2
🌟 Selected for report: 0x1f8b
Also found by: BowTiedWardens, Lambda, StErMi, berndartmueller, csanuragjain, neumo, rfa
https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/BatchRequests.sol#L89
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
Assume 10 address are present in contracts
Admin decides to remove address X which is present at index contracts[2]
Admin calls removeAddress for same which makes contracts[2] = address(0)
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
https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Migration.sol#L48
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
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
🌟 Selected for report: csanuragjain
158.9994 USDC - $159.00
https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Yieldy.sol#L91
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
REBASE_ROLE calls rebase function with say profit 10. Assume currentTotalSupply is 90
updatedTotalSupply is calculated as updatedTotalSupply = currentTotalSupply + _profit. Thus updatedTotalSupply becomes 90+10=100
Assume MAX_SUPPLY is 91. Since updatedTotalSupply>MAX_SUPPLY so updatedTotalSupply is updated to be 91
Now _storeRebase function is called with updatedTotalSupply (91), _profit(10)
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
🌟 Selected for report: csanuragjain
1211.7009 USDC - $1,211.70
https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/LiquidityReserve.sol#L161
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
Whale A provided initial liquidity plus more liquidity using enableLiquidityReserve and addLiquidity function
There are other small liquidity providers as well
Now Whale A decides to remove all the liquidity provided
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" );
🌟 Selected for report: csanuragjain
Also found by: MiloTruck
https://github.com/code-423n4/2022-06-yieldy/blob/main/src/contracts/Staking.sol#L319
_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
// the only way balance < _amount is when using unstakeAllFromTokemak uint256 amountToRequest = balance < _amount ? balance : _amount;
Now assuming balance < _amount then amountToRequest becomes balance
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
🌟 Selected for report: IllIllI
Also found by: 0x1337, 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xmint, Bnke0x0, BowTiedWardens, Chom, ElKu, FudgyDRS, Funen, GalloDaSballo, GimelSec, JC, Kaiziron, Lambda, Limbooo, Metatron, MiloTruck, Noah3o6, Picodes, PumpkingWok, PwnedNoMore, Sm4rty, StErMi, TomJ, TrungOre, UnusualTurtle, Waze, _Adam, aga7hokakological, ak1, antonttc, berndartmueller, cccz, cryptphi, csanuragjain, defsec, delfin454000, dipp, elprofesor, exd0tpy, fatherOfBlocks, hake, hansfriese, hubble, joestakey, kenta, ladboy233, mics, oyc_109, pashov, pedr02b2, reassor, robee, samruna, scaraven, shung, sikorico, simon135, sseefried, tchkvsky, unforgiven, zzzitron
54.6089 USDC - $54.61
Function sendWithdrawalRequests: No need to check IStaking(contracts[i]).canBatchTransactions() as this is already done in IStaking(contracts[i]).sendWithdrawalRequests();
Function removeLiquidity: require(isReserveEnabled, "Not enabled yet"); should be added otherwise there is no liquidity to remove
Function initialize: L88-L91 is complete duplicate of L84-L87 . Remove either one of them