oksolc is a Zig implementation of the Solidity compiler that we built for our
internal use in developing Chainwall.
Its goal is to provide an alternative implementation of Solidity for development purposes, allowing faster iteration on the developer experience.
We don’t consider oksolc to be production ready for deploying smart
contracts onchain, and recommend using the original solc compiler for
deployment. That said, we strive to be byte-compatible at this stage with
Solidity 0.8.36. Any deviation in compiler output should be considered a bug and
reported in Issues.
The supported compilation path is the optimized, via-IR compilation through the Standard JSON interface.
The project provides:
oksolc, a small command-line interfacelibsolc-compatible C ABI and installed libsolc.hsolidityNote this project was built with AI assistance (using GPT 5.5 then 5.6 Sol) but under strict human guidance and control, our team having previous experience in building compilers and in formal verification. We intend to publish the methods and controls that we used.
The compatibility target is the original Solidity 0.8.36 compiler for Standard
JSON, creation bytecode, diagnostics, and deterministic output.
The compile command enables the optimizer with 200 runs. Use standard-json
when exact control of compiler settings or output selection is required.
oksolc has an independent product version; the Solidity version identifies its compatibility target. See CHANGELOG.md for release history.
$ oksolc version
oksolc 0.1.4 (Solidity 0.8.36)
$ oksolc --version
oksolc, a solidity compiler commandline interface
Version: 0.8.36+oksolc.0.1.4
oksolc version --json returns version (the product version),
solidity_version (the compatibility target), compatibility_version (the
Solidity SemVer with oksolc build metadata), and build_identity (the compiler
content identity, or null if unavailable). Include this output in bug reports.
The public Zig module exposes the product version as solidity.version and the
Solidity target as solidity.baseline.version.
--version and the C ABI's solidity_version() retain a Solidity-compatible
SemVer for tools such as Foundry. Even development releases put the oksolc
version after +, so the Solidity target is still treated as a release.
Contract metadata and CBOR keep the pinned reference compiler identity to
preserve output and bytecode compatibility. Use the product version for upgrade
comparisons; SemVer precedence ignores the build metadata after +.
0.16.07.0.2 (tsc) and Bun 1.4.2 only for the optional web browserfuzz-json-adapter and fuzz (limited to
the yyjson adapter for now)solc version 0.8.36 for optional reference audits and benchmark
comparisonszstd to replay the bundled external benchmarks; Forge and Git to capture
fresh requests, plus Node.js/npm for old Uniswap and Node.js for Pendle setupThe first Zig build downloads the dependencies declared in build.zig.zon.
Build the CLI, shared library, and C header:
zig build -Doptimize=ReleaseFast
The executable is at zig-out/bin/oksolc; the library and header are in
zig-out/lib and zig-out/include. Add zig-out/bin to your PATH or install
to a different prefix:
zig build -Doptimize=ReleaseFast --prefix "$HOME/.local"
For development, omit -Doptimize for Debug mode, or use
-Doptimize=ReleaseSafe for an optimized build with runtime safety checks. To
build only the CLI, use zig build build-cli.
The web browser is disabled by default, so ordinary builds require neither Bun
nor TypeScript. To include oksolc browse and oksolc serve --browse, install
the pinned browser tools and opt in:
zig build -Doptimize=ReleaseFast -Dbrowser=true
Distribution builds can strip debug information and select a target:
zig build -Dtarget=aarch64-macos -Doptimize=ReleaseFast -Dstrip=true \
--prefix build/macos-arm64
zig build -Dtarget=x86_64-linux-gnu -Doptimize=ReleaseFast -Dstrip=true \
--prefix build/linux-amd64
Compile one or more Solidity files and write the Standard JSON result to stdout:
oksolc compile Contract.sol Library.sol
For control over compiler settings and requested artifacts, supply a Standard
JSON request from a file or stdin. Use -o to save the result:
oksolc standard-json request.json
oksolc standard-json - < request.json
oksolc standard-json -o build/output.json request.json
For filesystem imports, --base-path sets the source lookup root and repeatable
--include-path options add library directories (include paths require an
explicit base path).
AS of now, source paths must stay within the configured roots and cannot contain symlinks.
Independent contract backends can compile in parallel. --jobs sets total
concurrency, including the main thread:
oksolc compile --parallel --jobs 4 Contract.sol Library.sol
Add --progress for terminal progress, or --profile-optimizer FILE to save
compiler timings as JSON. Run oksolc --help or oksolc <command> --help for
all options.
Point your project’s foundry.toml at the built executable and enable the
supported optimized via-IR pipeline:
[profile.default]
solc = "/absolute/path/to/oksolc/zig-out/bin/oksolc"
via_ir = true
optimizer = true
optimizer_runs = 200
Then run forge build as usual. Run forge clean first if you need to rebuild
artifacts produced by a previous compiler.
To enable parallel compilation for the project, add an oksolc.toml alongside
foundry.toml:
parallel = true
jobs = 4
For projects that manage libraries as Git submodules:
oksolc install
This uses Git to install the submodules needed by remappings.txt, including
nested dependencies, at the commits recorded by the repository. Without
remappings.txt, it installs all declared submodules; an empty file selects
none.
Git must be on PATH. Use --base-path PATH to select another project and
--jobs N to change the number of concurrent clones (default: 4). Git handles
credentials and checkout conflicts; resolve any conflict and rerun to continue.
Build with -Dbrowser=true to include the web browser, which updates as you edit:
oksolc serve --browse
Open http://127.0.0.1:8080. The browser provides source navigation, search,
definition links, references, diagnostics, ABI, bytecode, and other compiler
artifacts. Use --port to choose another port.
By default, serve watches Solidity files in src/ and their imported
dependencies. It reads remappings.txt and recompiles when sources, used
imports, or remappings change. To watch another source directory, set it in
oksolc.toml:
source-path = "contracts"
You can also use --source-path contracts. Restart the server after changing
oksolc.toml.
For a single compilation or an existing Standard JSON request/output pair:
oksolc browse src/Vault.sol
oksolc browse --request input.json
oksolc browse --request input.json --import-output output.json
Compilations are saved in .oksolc/browser.sqlite.
Note you should add .oksolc/ to your project .gitignore.
Run oksolc browse to reopen saved results. Select an older compilation to
inspect it, or Follow latest to return to live updates. Use
--database FILE for another location or --database :memory: for a temporary
session.
Without --browse, oksolc serve writes one Standard JSON result per line. You
can also watch a request file and update an output file after each change:
oksolc watch request.json -o output.json
For tool integrations, oksolc serve --stdio keeps a compiler session alive and
exchanges Standard JSON messages.
Project settings live in oksolc.toml. The project root is the nearest parent
containing that file or a .git marker, or the current directory if neither
exists. Commands accepting --base-path use that path as the project root.
User defaults live in $XDG_CONFIG_HOME/oksolc/config.toml, normally
~/.config/oksolc/config.toml. Project settings override user defaults, with
one exception: persistent compiler caching must be enabled in the user
configuration, outside the repository:
cache = true
Every compilation uses the incremental compiler. Long-running serve and
watch sessions reuse work in memory; persistent caching allows reuse between
processes. Each project’s cache is stored under
$XDG_CACHE_HOME/oksolc/projects-v2, normally ~/.cache/oksolc/projects-v2,
and authenticated with a local key created in the user configuration directory.
Use --no-cache or set cache = false in oksolc.toml to disable persistence.
Browser snapshots are saved separately, so they remain available with caching
off.
Inspect, prune, or remove the current project’s compiler cache:
oksolc cache stats
oksolc cache prune --max-bytes 8GiB --max-entries 51200
oksolc clean
Cache limits can also be set in oksolc.toml. The defaults are:
cache-max-entries = 102400
cache-max-bytes = "16GiB"
cache-busy-timeout-ms = 250
CI runs unit and ownership tests in Debug and compiler interface and output checks in ReleaseFast, in parallel. Debug retains runtime safety checks and avoids optimizing every unit-test binary. Run the same checks locally:
zig build test-unit -Doptimize=Debug -Dbrowser=true
zig build cli-smoke libsolc-c-smoke compatibility-check -Doptimize=ReleaseFast
zig build fmt-check
zig build lint
The separate fuzz workflow runs in ReleaseSafe. zig build test still runs
the combined suite, including compiler smoke tests, compatibility checks, and
fuzz seeds; use -Doptimize=ReleaseSafe for a full optimized safety-check run.
CI validates workflow definitions with actionlint. Run the same check locally before changing the workflows:
go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 -color
zig build check compiles the compiler, CLI, and tests without running the
unit-test executables. For browser changes, use:
zig build typecheck-browser test-browser-types
zig build browser-smoke test-cli test-browser-store -Dbrowser=true -Doptimize=ReleaseSafe
Compiler and CLI tests also work without the browser tools; omit -Dbrowser=true
to test the default build. Browser HTTP smoke targets (including
diagnostic-limit-smoke) require -Dbrowser=true. Explicit asset targets such
as build-browser, typecheck-browser, and test-browser-types always use the
browser tools.
The test suite compares against checked-in solc 0.8.36 outputs. Unoptimized
contract IR is compared as Yul tokens, allowing whitespace and comment changes
from direct tree generation. All other output bytes must match exactly. Run that
check alone, or audit the fixtures against your installed solc:
zig build compatibility-check
zig build reference-check -Dbenchmark-reference-solc=solc
See the compatibility corpus for fixture details. To run the parser, JSON, and Standard JSON fuzzers, plus the yyjson adapter under ASan/UBSan:
zig build fuzz --fuzz=10K -Dadapter-fuzz-runs=10000 -j2
Run benchmarks on an otherwise idle machine with a native ReleaseFast build.
Reports are written under build/benchmarks.
The local suite checks exact Standard JSON output against system solc, then
times three contracts:
zig build benchmark-local -Doptimize=ReleaseFast \
-Dbenchmark-reference-solc=solc -Dbenchmark-runs=3
For focused compiler and optimizer workloads:
zig build benchmark-zbench -Doptimize=ReleaseFast
For incremental compilation, the synthetic edit traces check output compatibility and record cache metrics:
zig build benchmark-incremental -Doptimize=ReleaseFast
The external suite compares oksolc with original solc 0.8.36. Replay the
imported Standard JSON requests without project downloads or Forge:
zig build benchmark-external -Doptimize=ReleaseFast \
-Dbenchmark-reference-solc=solc -Dbenchmark-runs=3 -Dbenchmark-warmups=1 \
-- --bundled-requests
Select projects with repeated --project NAME flags. For example, to compare
only Pendle, including all its production contracts and imported dependencies:
zig build benchmark-external -Doptimize=ReleaseFast \
-- --bundled-requests --project pendle-v2-2026-09-16
To download the pinned projects and capture fresh requests through Forge:
test/benchmarks/external-setup.sh
zig build benchmark-external -Doptimize=ReleaseFast
Setup also accepts --project NAME. Project checkouts go in the ignored
benchmarks/ directory; override it with BENCHMARK_DIR. Captured requests
are retained under build/benchmarks/external/<project>/requests/. To repeat
the comparison using exactly those requests:
zig build benchmark-external -Doptimize=ReleaseFast \
-- --reuse-captured-requests build/benchmarks/external
Use a new BENCHMARK_REPORT_DIR for another fresh capture. It also controls
where per-project JSON reports and numeric summaries are written. The direct
launcher accepts compiler paths and the measured run count:
zig build build-cli -Doptimize=ReleaseFast
test/benchmarks/external-compare.sh --bundled-requests \
solc zig-out/bin/oksolc 3
| Path | Contents |
|---|---|
src/cli/ | CLI and local compiler browser |
src/libsolidity/ | Solidity frontend and via-IR code generation |
src/libyul/ | Yul parser, analysis, code generation, and optimizer |
src/libevmasm/ | EVM assembly and optimization |
src/libsolc/ | Standard JSON dispatcher and C ABI |
src/incremental/ | Incremental compilation and persistent caching |
src/root.zig | Public solidity Zig API |
include/libsolc.h | Public C header |
test/zig/ | Unit, integration, CLI, and compatibility tests |
test/benchmarks/ | Benchmark fixtures and launchers |
build.zig | Build, test, and benchmark steps |
oksolc is licensed under the GNU General Public License v3.0.
See THIRD_PARTY_LICENSES.txt for dependency notices.
Zig
94.5%
Python
2.0%
oksolc is a Zig implementation of the Solidity compiler that we built for our
internal use in developing Chainwall.
Its goal is to provide an alternative implementation of Solidity for development purposes, allowing faster iteration on the developer experience.
We don’t consider oksolc to be production ready for deploying smart
contracts onchain, and recommend using the original solc compiler for
deployment. That said, we strive to be byte-compatible at this stage with
Solidity 0.8.36. Any deviation in compiler output should be considered a bug and
reported in Issues.
The supported compilation path is the optimized, via-IR compilation through the Standard JSON interface.
The project provides:
oksolc, a small command-line interfacelibsolc-compatible C ABI and installed libsolc.hsolidityNote this project was built with AI assistance (using GPT 5.5 then 5.6 Sol) but under strict human guidance and control, our team having previous experience in building compilers and in formal verification. We intend to publish the methods and controls that we used.
The compatibility target is the original Solidity 0.8.36 compiler for Standard
JSON, creation bytecode, diagnostics, and deterministic output.
The compile command enables the optimizer with 200 runs. Use standard-json
when exact control of compiler settings or output selection is required.
oksolc has an independent product version; the Solidity version identifies its compatibility target. See CHANGELOG.md for release history.
$ oksolc version
oksolc 0.1.4 (Solidity 0.8.36)
$ oksolc --version
oksolc, a solidity compiler commandline interface
Version: 0.8.36+oksolc.0.1.4
oksolc version --json returns version (the product version),
solidity_version (the compatibility target), compatibility_version (the
Solidity SemVer with oksolc build metadata), and build_identity (the compiler
content identity, or null if unavailable). Include this output in bug reports.
The public Zig module exposes the product version as solidity.version and the
Solidity target as solidity.baseline.version.
--version and the C ABI's solidity_version() retain a Solidity-compatible
SemVer for tools such as Foundry. Even development releases put the oksolc
version after +, so the Solidity target is still treated as a release.
Contract metadata and CBOR keep the pinned reference compiler identity to
preserve output and bytecode compatibility. Use the product version for upgrade
comparisons; SemVer precedence ignores the build metadata after +.
0.16.07.0.2 (tsc) and Bun 1.4.2 only for the optional web browserfuzz-json-adapter and fuzz (limited to
the yyjson adapter for now)solc version 0.8.36 for optional reference audits and benchmark
comparisonszstd to replay the bundled external benchmarks; Forge and Git to capture
fresh requests, plus Node.js/npm for old Uniswap and Node.js for Pendle setupThe first Zig build downloads the dependencies declared in build.zig.zon.
Build the CLI, shared library, and C header:
zig build -Doptimize=ReleaseFast
The executable is at zig-out/bin/oksolc; the library and header are in
zig-out/lib and zig-out/include. Add zig-out/bin to your PATH or install
to a different prefix:
zig build -Doptimize=ReleaseFast --prefix "$HOME/.local"
For development, omit -Doptimize for Debug mode, or use
-Doptimize=ReleaseSafe for an optimized build with runtime safety checks. To
build only the CLI, use zig build build-cli.
The web browser is disabled by default, so ordinary builds require neither Bun
nor TypeScript. To include oksolc browse and oksolc serve --browse, install
the pinned browser tools and opt in:
zig build -Doptimize=ReleaseFast -Dbrowser=true
Distribution builds can strip debug information and select a target:
zig build -Dtarget=aarch64-macos -Doptimize=ReleaseFast -Dstrip=true \
--prefix build/macos-arm64
zig build -Dtarget=x86_64-linux-gnu -Doptimize=ReleaseFast -Dstrip=true \
--prefix build/linux-amd64
Compile one or more Solidity files and write the Standard JSON result to stdout:
oksolc compile Contract.sol Library.sol
For control over compiler settings and requested artifacts, supply a Standard
JSON request from a file or stdin. Use -o to save the result:
oksolc standard-json request.json
oksolc standard-json - < request.json
oksolc standard-json -o build/output.json request.json
For filesystem imports, --base-path sets the source lookup root and repeatable
--include-path options add library directories (include paths require an
explicit base path).
AS of now, source paths must stay within the configured roots and cannot contain symlinks.
Independent contract backends can compile in parallel. --jobs sets total
concurrency, including the main thread:
oksolc compile --parallel --jobs 4 Contract.sol Library.sol
Add --progress for terminal progress, or --profile-optimizer FILE to save
compiler timings as JSON. Run oksolc --help or oksolc <command> --help for
all options.
Point your project’s foundry.toml at the built executable and enable the
supported optimized via-IR pipeline:
[profile.default]
solc = "/absolute/path/to/oksolc/zig-out/bin/oksolc"
via_ir = true
optimizer = true
optimizer_runs = 200
Then run forge build as usual. Run forge clean first if you need to rebuild
artifacts produced by a previous compiler.
To enable parallel compilation for the project, add an oksolc.toml alongside
foundry.toml:
parallel = true
jobs = 4
For projects that manage libraries as Git submodules:
oksolc install
This uses Git to install the submodules needed by remappings.txt, including
nested dependencies, at the commits recorded by the repository. Without
remappings.txt, it installs all declared submodules; an empty file selects
none.
Git must be on PATH. Use --base-path PATH to select another project and
--jobs N to change the number of concurrent clones (default: 4). Git handles
credentials and checkout conflicts; resolve any conflict and rerun to continue.
Build with -Dbrowser=true to include the web browser, which updates as you edit:
oksolc serve --browse
Open http://127.0.0.1:8080. The browser provides source navigation, search,
definition links, references, diagnostics, ABI, bytecode, and other compiler
artifacts. Use --port to choose another port.
By default, serve watches Solidity files in src/ and their imported
dependencies. It reads remappings.txt and recompiles when sources, used
imports, or remappings change. To watch another source directory, set it in
oksolc.toml:
source-path = "contracts"
You can also use --source-path contracts. Restart the server after changing
oksolc.toml.
For a single compilation or an existing Standard JSON request/output pair:
oksolc browse src/Vault.sol
oksolc browse --request input.json
oksolc browse --request input.json --import-output output.json
Compilations are saved in .oksolc/browser.sqlite.
Note you should add .oksolc/ to your project .gitignore.
Run oksolc browse to reopen saved results. Select an older compilation to
inspect it, or Follow latest to return to live updates. Use
--database FILE for another location or --database :memory: for a temporary
session.
Without --browse, oksolc serve writes one Standard JSON result per line. You
can also watch a request file and update an output file after each change:
oksolc watch request.json -o output.json
For tool integrations, oksolc serve --stdio keeps a compiler session alive and
exchanges Standard JSON messages.
Project settings live in oksolc.toml. The project root is the nearest parent
containing that file or a .git marker, or the current directory if neither
exists. Commands accepting --base-path use that path as the project root.
User defaults live in $XDG_CONFIG_HOME/oksolc/config.toml, normally
~/.config/oksolc/config.toml. Project settings override user defaults, with
one exception: persistent compiler caching must be enabled in the user
configuration, outside the repository:
cache = true
Every compilation uses the incremental compiler. Long-running serve and
watch sessions reuse work in memory; persistent caching allows reuse between
processes. Each project’s cache is stored under
$XDG_CACHE_HOME/oksolc/projects-v2, normally ~/.cache/oksolc/projects-v2,
and authenticated with a local key created in the user configuration directory.
Use --no-cache or set cache = false in oksolc.toml to disable persistence.
Browser snapshots are saved separately, so they remain available with caching
off.
Inspect, prune, or remove the current project’s compiler cache:
oksolc cache stats
oksolc cache prune --max-bytes 8GiB --max-entries 51200
oksolc clean
Cache limits can also be set in oksolc.toml. The defaults are:
cache-max-entries = 102400
cache-max-bytes = "16GiB"
cache-busy-timeout-ms = 250
CI runs unit and ownership tests in Debug and compiler interface and output checks in ReleaseFast, in parallel. Debug retains runtime safety checks and avoids optimizing every unit-test binary. Run the same checks locally:
zig build test-unit -Doptimize=Debug -Dbrowser=true
zig build cli-smoke libsolc-c-smoke compatibility-check -Doptimize=ReleaseFast
zig build fmt-check
zig build lint
The separate fuzz workflow runs in ReleaseSafe. zig build test still runs
the combined suite, including compiler smoke tests, compatibility checks, and
fuzz seeds; use -Doptimize=ReleaseSafe for a full optimized safety-check run.
CI validates workflow definitions with actionlint. Run the same check locally before changing the workflows:
go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 -color
zig build check compiles the compiler, CLI, and tests without running the
unit-test executables. For browser changes, use:
zig build typecheck-browser test-browser-types
zig build browser-smoke test-cli test-browser-store -Dbrowser=true -Doptimize=ReleaseSafe
Compiler and CLI tests also work without the browser tools; omit -Dbrowser=true
to test the default build. Browser HTTP smoke targets (including
diagnostic-limit-smoke) require -Dbrowser=true. Explicit asset targets such
as build-browser, typecheck-browser, and test-browser-types always use the
browser tools.
The test suite compares against checked-in solc 0.8.36 outputs. Unoptimized
contract IR is compared as Yul tokens, allowing whitespace and comment changes
from direct tree generation. All other output bytes must match exactly. Run that
check alone, or audit the fixtures against your installed solc:
zig build compatibility-check
zig build reference-check -Dbenchmark-reference-solc=solc
See the compatibility corpus for fixture details. To run the parser, JSON, and Standard JSON fuzzers, plus the yyjson adapter under ASan/UBSan:
zig build fuzz --fuzz=10K -Dadapter-fuzz-runs=10000 -j2
Run benchmarks on an otherwise idle machine with a native ReleaseFast build.
Reports are written under build/benchmarks.
The local suite checks exact Standard JSON output against system solc, then
times three contracts:
zig build benchmark-local -Doptimize=ReleaseFast \
-Dbenchmark-reference-solc=solc -Dbenchmark-runs=3
For focused compiler and optimizer workloads:
zig build benchmark-zbench -Doptimize=ReleaseFast
For incremental compilation, the synthetic edit traces check output compatibility and record cache metrics:
zig build benchmark-incremental -Doptimize=ReleaseFast
The external suite compares oksolc with original solc 0.8.36. Replay the
imported Standard JSON requests without project downloads or Forge:
zig build benchmark-external -Doptimize=ReleaseFast \
-Dbenchmark-reference-solc=solc -Dbenchmark-runs=3 -Dbenchmark-warmups=1 \
-- --bundled-requests
Select projects with repeated --project NAME flags. For example, to compare
only Pendle, including all its production contracts and imported dependencies:
zig build benchmark-external -Doptimize=ReleaseFast \
-- --bundled-requests --project pendle-v2-2026-09-16
To download the pinned projects and capture fresh requests through Forge:
test/benchmarks/external-setup.sh
zig build benchmark-external -Doptimize=ReleaseFast
Setup also accepts --project NAME. Project checkouts go in the ignored
benchmarks/ directory; override it with BENCHMARK_DIR. Captured requests
are retained under build/benchmarks/external/<project>/requests/. To repeat
the comparison using exactly those requests:
zig build benchmark-external -Doptimize=ReleaseFast \
-- --reuse-captured-requests build/benchmarks/external
Use a new BENCHMARK_REPORT_DIR for another fresh capture. It also controls
where per-project JSON reports and numeric summaries are written. The direct
launcher accepts compiler paths and the measured run count:
zig build build-cli -Doptimize=ReleaseFast
test/benchmarks/external-compare.sh --bundled-requests \
solc zig-out/bin/oksolc 3
| Path | Contents |
|---|---|
src/cli/ | CLI and local compiler browser |
src/libsolidity/ | Solidity frontend and via-IR code generation |
src/libyul/ | Yul parser, analysis, code generation, and optimizer |
src/libevmasm/ | EVM assembly and optimization |
src/libsolc/ | Standard JSON dispatcher and C ABI |
src/incremental/ | Incremental compilation and persistent caching |
src/root.zig | Public solidity Zig API |
include/libsolc.h | Public C header |
test/zig/ | Unit, integration, CLI, and compatibility tests |
test/benchmarks/ | Benchmark fixtures and launchers |
build.zig | Build, test, and benchmark steps |
oksolc is licensed under the GNU General Public License v3.0.
See THIRD_PARTY_LICENSES.txt for dependency notices.
Zig
94.5%
Python
2.0%