Opcode Summary

PropertyValue
Opcode0x0A
MnemonicEXP
Gas10 + 50 × (byte length of exponent)
Stack Inputa, b
Stack Output(a ** b) % 2^256
BehaviorUnsigned 256-bit exponentiation. Result wraps modulo 2^256 on overflow. Dynamic gas cost scales with the byte size of the exponent.

Threat Surface

EXP is the most overflow-prone arithmetic opcode in the EVM. While ADD overflows only when the sum of two numbers exceeds 2^256, and MUL overflows when the product of two 128-bit numbers exceeds 2^256, EXP overflows with trivially small inputs. 2 ** 256 already wraps to 0. 3 ** 162 exceeds 2^256. Even 10 ** 78 overflows. A base of just 2 with an exponent of 256 — both values that fit in a single byte — produces a result that cannot fit in the entire uint256 range.

This makes EXP uniquely dangerous: the magnitude explosion is exponential, not linear (ADD) or quadratic (MUL). A developer who correctly reasons that multiplying two 128-bit numbers is safe may incorrectly assume that exponentiating a small base by a moderate exponent is also safe. The intuition fails catastrophically — 2 ** 255 is the largest power of 2 that fits in uint256, but 2 ** 256 wraps silently to 0.

EXP also introduces a unique protocol-level attack surface through its dynamic gas cost. Unlike ADD (3 gas) and MUL (5 gas), EXP costs 10 + 50 * byte_len(exponent), ranging from 10 gas (exponent = 0) to 10 + 50 × 32 = 1610 gas (256-bit exponent). This dynamic pricing was itself the result of a security incident: the original cost (10 + 10 per byte) was underpriced by 4-8x, enabling DoS attacks on the Ethereum network in 2016 that required the Spurious Dragon hard fork (EIP-160) to fix.

In DeFi, EXP appears in compound interest calculations ((1 + rate) ** periods), bonding curves, and weighted AMM invariants. These are precisely the contexts where overflow produces the most financially devastating results — a compound interest calculation that wraps to zero means the protocol believes no interest has accrued, or worse, computes a phantom value that enables fund extraction.


Smart Contract Threats

T1: Exponentiation Overflow / Silent Wrapping (Critical)

Exponentiation overflows far more easily than any other arithmetic operation. The EVM’s EXP wraps silently: 2 ** 256 == 0, 3 ** 162 == 0x... (garbage). Even bases that appear small overflow with moderate exponents:

  • Base 2: overflows at exponent 256 (2^256 ≡ 0)
  • Base 3: overflows at exponent 162 (3^162 > 2^256)
  • Base 10: overflows at exponent 78 (10^78 > 2^256)
  • Base 256: overflows at exponent 32 (256^32 = 2^256 ≡ 0)
  • Base 10^18 (1 WAD): overflows at exponent 5 ((10^18)^5 = 10^90 > 2^256)

Any contract that computes base ** exponent where either operand is user-controlled — without bounding both values — is vulnerable. Common dangerous patterns:

  • Compound interest: (1 + rate) ** periods where periods is derived from time elapsed
  • Bonding curves: price = base ** supply or polynomial pricing a * x^n
  • Token economics: decayFactor ** epochs for inflation/deflation schedules
  • Governance: votingPower = stake ** weight with configurable weight parameters

Pre-Solidity 0.8.0: No automatic overflow check. The EXP opcode returns the lower 256 bits of the true result with no indication of overflow.

Solidity 0.8.0+: The compiler inserts overflow checks for the ** operator. However, the check uses iterative squaring at the Solidity level, not a simple post-hoc verification like MUL’s a * b / a == b pattern. This makes the overflow detection itself more gas-expensive for EXP than for other operations.

T2: Gas Griefing via Large Exponents (High)

EXP’s dynamic gas cost — 10 + 50 * byte_len(exponent) — means an attacker who controls the exponent can force a contract to consume up to 1,610 gas per EXP operation. While this isn’t enormous in isolation, it becomes significant when:

  • Loops: A contract computes EXP inside a loop with attacker-controlled iteration count
  • Batch operations: Multiple EXP computations in a single transaction
  • Gas estimation mismatch: Off-chain gas estimation uses a different exponent size than the actual on-chain execution, causing transactions to fail

The gas range is 161x (1,610 / 10), making it difficult to estimate gas costs accurately for functions that use EXP with variable inputs. A function that costs 10 gas for a ** 0 costs 1,610 gas for a ** (2^256 - 1).

function computeReward(uint256 base, uint256 exponent) external view returns (uint256) {
    return base ** exponent;
}

An attacker calling this with exponent = type(uint256).max forces 1,610 gas for the EXP alone, plus the Solidity 0.8+ overflow check (which will revert, but only after consuming the gas for the check computation).

T3: Compound Interest Miscalculation (High)

DeFi protocols computing compound interest must evaluate (1 + rate) ** periods. This is the single most common use of exponentiation in smart contracts, and it is fraught with overflow risk:

  • Rate expressed in WAD (10^18): If rate = 1.05e18 (5% per period) and periods = 365, then (1.05e18) ** 365 overflows uint256 almost immediately because the base itself is already 10^18.
  • Iterative compounding: Protocols that avoid EXP by computing principal *= (1 + rate) in a loop for each period face MUL overflow at every iteration, plus O(n) gas cost.
  • Exponentiation by squaring: The standard optimization (rpow) computes base^exp in O(log n) multiplications. Each intermediate MUL can overflow, and the final result wraps silently in unchecked contexts.

The fundamental tension: compound interest requires repeated multiplication of values near 10^18 (WAD-scaled), and the result grows exponentially. Even well-audited libraries like DSMath’s rpow and Solmate’s rpow require careful input bounds to avoid overflow in intermediate steps.

T4: Unchecked Exponentiation in Assembly or Unchecked Blocks (High)

Solidity 0.8+‘s overflow protection for ** is more complex (and gas-expensive) than for + or *. This creates stronger incentive for developers to wrap EXP in unchecked { } blocks for gas savings, which is extremely dangerous:

unchecked {
    uint256 result = base ** exp;
}

In unchecked blocks, the compiler emits the raw EXP opcode with no overflow verification. Given how quickly exponentiation overflows, the “safe range” is far smaller than developers typically assume. A base of 2 is only safe for exponents up to 255. A base of 10 is only safe for exponents up to 77.

Inline assembly (exp(a, b) in Yul) also bypasses all Solidity overflow checks and directly emits the EXP opcode.

T5: Solidity Compiler Exponentiation Bug (Medium)

Solidity versions prior to 0.4.25 contained a compiler bug (ExpExponentCleanup) where the exponentiation operator ** produced incorrect results when the exponent type was smaller than 256 bits (e.g., uint8). The compiler’s “lazy cleanup” optimization failed to zero out dirty higher-order bits in the exponent before performing exponentiation.

For example, uint8(0) ** uint8(uint8(2) ** uint8(8)) could produce inconsistent results depending on compilation context — sometimes returning unexpected values, sometimes triggering VM errors. The bug was rated “high exploitability, very low likelihood” by the Solidity team.

Any contract compiled with solc < 0.4.25 that uses non-uint256 types in exponentiation may produce incorrect results. While the likelihood of encountering this in practice is low, legacy contracts on mainnet compiled with affected versions remain vulnerable.

T6: Weighted AMM Power Function Errors (High)

Weighted AMMs (Balancer-style) compute invariants using power functions: balance^weight where weights are fractional. These require custom fixed-point exponentiation implementations (since the EVM’s EXP only supports integer exponents). Incorrect implementations have caused massive losses:

  • ValueDeFi ($11M, May 2021): Adopted the Bancor power() function for weighted pools but violated the function’s precondition that baseN >= baseD. Attackers crafted swaps that broke this assumption, causing the power function to return incorrect invariant values and enabling fund extraction from nine non-50/50 pools.
  • Balancer ($121M, November 2025): Rounding errors in the power function’s integer math, where the direction of rounding in k^x exponent calculations depended on whether the invariant ratio was greater or less than 1.

These exploits involve custom power-function implementations rather than the raw EXP opcode, but they stem from the same fundamental challenge: exponentiation math is difficult to implement correctly in integer arithmetic.


Protocol-Level Threats

P1: Dynamic Gas Cost as DoS Vector (Medium)

EXP is one of the few arithmetic opcodes with dynamic gas cost. The cost formula 10 + 50 * byte_len(exponent) means:

Exponent RangeByte LengthGas Cost
0010
1 – 255160
256 – 65,5352110
2^248 – 2^256-1321,610

This 161x range creates gas estimation challenges:

  • Off-chain gas estimators may underestimate if they simulate with small exponents but on-chain execution uses large ones
  • Contracts calling other contracts that use EXP with user inputs cannot accurately predict gas consumption
  • Relayers and meta-transaction systems may set insufficient gas limits

P2: Historical Underpricing and Network DoS (High — Historical)

Prior to EIP-160 (Spurious Dragon hard fork, November 2016), EXP cost only 10 + 10 * byte_len(exponent) — 4-8x cheaper than its actual computational cost. This underpricing was identified during the September-October 2016 Ethereum DoS attacks. While the initial attacks primarily exploited EXTCODESIZE and EXTCODECOPY, the EXP mispricing was flagged as a critical vulnerability that could enable similar computational DoS.

EIP-160 increased the per-byte cost from 10 to 50 gas, implemented at block 2,675,000. This was the first (and so far only) time an arithmetic opcode’s gas cost was repriced due to a security incident.

P3: Consensus Safety (Low)

EXP is deterministic for all input pairs. The result (a ** b) mod 2^256 is unambiguous. All major EVM clients (geth, Nethermind, Besu, Erigon, reth) implement EXP using big-integer exponentiation with modular reduction. The dynamic gas calculation (10 + 50 * byte_len(b)) is straightforward. No known consensus divergence has occurred due to EXP.

The only theoretical risk is in the byte-length calculation: byte_len(0) = 0, byte_len(1) = 1, byte_len(255) = 1, byte_len(256) = 2. Client implementations must agree on this computation, but it is trivial and well-tested.

P4: No Direct State Impact (None)

EXP modifies only the stack. It cannot cause state bloat, storage writes, or memory expansion.


Edge Cases

Edge CaseBehaviorSecurity Implication
0 ** 0Returns 1Mathematically contentious (0^0 is undefined in some contexts), but the EVM defines it as 1. Contracts relying on 0 ** 0 == 0 will break.
0 ** n (n > 0)Returns 0Safe; zero raised to any positive power is zero.
a ** 0 (a > 0)Returns 1Safe; any nonzero base to the zero power is 1. Gas cost is only 10 (exponent has 0 bytes).
1 ** nReturns 1Safe; identity base. Never overflows regardless of exponent.
a ** 1Returns aSafe; identity exponent. Equivalent to a no-op on the base.
2 ** 255Returns 2^255 (largest power of 2 in uint256)Safe; but 2 ** 256 == 0 (phantom zero). One exponent increment crosses the overflow boundary.
2 ** 256Returns 0Phantom zero: the most natural EXP overflow. Two small values produce exactly zero.
MAX_UINT256 ** 2Returns 1(-1)^2 = 1 in two’s complement. Deceptive for unsigned interpretation: the largest uint256 squared yields 1.
MAX_UINT256 ** MAX_UINT256Returns MAX_UINT256(-1)^(odd) = -1 in two’s complement. Returns MAX_UINT256 since the exponent is odd.
10 ** 77Returns 10^77 (fits in uint256)Safe; but 10 ** 78 overflows. One increment in the exponent causes overflow.
(10^18) ** 4Returns 10^72 (fits)Safe; but (10^18) ** 5 = 10^90 overflows. WAD-scaled values overflow at exponent 5.
Exponent = 2^256 - 1Gas cost = 1,610 (32-byte exponent)Maximum gas cost. Result depends on base: 0^MAX = 0, 1^MAX = 1, 2^MAX wraps.
Small base, large exponentWraps unpredictablyThe result modulo 2^256 bears no relation to the true mathematical value.

