Platform: Code4rena
Start Date: 08/03/2023
Pot Size: $60,500 USDC
Total HM: 2
Participants: 123
Period: 7 days
Judge: hansfriese
Id: 220
League: ETH
Rank: 97/123
Findings: 1
Award: $29.67
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xSmartContract
Also found by: 0x1f8b, 0x6980, 0xAgro, 0xSolus, 0xhacksmithh, 0xkazim, ABA, BPZ, BowTiedOriole, ChainReview, DadeKuma, DeFiHackLabs, Deathstore, DevABDee, Diana, Dravee, Dug, Englave, Go-Langer, Haipls, IceBear, Inspex, Jeiwan, Kek, Kresh, Madalad, MatricksDeCoder, MyFDsYours, RaymondFam, Rolezn, SAAJ, Sathish9098, Taloner, Udsen, Viktor_Cortess, atharvasama, ayden, brgltd, btk, carlitox477, catellatech, chaduke, codeislight, deadrxsezzz, descharre, erictee, fatherOfBlocks, favelanky, glcanvas, handsomegiraffe, jasonxiale, jekapi, joestakey, lemonr, luxartvinsec, martin, matrix_0wl, minhquanym, mrpathfindr, nadin, oyc_109, parsely, peanuts, pfedprog, rbserver, rokso, saian, santipu_, scokaf, slvDev, tsvetanovv, ubl4nk, ulqiorra, yamapyblack, zaskoh
29.6697 USDC - $29.67
The AssetType enum has four values corresponding to values 0-3. However, checks for assetType in the code base use the '> 4' qualifier. If the user inputs an assetType of 4, this will result in an incorrect error message.
NeoTokyoStaker.sol#L1205 NeoTokyoStaker.sol#L1668
L1205: if (uint8(_assetType) > 4) { L1206: revert InvalidAssetType(uint256(_assetType)); L1207: }
L1668: if (uint8(_assetType) == 2 || uint8(_assetType) > 4) { L1669: revert InvalidAssetType(uint256(_assetType)); L1700: }
Use > 3 for these checks.
getPoolReward divides by pool.totalPoints prior to multiplying by totalReward. Multiplication should be done first to avoid precision loss.
uint256 share = points * _PRECISION / pool.totalPoints * totalReward;
uint256 share = points * _PRECISION * totalReward / pool.totalPoints;
configureIdentifyCreditYields accepts two arrays as function parameters: _timelockIds and _encodedSettings. There is no check confirming that these arrays are the same length.
function configureTimelockOptions ( AssetType _assetType, uint256[] memory _timelockIds, uint256[] memory _encodedSettings ) external hasValidPermit(bytes32(uint256(_assetType)), CONFIGURE_TIMELOCKS) { for (uint256 i; i < _timelockIds.length; ) { timelockOptions[_assetType][_timelockIds[i]] = _encodedSettings[i]; unchecked { ++i; } } }
Add require statement to confirm _timelockIds and _encodedSettings are the same length.
require(_timelockIds.length == _encodedSettings.length);
The constructor for BYTES2 accepts the address for the BYTES 1.0 contract. The NatSpec incorrectly says 2.0.
@param _bytes The address of the BYTES 2.0 ERC-20 token contract.
Adjust NatSpec to say 'The address of the BYTES 1.0 ERC-20 token contract.'
The function upgradeBytes starts with a call that confirms the user's balance is greater than _amount. This check is not necessary because the subsequent burn call will implicitly check this balance.
if (IERC20(BYTES1).balanceOf(msg.sender) < _amount) { revert DoNotHaveEnoughOldBytes(_amount); } // Burn the original BYTES 1.0 tokens and mint replacement BYTES 2.0. IByteContract(BYTES1).burn(msg.sender, _amount);
Consider removing the first if statement. If the user's balance is less than _amount, the burn call will revert.
#0 - c4-judge
2023-03-17T02:56:08Z
hansfriese marked the issue as grade-b