Skip to main content

integer-overflow

Integer safety patterns for Solidity 0.8+. Use when working with unchecked blocks, safe casting, or intermediate calculation overflow risks. Covers automatic checks, intentional overflow, phantom overflow, and safe math patterns.

설치로 이동

소스 정보

저장소
ccashwell/evm-cortex
최근 소스 활동
2026년 4월 10일 16:31
감지된 SKILL.md 언어
영어
스타
131
포크
18

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
integer-overflow
description
Integer safety patterns for Solidity 0.8+. Use when working with unchecked blocks, safe casting, or intermediate calculation overflow risks. Covers automatic checks, intentional overflow, phantom overflow, and safe math patterns.
# Integer Safety ## Solidity 0.8+ Automatic Checks Since Solidity 0.8, arithmetic operations revert on overflow/underflow by default. This eliminates the need for SafeMath but introduces new considerations. ```solidity // These all revert automatically on overflow (Solidity 0.8+) uint256 a = type(uint256).max; uint256 b = a + 1; // reverts: arithmetic overflow uint256 c = 0; uint256 d = c - 1; // reverts: arithmetic underflow uint8 e = 255; uint8 f = e + 1; // reverts: arithmetic overflow ``` ## Unchecked Blocks Use `unchecked` when overflow is **mathematically impossible** and gas savings matter. ```solidity // SAFE: loop counter cannot overflow (bounded by array length) for (uint256 i; i < arr.length;) { processItem(arr[i]); unchecked { ++i; } } // SAFE: subtraction will not underflow (checked by prior condition) function withdraw(uint256 amount) external { uint256 balance = balances[msg.sender]; if (balance < amount) revert InsufficientBalance(); unchecked { balances[msg.sender] = balance - amount; // balance >= amount guaranteed } } // SAFE: hash computation (intentional wrapping) unchecked { uint256 hash = uint256(keccak256(abi.encodePacked(a))) + nonce; } ``` ### When Unchecked Is Dangerous ```solidity // DANGEROUS: user-controlled values in unchecked unchecked { uint256 result = userInput1 + userInput2; // could overflow silently } // DANGEROUS: complex arithmetic with multiple operations unchecked { uint256 result = (a * b + c) / d; // any step could overflow } ``` ## Phantom Overflow Intermediate calculations can overflow even when the final result fits. ```solidity // VULNERABLE: a * b can overflow even if (a * b) / c fits in uint256 function mulDiv(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) { return a * b / c; // reverts if a * b > type(uint256).max } // Example: mulDiv(2e18, 3e18, 1e18) should return 6e18 // But 2e18 * 3e18 = 6e36, which overflows uint256? No, 6e36 < 2^256 // But mulDiv(type(uint128).max, type(uint128).max, 1) WILL overflow // FIXED: use Solmate's FixedPointMathLib which handles phantom overflow import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; function mulDiv(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) { return FixedPointMathLib.mulDiv(a, b, c); // assembly-based, no phantom overflow } ``` ### mulDiv Implementation Concept ```solidity // FixedPointMathLib.mulDiv uses 512-bit intermediate math in assembly: // 1. Compute full 512-bit product of a * b // 2. Divide the 512-bit result by c // 3. Return the 256-bit quotient (reverts if it doesn't fit) ``` ## Safe Casting Narrowing casts can silently truncate in Solidity. Always use explicit safe casting. ```solidity // VULNERABLE: silent truncation uint256 bigNumber = 300; uint8 small = uint8(bigNumber); // small = 44 (300 % 256), NO revert! // SAFE: explicit overflow check import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; using SafeCast for uint256; uint256 bigNumber = 300; uint8 small = bigNumber.toUint8(); // reverts: SafeCast: value doesn't fit in 8 bits ``` ### Common Safe Cast Operations ```solidity using SafeCast for uint256; using SafeCast for int256; uint256 value = 1000; uint128 a = value.toUint128(); // reverts if > type(uint128).max uint96 b = value.toUint96(); // reverts if > type(uint96).max uint64 c = value.toUint64(); // reverts if > type(uint64).max uint48 d = value.toUint48(); // reverts if > type(uint48).max uint32 e = value.toUint32(); // reverts if > type(uint32).max int256 signed = int256(value); // reverts if > type(int256).max ``` ## Type Boundaries ```solidity // Know your type limits type(uint8).max == 255 type(uint16).max == 65_535 type(uint32).max == 4_294_967_295 type(uint48).max == 281_474_976_710_655 type(uint64).max == 18_446_744_073_709_551_615 type(uint96).max == 79_228_162_514_264_337_593_543_950_335 type(uint128).max == 340_282_366_920_938_463_463_374_607_431_768_211_455 type(uint256).max == 2^256 - 1 type(int256).min == -(2^255) type(int256).max == 2^255 - 1 ``` ## Signed Integer Gotchas ```solidity // Negation overflow: -type(int256).min overflows int256 minValue = type(int256).min; int256 negated = -minValue; // REVERTS: overflow (no positive equivalent) // Division edge case int256 result = type(int256).min / (-1); // REVERTS: same as negation overflow // Abs function must handle min value function abs(int256 x) internal pure returns (uint256) { if (x == type(int256).min) revert AbsOverflow(); return uint256(x >= 0 ? x : -x); } ``` ## Accumulator Overflow For accounting that accumulates over time, consider if the accumulator can overflow. ```solidity // Reward accumulator pattern // rewardPerTokenStored grows continuously — can it overflow uint256? // With 1e18 precision and 1e18 rewards/sec for 100 years: // 1e18 * 1e18 * 100 * 365 * 86400 ≈ 3.15e33, well under 2^256 ≈ 1.15e77 // Safe for practical purposes, but document the assumption uint256 public rewardPerTokenStored; function rewardPerToken() public view returns (uint256) { if (totalSupply == 0) return rewardPerTokenStored; return rewardPerTokenStored + ( (lastRewardTime() - lastUpdateTime) * rewardRate * PRECISION / totalSupply ); } ``` ## Integer Safety Checklist - [ ] `unchecked` only used where overflow is mathematically impossible - [ ] Comment explaining why overflow is impossible for each `unchecked` block - [ ] No silent narrowing casts — use SafeCast - [ ] mulDiv from Solmate for multiplication followed by division - [ ] Accumulator overflow analyzed for worst-case scenarios - [ ] Signed integer edge cases handled (`type(int256).min`) - [ ] Type boundaries documented for packed struct fields
GitHub에서 보기