Real-World Exploits

Exploit 1: Ethereum Network DoS via Underpriced EXP — Network Degradation (September–October 2016)

Root cause: EXP opcode gas cost (10 + 10 * byte_len(exponent)) was 4-8x lower than its actual computational cost, enabling cheap DoS transactions.

Details: During September and October 2016, attackers launched sustained denial-of-service attacks against the Ethereum network by crafting transactions that exploited underpriced opcodes. While the primary attack vector was EXTCODESIZE (which caused ~50,000 disk fetches per transaction), the EXP opcode was identified as severely underpriced during post-incident analysis. Benchmarks showed that EXP’s computational cost was 4-8x higher than what its gas price reflected.

An attacker could construct transactions containing many EXP operations with large exponents (maximizing computation) at a fraction of the true cost. This allowed the attacker to force validators to perform expensive modular exponentiation computations while paying minimal gas, degrading block validation times from normal levels to 20-60 seconds per block and reducing the block creation rate by 2-3x.

EXP’s role: EXP was one of several underpriced opcodes that collectively enabled the DoS attack. Its dynamic nature made it particularly valuable to attackers — a single EXP with a 32-byte exponent costs 32 times more computation than with a 1-byte exponent, but under the old pricing the gas difference was only 10 + 10*32 = 330 vs 10 + 10*1 = 20, a mere 16.5x ratio for a much larger computational difference.

Impact: Block validation slowed dramatically across the network. The Ethereum Foundation executed two emergency hard forks: Tangerine Whistle (EIP-150, October 2016) for IO-heavy opcodes, and Spurious Dragon (EIP-160, November 2016) which repriced EXP from 10 + 10/byte to 10 + 50/byte. The network lost significant throughput over a period of weeks.

References:


Exploit 2: Solidity Compiler ExpExponentCleanup Bug — Incorrect Results (Fixed September 2018)

Root cause: Solidity compiler bug where dirty higher-order bits in non-uint256 exponent types caused the ** operator to produce incorrect results.

Details: Solidity versions prior to 0.4.25 used a “lazy cleanup” optimization that deferred zeroing of higher-order bits in intermediate values. This optimization is safe for ADD and MUL (where overflow wrapping produces the same lower bits regardless of dirty upper bits), but it fails for exponentiation because the EXP operation is sensitive to the full value of the exponent: 0 ** 0 = 1 but 0 ** 256 = 0, so dirty bits turning a 0 exponent into 256 changes the result from 1 to 0.

The bug manifested when using types smaller than uint256 as exponents:

uint8 x = 0;
uint8 y = uint8(uint8(2) ** uint8(8));  // y should be 0 (256 mod 256)
uint8 result = x ** y;  // Should be 0**0 = 1, but dirty bits make y = 256 internally
// result could be 0 instead of 1

EXP’s role: The EXP opcode itself behaves correctly — it computes (a ** b) mod 2^256 for whatever a and b are on the stack. The bug was in how the Solidity compiler prepared the exponent value before pushing it to the stack. Dirty higher-order bits meant the stack value didn’t match the intended Solidity value, causing EXP to compute a different exponentiation than the programmer intended.

Impact: Any contract compiled with solc < 0.4.25 using non-uint256 exponent types could produce incorrect results. The Solidity team rated the bug as “high exploitability” but “very low likelihood of occurrence” since it requires specific type combinations. The fix was released in Solidity 0.4.25 (September 13, 2018) as a bugfix-only release.

References:


Exploit 3: ValueDeFi Power Function Exploit — $11M Stolen (May 2021)

Root cause: Incorrect implementation of the Bancor power() function for weighted AMM invariant calculations, where the precondition baseN >= baseD was violated by attacker-crafted inputs.

