Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add validation for ERC20 premint amount to prevent "Literal too large" error #488

Merged
merged 8 commits into from
Mar 26, 2025

Conversation

hashpalk
Copy link
Contributor

@hashpalk hashpalk commented Mar 19, 2025

This solves issue #241 where the ERC20 token generator previously allowed arbitrarily large numbers in the premint field, which could lead to a "Literal too large" compilation error in Solidity. This occurred because very large numbers exceeded Solidity's number literal limit when combined with the token's 18 decimal places.

Changes:

  • Add validation to check if the final token amount (including 18 decimals) exceeds Solidity's 77-digit literal limit
  • Pre-calculate the full amount with decimals instead of using runtime multiplication
  • Add clear error message when amount is too large
  • Generate simpler and more direct minting code

This prevents contract compilation failures while still allowing reasonably large premint amounts up to Solidity's literal limits.

…RC20 decimals. Added validation to prevent exceeding Solidity literal limits.
Copy link

github-actions bot commented Mar 19, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@hashpalk
Copy link
Contributor Author

I have read the CLA Document and I hereby sign the CLA

Copy link
Member

@ericglau ericglau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. I think the check here should take a slightly different approach, please see my comments.

const exp = decimalPlace <= 0 ? 'decimals()' : `(decimals() - ${decimalPlace})`;

// Add 18 decimals to the number (standard ERC20 decimals)
const fullAmount = units + '000000000000000000';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This number should not be hardcoded as 18 decimals. While 18 is the default, users who take the generated contract as a starting point could override the decimals() function of ERC20.sol to change the intended display decimals. The premint amount should take this value into consideration.

For example, if the user enters a Premint of 1000 in the UI, and they override decimals() to 2, then the actual premint calculation should result in 100000.

const fullAmount = units + '000000000000000000';

// Check if the final number would be too large
if (fullAmount.length > 77) { // Solidity has a limit on number literals
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solidity's limit on literals is not based on character length. Rather, this must be less than 2**256. There is some documentation here which is for Yul, but it seems to be the same limit for Solidity.

Here is an example of a way to validate the size of a uint (that example is currently for Cairo but something similar could be done for Solidity).


c.addConstructorArgument({ type: 'address', name: 'recipient' });

const mintLine = `_mint(recipient, ${units} * 10 ** ${exp});`;
// Generate the mint line with the full amount directly
const mintLine = `_mint(recipient, ${fullAmount});`;
Copy link
Member

@ericglau ericglau Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous format should be used, so that decimals() from the user's contract is included in the calculation.

Overall, it seems that two checks should be made:

  1. Check that the value of units is less than 2**256
  2. Check that the calculated value of ${units} * 10 ** ${exp} is less than 2**256, because 2**256 - 1 is the largest possible value of the uint256 type as an argument for the _mint function.
    • While decimals() could be overridden by the user and therefore ${exp} cannot be definitely known, for the purposes of this check we can assume decimals() is 18. Solidity would revert on overflow anyways if the actual calculation at runtime is larger than the max value of uint256.

@hashpalk
Copy link
Contributor Author

hey @ericglau, I have tried to follow the approach you suggested. I had to add ES2020.BigInt as it is not available in ES2019 or ES2018.

can you check if I am going in the right direction?

@ericglau
Copy link
Member

ericglau commented Mar 21, 2025

@hashpalk Thanks for following up, this is looking good! I pushed some refactors, fixed the calculation to handle negative exponents, and added tests. It seems to work without adding ES2020.BigInt, where do you see the error if you don't add it?

@ericglau ericglau requested a review from CoveMB March 21, 2025 04:09
@hashpalk
Copy link
Contributor Author

hey @ericglau, when I was using BigInt from ES2019, it was saying something like BigInt not found. I was also confused, as BigInt was used in other places. So I had to take it from ES2020.
However, it looks like it is working now after your changes (without ES2020.BigInt). I am guessing it could be some temporary issue with the IDE

@hashpalk
Copy link
Contributor Author

hi @CoveMB, just following up on this PR—whenever you have a chance, could you take a look and share any feedback? Let me know if you need any clarifications from my end. Appreciate your time!

Copy link
Contributor

@CoveMB CoveMB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, mostly some nits 🌾

@ericglau ericglau requested a review from CoveMB March 25, 2025 15:30
Copy link
Contributor

@CoveMB CoveMB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hashpalk
Copy link
Contributor Author

@ericglau, @CoveMB thanks for the review. Looks like I do not have the option for merging.

@ericglau ericglau merged commit ccadb18 into OpenZeppelin:master Mar 26, 2025
13 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Mar 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants