ethereumjs-monorepo

@ethereumjs/common v10

NPM Package GitHub Issues Actions Status Code Coverage Discord

| Resources common to all EthereumJS implementations. | | ————————————————— |

Common holds the chain configuration, active hardfork, EIP set, and protocol parameters shared across the EthereumJS libraries. Instantiate one Common per network context and pass it to tx, block, evm, vm, and related packages.

Runnable examples live in examples/.

Table of Contents

Installation

npm install @ethereumjs/common

Getting Started

import / require

import (ESM, TypeScript):

import { Chain, Common, Hardfork, Mainnet } from '@ethereumjs/common'

require (CommonJS, Node.js):

const { Common, Hardfork, Mainnet } = require('@ethereumjs/common')

Instantiate Common

Pick a built-in chain preset (Mainnet, Sepolia, …) and optionally pin a hardfork. When omitted, the chain’s defaultHardfork is used (Hardfork.Prague on Mainnet today).

// ./examples/instantiation.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

const withHardfork = new Common({ chain: Mainnet, hardfork: Hardfork.Prague })
const withDefault = new Common({ chain: Mainnet })

console.log(`Explicit hardfork: ${withHardfork.hardfork()}`)
console.log(
  `Default hardfork: ${withDefault.hardfork()} (DEFAULT_HARDFORK=${withDefault.DEFAULT_HARDFORK})`,
)

Chain Presets

Built-in presets: Mainnet, Sepolia, Holesky, Hoodi. Each exposes chainId(), genesis(), hardforks(), bootstrapNodes(), dnsNetworks(), and consensus metadata.

// ./examples/testnetChains.ts

import { Common, Holesky, Hoodi, Mainnet, Sepolia } from '@ethereumjs/common'

for (const chain of [Mainnet, Sepolia, Holesky, Hoodi]) {
  const common = new Common({ chain })
  console.log(
    `${common.chainName()}: chainId=${common.chainId()} hardfork=${common.hardfork()} bootstrapNodes=${common.bootstrapNodes().length}`,
  )
}

Chain fields are defined in chains.ts and the ChainConfig type in types.ts.

Hardfork Selection

Pin at construction

Set hardfork in the constructor when you know the fork up front (tests, single-fork tooling).

Resolve from block headers

For block replay, syncing, or VM runs, use getHardforkBy() / setHardforkBy(). Pre-merge forks use block number; post-merge forks need timestamp (and typically block number as well).

// ./examples/hardforkByBlock.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

const common = new Common({ chain: Mainnet })

// Pre-merge: block number alone determines the active hardfork
console.log(`HF at block 12_965_000 (London): ${common.getHardforkBy({ blockNumber: 12_965_000n })}`)
common.setHardforkBy({ blockNumber: 12_965_000n })
console.log(`After setHardforkBy: ${common.hardfork()}`)

// Post-merge: pass timestamp (and block number) for timestamp-based forks
common.setHardforkBy({ blockNumber: 19_000_000n, timestamp: 1_710_338_135n })
console.log(`HF at Cancun timestamp: ${common.hardfork()}`)

common.setHardforkBy({ blockNumber: 19_000_000n, timestamp: 1_746_612_311n })
console.log(`HF at Prague timestamp: ${common.hardfork()}`)
console.log(`Prague active on block 19M: ${common.hardforkIsActiveOnBlock(Hardfork.Prague, 19_000_000n)}`)

This mirrors what @ethereumjs/vm does when executing a block.

Supported hardforks

Past and upcoming hardforks include chainstart through osaka, plus in-development amsterdam. Hardfork.Prague is the current Mainnet default; Hardfork.Amsterdam is experimental — see the canonical Amsterdam overview in @ethereumjs/vm for release ↔ spec tracking.

Parameter Access

Hardfork and EIP parameters (gas costs, limits, rewards, …) are read with param(), paramByHardfork(), and paramByBlock(). Parameter definitions live in hardforks.ts and eips.ts.

// ./examples/paramAccess.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

// Hardfork-local params (defined on the BPO hardfork schedule)
const bpo = new Common({ chain: Mainnet, hardfork: Hardfork.Bpo1 })
console.log(`BPO target blob count: ${bpo.param('target')}`)

// Downstream packages ship default EIP param sets; inject manually on standalone Common
const common = new Common({ chain: Mainnet, hardfork: Hardfork.London })
common.updateParams({ 1559: { initialBaseFee: 1_000_000_000 } })
console.log(`London initialBaseFee: ${common.param('initialBaseFee')}`)

