EVM Precompiles Are Powerful

Precompiles are the escape hatch. When the EVM isn’t fast enough or can’t do what you need, you write a precompile.

They’re powerful. They’re also dangerous. Here’s how to build them without shooting yourself in the foot.

What’s a Precompile?

A precompile is native code that lives at a special address on the blockchain. When a contract calls that address, instead of executing EVM bytecode, the node runs optimized native code.

Ethereum has precompiles for cryptographic operations: SHA-256, RIPEMD-160, elliptic curve math. These would be too slow or impossible in pure EVM.

When to Use Them

Use precompiles for:

  • Cryptographic primitives not supported by EVM
  • Computationally intensive operations
  • Bridging to other systems (runtime calls in Substrate)

Don’t use precompiles for:

  • Things that can be done efficiently in Solidity
  • Business logic that might need to change
  • Anything that doesn’t need consensus

Once deployed, precompiles are hard to change. They’re part of the protocol.

The Interface

Precompiles receive raw bytes and return raw bytes. The calling convention is simple:

fn execute(input: &[u8], gas_limit: u64) -> PrecompileResult {
    // Parse input
    // Do computation
    // Return output or error
}

Use Solidity’s ABI encoding for the interface. It’s standard, well-tooled, and what contracts expect.

Gas Metering

This is where most mistakes happen.

Every operation must cost gas proportional to its computation. Too little gas: the chain is vulnerable to DoS attacks. Too much: the precompile is unusable.

Benchmark your operations. Measure CPU cycles. Convert to gas using the chain’s gas-to-compute ratio.

let base_cost = 15;
let per_word_cost = 3;
let total_gas = base_cost + (input.len() / 32) * per_word_cost;

Be conservative. Undercharging is a security vulnerability. Overcharging is just inefficient.

Security Considerations

Input validation: Precompiles receive arbitrary bytes. Validate everything. Invalid inputs should return an error, not panic.

Memory safety: You’re writing code that runs on every node. A buffer overflow could be catastrophic.

Determinism: Same input must always produce same output. No randomness, no external calls, no system state.

Upgrade path: Think about how you’ll fix bugs. Can the precompile be disabled? Can its address change?

Testing

Test exhaustively:

  • Valid inputs with expected outputs
  • Invalid inputs that should fail gracefully
  • Edge cases: empty input, maximum length input, malformed encoding
  • Gas costs match documentation

Fuzz testing helps. Random inputs find bugs you didn’t think of.

Moonbeam’s OpenGov Precompiles

I learned the power of precompiles firsthand while working on Moonbeam’s OpenGov integration. Polkadot’s governance system lives in Substrate pallets, entirely outside the EVM’s reach. To let Solidity developers participate in governance, we built precompiles that bridge the gap.

The result is something remarkable: a Polkadot rollup where EVM users can vote on referenda, delegate conviction, and interact with the full governance system, all through familiar Solidity interfaces. The precompiles translate between EVM calls and Substrate runtime calls, exposing powerful native functionality to the contract layer.

This is the real promise of precompiles in Polkadot’s architecture. You’re not just adding cryptographic primitives. You’re connecting the EVM to an entire ecosystem of Substrate pallets: staking, governance, identity, whatever you need. The EVM becomes a programmable interface to the underlying chain, not a walled garden.

The L2 Optimization Opportunity

Think about what this enables for Polkadot L2s. A chain built on Substrate with an EVM can optimize any subset of EVM computation by moving it to precompiles. Heavy computation? Write it in Rust, expose it at a precompile address, charge appropriate gas. The EVM handles what it’s good at (contract logic, composability) while expensive operations run at native speed.

This is the architectural flexibility that makes EVM-compatible Substrate chains interesting. You get the network effects of Solidity tooling and developer familiarity, plus the ability to escape the EVM’s constraints when necessary.

Where’s Everyone Else?

Here’s what puzzles me: Moonbeam has been essentially alone in deeply exploring this design space. One company, iterating on precompile patterns for years. The technical approach is powerful, the results are working in production, and yet the broader ecosystem hasn’t produced multiple teams pushing in similar directions.

Eric Raymond’s Linus’s Law (“given enough eyeballs, all bugs are shallow”) applies to design as much as debugging. When multiple independent teams explore a problem space, they surface different solutions, challenge each other’s assumptions, and collectively find better answers than any single team would alone.

Ethereum’s precompile additions go through a process with multiple stakeholders proposing, critiquing, and refining. The result is battle-tested standards that work for diverse use cases. In Polkadot, precompile innovation has been concentrated rather than distributed.

This isn’t about blame. Moonbeam did the work and deserves credit for it. It’s an observation about ecosystem dynamics. Competitive design diversity produces better outcomes than single-stakeholder development. The most robust solutions emerge when multiple teams are designing for different needs and comparing notes.

If more teams had been building EVM-Substrate bridges with different requirements, we’d probably have better patterns by now. That’s the cost of concentration.

The Golden Rule

Precompiles are protocol-level code. They need the same rigor as consensus code. Every bug is a potential chain halt or security vulnerability.

If you’re not sure you need a precompile, you probably don’t. The EVM is more capable than it looks.