Skip to main content

Compiling Contracts

OXN runs a standard EVM. Most compiler configurations work unchanged. But two settings are non-negotiable, and this page covers them along with the common gotchas.

The two settings that matter

1. evmVersion: "paris" — required.

Newer EVM versions (shanghai, cancun) introduce opcodes (PUSH0, TLOAD, TSTORE, MCOPY, BLOBHASH) that OXN does not implement. Contracts compiled with newer targets deploy successfully but revert at runtime with invalid code.

2. Solidity ^0.8.20 or later, with the paris target. evmVersion was added as a compiler flag well before 0.8.20; 0.8.20 is just when the default flipped to shanghai.

ToolchainConfig line
Hardhatsolidity.settings.evmVersion: "paris" in hardhat.config.js
Foundryevm_version = "paris" in foundry.toml
solc-jssettings.evmVersion: "paris" in the standard-JSON input

Optimizer

The Solidity optimizer works normally on OXN. Recommended settings:

optimizer: { enabled: true, runs: 200 }

runs is the "expected number of transactions per deploy" — higher values optimize for runtime cost at the expense of deploy cost, lower values do the opposite. 200 is a reasonable default that balances both.

For contracts with heavy computation on encrypted state, consider bumping to 1000 — the encryption overhead is largely constant, and per-call optimization pays off.

Solidity version compatibility

Solidity rangeRecommended evmVersionNotes
0.8.19 and earlierparis (default)Works without explicit override.
0.8.200.8.24paris (explicit)Default is shanghai; must override.
0.8.250.8.27paris (explicit)Default is cancun; must override.

Older Solidity versions (0.7.x, 0.6.x) work for legacy code but lack modern language features. Recommend 0.8.24 as a stable current default.

module.exports = {
solidity: {
version: "0.8.24",
settings: {
evmVersion: "paris",
optimizer: { enabled: true, runs: 200 },
},
},
};
[profile.default]
solc = "0.8.24"
evm_version = "paris"
optimizer = true
optimizer_runs = 200

Compilation errors and fixes

"Compiler error: Source file requires different compiler version" — Your pragma solidity doesn't match the compiler you configured. Update either the pragma or the config.

"Warning: This contract has a payable fallback function" — Not OXN-specific. Same behavior as Ethereum.

"Error: PUSH0 was introduced in Shanghai but the current EVM version is Paris" — Wrong. This error means the compiler was invoked with paris but the source (or an imported library) requires Shanghai features. Check inline assembly for explicit PUSH0.

Bytecode size diagnostic

If you're not sure whether you accidentally compiled with shanghai, check the bytecode size:

const artifact = require("./artifacts/contracts/MyToken.sol/MyToken.json");
const bytecodeLength = artifact.bytecode.length / 2 - 1; // hex length -> byte length
console.log(`bytecode size: ${bytecodeLength} bytes`);

const push0Count = (artifact.bytecode.match(/5f/g) || []).length;
console.log(`potential PUSH0 count: ${push0Count}`);

A paris-compiled ERC-20 is roughly 5,800 bytes with essentially no 5f bytes. A shanghai-compiled ERC-20 is roughly 6,200 bytes with ~180 5f bytes — those are the PUSH0 instructions.

If your push0Count is high, you compiled with the wrong target.

Next steps