Details: ValueDeFi’s vSwap AMM supported non-50/50 weighted pools (similar to Balancer). The weighted constant product invariant requires computing balance ^ weight where weights are fractional. ValueDeFi adopted the Bancor formula’s power(baseN, baseD, expN, expD) function, which computes (baseN/baseD) ^ (expN/expD) using fixed-point logarithms and exponentiation.

The Bancor power() function has an explicit precondition: baseN >= baseD (the base must be >= 1). ValueDeFi’s swap function did not enforce this constraint. An attacker crafted swap parameters that caused baseN < baseD, violating the assumption and producing wildly incorrect invariant calculations. The power function returned values that made the constant-product check pass despite the attacker extracting far more tokens than they deposited.

The attack pattern:

  1. Send small amounts of a token to a pool to manipulate reserves
  2. Execute swaps withdrawing large amounts of one token while depositing tiny amounts of another
  3. The broken power() function incorrectly validated these unbalanced swaps

EXP’s role: The power() function is a higher-level implementation of exponentiation for fractional exponents (which the EVM’s integer-only EXP opcode cannot handle). The exploit demonstrates the broader threat: any custom exponentiation implementation carries extreme risk because the mathematics of exponentiation are unforgiving of edge cases.

Impact: Approximately $11M drained from nine non-50/50 weighted pools across tokens including 8.5M BDO, 1.2M BAC, and 11K FIRO. This was ValueDeFi’s third major exploit in six months.

References:


Exploit 4: Balancer V2 Power Function Rounding — $121M Stolen (November 2025)

Root cause: Rounding errors in the power function’s integer math within Balancer’s ComposableStablePools, where the direction of rounding in exponent calculations (k^x) was incorrect depending on whether the invariant ratio was greater or less than 1.

