> For the complete documentation index, see [llms.txt](https://bluwhale.gitbook.io/bluwhaleai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bluwhale.gitbook.io/bluwhaleai/oceanum-oxn/smart-contract-development/compiling-contracts.md).

# Compiling Contracts

Oceanum (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 <a href="#the-two-settings-that-matter" id="the-two-settings-that-matter"></a>

**1. `evmVersion: "paris"`** — required.

Newer EVM versions (`shanghai`, `cancun`) introduce opcodes (`PUSH0`, `TLOAD`, `TSTORE`, `MCOPY`, `BLOBHASH`) that Oceanum (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`.

| Toolchain | Config line                                                    |
| --------- | -------------------------------------------------------------- |
| Hardhat   | `solidity.settings.evmVersion: "paris"` in `hardhat.config.js` |
| Foundry   | `evm_version = "paris"` in `foundry.toml`                      |
| solc-js   | `settings.evmVersion: "paris"` in the standard-JSON input      |

### Optimizer <a href="#optimizer" id="optimizer"></a>

The Solidity optimizer works normally on Oceanum (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 <a href="#solidity-version-compatibility" id="solidity-version-compatibility"></a>

| Solidity range       | Recommended `evmVersion` | Notes                                     |
| -------------------- | ------------------------ | ----------------------------------------- |
| `0.8.19` and earlier | `paris` (default)        | Works without explicit override.          |
| `0.8.20` – `0.8.24`  | `paris` (explicit)       | Default is `shanghai`; **must override**. |
| `0.8.25` – `0.8.27`  | `paris` (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.

### Recommended `hardhat.config.js` snippet <a href="#recommended-hardhatconfigjs-snippet" id="recommended-hardhatconfigjs-snippet"></a>

```
module.exports = {
  solidity: {
    version: "0.8.24",
    settings: {
      evmVersion: "paris",
      optimizer: { enabled: true, runs: 200 },
    },
  },
};
```

### Recommended `foundry.toml` snippet <a href="#recommended-foundrytoml-snippet" id="recommended-foundrytoml-snippet"></a>

```
[profile.default]
solc = "0.8.24"
evm_version = "paris"
optimizer = true
optimizer_runs = 200
```

### Compilation errors and fixes <a href="#compilation-errors-and-fixes" id="compilation-errors-and-fixes"></a>

**"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 <a href="#bytecode-size-diagnostic" id="bytecode-size-diagnostic"></a>

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 <a href="#next-steps" id="next-steps"></a>

* [**Testing Contracts Locally**](https://docs.bout.network/build/testing-local)
* [**Deploying Contracts**](https://docs.bout.network/build/deploying)
* [**EVM Compatibility**](https://docs.bout.network/concepts/evm-compatibility) — full opcode support matrix

[Edit this page](https://github.com/oxn-network/oxn-docs/edit/main/docs/06-build/compiling.md)[PreviousDevelopment Environment Setup](https://docs.bout.network/build/dev-environment)[NextTesting Contracts Locally](https://docs.bout.network/build/testing-local)
