Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: low
Likelihood: high
Invalid

Large Numeric Literal

Large Numeric Literal

Description

Large numeric literals should use scientific notation or named constants to improve code readability and reduce the risk of errors when working with large numbers.

The INITIAL_SUPPLY constant uses a large numeric literal with many zeros that is difficult to read quickly, verify for correctness, and could lead to errors when copying or modifying similar large values in the codebase.

@> uint256 public constant INITIAL_SUPPLY = 1000000000 * 10 ** 18;

Risk

Likelihood: High

  • Developers may miscount zeros when reviewing or modifying large numbers during code reviews

  • Copy-paste errors can easily occur when working with similar large values across the codebase

  • Code reviews become more error-prone and time-consuming with hard-to-read numeric literals

Impact: Low

  • Significantly reduced code readability affects development efficiency and review quality

  • Increased potential for critical errors when modifying or copying similar numeric values

  • Developer confusion about intended token supply could lead to incorrect assumptions

  • Maintenance challenges when working with related numeric constants in future updates

Proof of Concept

// Demonstrate readability and error-prone issues
contract LargeNumberTest {
// Current problematic approach
uint256 public constant INITIAL_SUPPLY_HARD = 1000000000 * 10 ** 18;
uint256 public constant DAILY_LIMIT_HARD = 10000000 * 10 ** 18;
uint256 public constant MAX_MINT_HARD = 100000000 * 10 ** 18;
// Improved readable approach
uint256 public constant BILLION = 1e9;
uint256 public constant MILLION = 1e6;
uint256 public constant DECIMALS = 18;
uint256 public constant INITIAL_SUPPLY_CLEAR = 1e27; // 1 billion with 18 decimals
uint256 public constant DAILY_LIMIT_CLEAR = 10 * MILLION * 10**DECIMALS;
uint256 public constant MAX_MINT_CLEAR = 100 * MILLION * 10**DECIMALS;
// Demonstrate counting difficulty
function demonstrateCountingErrors() external pure returns (
string memory problem1,
string memory problem2,
string memory problem3,
uint256 actualValue,
uint256 intendedValue
) {
problem1 = "Is 1000000000 one billion or ten billion? Hard to count zeros quickly";
problem2 = "Copy-paste from similar constants may introduce extra or missing zeros";
problem3 = "Code review requires careful zero counting for every large number";
// Common error: developer thinks they're setting 10 billion but actually sets 1 billion
actualValue = 1000000000 * 10**18; // 1 billion tokens
intendedValue = 10000000000 * 10**18; // 10 billion tokens (one extra zero)
return (problem1, problem2, problem3, actualValue, intendedValue);
}
// Show maintenance challenges
function showMaintenanceChallenges() external pure returns (
string[] memory challenges
) {
challenges = new string[](4);
challenges[0] = "Difficult to verify correctness during code reviews";
challenges[1] = "Error-prone when copying values to related constants";
challenges[2] = "Hard to understand intended scale without careful counting";
challenges[3] = "Inconsistent number formatting across the codebase";
return challenges;
}
// Demonstrate better alternatives
function showBetterAlternatives() external pure returns (
uint256 scientific,
uint256 namedConstants,
uint256 calculated,
string memory benefit
) {
scientific = 1e27; // Scientific notation
namedConstants = BILLION * 10**DECIMALS; // Named constants
calculated = 1000 * MILLION * 10**DECIMALS; // Descriptive calculation
benefit = "All clearly show 1 billion tokens with 18 decimals";
return (scientific, namedConstants, calculated, benefit);
}
}

Real error scenario:

  1. Developer needs to add a new constant for maximum daily mint

  2. Copies INITIAL_SUPPLY = 1000000000 * 10 ** 18

  3. Intends to make it 500 million: 500000000 * 10 ** 18

  4. Accidentally types: 5000000000 * 10 ** 18 (5 billion instead)

  5. Error goes unnoticed in code review due to difficulty counting zeros

  6. Deployed contract has 10x higher limit than intended

  7. Economic model is broken due to number readability issue

Recommended Mitigation

The mitigation replaces large numeric literals with clear, readable alternatives using scientific notation and named constants that make the intended values immediately obvious and reduce the risk of errors.

// Replace hard-to-read large numbers with clear alternatives
- uint256 public constant INITIAL_SUPPLY = 1000000000 * 10 ** 18;
+ uint256 public constant INITIAL_SUPPLY = 1e27; // 1 billion tokens with 18 decimals
// Alternative approaches for even better readability:
+ uint256 public constant TOKEN_DECIMALS = 18;
+ uint256 public constant BILLION = 1e9;
+ uint256 public constant MILLION = 1e6;
+
+ // Use descriptive constants for clarity
+ uint256 public constant INITIAL_SUPPLY_READABLE = BILLION * 10**TOKEN_DECIMALS;
// Apply same principle to other large numbers in the codebase
+ uint256 public constant DEFAULT_FAUCET_DRIP = 1000 * 10**TOKEN_DECIMALS; // 1,000 tokens
+ uint256 public constant DEFAULT_DAILY_LIMIT = 100; // 100 users per day
+ uint256 public constant DEFAULT_ETH_DRIP = 5e15; // 0.005 ETH in wei
+ uint256 public constant DEFAULT_DAILY_ETH_CAP = 1e18; // 1 ETH in wei
// Update constructor to use clear constants
constructor(
string memory name_,
string memory symbol_,
- uint256 faucetDrip_, // Remove parameters for values that should be standard
- uint256 sepEthDrip_,
- uint256 dailySepEthCap_
+ uint256 faucetDrip_, // Keep if customization needed
+ uint256 sepEthDrip_,
+ uint256 dailySepEthCap_
) ERC20(name_, symbol_) Ownable(msg.sender) {
faucetDrip = faucetDrip_;
sepEthAmountToDrip = sepEthDrip_;
dailySepEthCap = dailySepEthCap_;
_mint(address(this), INITIAL_SUPPLY);
}
// Add documentation explaining the values
+ /**
+ * @dev Token Supply and Distribution Constants
+ *
+ * INITIAL_SUPPLY: 1,000,000,000 tokens (1 billion)
+ * - Calculated as 1e27 (1e9 * 1e18 for 18 decimals)
+ * - Provides sufficient supply for long-term testnet usage
+ *
+ * DEFAULT_FAUCET_DRIP: 1,000 tokens per claim
+ * - Balances user utility with supply conservation
+ * - Allows ~1 million total claims from initial supply
+ *
+ * DEFAULT_ETH_DRIP: 0.005 ETH per first claim
+ * - Provides gas for several transactions on testnets
+ * - Conservative amount to prevent abuse
+ */
// Create a constants library for reuse across related contracts
+ library FaucetConstants {
+ uint256 public constant TOKEN_DECIMALS = 18;
+ uint256 public constant BILLION = 1e9;
+ uint256 public constant MILLION = 1e6;
+
+ // Token amounts (in base units with decimals)
+ uint256 public constant BILLION_TOKENS = BILLION * 10**TOKEN_DECIMALS;
+ uint256 public constant MILLION_TOKENS = MILLION * 10**TOKEN_DECIMALS;
+ uint256 public constant THOUSAND_TOKENS = 1000 * 10**TOKEN_DECIMALS;
+
+ // ETH amounts (in wei)
+ uint256 public constant ONE_ETH = 1e18;
+ uint256 public constant TENTH_ETH = 1e17;
+ uint256 public constant HUNDREDTH_ETH = 1e16;
+ }
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.