// paramByBlock() picks the hardfork active at a block (then reads the param)
console.log(`HF at block 12_965_000: ${common.getHardforkBy({ blockNumber: 12_965_000n })}`)
console.log(
  `initialBaseFee at block 12_965_000: ${common.paramByBlock('initialBaseFee', 12_965_000n)}`,
)

Downstream packages may supply extra param dictionaries (e.g. @ethereumjs/tx paramsTx for tx-specific EIP params). Pass them via the constructor params option when needed.

Blob Gas Schedule

EIP-4844 blob gas limits and EIP-7892 BPO schedule changes are exposed through getBlobGasSchedule(). BPO hardforks (Bpo1, …) carry target / max on the hardfork definition; earlier forks need EIP-4844 params (merged automatically when using @ethereumjs/vm / @ethereumjs/evm, or via updateParams() on standalone Common).

// ./examples/blobGasSchedule.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

const blob4844Params = {
  targetBlobGasPerBlock: 393216,
  maxBlobGasPerBlock: 786432,
  blobGasPriceUpdateFraction: 3338477,
  blobGasPerBlob: 131072,
}

// Pre-BPO: EIP-4844 param names
const cancun = new Common({ chain: Mainnet, hardfork: Hardfork.Cancun })
cancun.updateParams({ 4844: blob4844Params })
const cancunSchedule = cancun.getBlobGasSchedule()
console.log(
  `Cancun: target=${cancunSchedule.targetBlobGasPerBlock} max=${cancunSchedule.maxBlobGasPerBlock}`,
)

// BPO hardforks: target/max counts are on the HF; multiply by blobGasPerBlob
for (const hardfork of [Hardfork.Bpo1, Hardfork.Bpo2]) {
  const common = new Common({ chain: Mainnet, hardfork })
  common.updateParams({ 4844: { blobGasPerBlob: blob4844Params.blobGasPerBlob } })
  const schedule = common.getBlobGasSchedule()
  console.log(
    `${hardfork}: target=${schedule.targetBlobGasPerBlock} max=${schedule.maxBlobGasPerBlock} updateFraction=${schedule.blobGasPriceUpdateFraction}`,
  )
}

EIP Activation

EIPs activate through the hardfork schedule and/or the constructor eips array. Query with isActivatedEIP().

// ./examples/activateEIPs.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

// Default-on via hardfork schedule (Prague ships EIP-7702)
const prague = new Common({ chain: Mainnet, hardfork: Hardfork.Prague })
console.log(`EIP-7702 on Prague: ${prague.isActivatedEIP(7702)}`)

// Opt-in before schedule: activate on an earlier hardfork via constructor `eips`
const early7702 = new Common({ chain: Mainnet, hardfork: Hardfork.Cancun, eips: [7702] })
console.log(`EIP-7702 forced on Cancun: ${early7702.isActivatedEIP(7702)}`)

// Experimental Amsterdam fork (in development) — full bundle via Hardfork.Amsterdam
const amsterdam = new Common({ chain: Mainnet, hardfork: Hardfork.Amsterdam })
console.log(`EIP-7928 BAL on Amsterdam: ${amsterdam.isActivatedEIP(7928)}`)
console.log(`EIP-7708 transfer logs: ${amsterdam.isActivatedEIP(7708)}`)
console.log(`EIP-8037 two-dimensional gas: ${amsterdam.isActivatedEIP(8037)}`)
console.log(`EIP-7843 SLOTNUM / slotNumber: ${amsterdam.isActivatedEIP(7843)}`)

Supported EIPs

The following EIPs are currently supported (sorted by EIP number):

Annotations:

Events

common.events is an EventEmitter3 instance:

Event Description
hardforkChanged Emitted when setHardfork() changes the active hardfork
// ./examples/hardforkEvents.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'

const common = new Common({ chain: Mainnet, hardfork: Hardfork.London })

common.events.on('hardforkChanged', (hardfork) => {
  console.log(`hardforkChanged event: ${hardfork}`)
})

common.setHardfork(Hardfork.Prague)

Custom and Private Chains

createCustomCommon() adjusts a base preset or supplies a full ChainConfig. Use it for L2 chain IDs, devnets, and PoA networks.

Chain ID override (L2 pattern)

// ./examples/customChainId.ts

import { Mainnet, createCustomCommon } from '@ethereumjs/common'

// Keep Mainnet params but override chainId — typical for L2 / private networks
const l2Common = createCustomCommon({ chainId: 42161 }, Mainnet)

