Yieldy contest - saian'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: 91/99

Findings: 1

Award: $26.57

🌟 Selected for report: 0

🚀 Solo Findings: 0

add unchecked to save gas

Expression that cant overflow/underflow can be placed in a unchecked block which will avoid the default overflow/underflow checks introduced in 0.8 and save gas

Proof of concept

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

require(creditAmount <= creditBalances[msg.sender], "Not enough funds"); creditBalances[msg.sender] = creditBalances[msg.sender] - creditAmount;

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

require(_allowances[_from][msg.sender] >= _value, "Allowance too low"); uint256 newValue = _allowances[_from][msg.sender] - _value;

Cache storage variabes and save gas

Storage variables can be cached in a local variables and reused instead of reading from storage to save gas

Proof of concept

CURVE_POOL in setToAndFromCurve()

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

replace curvePoolTo, curvePoolFrom with from, to

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

curvePoolFrom = from; curvePoolTo = to; emit LogSetCurvePool(CURVE_POOL, curvePoolTo, curvePoolFrom);

decimal can be replaced with function parameter _decimal

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

decimal = _decimal; WAD = 10**decimal;

_totalSupply can be replaced with currentTotalSupply

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

uint256 currentTotalSupply = _totalSupply; require(_totalSupply > 0, "Can't rebase if not circulating");

_totalSupply in

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

contract[i] in

if ( contracts[i] != address(0) && IStaking(contracts[i]).canBatchTransactions() ) { IStaking(contracts[i]).sendWithdrawalRequests(); }

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

contracts[i] in

bool canBatch = IStaking(contracts[i]).canBatchTransactions(); batch[i] = Batch(contracts[i], canBatch);

contracts[_index] in

return ( contracts[_index], IStaking(contracts[_index]).canBatchTransactions() );

Avoid initialising variables with default values

When variables are created it contains default values, explicitly initialising with default values(0, address(0), false) is not necessary

Proof of concept

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

int128 from = 0; int128 to = 0;

Code can be simplified

Proof of concept

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

address address0 = ICurvePool(CURVE_POOL).coins(0); address address1 = ICurvePool(CURVE_POOL).coins(1); int128 from = 0; int128 to = 0; if (TOKE_POOL == address0 && STAKING_TOKEN == address1) { to = 1; } else if (TOKE_POOL == address1 && STAKING_TOKEN == address0) { from = 1; } require(from == 1 || to == 1, "Invalid Curve Pool"); curvePoolFrom = from; curvePoolTo = to;
address address0 = ICurvePool(CURVE_POOL).coins(0); address address1 = ICurvePool(CURVE_POOL).coins(1); if (TOKE_POOL == address0 && STAKING_TOKEN == address1) { curvePoolTo = 1; } else if (TOKE_POOL == address1 && STAKING_TOKEN == address0) { curvePoolFrom = 1; } else { revert("Invalid Curve Pool"); }

exit out of loop after delete

exit out of the loop after deleting address instead of iterating over the entire array

Proof of concept

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

for (uint256 i; i < contractsLength; ) { if (contracts[i] == _address) { delete contracts[i]; } unchecked { ++i; } }
Mitigation

Add return statement after delete statement, or swap last index with target index and pop the last element to avoid iterating over long array

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