Yieldy contest - Waze'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: 54/99

Findings: 2

Award: $80.04

🌟 Selected for report: 0

🚀 Solo Findings: 0

#1 Unused code Impact inefficiency code make gas cost higher.

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L84-L90

Tool Used Manual review

Recommend Mitigation Steps remove one of these

IERC20Upgradeable(YIELDY_TOKEN).approve( LIQUIDITY_RESERVE, type(uint256).max ); IERC20Upgradeable(YIELDY_TOKEN).approve( LIQUIDITY_RESERVE, type(uint256).max

#2 Use call instead transfer Impact usage of send() or transfer() would cause an out of gas error.

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L471

Tool Used remix

Recommend Mitigation Steps use .call() because .transfer() fowards 2300 gas whereas .call() forwards all / set gas.

#3 Missing natspec param orderUid Impact preSign function have natspec comment which is missing the orderUid function parameter. Issues with comments are low risk based on Code4rena risk categories.

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L769

Tool Used Remix

Recommend Mitigation Steps Add natspec comments include orderUid parameter in preSign function.

#4 TransferFrom must be external Impact Visibility of transferFrom must external

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Yieldy.sol#L205

Tool Used Manual review

Recommend Mitigation Steps check OZ docs for implementation transferFrom.

#5 Missing natspec parm index Impact canBatchContractByIndex function have natspec comment which is missing the index function parameter. Issues with comments are low risk based on Code4rena risk categories.

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L47

Tool Used Remix

Recommend Mitigation Steps Add natspec comments include index parameter in canBatchContractByIndex function.

#6 Must be indexed Impact event is missing indexed fields.

Proof of Concept https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L32

Tool Used Manual review

Recommend Mitigation Steps Add indexed at affilateAddress.

#1 Use require jnstead &&

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L54-L63

use require instead of && for efficient gas cost. change it from

require( _stakingToken != address(0) && _yieldyToken != address(0) && _tokeToken != address(0) && _tokePool != address(0) && _tokeManager != address(0) && _tokeReward != address(0) && _liquidityReserve != address(0), "Invalid address" );

to

require(_stakingToken != address(0), "Invalid address"); require(_yieldyToken != address(0), "Invalid address"); require(_tokeToken != address(0), "Invalid address"); require(_tokePool != address(0),"Invalid address"); require(_tokeManager != address(0),"Invalid address"); require(_tokeReward != address(0),"Invalid address"); require(_liquidityReserve != address(0),"Invalid address");

#2 Use != 0 instead of > 0.

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L118

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L305

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L392

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L410

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L470

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L533

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L604

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Yieldy.sol#L83

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Yieldy.sol#L96

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/LiquidityReserve.sol#L223

for unsigned integer, >0 is less efficient then !=0, so use !=0 instead of >0. apply to others.

#3 Use storage instead memory

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L35

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L264

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L278

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L281

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L466

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L486

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L518

Use storage instead of memory to reduce the gas fee. i suggest to change

Claim memory userWarmInfo = warmUpInfo[_user];

to

Claim storage userWarmInfo = warmUpInfo[_user];

#4 use require Instead && #2

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L574

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L611

use require instead of && for efficient gas cost. change it from

require( !isUnstakingPaused && !isInstantUnstakingPaused, "Unstaking is paused");

to

require(!isUnstakingPaused,"Unstaking is paused"); require(!isInstantUnstakingPaused,"Unstaking is paused");

#5 Instead && curvepool

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L605

require( CURVE_POOL != address(0) && (curvePoolFrom == 1 || curvePoolTo == 1), "Invalid Curve Pool");

to

require(CURVE_POOL != address(0), "Invalid Curve Pool"); require(curvePoolFrom == 1 || curvePoolTo == 1), "Invalid Curve Pool");

#6 Pre increment

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L708

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L24

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L40

use pre increment e.g ++i because pre-increment more cheaper gas than post increment e.g i++. i suggest to use pre increment.

#7 Calldata

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L73

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Yieldy.sol#L29

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/LiquidityReserve.sol#L37

In the external functions where the function argument is read-only, the function() has an inputed parameter that using memory, if this function didnt change the parameter, its cheaper to use calldata then memory. so we suggest to change it.

#8 unnecessary code

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

fusion the code in if statement

if (updatedTotalSupply > MAX_SUPPLY) { updatedTotalSupply = MAX_SUPPLY;

to

if (updatedTotalSupply >= MAX_SUPPLY) {}

#9 Use require instead if

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Yieldy.sol#L280

i suggest to change from

if (_amount == 0) { return;

to

require(amount != 0, "amount can't be zero);

#10 Cache requestedWithdrawals.amount

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L305

cache the requestedWithdrawals.amount because it use multiple time. cache it can reduce gas.

#11 Cache iyield as token

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L435-L447

https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L471

cache the IYieldy(YIELDY_TOKEN) because use mutiple times e.g

if (warmUpPeriod == 0) { IYieldy(YIELDY_TOKEN).mint(_recipient, _amount); } else { // create a claim and mint tokens so a user can claim them once warm up has passed warmUpInfo[_recipient] = Claim({ amount: info.amount + _amount, credits: info.credits + IYieldy(YIELDY_TOKEN).creditsForTokenBalance(_amount), expiry: epoch.number + warmUpPeriod }); IYieldy(YIELDY_TOKEN).mint(address(this), _amount); }

change to

IYieldy token = IYieldy(YIELDY_TOKEN); if (warmUpPeriod == 0) { token.mint(_recipient, _amount); } else { // create a claim and mint tokens so a user can claim them once warm up has passed warmUpInfo[_recipient] = Claim({ amount: info.amount + _amount, credits: info.credits + token.creditsForTokenBalance(_amount), expiry: epoch.number + warmUpPeriod }); token.mint(address(this), _amount); }
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