Skip to content
Smart-Contract Development4 min read

Solidity v0.8.31: Osaka EVM Default, CLZ Opcode, and the 0.9.0 Deprecation Clock Starts

The December 2025 Solidity release sets `osaka` as the default EVM target, ships the CLZ opcode from EIP-7939, and fires the starting gun on a wave of 0.9.0 breaking changes — here's what it means for contract authors today.

By TRAGenX Desk

Share

On 3 December 2025, the Solidity team pushed v0.8.31 — a release that does more than add features. It officially flags Ethereum's Fusaka upgrade as the compilation target and begins printing pink slips for a cluster of legacy language features. If you ship contracts, there are decisions to make before 0.9.0 lands.

Osaka Becomes the Default EVM Version

The biggest implicit change: the compiler's default --evm-version flag is now osaka. Fusaka (the portmanteau of Fulu + Osaka, Ethereum's next scheduled hardfork) introduces new EVM capabilities, and Solidity v0.8.31 is the first compiler that targets them out of the box. Teams compiling without an explicit --evm-version flag will now produce bytecode that requires an Osaka-capable node. If you are deploying to pre-Fusaka networks — L2s that haven't upgraded, testnets lagging the mainnet schedule, or private chains — pin your version explicitly: --evm-version paris (or whichever version your target network runs) to avoid deploying incompatible bytecode.

CLZ Opcode: EIP-7939 Lands in Yul

EIP-7939 introduces the CLZ (count leading zeros) opcode to the EVM, and Solidity surfaces it through a new Yul builtin clz(x). It returns the number of leading zero bits in a 256-bit word — an operation previously requiring multi-step bit-shifting or lookup tables. Practically, CLZ is useful for:

  • Log₂ approximations without PRNG or external libraries — handy for AMM tick math and fixed-point scaling.
  • Compact data encoding — finding the highest set bit to pack variable-length values efficiently on-chain.
  • Data-structure operations — binary tries and priority queues that need floor(log2(n)).
  • Compression routines in Yul assembly where gas cost of the naive implementation was prohibitive.

In high-level Solidity (non-assembly), you will not call clz() directly — but libraries like OpenZeppelin's Math and Uniswap's tick libraries are likely to adopt the opcode internally once mainnet activates it, shaving gas from already tight inner loops.

Storage Layout: constant Variables Now Allowed in Base Slot Expressions

The custom storage layout feature — which lets you dictate exactly where state variables live in storage — now accepts constant state variables in the base slot expression. Previously only literal integers were permitted. This matters for proxy and diamond-pattern contracts that need deterministic, named slots across implementation upgrades. You can now write something like uint256 constant SLOT = keccak256('my.contract.storage') - 1; and reference SLOT directly in your layout annotations rather than hard-coding the hex value.

The 0.9.0 Deprecation Wave Begins

This release starts emitting deprecation warnings for four features slated for removal in the upcoming breaking 0.9.0 release:

  1. ABI coder v1 — the legacy encoder/decoder. Migrate to pragma abicoder v2 (or simply remove the pragma; v2 has been the default since 0.8.0).
  2. Virtual modifiers — modifiers marked virtual without being overridden. The language is tightening its model of inheritance.
  3. `send()` and `transfer()` on address types — both carry the infamous 2300-gas stipend, a footgun in a post-EIP-1884 world. The replacement is a direct low-level call{value: ...}('') with explicit gas handling.
  4. Comparisons between contract-type variables — a subtle ambiguity; compare .address properties explicitly instead.

None of these break compilation yet — you get warnings, not errors. But the window to migrate cleanly is now. Projects running CI with solc warnings-as-errors will fail immediately and should update their code before upgrading the compiler.

ARM Linux Builds

Official ARM Linux binaries ship with v0.8.31 — a quality-of-life win for teams building on Apple Silicon in Linux VMs or deploying CI on ARM64 cloud runners (AWS Graviton, Ampere, etc.). No more cross-compiling or pulling unofficial binaries.

What to Do This Week

  • Audit your `--evm-version` flags. Any pipeline that omits the flag now targets osaka. Confirm your deployment environment is Fusaka-ready or pin the version.
  • Search for `pragma abicoder v1` and ABI coder v1 in your codebase and migrate — this is the most common of the deprecated patterns.
  • Replace `transfer()` and `send()` with checked call{value: ...}('') patterns. Slither and similar tools can automate detection.
  • Test on an Osaka-capable testnet if you want to benchmark CLZ-using library code ahead of mainnet activation.

FAQ

Frequently asked questions

Does upgrading to Solidity v0.8.31 break existing contracts?
Not automatically. Deployed bytecode is immutable. The risk is in recompilation: if you compile existing source without pinning `--evm-version`, the output now targets `osaka` and may not execute on older nodes or L2s that haven't activated Fusaka. Pin your EVM version in your Hardhat/Foundry config to match your deployment target.
When does the `send()` / `transfer()` removal actually happen?
In Solidity 0.9.0, which has no confirmed release date yet. Right now (v0.8.31) these functions only emit deprecation warnings. You have time to migrate, but the earlier you do, the less painful it is — especially for large codebases.
What is the Fusaka upgrade and when does it activate on Ethereum mainnet?
Fusaka (Fulu + Osaka) is the next scheduled Ethereum hardfork after Pectra. It focuses on EVM improvements (including EIP-7939 CLZ) and data-availability enhancements. As of the Solidity 0.8.31 release date (December 2025), a mainnet activation date had not been finalised — monitor ethereum.org/roadmap for the latest timeline.

Sources

Share

Read next