This PR introduces powerful code size optimizations. This is achieved with an additional IR layer in between Yul and LLVM IR. It works quite well (see below for a comparison) because it captures optimization gains that neither solc nor LLVM can realize. The feature is gated behind `--newyork` or a corresponding standard JSON input setting and **off by default**. ### How it works We implemented an SSA IR modelled after or inspired by the [MLIR SCF dialect](https://mlir.llvm.org/docs/Dialects/SCFDialect/). Yul is translated into this IR and the IR implements mainly the following optimizations: - **Type narrowing**: narrows 256-bit values to I1..I160 where provable (bidirectional + interprocedural), so LLVM emits native 32/64-bit ops instead of software 256-bit arithmetic. - **FMP range proof**: exposes the `mload(0x40) < heap_size` bound to LLVM IPSCCP, eliminating trailing overflow checks on FMP-derived offsets. Single largest code-size contributor. - **Heap analysis**: skips big-endian byte-swaps where native little-endian layout is safe. - **mem_opt / keccak fusion+folding**, **compound outlining** (mapping sload/sstore), **guard narrowing**, **inlining** tuned for PolkaVM, and **exact + fuzzy function dedup**. ### Results The optimizations implemented with the newyork IR bring substantial code size improvements. - Integration contracts: approximately **-20% to -50%** code size. - OpenZeppelin Wizard corpus: around **-47%** code size. This table shows the code size improvements on various OpenZeppelin ERC implementations, taken from their [contracts wizard](https://wizard.openzeppelin.com/), with almost all features enabled. | Contract | Default: (bytes) | With `--newyork`: (bytes) | Reduction | |---|---:|---:|---:| | erc1155 | 59,206 | 30,649 | -48.2% | | erc20 | 81,697 | 42,893 | -47.5% | | erc721 | 92,052 | 49,423 | -46.3% | | oz_gov | 141,861 | 81,159 | -42.8% | | oz_rwa | 77,274 | 37,975 | -50.9% | | oz_simple_erc20 | 29,950 | 16,554 | -44.7% | | oz_stable | 82,117 | 39,032 | -52.5% | | **Total** | **564,157** | **297,685** | **-47.2%** | We believe this to be a reasonably representative dataset and conclude that the newyork IR achieves drastic code size reductions on real world dApp implementations. ### Methodology, security and runtime performance Since the main contributors to these improvements are the FMP range proofs and the type narrowing, we don't expect big runtime performance regressions (it may even benefit runtime performance in some cases). The PR also includes docs (`book/src/developer_guide/newyork_{optimizer,ir}.md`) and many new integration tests, including regression tests for known FMP soundness traps. The PR was authored collaboratively and reviewed extensively by the `revive` maintainers, as well as Claude Opus, Claude Fable, Qwen, Minimax and Deepseek LLMs, over a span of many months. The `newyork` compiler pipeline introduces no new regressions over our integration and differential test suites (containing over 30000 test cases). This was achieved by careful manual reviews and many LLM bughunt loops. Additionally, a final security review by Anthropic's Fable 5 LLM found no remaining soundness issues. Nonetheless, like any brand new software, please consider this an experimental feature upon release. --------- Signed-off-by: xermicus <bigcyrill@hotmail.com> Signed-off-by: xermicus <cyrill@parity.io> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: neo <me@90f9.org> Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
revive
Yul recompiler to LLVM, targetting RISC-V on PolkaVM.
Check the docs or visit contracts.polkadot.io to learn more about revive and contracts on Polkadot!
Discussion around the development is hosted on the Polkadot Forum.
Warning
Solidity on PVM is running on the
pallet-reviveruntime. This introduces observable semantic differences in comparison with the EVM.Study the differences section carefully. Ignoring these differences may lead to defunct contracts.
Notable examples:
- The 63/64 gas rule isn't implemented in the pallet (introduces potential DoS vector when calling other contracts)
- Contract instantiation works differently (by hash instead of by code)
- The gas model implemented by
pallet-revivediffers from Ethereum- The heap size is fixed instead of gas-metered and there's a fixed amount of stack size (contracts working fine on EVM may trap on PVM)
Installation
Building Solidity contracts for PolkaVM requires installing the following two compilers:
resolc: The revive Solidity compiler Yul frontend and PolkaVM code generator (provided by this repository).solc: The Ethereum Solidity reference compiler implemenation.resolcusessolcduring the compilation process, please refer to the Ethereum Solidity documentation for installation instructions.
resolc binary releases
resolc is distributed as a standalone binary (with solc as the only external dependency). Please download one of our binary releases for your target platform and mind the platform specific instructions below. We also provide nightly builds.
MacOS users
MacOS users need to clear the
downloadedattribute from the binary and set the executable flag.xattr -rc resolc-universal-apple-darwin chmod +x resolc-universal-apple-darwin
Linux users
Linux users need to set the executable flag.
chmod +x resolc-x86_64-unknown-linux-musl
resolc NPM package
We distribute the revive compiler as node.js module and hardhat plugin.
Note: The solc dependency is bundled via NPM packaging and defaults to the latest supported version.
Building from source
Building revive requires a stable Rust installation and a C++ toolchain for building LLVM on your system.
LLVM
revive depends on a custom build of LLVM v18.1.8 with the RISC-V embedded target, including the compiler-rt builtins. You can either download a build from our releases (recommended for older hardware) or build it from source.
Download from our LLVM releases
Download the latest LLVM build from our releases.
MacOS users need to clear the
downloadedattribute from all binaries after extracting the archive:xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
After extracting the archive, point $LLVM_SYS_221_PREFIX to it:
export LLVM_SYS_221_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
Building from source
The Makefile provides a shortcut target to obtain a compatible LLVM build, using the provided revive-llvm utility. Once installed, point $LLVM_SYS_221_PREFIX to the installation afterwards:
make install-llvm
export LLVM_SYS_221_PREFIX=${PWD}/target-llvm/gnu/target-final
The resolc Solidity frontend
To build the resolc Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the LLVM_SYS_221_PREFIX environment variable pointing to it (see above).
To install the resolc Solidity frontend executable:
make install-bin
resolc --version
Development
Please consult the Developer Guide to learn more about how contribute to the project.
Acknowledgements
The revive compiler project, after some early experiments with EVM bytecode translations, decided to fork the era-compiler framework.
Frontend, code generator and some supporting libraries are based of ZKSync zksolc. I'd like to express my gratitude and thank the original authors for providing a useable code base under a generous license.