Skip to main content

EVM Compatibility

OXN runs a fully compatible EVM inside its enclave. In practice, nearly every contract that runs on Ethereum will also run on OXN unmodified. This page documents the small number of places where behavior differs, so you can spot them before they cause a surprise.

Compiler settings that matter

Pin evmVersion to "paris". This is the single most important setting on OXN and the most common source of "invalid code" errors.

Solidity 0.8.20 and later default to evmVersion: "shanghai", which emits the PUSH0 opcode (0x5F). OXN's runtime does not yet implement PUSH0. Contracts compiled with the Shanghai default will deploy successfully but revert at runtime with invalid code on any execution path that reaches a PUSH0 — and there will be many of them in typical Solidity output.

ToolchainSetting
Hardhatsolidity.settings.evmVersion: "paris" in hardhat.config.js
Foundryevm_version = "paris" in foundry.toml
solc-jssettings.evmVersion: "paris"

Diagnostic: if your bytecode.length grew significantly after upgrading solc, and you now see invalid code errors, PUSH0 is likely the cause. paris-compiled ERC-20 is typically ~5.8 KB; shanghai-compiled is ~6.2 KB with ~180 PUSH0 instructions.

Opcode support matrix

EVM versionOpcodes introducedOXN support
FrontierBase instruction setFull
HomesteadDELEGATECALLFull
ByzantiumRETURNDATASIZE, RETURNDATACOPY, REVERT, STATICCALLFull
ConstantinopleSHL, SHR, SAR, CREATE2, EXTCODEHASHFull
IstanbulCHAINID, SELFBALANCE, EXTCODEHASH gas changesFull
BerlinEIP-2929 gas repricingFull
LondonEIP-1559 (base fee), BASEFEE opcodePartial (BASEFEE returns 0 or fixed value; no EIP-1559 fee auction)
ParisThe Merge (DIFFICULTYPREVRANDAO)Full
ShanghaiPUSH0, warm COINBASE, EIP-3651Not supported
CancunTransient storage (TLOAD, TSTORE), MCOPY, BLOBHASHNot supported

Set evmVersion: "paris" to stay inside the supported set.

Standard EVM precompiles

Ethereum's standard precompiles at addresses 0x01 through 0x0a are supported:

AddressFunctionOXN support
0x01ecrecoverFull
0x02sha256Full
0x03ripemd160Full
0x04identityFull
0x05modexpFull
0x06ecAdd (bn128)Full
0x07ecMul (bn128)Full
0x08ecPairing (bn128)Full
0x09blake2fFull
0x0apointEvaluation (KZG)Not supported

OpenZeppelin, Solmate, and most standard libraries rely only on 0x010x09, which are all present. pointEvaluation (used in EIP-4844 blob validation) is not needed on OXN because OXN does not have blob transactions.

Behavior differences from Ethereum

Block environment.

Opcode / globalEthereumOXN
block.numberEthereum block heightOXN block height
block.timestampUnix timestamp of the blockSame
blockhash(n)Hash of block n (last 256)Same
block.chainid1 (mainnet)186 (OXN testnet)
block.coinbaseMiner / proposer addressZero address or fixed sentinel
block.difficulty / PREVRANDAORandomness beaconFixed sentinel — do not use for randomness
block.basefeeEIP-1559 base feeZero or fixed — legacy fee model in use

Randomness. block.difficulty / PREVRANDAO, block.timestamp, and block.hash are all publicly predictable. Do not use them for randomness in confidential contracts. Use the Sapphire.randomBytes precompile — see Precompiles: Randomness.

Gas estimation. Set gasLimit explicitly rather than relying on eth_estimateGas. See Gas and Fees.

Event log visibility. Standard on Ethereum: any observer can decode all events. On OXN: encrypted, and only the caller who emitted them can decode. See Confidentiality Model.

Revert reason visibility. Standard on Ethereum: any observer can read the revert reason. On OXN: encrypted, decodable only by the caller. Debugging from outside is impossible without the caller's session key.

Testing your contract for OXN compatibility

A quick checklist before shipping:

  • evmVersion: "paris" in your compiler config
  • No use of PUSH0 (implicit — comes from evmVersion)
  • No reliance on block.difficulty / PREVRANDAO for randomness
  • No reliance on EIP-1559 fee parameters (maxFeePerGas, maxPriorityFeePerGas)
  • No use of transient storage (TLOAD, TSTORE)
  • Explicit gasLimit on every transaction
  • Events designed with the OXN encryption model in mind (if global indexing is required, add a public event or use a relay)

Run integration tests against OXN Testnet, not just a local Hardhat network. Local emulators do not model confidentiality or the OXN-specific opcode support.

Migration effort from Ethereum

For most contracts, migration is a two-line change: evmVersion: "paris" in the compiler config, and explicit gasLimit in the deployment script.

Contracts that use encryption features (Sapphire.encrypt, signed queries, etc.) are OXN-native and won't compile against a public EVM chain — that's expected. If your migration goal is to write a contract that works on both Ethereum and OXN, keep the OXN-specific code paths behind a flag or a separate contract.

See Migrating an Ethereum dApp to OXN for a step-by-step walkthrough.

Next steps