console.log(`chainId=${l2Common.chainId()} name=${l2Common.chainName()}`)
console.log(`Hardfork schedule inherited (${l2Common.hardforks().length} entries)`)

See the @ethereumjs/tx README for signing with a custom Common.

Full custom ChainConfig

// ./examples/customChain.ts

import { Hardfork, Mainnet, createCustomCommon } from '@ethereumjs/common'
import { customChainConfig } from '@ethereumjs/testdata'

const common = createCustomCommon(customChainConfig, Mainnet)

console.log(`Chain ${common.chainName()} (chainId=${common.chainId()})`)
console.log(`Hardfork at block 4: ${common.getHardforkBy({ blockNumber: 4n })}`)
console.log(`Bootstrap nodes: ${common.bootstrapNodes().length}`)

common.setHardfork(Hardfork.Byzantium)
console.log(`Active hardfork on custom chain: ${common.hardfork()}`)

PoA / Clique consensus metadata

// ./examples/consensusConfig.ts

import { Common, Hardfork } from '@ethereumjs/common'
import { testnetMergeChainConfig } from '@ethereumjs/testdata'

const common = new Common({ chain: testnetMergeChainConfig, hardfork: Hardfork.London })

console.log(`consensusType: ${common.consensusType()}`)
console.log(`consensusAlgorithm: ${common.consensusAlgorithm()}`)

const clique = common.consensusConfig()
console.log(`clique period=${clique.period}s epoch=${clique.epoch} blocks`)

From Geth genesis JSON

For devnets and testnets, derive Common from a Geth genesis.json (chain config + alloc):

// ./examples/fromGethGenesis.ts

import { createCommonFromGethGenesis } from '@ethereumjs/common'
import { postMergeGethGenesis } from '@ethereumjs/testdata'
import { hexToBytes } from '@ethereumjs/util'

const genesisHash = hexToBytes('0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a')
const common = createCommonFromGethGenesis(postMergeGethGenesis, {
  chain: 'customChain',
  genesisHash,
})
// Defer genesisHash when unknown at init time — set later after computing the genesis block hash
common.setForkHashes(genesisHash)

console.log(`Hardfork is ${common.hardfork()} chainId=${common.chainId()}`)
console.log(`Paris fork hash: ${common.forkHash('paris')}`)

Custom Cryptography (WASM / KZG)

By default, EthereumJS uses audited pure-JS crypto from ethereum-cryptography. For performance or blob/KZG support, pass replacements on customCrypto (types.ts).

Note: WASM backends add supply-chain and audit surface. Evaluate before enabling in production.

keccak256 (WASM example)

// ./examples/customCrypto.ts

import { createBlock } from '@ethereumjs/block'
import { Common, Mainnet } from '@ethereumjs/common'
import { keccak256, waitReady } from '@polkadot/wasm-crypto'

const main = async () => {
  await waitReady()

  const common = new Common({ chain: Mainnet, customCrypto: { keccak256 } })
  const block = createBlock({}, { common })

  // Downstream calls on objects sharing this `common` use the custom hash
  console.log(block.hash())
}

void main()

KZG for EIP-4844 / PeerDAS

KZG is required for blob transactions (EIP-4844) and cell proofs (EIP-7594). Wire any library implementing the KZG interface; the example below uses micro-eth-signer:

// ./examples/initKZG.ts

import { Common, Hardfork, Mainnet } from '@ethereumjs/common'
import { trustedSetup } from '@paulmillr/trusted-setups/fast-peerdas.js'
import { KZG as microEthKZG } from 'micro-eth-signer/kzg.js'

const main = async () => {
  const kzg = new microEthKZG(trustedSetup)
  const common = new Common({
    chain: Mainnet,
    hardfork: Hardfork.Cancun,
    customCrypto: { kzg },
  })
  console.log(common.customCrypto.kzg !== undefined)
}

void main()

Browser

Hybrid ESM/CJS builds ship with v10; libraries are pure JS by default (no hard-wired WASM). See examples/browser.html for a local dev-server setup.

API

Generated TypeDoc: Documentation

Helper methods include paramByBlock(), hardforkIsActiveOnBlock(), forkHash(), setForkHashes(), copy(), and updateParams() for advanced overrides.

Hybrid CJS/ESM builds: ESM import resolves to dist/esm/; Node require resolves to dist/cjs/.

EthereumJS

The EthereumJS GitHub organization and its repositories are managed by members of the former Ethereum Foundation JavaScript team and the broader Ethereum community. See developer docs and code of conduct.

License

MIT