Details: Balancer V2’s weighted math computes pool invariants using power functions with fractional exponents. A previously identified issue (GitHub PR #984, September 2024) showed that computeBalance needed different rounding directions for the exponent depending on the invariant ratio. When the ratio was < 1, the exponent should round up (making the result smaller, favoring the protocol), but the implementation rounded down (making the result larger, favoring the attacker).

Attackers combined this with precision loss in the _upscaleArray function to execute 65+ micro-swaps within single atomic batchSwap transactions. Each micro-swap compounded a tiny rounding error (8-9 wei range per operation), but the accumulated error across many operations was enough to suppress BPT token prices and extract value through arbitrage cycles across six blockchain networks.

EXP’s role: The exploit targeted custom fixed-point power function implementations that extend the EVM’s integer-only EXP to fractional exponents. The rounding direction in exponentiation — whether to round intermediate values up or down — is critical and non-obvious. This is a direct consequence of implementing exponentiation in integer-only arithmetic.

Impact: 128.6M drained across six chains. Approximately $45.7M was recovered by whitehat rescuers. Vulnerable pools were paused within minutes.

References:


Attack Scenarios

Scenario A: Exponentiation Overflow in Compound Interest

// Solidity < 0.8.0, no SafeMath on EXP
contract VulnerableLending {
    uint256 constant WAD = 1e18;
 
    function accruedDebt(
        uint256 principal,
        uint256 ratePerSecond,  // e.g., 1.000000001e18 for ~3.15% APY
        uint256 elapsed         // seconds since last update
    ) public pure returns (uint256) {
        // (ratePerSecond ** elapsed) overflows for large elapsed values
        // ratePerSecond ~ 1e18, so (1e18)^2 = 1e36 (fits),
        // but exponentiation by squaring does intermediate MULs
        // that overflow as elapsed grows
        uint256 compoundFactor = ratePerSecond ** elapsed;  // OVERFLOW
        return principal * compoundFactor / WAD;
    }
}

Attack: For a lending protocol that hasn’t been touched in a long time, elapsed can be very large (millions of seconds). The compound factor overflows, wrapping to a small or zero value, making accruedDebt return near-zero. Borrower repays almost nothing.

Scenario B: Gas Griefing via Exponent Size

contract RewardCalculator {
    function calculateDecay(
        uint256 initialReward,
        uint256 decayBase,
        uint256 epochs  // user-controlled
    ) external pure returns (uint256) {
        // Gas cost of EXP depends on byte size of epochs
        // epochs = 1 -> 60 gas for EXP
        // epochs = 2^256-1 -> 1,610 gas for EXP
        uint256 decayFactor = decayBase ** epochs;
        return initialReward * decayFactor / 1e18;
    }
}

Attack: A relayer or meta-transaction system estimates gas with epochs = 10 (60 gas for EXP). The attacker submits with epochs = 2^256 - 1 (1,610 gas for EXP). If the gas limit is tight, the transaction reverts. If inside a loop, the gas difference is amplified by the iteration count.

Scenario C: Phantom Zero from Small Base

// Solidity < 0.8.0
contract VulnerableBondingCurve {
    function getPrice(uint256 supply) public pure returns (uint256) {
        // price = supply^3 / 1e18 (cubic bonding curve)
        uint256 cubed = supply ** 3;  // Overflows when supply > ~4.8e25
        return cubed / 1e18;
    }
 
    function buy(uint256 amount) external payable {
        uint256 cost = getPrice(totalSupply + amount) - getPrice(totalSupply);
        require(msg.value >= cost);
        _mint(msg.sender, amount);
    }
}

Attack: When supply exceeds ~4.8 × 10^25 (roughly 48 million tokens at 18 decimals), supply ** 3 overflows. The attacker pushes supply past this threshold (or it naturally grows to this level in a high-supply token), causing getPrice to return a small wrapped value. Tokens are then purchased for far less than their actual bonding curve price.

Scenario D: Unchecked EXP in Gas-Optimized Library

// Solidity 0.8.x -- common rpow implementation
function rpow(uint256 x, uint256 n, uint256 base) internal pure returns (uint256 z) {
    assembly {
        z := base
        switch x
        case 0 { z := base }
        default {
            switch mod(n, 2)
            case 0 { z := base }
            default { z := x }
            let half := div(base, 2)
            for { n := div(n, 2) } n { n := div(n, 2) } {
                let xx := mul(x, x)       // No overflow check!
                if iszero(eq(div(xx, x), x)) { revert(0, 0) }
                let xxRound := add(xx, half)
                if lt(xxRound, xx) { revert(0, 0) }
                x := div(xxRound, base)
                if mod(n, 2) {
                    let zx := mul(z, x)    // No overflow check!
                    if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
                    let zxRound := add(zx, half)
                    if lt(zxRound, zx) { revert(0, 0) }
                    z := div(zxRound, base)
                }
            }
        }
    }
}

This pattern (from DSMath/Solmate) manually checks for overflow at each intermediate multiplication. If any check is removed or the revert conditions are subtly wrong, the function silently returns a wrapped value. Forks and modifications of these libraries are a persistent source of exponentiation bugs.


Mitigations

ThreatMitigationImplementation
T1: Exponentiation overflowUse Solidity >= 0.8.0 (automatic overflow revert for **)Default behavior; compiler inserts iterative overflow checks during exponentiation by squaring
T1: Bound inputsEnforce maximum base and exponent before computingrequire(exponent <= MAX_SAFE_EXP[base]) with a precomputed lookup table
T2: Gas griefingCap exponent size in user-facing functionsrequire(exponent <= MAX_EXPONENT) before any EXP computation
T2: Gas estimationUse worst-case gas estimates for EXP-containing functionsEstimate with 32-byte exponent (1,610 gas) as upper bound
T3: Compound interest overflowUse audited rpow library with built-in overflow checksDSMath rpow(), Solmate rpow(), or PRBMath powu() with WAD-scaled arithmetic
T3: ApproximationUse linear approximation for small rates over short periods(1 + rate)^n ≈ 1 + n*rate when n*rate is small (Taylor series first term)
T4: Unchecked/assembly EXPVerify overflow checks at every intermediate step in rpowAudit all mul operations in assembly rpow for division-based overflow checks
T5: Compiler bugUse Solidity >= 0.4.25Upgrade from affected compiler versions; recompile and redeploy
T6: Power function errorsUse battle-tested implementations; enforce preconditionsBalancer’s LogExpMath, Bancor’s power() with explicit require(baseN >= baseD)
General: Static analysisDetect unchecked exponentiation in auditsSlither, Mythril, Certora formal verification; fuzz-test with extreme exponent values

Compiler/EIP-Based Protections

  • Solidity 0.8.0+ (2020): Automatic revert on exponentiation overflow. The compiler generates exponentiation-by-squaring with overflow checks at each intermediate multiplication. More gas-expensive than raw EXP but eliminates silent wrapping.
  • Solidity 0.4.25 (2018): Fixed the ExpExponentCleanup compiler bug for non-uint256 exponent types.
  • EIP-160 (2016): Repriced EXP from 10 + 10/byte to 10 + 50/byte, closing the 4-8x underpricing gap that enabled DoS attacks.
  • EIP-198: Introduced the MODEXP precompile (address 0x05) for modular exponentiation of arbitrary-precision integers. For cryptographic use cases, MODEXP is both safer (no overflow by design, since results are reduced modulo a modulus) and more efficient than using EXP + MULMOD chains.
  • Audited libraries: DSMath rpow, Solmate rpow, PRBMath powu, OpenZeppelin Math.pow provide checked exponentiation with WAD/RAY scaling. These are the recommended approach for any DeFi exponentiation.

Safe Exponentiation Bounds

Quick reference for maximum safe exponents (largest n where base^n < 2^256):

BaseMax Safe ExponentNotes
22552^255 fits; 2^256 = 0
31613^161 < 2^256 < 3^162
107710^77 < 2^256 < 10^78
25631256^31 = 2^248; 256^32 = 2^256 = 0
10^18 (WAD)4(10^18)^4 = 10^72; (10^18)^5 = 10^90 overflows
2^1281(2^128)^2 = 2^256 = 0; only exponent 1 is safe

Severity Summary

Threat IDCategorySeverityLikelihoodReal-World Precedent
T1Smart ContractCriticalHigh (pre-0.8) / Low (post-0.8)Exponentiation overflow in bonding curves, compound interest
T2Smart ContractHighMediumGas griefing via EXP dynamic cost
T3Smart ContractHighMediumDeFi compound interest miscalculations
T4Smart ContractHighMediumUnchecked assembly rpow in gas-optimized protocols
T5Smart ContractMediumVery LowSolidity ExpExponentCleanup bug (fixed 0.4.25)
T6Smart ContractCriticalMediumValueDeFi (121M)
P1ProtocolMediumMediumGas estimation failures for EXP-heavy functions
P2ProtocolHigh (historical)N/A (mitigated)2016 Ethereum DoS attacks → EIP-160
P3ProtocolLowN/A

OpcodeRelationship
MUL (0x02)Exponentiation is repeated multiplication; EXP overflows even faster than MUL. Custom rpow implementations reduce EXP to a chain of MUL operations.
MULMOD (0x09)Modular multiplication avoids overflow by design. Used in modular exponentiation patterns as a safer alternative when computing (base^exp) mod N.
ADD (0x01)ADD appears in the gas cost formula for EXP and in Taylor-series approximations of exponentiation (1 + n*rate). Overflow in ADD-based compound interest loops is an alternative to using EXP.
DIV (0x04)Used in overflow detection for intermediate MUL steps within rpow implementations (a * b / a == b). Also used in WAD-scaled exponentiation to normalize after each multiplication.
SHL (0x1B)Left shift is equivalent to 2^n for power-of-two bases (a << n == a * 2^n). SHL costs 3 gas vs EXP’s dynamic cost, so compilers optimize 2 ** n to 1 << n.