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.
contract LargeNumberTest {
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;
uint256 public constant BILLION = 1e9;
uint256 public constant MILLION = 1e6;
uint256 public constant DECIMALS = 18;
uint256 public constant INITIAL_SUPPLY_CLEAR = 1e27;
uint256 public constant DAILY_LIMIT_CLEAR = 10 * MILLION * 10**DECIMALS;
uint256 public constant MAX_MINT_CLEAR = 100 * MILLION * 10**DECIMALS;
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";
actualValue = 1000000000 * 10**18;
intendedValue = 10000000000 * 10**18;
return (problem1, problem2, problem3, actualValue, intendedValue);
}
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;
}
function showBetterAlternatives() external pure returns (
uint256 scientific,
uint256 namedConstants,
uint256 calculated,
string memory benefit
) {
scientific = 1e27;
namedConstants = BILLION * 10**DECIMALS;
calculated = 1000 * MILLION * 10**DECIMALS;
benefit = "All clearly show 1 billion tokens with 18 decimals";
return (scientific, namedConstants, calculated, benefit);
}
}
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;
+ }