Skip to main content

Try it Live

Run Hardfork examples in the interactive playground

    Range Direction

    Forward Range (start < end)

    Returns hardforks in chronological order:
    import { Hardfork, BERLIN, CANCUN } from 'tevm'
    
    const forks = Hardfork.range(BERLIN, CANCUN)
    // [BERLIN, LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN]
    

    Reverse Range (start > end)

    Returns hardforks in reverse chronological order:
    import { Hardfork, CANCUN, BERLIN } from 'tevm'
    
    const forks = Hardfork.range(CANCUN, BERLIN)
    // [CANCUN, SHANGHAI, MERGE, GRAY_GLACIER, ARROW_GLACIER, LONDON, BERLIN]
    

    Single Hardfork (start === end)

    Returns array with single element:
    import { Hardfork, LONDON } from 'tevm'
    
    const forks = Hardfork.range(LONDON, LONDON)
    // [LONDON]
    

    Usage Patterns

    Upgrade Path

    Get hardforks to upgrade through:
    import { Hardfork, BERLIN, CANCUN } from 'tevm'
    
    function getUpgradePath(from: BrandedHardfork, to: BrandedHardfork) {
      const path = Hardfork.range(from, to)
      return path.slice(1)  // Exclude current version
    }
    
    const upgrades = getUpgradePath(BERLIN, CANCUN)
    // [LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN]
    
    console.log(`Need to upgrade through ${upgrades.length} hardforks`)
    

    Feature Changes

    List features introduced in range:
    import { Hardfork, LONDON, CANCUN } from 'tevm'
    
    function listFeatureChanges(start: BrandedHardfork, end: BrandedHardfork) {
      const forks = Hardfork.range(start, end)
    
      return forks.map(fork => {
        const name = Hardfork.toString(fork)
        const features = []
    
        if (fork.hasEIP1559() && !start.hasEIP1559()) {
          features.push("EIP-1559 base fee")
        }
        if (fork.hasEIP3855() && !start.hasEIP3855()) {
          features.push("PUSH0 opcode")
        }
        if (fork.hasEIP4844() && !start.hasEIP4844()) {
          features.push("Blob transactions")
        }
        if (fork.isPostMerge() && !start.isPostMerge()) {
          features.push("Proof of Stake")
        }
    
        return { name, features }
      })
    }
    
    const changes = listFeatureChanges(LONDON, CANCUN)
    // [
    //   { name: "london", features: [] },
    //   { name: "arrowglacier", features: [] },
    //   { name: "grayglacier", features: [] },
    //   { name: "merge", features: ["Proof of Stake"] },
    //   { name: "shanghai", features: ["PUSH0 opcode"] },
    //   { name: "cancun", features: ["Blob transactions"] }
    // ]
    

    Migration Planning

    Plan network upgrade:
    import { Hardfork, BERLIN, PRAGUE } from 'tevm'
    
    function planMigration(current: BrandedHardfork, target: BrandedHardfork) {
      if (current.isAtLeast(target)) {
        return { needed: false, message: "Already at target version" }
      }
    
      const path = Hardfork.range(current, target).slice(1)
    
      return {
        needed: true,
        steps: path.length,
        hardforks: path.map(Hardfork.toString),
        features: path.map(fork => ({
          name: Hardfork.toString(fork),
          eip1559: fork.hasEIP1559(),
          push0: fork.hasEIP3855(),
          blobs: fork.hasEIP4844(),
          transient: fork.hasEIP1153(),
          pos: fork.isPostMerge()
        }))
      }
    }
    
    const plan = planMigration(BERLIN, PRAGUE)
    console.log(`Upgrade requires ${plan.steps} steps`)
    

    Version Range Validation

    Check if fork is in supported range:
    import { Hardfork, BERLIN, SHANGHAI } from 'tevm'
    
    function isSupportedVersion(fork: BrandedHardfork): boolean {
      const MIN_VERSION = BERLIN
      const MAX_VERSION = SHANGHAI
    
      const supportedRange = Hardfork.range(MIN_VERSION, MAX_VERSION)
      return supportedRange.includes(fork)
    }
    
    isSupportedVersion(LONDON)   // true
    isSupportedVersion(CANCUN)   // false
    

    Breaking Changes Detection

    Find breaking changes in range:
    import { Hardfork } from 'tevm'
    
    function findBreakingChanges(start: BrandedHardfork, end: BrandedHardfork) {
      const forks = Hardfork.range(start, end)
      const breakingChanges = []
    
      for (const fork of forks) {
        if (fork.isPostMerge() && !start.isPostMerge()) {
          breakingChanges.push({
            fork: Hardfork.toString(fork),
            change: "DIFFICULTY opcode now returns PREVRANDAO"
          })
        }
      }
    
      return breakingChanges
    }
    

    Network Configuration

    Generate network upgrade timeline:
    import { Hardfork, LONDON, OSAKA } from 'tevm'
    
    function generateUpgradeTimeline(from: BrandedHardfork, to: BrandedHardfork) {
      const forks = Hardfork.range(from, to)
    
      return {
        current: Hardfork.toString(from),
        target: Hardfork.toString(to),
        steps: forks.map((fork, index) => ({
          step: index + 1,
          name: Hardfork.toString(fork),
          isPoS: fork.isPostMerge()
        }))
      }
    }
    

    Edge Cases

    Empty Range

    When start > end but reverse=false not supported, returns empty or throws:
    import { Hardfork, BERLIN, LONDON } from 'tevm'
    
    // Forward range works
    const forward = Hardfork.range(BERLIN, LONDON)  // [BERLIN, LONDON]
    
    // Reverse range also works
    const reverse = Hardfork.range(LONDON, BERLIN)  // [LONDON, BERLIN]
    

    Invalid Hardforks

    If hardforks don’t exist in order, an InvalidFormatError is thrown:
    import { Hardfork, LONDON } from 'tevm'
    import { InvalidFormatError } from 'tevm/errors'
    
    const invalidFork = "notahardfork" as any
    
    try {
      const range = Hardfork.range(invalidFork, LONDON)
    } catch (e) {
      if (e instanceof InvalidFormatError) {
        console.error(e.name)    // "InvalidFormatError"
        console.error(e.code)    // "HARDFORK_INVALID_RANGE"
        console.error(e.value)   // The invalid hardfork value
      }
    }
    

    Error Handling

    The range function throws InvalidFormatError when given invalid hardfork values:
    Error TypeCodeWhen Thrown
    InvalidFormatErrorHARDFORK_INVALID_RANGEStart or end hardfork is not a valid hardfork ID
    import { Hardfork, BERLIN } from 'tevm'
    import { InvalidFormatError } from 'tevm/errors'
    
    function safeRange(start: string, end: string) {
      try {
        return Hardfork.range(start as any, end as any)
      } catch (e) {
        if (e instanceof InvalidFormatError) {
          console.error(`Invalid hardfork: ${e.value}`)
          return null
        }
        throw e
      }
    }
    

    Performance

    Time Complexity: O(n) where n = range size Typical Time: ~100ns + (50ns × range size) Example Ranges:
    • BERLIN → LONDON: 2 hardforks (~150ns)
    • BERLIN → CANCUN: 7 hardforks (~450ns)
    • FRONTIER → OSAKA: 19 hardforks (~1050ns)

    See Also