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: 62/99
Findings: 2
Award: $79.73
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
53.1558 USDC - $53.16
Staking.sol#claim()
ignores return value when IYieldy(YIELDY_TOKEN).transfer()
Using transfer and ignoring the return value can lead to an unusual locking on contract fund
function claim(address _recipient) public { Claim memory info = warmUpInfo[_recipient]; if (_isClaimAvailable(_recipient)) { delete warmUpInfo[_recipient]; ...
After cashing info the data will be deleted, while the success of the transfer in Yieldy contract is not measured at all IYieldy(YIELDY_TOKEN).transfer(...
vscode, hardhat
Using SafeERC20Upgradeable library to call transfer.
IERC20Upgradeable(YIELDY_TOKEN).safeTransferFrom( _user, address(this), amountLeft );
In OpenZeppelin Contracts (proxy/utils/Initializable.sol):
[CAUTION]: An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation...
The implementation contract itself should be uninitializable by default to prevent initializing any feature implementation upgrades. Leaving such external function that can be used freely without logical reverting layer.
This can lead to takeover of 3 implementation contracts: - LiquidityReserve.sol - Staking.sol - Yieldy.sol since implementation contracts not initialized and can be initialized publicly.
As its mentioned in OpenZeppelin Contracts documentation:
To prevent the implementation contract from being used, you should invoke the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
/// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); }
External and public functions can lead to very big lost for the protocol. Function produced to accomplish very deep layer in the core system without knowing the caller integrity is very dangerous in long term.
BatchRequests.sol #L14
function sendWithdrawalRequests() external {
Stacking.sol#L111#L384#L406#L465#L485
function claimFromTokemak( Recipient calldata _recipient, uint8 _v, bytes32 _r, bytes32 _s ) external {... function sendWithdrawalRequests() public {... function stake(uint256 _amount, address _recipient) public {... function claim(address _recipient) public {... function claimWithdraw(address _recipient) public {...
LiquidityReserve.sol#L214
function unstakeAllRewardTokens() public {...
vscode
Use a security layer for every intended logic to prevent any logical weakness to be used freely.
Solidity version used in project is too recent to be trusted
pragma solidity 0.8.9;
All solidity files
Slither Analysis
Consider deploying with 0.8.7
if there are no features required from 0.8.9
🌟 Selected for report: BowTiedWardens
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xmint, 8olidity, ACai, Bnke0x0, Chom, ElKu, Fabble, Fitraldys, FudgyDRS, Funen, GalloDaSballo, GimelSec, IllIllI, JC, Kaiziron, Lambda, Limbooo, MiloTruck, Noah3o6, Nyamcil, Picodes, PwnedNoMore, Randyyy, RedOneN, Sm4rty, StErMi, TomJ, Tomio, TrungOre, UnusualTurtle, Waze, _Adam, aga7hokakological, ajtra, antonttc, asutorufos, bardamu, c3phas, defsec, delfin454000, exd0tpy, fatherOfBlocks, hansfriese, ignacio, joestakey, kenta, ladboy233, m_Rassska, mics, minhquanym, oyc_109, pashov, reassor, robee, s3cunda, sach1r0, saian, sashik_eth, scaraven, sikorico, simon135, slywaters
26.5706 USDC - $26.57
Yieldy.sol#transferFrom()
will revert on overflow arithmetic operationSubtraction of uint256
to a negative value in solidity version 0.8.9 will revert.
transferFrom()
is a public function takes the amount and calculate it to creditAmount
then suptracte it form creditBalances[_from]
where _from
is the address to subtract the transfer amount from. However, if the creditAmount
is less than creditBalances[_from]
will revert upon underflow on arithmetic operation
creditBalances[_from] = creditBalances[_from] - creditAmount;
creditAmount
requirement in Yieldy.sol#transfer()
Yieldy.sol#L190
require(creditAmount <= creditBalances[msg.sender], "Not enough funds");
or
_transfer
, since transferFrom()
and transfer()
implementations share the same logic.Custom Error is a convenient and gas-efficient way to revert errors. the require(_to != address(0), "Invalid address");
uses more line of Yul and can lead to more gas usage.
LiquidityReserve.sol Migration.sol Stacking.sol Yieldy.sol ...
Define custom error, which can be used inside and outside of contracts (including interfaces and libraries).
error InvalidAddress(address); ... if (_address == address(0)) revert InvalidAddress(_address);