Platform: Code4rena
Start Date: 20/09/2022
Pot Size: $30,000 USDC
Total HM: 12
Participants: 198
Period: 3 days
Judge: 0xean
Total Solo HM: 2
Id: 164
League: ETH
Rank: 6/198
Findings: 2
Award: $1,355.96
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: Czar102
Also found by: 0xDecorativePineapple, 0xNazgul, 0xSky, 0xbepresent, 0xmatt, Atarpara, Bahurum, DimitarDimitrov, Franfran, GimelSec, JGcarv, JLevick, Junnon, OptimismSec, Rolezn, Ruhum, Soosh, Tomo, Trust, __141345__, adriro, ajtra, bin2chen, cRat1st0s, cccz, cryptonue, d3e4, innertia, jag, joestakey, neumo, obront, pashov, pauliax, pcarranzav, peanuts, rajatbeladiya, rbserver, reassor, seyni, wagmi, zzykxx, zzzitron
0.7375 USDC - $0.74
In VariableSupplyERC20Token
, if token are using maxSupply
, it will assigned that value to mintableSupply
and whenever some tokens are minted, mintableSupply
is updated accordingly. And in case mintableSupply = 0
, it means there is no max supply limit.
require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT"); mintableSupply = maxSupply_;
In case token has maxSupply
, since mintableSupply
is reduced accordingly after every mint()
, its value can become mintableSupply = 0
and the token is no longer has max supply limit.
if(mintableSupply > 0) { require(amount <= mintableSupply, "INVALID_AMOUNT"); // We need to reduce the amount only if we're using the limit, if not just leave it be mintableSupply -= amount; }
Consider the scenario
maxSupply = 1000
, which means mintableSupply = 1000
mint()
with amount = 1000
, itโs okay and mintableSupply
is updatedmintableSupply -= amount; mintableSupply = 0;
mintableSupply == 0
now.Manual Review
Consider store maxSupply
value and change the check to
require(totalSupply + _amount <= maxSupply);
#0 - 0xean
2022-09-24T00:38:02Z
dupe of #3
๐ Selected for report: fatherOfBlocks
Also found by: wagmi
1355.2196 USDC - $1,355.22
In VTVLVesting
contract, vestingRecipients
list is declared as internal
which means we cannot read it values directly (like from Etherscan). We can only get its values from allVestingRecipients()
view function.
This function fetched all elements of the list from storage, which is really gas consuming and even can break the block gas limit in case the list is too large. Even though users donโt need to pay gas for view function, this function is still failed if its gas cost larger than block gas limit.
So in general, if there are too many vesting recipients, allVestingRecipients()
may be unabled to called and since vestingRecipients
is internal
, itโs cannot be read directly either.
Function allVestingRecipients()
returns the whole vestingRecipients
list
function allVestingRecipients() external view returns (address[] memory) { return vestingRecipients; // @audit out of gas }
And admin can add any number of vesting recipient he wants through createClaim()
or createClaimsBatch()
Manual Review
Consider adding another view function to read vestingRecipients
list, for example in range
function allVestingRecipients(uint startIdx, uint endIdx) external view returns (address[] memory)
#0 - lawrencehui
2022-10-07T17:22:01Z
dupe of #128