solidity Documentation

Solidity, the Smart Contract Programming Language

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy solidity on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name solidity --restart always argotorg/solidity:latest

Technical Documentation: argotorg/solidity

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

The Solidity Contract-Oriented Programming Language





You can talk to us on Gitter and Matrix, tweet at us on X (previously Twitter) or create a new topic in the Solidity forum. Questions, feedback, and suggestions are welcome!

Solidity is a statically-typed, contract-oriented, high-level language for implementing smart contracts on the Ethereum platform.

For a good overview and starting point, please check out the official Solidity Language Portal.

Table of Contents

Background

Solidity is a statically-typed curly-braces programming language designed for developing smart contracts
that run on the Ethereum Virtual Machine. Smart contracts are programs that are executed inside a peer-to-peer
network where nobody has special authority over the execution, and thus they allow anyone to implement tokens of value,
ownership, voting, and other kinds of logic.

When deploying contracts, you should use the latest released version of
Solidity. This is because breaking changes, as well as new features and bug fixes, are
introduced regularly. We currently use a 0.x version
number to indicate this fast pace of change.

Build and Install

Instructions about how to build and install the Solidity compiler can be
found in the Solidity documentation.

Example

A "Hello World" program in Solidity is of even less use than in other languages, but still:

solidity
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;

contract HelloWorld {
    function helloWorld() external pure returns (string memory) {
        return "Hello, World!";
    }
}

To get started with Solidity, you can use Remix, which is a
browser-based IDE. Here are some example contracts:

  1. Voting
  2. Blind Auction
  3. Safe remote purchase
  4. Micropayment Channel

Documentation

The Solidity documentation is hosted using Read the Docs.

Development

Solidity is still under development. Contributions are always welcome!
Please follow the
Developer's Guide
if you want to help.

You can find our current feature and bug priorities for forthcoming
releases in the projects section.

Maintainers

The Solidity programming language and compiler are open-source community projects governed by a core team.
The core team is part of the Argot Collective, a non-profit that develops and maintains Solidity.
The project was originally started at and sponsored by the Ethereum Foundation.

License

Solidity is licensed under GNU General Public License v3.0.

Some third-party code has its own licensing terms.

Security

The security policy may be found here.


Overview (`.circleci/README.md`)

CircleCI integration

Docker images

The docker images are built locally on the developer machine:

sh
cd .circleci/docker/

docker build -t ethereum/solidity-buildpack-deps:ubuntu2404-<revision> -f Dockerfile.ubuntu2404 .
docker push ethereum/solidity-buildpack-deps:ubuntu2404-<revision>

The current revisions per docker image are stored in circle ci pipeline parameters called -docker-image-rev (e.g., ubuntu-2404-docker-image-rev). Please update the value assigned to the parameter(s) corresponding to the docker image(s) being updated at the time of the update. Please verify that the value assigned to the parameter matches the revision part of the docker image tag (<revision> in the docker build/push snippet shown above). Otherwise, the docker image used by circle ci and the one actually pushed to docker hub will differ.

Once the docker image has been built and pushed to Docker Hub, you can find it at:

text
https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu2404-<revision>

where the image tag reflects the target OS and revision to build Solidity and run its tests on.

Testing docker images locally

sh
cd solidity
# Mounts your local solidity directory in docker container for testing
docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu2404-<revision> /bin/bash
cd /src/solidity
<commands_to_test_build_with_new_docker_image>

Overview (`docs/README.md`)

Solidity Language Docs

Local environment setup

  1. Install python https://www.python.org/downloads/
  2. Install sphinx (the tool used to generate the docs) https://www.sphinx-doc.org/en/master/usage/installation.html

Go to /docs and run ./docs.sh to install dependencies and build the project:

sh
cd docs
./docs.sh

That will output the generated htmls under _build/

Serve environment

py
python3 -m http.server -d _build/html --cgi 8080

Visit dev server at http://localhost:8080


Overview (`libyul/optimiser/README.md`)

Yul-Based Optimizer

The documentation of the Yul-based optimizer module has been moved to the official Solidity documentation.

Please refer to the optimizer documentation for a description of all optimization stages and how to use the optimizer and to the Yul documentation for more information on the optimization step sequence and a list of abbreviations for each step.


Overview (`test/compilationTests/README.md`)

This directory contains various Solidity contract source code files
that are compiled as part of the regular tests.

These contracts are externally contributed and their presence in this
repository does not make any statement about their quality or usefulness.


Overview (`test/ethdebugSchemaTests/README.md`)

ETHDebug schema tests

These tests validate Solidity's ETHDebug output against a pinned checkout of the upstream ethdebug/format JSON Schemas.

The schema checkout is a git submodule at test/ethdebugSchemaTests/ethdebug-format. Initialize it with:

bash
git submodule update --init test/ethdebugSchemaTests/ethdebug-format

Run the tests with:

bash
pytest test/ethdebugSchemaTests --solc-binary-path=build/solc/solc -v

The JSON inputs use contentFile entries to keep Solidity examples in regular
.sol fixture files under sources/. The pytest harness expands those entries
to Standard JSON content before invoking solc.

To update the schema version, bump the submodule commit and rerun this suite.


Overview (`test/evmc/README.md`)

EVMC

This is an import of EVMC version 12.0.0.

Steps when upgrading:

  • Copy all from include/evmc to test/evmc
    • Note that you should delete (or not copy in the first place) tooling.hpp and instructions.h.
  • Copy loader.c to test/evmc
  • MockedAccount.storage in mocked_host.hpp should be changed to a map from unordered_map as ordering is important for fuzzing. You'll also need to include <map>.
    See PR #11094 for more details.

Overview (`test/externalTests/README.md`)

Solidity external tests

This directory contains scripts for compiling some of the popular open-source projects using the
current version of the compiler and running their test suites.

Since projects often do not use the latest compiler, we keep a fork of each of these projects
at https://github.com/solidity-external-tests/. If changes are needed to make a project work with the
latest version of the compiler, they are maintained as a branch on top of the upstream master branch.
This is especially important for testing our breaking branch because we can not realistically expect
external projects to be instantly compatible with a compiler version that has not been released yet.
Applying necessary changes ourselves gives us confidence that breaking changes are sane and that
these projects can be upgraded at all.

Adding a new external project

  1. If the upstream code cannot be compiled without modifications, create a fork of the repository
    in https://github.com/solidity-external-tests/.
  2. In our fork, remove all the branches except for the main one (master, develop, main, etc).
    This branch is going to be always kept up to date with the upstream repository and should not
    contain any extra commits.
    • If the project is not up to date with the latest compiler version but has a branch that is,
      try to use that branch instead.
  3. In our fork, create a new branch named after the main branch and the compiler version from our
    develop branch.
    E.g. if the latest Solidity version is 0.7.5 and the main branch of the external project
    is called master, create master_070. This is where we will be adding our own commits.
  4. Create a script for compiling/testing the project and put it in test/externalTests/ in the
    Solidity repository.
    • The script should apply workarounds necessary to make the project actually use the compiler
      binary it receives as a parameter and possibly add generic workarounds that should
      work across different versions of the upstream project.
    • Very specific workarounds that may easily break with every upstream change are better done as
      commits in the newly added branch in the fork instead.
  5. List the script in test/externalTests.sh.
  6. Add the script to CircleCI configuration. Make sure to add both a compilation-only run and one that
    also executes the test suite. If the latter takes a significant amount of time (say, more than
    15 minutes) make it run nightly rather than on every PR.
  7. Make sure that tests pass both on develop and on breaking. If the compiler from breaking
    branch will not work without additional changes, add another branch, called after it in turn,
    and add necessary workarounds there. Continuing the example above, the new branch would be
    called master_080 and should be rebased on top of master_070.
    • The fewer commits in these branches, the better. Ideally, any changes needed to make the compiler
      work should be submitted upstream and our scripts should be using the upstream repository
      directly.

Updating external projects for a PR that introduces breaking changes in the compiler

If a PR to our breaking branch introduces changes that will make an external project no longer
compile or pass its tests, the fork needs to be modified (or created if it does not yet exist):

  • If a branch specific to the compiler version from breaking does not exist yet:
    1. Create the branch. It should be based on the version-specific branch used on develop.
    2. Make your PR modify the project script in test/externalScripts/ to use the new branch.
    3. You are free to add any changes you need in the new branch since it will not interfere with
      tests on breaking.
    4. Work on your PR until it is approved and merged into breaking.
  • If the branch already exists and our CI depends on it:
    1. If the external project after your changes can still work with breaking even without your PR or
      if you know that the PR is straightforward and will be merged immediately without interfering
      with tests on breaking for a significant amount of time, you can just push your modifications
      to the branch directly and skip straight to steps 4. and 6.
    2. Create a PR in the fork, targeting the existing version-specific branch.
    3. In your PR to breaking, modify the corresponding script in test/externalScripts/ to
      use the branch from your PR in the fork.
    4. Work on your PR until it is approved and ready to merge.
    5. Merge the PR in the fork.
    6. Discard your changes to the script and merge your PR into breaking.

Pulling upstream changes into a fork

  1. Pull changes directly into the main branch in the fork. This should be straightforward thanks to
    it not containing any of our customizations.
  2. If the project has been updated to a newer Solidity version, abandon the current version-specific
    branch used on develop (but do not delete it) and create a new one corresponding to the newer
    version. Then update project script in test/externalTests/ to use the new branch. E.g. if develop uses
    master_050 and the project has been updated to use Solidity 0.7.3, create master_070.
  3. Otherwise, rebase the current version-specific branch on the main branch of the fork. This may require
    tweaking some of the commits to apply our fixes in new places.
  4. If we have a separate branch for breaking, rebase it on top of the one used on develop.

The above is the workflow to use when the update is straightforward and looks safe. In that case it is
fine to just modify the branches directly. If this is not the case, it is recommended to first perform the
operation on copies of these version-specific branches and test them by creating PRs on develop and
breaking to see if tests pass. The PRs should just modify project scripts in test/externalScripts/
to use the updated copies of the branches and can be discarded afterwards without being merged.

Changes needed after a breaking release of the compiler

When a non-backwards-compatible version becomes the most recent release, breaking branch
gets merged into develop which automatically results in a switch to the newer version-specific
branches if they exist. If no changes on our part were necessary, it is completely fine to keep using
e.g. the master_060 of an external project in Solidity 0.8.x.

Since each project is handled separately, this approach may result in a mix of version-specific branches
between different external projects. For example, in one project we could have master_050 on
both develop and breaking and in another breaking could use master_080 while develop still
uses master_060.


Overview (`test/formal/README.md`)

The Solidity compiler implements several optimization rules.

This directory contains an effort to formally prove the correctness of those rules in:


Overview (`test/fuzztest/README.md`)

Property-based / fuzz tests

This directory holds property-based / fuzz tests built
on Google FuzzTest (vendored at deps/fuzztest).
Instead of asserting a fixed output for a fixed input, a property test states a property that must hold for all inputs
from a domain, and FuzzTest searches that domain for counterexamples.

Options

Two CMake options control this (defined in cmake/EthOptions.cmake):

  • PROPERTY_BASED_TESTS (default OFF) — master on/off switch. While it is OFF, deps/fuzztest is never added
    to the build, so none of its transitive FetchContent dependencies are configured.
  • PROPERTY_BASED_TESTS_MODE (default unittest, values unittest / fuzzing). Selects the run mode. Only
    meaningful when PROPERTY_BASED_TESTS is ON.
    • unittest: each FUZZ_TEST runs as an ordinary test case with a 1sec burst of random inputs.
    • fuzzing: coverage-guided fuzzing. Requires Clang.

Configure

sh
# unit-test mode (works with the default g++ build)
cmake -S . -B build-prop -G Ninja -DPROPERTY_BASED_TESTS=ON

# fuzzing mode (Clang required)
CC=clang CXX=clang++ cmake -S . -B build-fuzz -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/fuzztest.cmake

Overview (`tools/yulPhaser/README.md`)

yul-phaser

yul-phaser is an internal tool for finding good sequences of optimisation steps for Yul optimiser.

How it works

The space of possible solutions to this problem (usually referred to as phase-ordering problem) is extremely large and there may even be no single sequence that produces optimal results for all possible programs.

The tool uses genetic algorithms to find sequences that result in better programs than others and to iteratively refine them.
The input is a set of one or more Yul programs and each sequence is applied to all of these programs.
Optimised programs are given numeric scores according to the selected metric.

Optimisation step sequences are presented in an abbreviated form - as strings of letters where each character represents one step.
There's a table listing available abbreviations in the optimiser docs.

How to use it

The application has sensible defaults for most parameters.
An invocation can be as simple as:

bash
tools/yul-phaser ../test/libyul/yulOptimizerTests/fullSuite/*.yul \
    --random-population 100

This assumes that you have a working copy of the Solidity repository and you're in the build directory within that working copy.

Run yul-phaser --help for a full list of available options.

Restarting from a previous state

yul-phaser can save the list of sequences found after each round:

bash
tools/yul-phaser *.yul        \
    --random-population   100 \
    --population-autosave /tmp/population.txt

If you stop the application, you can later use the file to continue the search from the point you left off:

bash
tools/yul-phaser *.yul                         \
    --population-from-file /tmp/population.txt \
    --population-autosave  /tmp/population.txt

Analysing a sequence

Apart from running the genetic algorithm, yul-phaser can also provide useful information about a particular sequence.

For example, to see the value of a particular metric for a given sequence and program run:

bash
tools/yul-phaser *.yul            \
    --show-initial-population     \
    --rounds            0         \
    --metric            code-size \
    --metric-aggregator sum       \
    --population        <your sequence>

You can also easily see program code after being optimised using that sequence:

bash
tools/yul-phaser *.yul                    \
    --rounds     0                        \
    --mode       print-optimised-programs \
    --population <your sequence>

Using output from Solidity compiler

yul-phaser can process the intermediate representation produced by solc:

bash
solc/solc <sol file> --ir --output-dir <output directory>

After running this command you'll find one or more .yul files in the output directory.
These files contain whole Yul objects rather than just raw Yul programs but yul-phaser is prepared to handle them too.

Using optimisation step sequences with the compiler

You can tell Yul optimiser to use a specific sequence for your code by passing --yul-optimizations option to solc:

bash
solc/solc <sol file> --optimize --ir-optimized --yul-optimizations <sequence>

How to choose good parameters

Choosing good parameters for a genetic algorithm is not a trivial task but phaser's defaults are generally enough to find a sequence that gives results comparable or better than one hand-crafted by an experienced developer for a given set of programs.
The difficult part is providing a fairly representative set of input files.
If the files you give do not need certain optimisations the tool will find sequences that do not use these optimisations and perform badly for programs that could benefit from them.
If all the provided files greatly benefit from a specific optimisation, the sequence may not work well for programs that do not.

We have conducted a set of rough experiments to evaluate some combinations of parameter values.
The conclusions were used to adjust the defaults but you might still benefit from some general observations:

  1. The algorithm that performed the best was GEWEP.
  2. Using longer sequences in the initial population yields better results. The algorithm is good at removing superfluous steps.
  3. Preserving the top sequences from previous rounds improves results. Elite should contain at least a few individuals, especially when using the classic algorithm.
  4. Do not set mutation/deletion/addition chance too high. It makes results worse because it destroys the good patterns preserved by crossover. Values around 1-5% seem to work best.
  5. Keep the algorithm running for 1000 rounds or more. It usually finds good sequences faster than that but it can shorten them significantly if you let it run longer. This is especially important when starting with long sequences.

Overview (`libsolidity/codegen/ir/README.md`)

The Solidity to Yul Code Generator

This directory contains the new experimental code generator that
compiles Solidity to an intermediate representation in Yul
with EVM dialect.

The main semantic differences to the legacy code generator are the following:

  • Arithmetic operations cause a failing assertion if the result is not in range.
  • Resizing a storage array to a length larger than 2**64 causes a failing assertion.

Overview (`scripts/docker/buildpack-deps/README.md`)

buildpack-deps docker images

The buildpack-deps docker images are used to compile and test solidity within our CI.

GitHub Workflow

The creation of the images is triggered by a single workflow, defined in .github/workflows/buildpack-deps.yml.
For each resulting buildpack-deps docker image a strategy is defined in the workflow file - the image variant.
The workflow gets triggered, if any Dockerfile defined in scripts/docker/buildpack-deps/Dockerfile.* was changed
within the PR.

Versioning

The version of the docker images can be defined within the Dockerfile with LABEL version. A new docker image
will only be created and pushed, if the new version is incremented by 1 compared with the version of the Dockerfile
located in develop.

Build, Test & Push

Note that the whole workflow - including all defined strategies (image variants) - will be triggered,
even if only a single Dockerfile was changed. The full workflow will only get executed, if the corresponding
Dockerfile was changed. The execution of workflows of unchanged Dockerfiles will not continue and just return success.
See scripts/ci/docker_upgrade.sh.

If the version check was successful, the docker image will be built using the Dockerfile located in
scripts/docker/buildpack-deps/Dockerfile.*.

The resulting docker image will be tested by executing the corresponding scripts/ci/buildpack-deps_test_* scripts.
Some of these scripts are symlinked to scripts/ci/build.sh, except the following two:

  • buildpack-deps-ubuntu.clang.ossfuzz => scripts/ci/build_ossfuzz.sh
  • buildpack-deps_test_emscripten.sh => scripts/ci/build_emscripten.sh

These scripts scripts/ci/build.sh and scripts/ci/build_ossfuzz.sh are also used by CircleCI, see .circleci/config.yml.

If the tests passed successfully, the docker image will get tagged by the version defined within the corresponding Dockerfile.
Finally, a comment will be added to the PR that contains the full repository, version and repository digest
of the freshly created docker image.

The files .circleci/config.yml and scripts/build_emscripten.sh need to be updated with the new hash posted in the comment.


Overview (`test/compilationTests/MultiSigWallet/README.md`)

MultiSigWallet contracts, originally from

https://github.com/ConsenSys/MultiSigWallet


Overview (`test/compilationTests/corion/README.md`)

CORION contracts, originally from

https://github.com/CORIONplatform/solidity


Overview (`test/compilationTests/gnosis/README.md`)

Gnosis contracts, originally from

https://github.com/gnosis/gnosis-contracts


Overview (`test/compilationTests/milestonetracker/README.md`)

Giveth milestone tracker, originally from

https://github.com/Giveth/milestonetracker/


Overview (`test/tools/ossfuzz/README.md`)

Intro

oss-fuzz is Google's fuzzing infrastructure that performs continuous fuzzing. What this means is that, each and every upstream commit is automatically fetched by the infrastructure and fuzzed on a daily basis.

How to build fuzzers?

We have multiple fuzzers, some based on string input and others on protobuf input. To build them, please do the following:

  • Create a local docker image from Dockerfile.ubuntu.clang.ossfuzz in the .circleci/docker sub-directory. Please note that this step is likely to take at least an hour to complete. Therefore, it is recommended to do it when you are away from the computer (and the computer is plugged to power since we do not want a battery drain).
text
$ cd .circleci/docker
$ docker build -t solidity-ossfuzz-local -f Dockerfile.ubuntu.clang.ossfuzz .
  • Login to the docker container sourced from the image built in the previous step from the solidity parent directory
text
## Host
$ cd solidity
$ docker run -v `pwd`:/src/solidity -ti solidity-ossfuzz-local /bin/bash
## Docker shell
$ cd /src/solidity
  • Run cmake and build fuzzer harnesses
text
## Docker shell
$ cd /src/solidity
$ rm -rf fuzzer-build && mkdir fuzzer-build && cd fuzzer-build
## Compile protobuf C++ bindings
$ protoc --proto_path=../test/tools/ossfuzz yulProto.proto --cpp_out=../test/tools/ossfuzz
$ protoc --proto_path=../test/tools/ossfuzz abiV2Proto.proto --cpp_out=../test/tools/ossfuzz
$ protoc --proto_path=../test/tools/ossfuzz solProto.proto --cpp_out=../test/tools/ossfuzz
## Run cmake
$ export CC=clang CXX=clang++
$ cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/libfuzzer.cmake -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-Release} ..
$ make ossfuzz ossfuzz_proto ossfuzz_abiv2 -j

Why the elaborate docker image to build fuzzers?

For the following reasons:

  • Fuzzing binaries must link against libc++ and not libstdc++

    • This is because (1) MemorySanitizer (which flags uses of uninitialized memory) depends on libc++; and (2) because libc++ is instrumented (to check for memory and type errors) and libstdc++ not, the former may find more bugs.
  • Linking against libc++ requires us to compile everything solidity depends on from source (and link these against libc++ as well)

  • To reproduce the compiler versions used by upstream oss-fuzz bots, we need to reuse their docker image containing the said compiler versions

  • Some fuzzers depend on libprotobuf, libprotobuf-mutator, libevmone etc. which may not be available locally; even if they were they might not be the right versions

What is LIB\_FUZZING\_ENGINE?

oss-fuzz contains multiple fuzzer back-ends i.e., fuzzers. Each back-end may require different linker flags. oss-fuzz builder bot defines the correct linker flags via a bash environment variable called LIB_FUZZING_ENGINE.

For the solidity ossfuzz CI build, we use the libFuzzer back-end. This back-end requires us to manually set the LIB_FUZZING_ENGINE to -fsanitize=fuzzer.

What does the ossfuzz directory contain?

To help oss-fuzz do this, we (as project maintainers) need to provide the following:

  • test harnesses: C/C++ tests that define the LLVMFuzzerTestOneInput API. This determines what is to be fuzz tested.
  • build infrastructure: (c)make targets per fuzzing binary. Fuzzing requires coverage and memory instrumentation of the code to be fuzzed.
  • configuration files: These are files with the .options extension that are parsed by oss-fuzz. The only option that we use currently is the dictionary option that asks the fuzzing engines behind oss-fuzz to use the specified dictionary. The specified dictionary happens to be solidity.dict.

solidity.dict contains Solidity-specific syntactical tokens that are more likely to guide the fuzzer towards generating parseable and varied Solidity input.

To be consistent and aid better evaluation of the utility of the fuzzing dictionary, we stick to the following rules-of-thumb:

  • Full tokens such as block.number are preceded and followed by a whitespace
  • Incomplete tokens including function calls such as msg.sender.send() are abbreviated .send( to provide some leeway to the fuzzer to synthesize variants such as address(this).send()
  • Language keywords are suffixed by a whitespace with the exception of those that end a line of code such as break; and continue;

Overview (`test/libsolidity/semanticTests/externalContracts/_prbmath/README.md`)

Imported from https://github.com/hifi-finance/prb-math/commit/62021c1abc3413f20d0bdc8f941cf9f21d5a7d2d


Overview (`test/libsolidity/semanticTests/externalContracts/_stringutils/README.md`)

String utilities, originally from

https://github.com/Arachnid/solidity-stringutils


050 Breaking Changes (`docs/050-breaking-changes.rst`)


Solidity v0.5.0 Breaking Changes


This section highlights the main breaking changes introduced in Solidity
version 0.5.0, along with the reasoning behind the changes and how to update
affected code.
For the full list check
the release changelog <https://github.com/argotorg/solidity/releases/tag/v0.5.0>_.

.. note::
Contracts compiled with Solidity v0.5.0 can still interface with contracts
and even libraries compiled with older versions without recompiling or
redeploying them. Changing the interfaces to include data locations and
visibility and mutability specifiers suffices. See the
:ref:Interoperability With Older Contracts section below.

Semantic Only Changes

This section lists the changes that are semantic-only, thus potentially
hiding new and different behavior in existing code.

  • Signed right shift now uses proper arithmetic shift, i.e. rounding towards
    negative infinity, instead of rounding towards zero. Signed and unsigned
    shift will have dedicated opcodes in Constantinople, and are emulated by
    Solidity for the moment.

  • The continue statement in a do...while loop now jumps to the
    condition, which is the common behavior in such cases. It used to jump to the
    loop body. Thus, if the condition is false, the loop terminates.

  • The functions .call(), .delegatecall() and .staticcall() do not
    pad anymore when given a single bytes parameter.

  • Pure and view functions are now called using the opcode STATICCALL
    instead of CALL if the EVM version is Byzantium or later. This
    disallows state changes on the EVM level.

  • The ABI encoder now properly pads byte arrays and strings from calldata
    (msg.data and external function parameters) when used in external
    function calls and in abi.encode. For unpadded encoding, use
    abi.encodePacked.

  • The ABI decoder reverts in the beginning of functions and in
    abi.decode() if passed calldata is too short or points out of bounds.
    Note that dirty higher order bits are still simply ignored.

  • Forward all available gas with external function calls starting from
    Tangerine Whistle.

Semantic and Syntactic Changes

This section highlights changes that affect syntax and semantics.

  • The functions .call(), .delegatecall(), staticcall(),
    keccak256(), sha256() and ripemd160() now accept only a single
    bytes argument. Moreover, the argument is not padded. This was changed to
    make more explicit and clear how the arguments are concatenated. Change every
    .call() (and family) to a .call("") and every .call(signature, a, b, c) to use .call(abi.encodeWithSignature(signature, a, b, c)) (the
    last one only works for value types). Change every keccak256(a, b, c) to
    keccak256(abi.encodePacked(a, b, c)). Even though it is not a breaking
    change, it is suggested that developers change
    x.call(bytes4(keccak256("f(uint256)")), a, b) to
    x.call(abi.encodeWithSignature("f(uint256)", a, b)).

  • Functions .call(), .delegatecall() and .staticcall() now return
    (bool, bytes memory) to provide access to the return data. Change
    bool success = otherContract.call("f") to (bool success, bytes memory data) = otherContract.call("f").

  • Solidity now implements C99-style scoping rules for function local
    variables, that is, variables can only be used after they have been
    declared and only in the same or nested scopes. Variables declared in the
    initialization block of a for loop are valid at any point inside the
    loop.

Explicitness Requirements

This section lists changes where the code now needs to be more explicit.
For most of the topics the compiler will provide suggestions.

  • Explicit function visibility is now mandatory. Add public to every
    function and constructor, and external to every fallback or interface
    function that does not specify its visibility already.

  • Explicit data location for all variables of struct, array or mapping types is
    now mandatory. This is also applied to function parameters and return
    variables. For example, change uint[] x = z to uint[] storage x = z, and function f(uint[][] x) to function f(uint[][] memory x)
    where memory is the data location and might be replaced by storage or
    calldata accordingly. Note that external functions require
    parameters with a data location of calldata.

  • Contract types do not include address members anymore in
    order to separate the namespaces. Therefore, it is now necessary to
    explicitly convert values of contract type to addresses before using an
    address member. Example: if c is a contract, change
    c.transfer(...) to address(c).transfer(...),
    and c.balance to address(c).balance.

  • Explicit conversions between unrelated contract types are now disallowed. You can only
    convert from a contract type to one of its base or ancestor types. If you are sure that
    a contract is compatible with the contract type you want to convert to, although it does not
    inherit from it, you can work around this by converting to address first.
    Example: if A and B are contract types, B does not inherit from A and
    b is a contract of type B, you can still convert b to type A using A(address(b)).
    Note that you still need to watch out for matching payable fallback functions, as explained below.

  • The address type was split into address and address payable,
    where only address payable provides the transfer function. An
    address payable can be directly converted to an address, but the
    other way around is not allowed. Converting address to address payable is possible via conversion through uint160. If c is a
    contract, address(c) results in address payable only if c has a
    payable fallback function. If you use the :ref:withdraw pattern<withdrawal_pattern>,
    you most likely do not have to change your code because transfer
    is only used on msg.sender instead of stored addresses and msg.sender
    is an address payable.

  • Conversions between bytesX and uintY of different size are now
    disallowed due to bytesX padding on the right and uintY padding on
    the left which may cause unexpected conversion results. The size must now be
    adjusted within the type before the conversion. For example, you can convert
    a bytes4 (4 bytes) to a uint64 (8 bytes) by first converting the
    bytes4 variable to bytes8 and then to uint64. You get the
    opposite padding when converting through uint32. Before v0.5.0 any
    conversion between bytesX and uintY would go through uint8X. For
    example uint8(bytes3(0x291807)) would be converted to uint8(uint24(bytes3(0x291807)))
    (the result is 0x07).

  • Using msg.value in non-payable functions (or introducing it via a
    modifier) is disallowed as a security feature. Turn the function into
    payable or create a new internal function for the program logic that
    uses msg.value.

  • For clarity reasons, the command-line interface now requires - if the
    standard input is used as source.

Deprecated Elements

This section lists changes that deprecate prior features or syntax. Note that
many of these changes were already enabled in the experimental mode
v0.5.0.

Command-line and JSON Interfaces

  • The command-line option --formal (used to generate Why3 output for
    further formal verification) was deprecated and is now removed. A new
    formal verification module, the SMTChecker, is enabled via pragma experimental SMTChecker;.

  • The command-line option --julia was renamed to --yul due to the
    renaming of the intermediate language Julia to Yul.

  • The --clone-bin and --combined-json clone-bin command-line options
    were removed.

  • Remappings with empty prefix are disallowed.

  • The JSON AST fields constant and payable were removed. The
    information is now present in the stateMutability field.

  • The JSON AST field isConstructor of the FunctionDefinition
    node was replaced by a field called kind which can have the
    value "constructor", "fallback" or "function".

  • In unlinked binary hex files, library address placeholders are now
    the first 36 hex characters of the keccak256 hash of the fully qualified
    library name, surrounded by $...$. Previously,
    just the fully qualified library name was used.
    This reduces the chances of collisions, especially when long paths are used.
    Binary files now also contain a list of mappings from these placeholders
    to the fully qualified names.

Constructors

  • Constructors must now be defined using the constructor keyword.

  • Calling base constructors without parentheses is now disallowed.

  • Specifying base constructor arguments multiple times in the same inheritance
    hierarchy is now disallowed.

  • Calling a constructor with arguments but with wrong argument count is now
    disallowed. If you only want to specify an inheritance relation without
    giving arguments, do not provide parentheses at all.

Functions

  • Function callcode is now disallowed (in favor of delegatecall). It
    is still possible to use it via inline assembly.

  • suicide is now disallowed (in favor of selfdestruct).

  • sha3 is now disallowed (in favor of keccak256).

  • throw is now disallowed (in favor of revert, require and
    assert).

Conversions

  • Explicit and implicit conversions from decimal literals to bytesXX types
    is now disallowed.

  • Explicit and implicit conversions from hex literals to bytesXX types
    of different size is now disallowed.

Literals and Suffixes

  • The unit denomination years is now disallowed due to complications and
    confusions about leap years.

  • Trailing dots that are not followed by a number are now disallowed.

  • Combining hex numbers with unit denominations (e.g. 0x1e wei) is now
    disallowed.

  • The prefix 0X for hex numbers is disallowed, only 0x is possible.

Variables

  • Declaring empty structs is now disallowed for clarity.

  • The var keyword is now disallowed to favor explicitness.

  • Assignments between tuples with different number of components is now
    disallowed.

  • Values for constants that are not compile-time constants are disallowed.

  • Multi-variable declarations with mismatching number of values are now
    disallowed.

  • Uninitialized storage variables are now disallowed.

  • Empty tuple components are now disallowed.

  • Detecting cyclic dependencies in variables and structs is limited in
    recursion to 256.

  • Fixed-size arrays with a length of zero are now disallowed.

Syntax

  • Using constant as function state mutability modifier is now disallowed.

  • Boolean expressions cannot use arithmetic operations.

  • The unary + operator is now disallowed.

  • Literals cannot anymore be used with abi.encodePacked without prior
    conversion to an explicit type.

  • Empty return statements for functions with one or more return values are now
    disallowed.

  • The "loose assembly" syntax is now disallowed entirely, that is, jump labels,
    jumps and non-functional instructions cannot be used anymore. Use the new
    while, switch and if constructs instead.

  • Functions without implementation cannot use modifiers anymore.

  • Function types with named return values are now disallowed.

  • Single statement variable declarations inside if/while/for bodies that are
    not blocks are now disallowed.

  • New keywords: calldata and constructor.

  • New reserved keywords: alias, apply, auto, copyof,
    define, immutable, implements, macro, mutable,
    override, partial, promise, reference, sealed,
    sizeof, supports, typedef and unchecked.

.. _interoperability:

Interoperability With Older Contracts

It is still possible to interface with contracts written for Solidity versions prior to
v0.5.0 (or the other way around) by defining interfaces for them.
Consider you have the following pre-0.5.0 contract already deployed:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
// This will report a warning until version 0.4.25 of the compiler
// This will not compile after 0.5.0
contract OldContract {
    function someOldFunction(uint8 a) {
        //...
    }
    function anotherOldFunction() constant returns (bool) {
        //...
    }
    // ...
}

This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
interface OldContract {
    function someOldFunction(uint8 a) external;
    function anotherOldFunction() external returns (bool);
}

Note that we did not declare anotherOldFunction to be view, despite it being declared constant in the original
contract. This is due to the fact that starting with Solidity v0.5.0 staticcall is used to call view functions.
Prior to v0.5.0 the constant keyword was not enforced, so calling a function declared constant with staticcall
may still revert, since the constant function may still attempt to modify storage. Consequently, when defining an
interface for older contracts, you should only use view in place of constant in case you are absolutely sure that
the function will work with staticcall.

Given the interface defined above, you can now easily use the already deployed pre-0.5.0 contract:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

interface OldContract {
    function someOldFunction(uint8 a) external;
    function anotherOldFunction() external returns (bool);
}

contract NewContract {
    function doSomething(OldContract a) public returns (bool) {
        a.someOldFunction(0x42);
        return a.anotherOldFunction();
    }
}

Similarly, pre-0.5.0 libraries can be used by defining the functions of the library without implementation and
supplying the address of the pre-0.5.0 library during linking (see :ref:commandline-compiler for how to use the
commandline compiler for linking):

.. code-block:: solidity

text
// This will not compile after 0.6.0
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;

library OldLibrary {
    function someFunction(uint8 a) public returns(bool);
}

contract NewContract {
    function f(uint8 a) public returns (bool) {
        return OldLibrary.someFunction(a);
    }
}

Example

The following example shows a contract and its updated version for Solidity
v0.5.0 with some of the changes listed in this section.

Old version:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
// This will not compile after 0.5.0

contract OtherContract {
    uint x;
    function f(uint y) external {
        x = y;
    }
    function() payable external {}
}

contract Old {
    OtherContract other;
    uint myNumber;

    // Function mutability not provided, not an error.
    function someInteger() internal returns (uint) { return 2; }

    // Function visibility not provided, not an error.
    // Function mutability not provided, not an error.
    function f(uint x) returns (bytes) {
        // Var is fine in this version.
        var z = someInteger();
        x += z;
        // Throw is fine in this version.
        if (x > 100)
            throw;
        bytes memory b = new bytes(x);
        y = -3 >> 1;
        // y == -1 (wrong, should be -2)
        do {
            x += 1;
            if (x > 10) continue;
            // 'Continue' causes an infinite loop.
        } while (x < 11);
        // Call returns only a Bool.
        bool success = address(other).call("f");
        if (!success)
            revert();
        else {
            // Local variables could be declared after their use.
            int y;
        }
        return b;
    }

    // No need for an explicit data location for 'arr'
    function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
        otherContract.transfer(1 ether);

        // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
        // the first 4 bytes of x will be lost. This might lead to
        // unexpected behavior since bytesX are right padded.
        uint32 y = uint32(x);
        myNumber += y + msg.value;
    }
}

New version:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
// This will not compile after 0.6.0

contract OtherContract {
    uint x;
    function f(uint y) external {
        x = y;
    }
    function() payable external {}
}

contract New {
    OtherContract other;
    uint myNumber;

    // Function mutability must be specified.
    function someInteger() internal pure returns (uint) { return 2; }

    // Function visibility must be specified.
    // Function mutability must be specified.
    function f(uint x) public returns (bytes memory) {
        // The type must now be explicitly given.
        uint z = someInteger();
        x += z;
        // Throw is now disallowed.
        require(x <= 100);
        int y = -3 >> 1;
        require(y == -2);
        do {
            x += 1;
            if (x > 10) continue;
            // 'Continue' jumps to the condition below.
        } while (x < 11);

        // Call returns (bool, bytes).
        // Data location must be specified.
        (bool success, bytes memory data) = address(other).call("f");
        if (!success)
            revert();
        return data;
    }

    using AddressMakePayable for address;
    // Data location for 'arr' must be specified
    function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
        // 'otherContract.transfer' is not provided.
        // Since the code of 'OtherContract' is known and has the fallback
        // function, address(otherContract) has type 'address payable'.
        address(otherContract).transfer(1 ether);

        // 'unknownContract.transfer' is not provided.
        // 'address(unknownContract).transfer' is not provided
        // since 'address(unknownContract)' is not 'address payable'.
        // If the function takes an 'address' which you want to send
        // funds to, you can convert it to 'address payable' via 'uint160'.
        // Note: This is not recommended and the explicit type
        // 'address payable' should be used whenever possible.
        // To increase clarity, we suggest the use of a library for
        // the conversion (provided after the contract in this example).
        address payable addr = unknownContract.makePayable();
        require(addr.send(1 ether));

        // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
        // the conversion is not allowed.
        // We need to convert to a common size first:
        bytes4 x4 = bytes4(x); // Padding happens on the right
        uint32 y = uint32(x4); // Conversion is consistent
        // 'msg.value' cannot be used in a 'non-payable' function.
        // We need to make the function payable
        myNumber += y + msg.value;
    }
}

// We can define a library for explicitly converting ``address``
// to ``address payable`` as a workaround.
library AddressMakePayable {
    function makePayable(address x) internal pure returns (address payable) {
        return address(uint160(x));
    }
}

060 Breaking Changes (`docs/060-breaking-changes.rst`)


Solidity v0.6.0 Breaking Changes


This section highlights the main breaking changes introduced in Solidity
version 0.6.0, along with the reasoning behind the changes and how to update
affected code.
For the full list check
the release changelog <https://github.com/argotorg/solidity/releases/tag/v0.6.0>_.

Changes the Compiler Might not Warn About

This section lists changes where the behavior of your code might
change without the compiler telling you about it.

  • The resulting type of an exponentiation is the type of the base. It used to be the smallest type
    that can hold both the type of the base and the type of the exponent, as with symmetric
    operations. Additionally, signed types are allowed for the base of the exponentiation.

Explicitness Requirements

This section lists changes where the code now needs to be more explicit,
but the semantics do not change.
For most of the topics the compiler will provide suggestions.

  • Functions can now only be overridden when they are either marked with the
    virtual keyword or defined in an interface. Functions without
    implementation outside an interface have to be marked virtual.
    When overriding a function or modifier, the new keyword override
    must be used. When overriding a function or modifier defined in multiple
    parallel bases, all bases must be listed in parentheses after the keyword
    like so: override(Base1, Base2).

  • Member-access to length of arrays is now always read-only, even for storage arrays. It is no
    longer possible to resize storage arrays by assigning a new value to their length. Use push(),
    push(value) or pop() instead, or assign a full array, which will of course overwrite the existing content.
    The reason behind this is to prevent storage collisions of gigantic
    storage arrays.

  • The new keyword abstract can be used to mark contracts as abstract. It has to be used
    if a contract does not implement all its functions. Abstract contracts cannot be created using the new operator,
    and it is not possible to generate bytecode for them during compilation.

  • Libraries have to implement all their functions, not only the internal ones.

  • The names of variables declared in inline assembly may no longer end in _slot or _offset.

  • Variable declarations in inline assembly may no longer shadow any declaration outside the inline assembly block.
    If the name contains a dot, its prefix up to the dot may not conflict with any declaration outside the inline
    assembly block.

  • In inline assembly, opcodes that do not take arguments are now represented as "built-in functions" instead of standalone identifiers. So gas is now gas().

  • State variable shadowing is now disallowed. A derived contract can only
    declare a state variable x, if there is no visible state variable with
    the same name in any of its bases.

Semantic and Syntactic Changes

This section lists changes where you have to modify your code
and it does something else afterwards.

  • Conversions from external function types to address are now disallowed. Instead external
    function types have a member called address, similar to the existing selector member.

  • The function push(value) for dynamic storage arrays does not return the new length anymore (it returns nothing).

  • The unnamed function commonly referred to as "fallback function" was split up into a new
    fallback function that is defined using the fallback keyword and a receive ether function
    defined using the receive keyword.

    • If present, the receive ether function is called whenever the call data is empty (whether
      or not ether is received). This function is implicitly payable.

    • The new fallback function is called when no other function matches (if the receive ether
      function does not exist then this includes calls with empty call data).
      You can make this function payable or not. If it is not payable then transactions
      not matching any other function which send value will revert. You should only need to
      implement the new fallback function if you are following an upgrade or proxy pattern.

New Features

This section lists things that were not possible prior to Solidity 0.6.0
or were more difficult to achieve.

  • The :ref:try/catch statement allows you to react on failed external calls.
  • struct and enum types can be declared at file level.
  • Array slices can be used for calldata arrays, for example abi.decode(msg.data[4:], (uint, uint))
    is a low-level way to decode the function call payload.
  • Natspec supports multiple return parameters in developer documentation, enforcing the same naming check as @param.
  • Yul and Inline Assembly have a new statement called leave that exits the current function.
  • Conversions from address to address payable are now possible via payable(x), where
    x must be of type address.

Interface Changes

This section lists changes that are unrelated to the language itself, but that have an effect on the interfaces of
the compiler. These may change the way how you use the compiler on the command-line, how you use its programmable
interface, or how you analyze the output produced by it.

New Error Reporter

text
A new error reporter was introduced, which aims at producing more accessible error messages on the command-line.
It is enabled by default, but passing ``--old-reporter`` falls back to the deprecated old error reporter.

Metadata Hash Options

The compiler now appends the IPFS <https://ipfs.io/>_ hash of the metadata file to the end of the bytecode by default
(for details, see documentation on :doc:contract metadata <metadata>). Before 0.6.0, the compiler appended the
Swarm <https://www.ethswarm.org/>_ hash by default, and in order to still support this behavior,
the new command-line option --metadata-hash was introduced. It allows you to select the hash to be produced and
appended, by passing either ipfs or swarm as value to the --metadata-hash command-line option.
Passing the value none completely removes the hash.

These changes can also be used via the :ref:Standard JSON Interface<compiler-api> and effect the metadata JSON generated by the compiler.

The recommended way to read the metadata is to read the last two bytes to determine the length of the CBOR encoding
and perform a proper decoding on that data block as explained in the :ref:metadata section<encoding-of-the-metadata-hash-in-the-bytecode>.

Yul Optimizer

text
Together with the legacy bytecode optimizer, the :doc:`Yul <yul>` optimizer is now enabled by default when you call the compiler
with ``--optimize``. It can be disabled by calling the compiler with ``--no-optimize-yul``.
This mostly affects code that uses ABI coder v2.

C API Changes

The client code that uses the C API of libsolc is now in control of the memory used by the compiler. To make
this change consistent, solidity_free was renamed to solidity_reset, the functions solidity_alloc and
solidity_free were added and solidity_compile now returns a string that must be explicitly freed via
solidity_free().

How to update your code

This section gives detailed instructions on how to update prior code for every breaking change.

  • Change address(f) to f.address for f being of external function type.

  • Replace function () external [payable] { ... } by either receive() external payable { ... },
    fallback() external [payable] { ... } or both. Prefer
    using a receive function only, whenever possible.

  • Change uint length = array.push(value) to array.push(value);. The new length can be
    accessed via array.length.

  • Change array.length++ to array.push() to increase, and use pop() to decrease
    the length of a storage array.

  • For every named return parameter in a function's @dev documentation define a @return
    entry which contains the parameter's name as the first word. E.g. if you have function f() defined
    like function f() public returns (uint value) and a @dev annotating it, document its return
    parameters like so: @return value The return value.. You can mix named and un-named return parameters
    documentation so long as the notices are in the order they appear in the tuple return type.

  • Choose unique identifiers for variable declarations in inline assembly that do not conflict
    with declarations outside the inline assembly block.

  • Add virtual to every non-interface function you intend to override. Add virtual
    to all functions without implementation outside interfaces. For single inheritance, add
    override to every overriding function. For multiple inheritance, add override(A, B, ..),
    where you list all contracts that define the overridden function in the parentheses. When
    multiple bases define the same function, the inheriting contract must override all conflicting functions.

  • In inline assembly, add () to all opcodes that do not otherwise accept an argument.
    For example, change pc to pc(), and gas to gas().


070 Breaking Changes (`docs/070-breaking-changes.rst`)


Solidity v0.7.0 Breaking Changes


This section highlights the main breaking changes introduced in Solidity
version 0.7.0, along with the reasoning behind the changes and how to update
affected code.
For the full list check
the release changelog <https://github.com/argotorg/solidity/releases/tag/v0.7.0>_.

Silent Changes of the Semantics

  • Exponentiation and shifts of literals by non-literals (e.g. 1 << x or 2 ** x)
    will always use either the type uint256 (for non-negative literals) or
    int256 (for negative literals) to perform the operation.
    Previously, the operation was performed in the type of the shift amount / the
    exponent which can be misleading.

Changes to the Syntax

  • In external function and contract creation calls, Ether and gas is now specified using a new syntax:
    x.f{gas: 10000, value: 2 ether}(arg1, arg2).
    The old syntax -- x.f.gas(10000).value(2 ether)(arg1, arg2) -- will cause an error.

  • The global variable now is deprecated, block.timestamp should be used instead.
    The single identifier now is too generic for a global variable and could give the impression
    that it changes during transaction processing, whereas block.timestamp correctly
    reflects the fact that it is just a property of the block.

  • NatSpec comments on variables are only allowed for public state variables and not
    for local or internal variables.

  • The token gwei is a keyword now (used to specify, e.g. 2 gwei as a number)
    and cannot be used as an identifier.

  • String literals now can only contain printable ASCII characters and this also includes a variety of
    escape sequences, such as hexadecimal (\xff) and unicode escapes (\u20ac).

  • Unicode string literals are supported now to accommodate valid UTF-8 sequences. They are identified
    with the unicode prefix: unicode"Hello 😃".

  • State Mutability: The state mutability of functions can now be restricted during inheritance:
    Functions with default state mutability can be overridden by pure and view functions
    while view functions can be overridden by pure functions.
    At the same time, public state variables are considered view and even pure
    if they are constants.

Inline Assembly

  • Disallow . in user-defined function and variable names in inline assembly.
    It is still valid if you use Solidity in Yul-only mode.

  • Slot and offset of storage pointer variable x are accessed via x.slot
    and x.offset instead of x_slot and x_offset.

Removal of Unused or Unsafe Features

Mappings outside Storage

  • If a struct or array contains a mapping, it can only be used in storage.
    Previously, mapping members were silently skipped in memory, which
    is confusing and error-prone.

  • Assignments to structs or arrays in storage does not work if they contain
    mappings.
    Previously, mappings were silently skipped during the copy operation, which
    is misleading and error-prone.

Functions and Events

  • Visibility (public / internal) is not needed for constructors anymore:
    To prevent a contract from being created, it can be marked abstract.
    This makes the visibility concept for constructors obsolete.

  • Type Checker: Disallow virtual for library functions:
    Since libraries cannot be inherited from, library functions should not be virtual.

  • Multiple events with the same name and parameter types in the same
    inheritance hierarchy are disallowed.

  • using A for B only affects the contract it is mentioned in.
    Previously, the effect was inherited. Now, you have to repeat the using
    statement in all derived contracts that make use of the feature.

Expressions

  • Shifts by signed types are disallowed.
    Previously, shifts by negative amounts were allowed, but reverted at runtime.

  • The finney and szabo denominations are removed.
    They are rarely used and do not make the actual amount readily visible. Instead, explicit
    values like 1e20 or the very common gwei can be used.

Declarations

  • The keyword var cannot be used anymore.
    Previously, this keyword would parse but result in a type error and
    a suggestion about which type to use. Now, it results in a parser error.

Interface Changes

  • JSON AST: Mark hex string literals with kind: "hexString".
  • JSON AST: Members with value null are removed from JSON output.
  • NatSpec: Constructors and functions have consistent userdoc output.

How to update your code

This section gives detailed instructions on how to update prior code for every breaking change.

  • Change x.f.value(...)() to x.f{value: ...}(). Similarly (new C).value(...)() to
    new C{value: ...}() and x.f.gas(...).value(...)() to x.f{gas: ..., value: ...}().
  • Change now to block.timestamp.
  • Change types of right operand in shift operators to unsigned types. For example change x >> (256 - y) to
    x >> uint(256 - y).
  • Repeat the using A for B statements in all derived contracts if needed.
  • Remove the public keyword from every constructor.
  • Remove the internal keyword from every constructor and add abstract to the contract (if not already present).
  • Change _slot and _offset suffixes in inline assembly to .slot and .offset, respectively.

080 Breaking Changes (`docs/080-breaking-changes.rst`)


Solidity v0.8.0 Breaking Changes


This section highlights the main breaking changes introduced in Solidity
version 0.8.0.
For the full list check
the release changelog <https://github.com/argotorg/solidity/releases/tag/v0.8.0>_.

Silent Changes of the Semantics

This section lists changes where existing code changes its behavior without
the compiler notifying you about it.

  • Arithmetic operations revert on underflow and overflow. You can use unchecked { ... } to use
    the previous wrapping behavior.

    Checks for overflow are very common, so we made them the default to increase readability of code,
    even if it comes at a slight increase of gas costs.

  • ABI coder v2 is activated by default.

    You can choose to use the old behavior using pragma abicoder v1;.
    The pragma pragma experimental ABIEncoderV2; is still valid, but it is deprecated and has no effect.
    If you want to be explicit, please use pragma abicoder v2; instead.

    Note that ABI coder v2 supports more types than v1 and performs more sanity checks on the inputs.
    ABI coder v2 makes some function calls more expensive and it can also make contract calls
    revert that did not revert with ABI coder v1 when they contain data that does not conform to the
    parameter types.

  • Exponentiation is right associative, i.e., the expression a**b**c is parsed as a**(b**c).
    Before 0.8.0, it was parsed as (a**b)**c.

    This is the common way to parse the exponentiation operator.

  • Failing assertions and other internal checks like division by zero or arithmetic overflow do
    not use the invalid opcode but instead the revert opcode.
    More specifically, they will use error data equal to a function call to Panic(uint256) with an error code specific
    to the circumstances.

    This will save gas on errors while it still allows static analysis tools to distinguish
    these situations from a revert on invalid input, like a failing require.

  • If a byte array in storage is accessed whose length is encoded incorrectly, a panic is caused.
    A contract cannot get into this situation unless inline assembly is used to modify the raw representation of storage byte arrays.

  • If constants are used in array length expressions, previous versions of Solidity would use arbitrary precision
    in all branches of the evaluation tree. Now, if constant variables are used as intermediate expressions,
    their values will be properly rounded in the same way as when they are used in run-time expressions.

  • The type byte has been removed. It was an alias of bytes1.

New Restrictions

This section lists changes that might cause existing contracts to not compile anymore.

  • There are new restrictions related to explicit conversions of literals. The previous behavior in
    the following cases was likely ambiguous:

    1. Explicit conversions from negative literals and literals larger than type(uint160).max to
      address are disallowed.
    2. Explicit conversions between literals and an integer type T are only allowed if the literal
      lies between type(T).min and type(T).max. In particular, replace usages of uint(-1)
      with type(uint).max.
    3. Explicit conversions between literals and enums are only allowed if the literal can
      represent a value in the enum.
    4. Explicit conversions between literals and address type (e.g. address(literal)) have the
      type address instead of address payable. One can get a payable address type by using an
      explicit conversion, i.e., payable(literal).
  • :ref:Address literals<address_literals> have the type address instead of address payable. They can be converted to address payable by using an explicit conversion, e.g.
    payable(0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF).

  • There are new restrictions on explicit type conversions. The conversion is only allowed when there
    is at most one change in sign, width or type-category (int, address, bytesNN, etc.).
    To perform multiple changes, use multiple conversions.

    Let us use the notation T(S) to denote the explicit conversion T(x), where, T and
    S are types, and x is any arbitrary variable of type S. An example of such a
    disallowed conversion would be uint16(int8) since it changes both width (8 bits to 16 bits)
    and sign (signed integer to unsigned integer). In order to do the conversion, one has to go
    through an intermediate type. In the previous example, this would be uint16(uint8(int8)) or
    uint16(int16(int8)). Note that the two ways to convert will produce different results e.g.,
    for -1. The following are some examples of conversions that are disallowed by this rule.

    • address(uint) and uint(address): converting both type-category and width. Replace this by
      address(uint160(uint)) and uint(uint160(address)) respectively.
    • payable(uint160), payable(bytes20) and payable(integer-literal): converting both
      type-category and state-mutability. Replace this by payable(address(uint160)),
      payable(address(bytes20)) and payable(address(integer-literal)) respectively. Note that
      payable(0) is valid and is an exception to the rule.
    • int80(bytes10) and bytes10(int80): converting both type-category and sign. Replace this by
      int80(uint80(bytes10)) and bytes10(uint80(int80) respectively.
    • Contract(uint): converting both type-category and width. Replace this by
      Contract(address(uint160(uint))).

    These conversions were disallowed to avoid ambiguity. For example, in the expression uint16 x = uint16(int8(-1)), the value of x would depend on whether the sign or the width conversion
    was applied first.

  • Function call options can only be given once, i.e. c.f{gas: 10000}{value: 1}() is invalid and has to be changed to c.f{gas: 10000, value: 1}().

  • The global functions log0, log1, log2, log3 and log4 have been removed.

    These are low-level functions that were largely unused. Their behavior can be accessed from inline assembly.

  • enum definitions cannot contain more than 256 members.

    This will make it safe to assume that the underlying type in the ABI is always uint8.

  • Declarations with the name this, super and _ are disallowed, with the exception of
    public functions and events. The exception is to make it possible to declare interfaces of contracts
    implemented in languages other than Solidity that do permit such function names.

  • Remove support for the \b, \f, and \v escape sequences in code.
    They can still be inserted via hexadecimal escapes, e.g. \x08, \x0c, and \x0b, respectively.

  • The global variables tx.origin and msg.sender have the type address instead of
    address payable. One can convert them into address payable by using an explicit
    conversion, i.e., payable(tx.origin) or payable(msg.sender).

    This change was done since the compiler cannot determine whether or not these addresses
    are payable or not, so it now requires an explicit conversion to make this requirement visible.

  • Explicit conversion into address type always returns a non-payable address type. In
    particular, the following explicit conversions have the type address instead of address payable:

    • address(u) where u is a variable of type uint160. One can convert u
      into the type address payable by using two explicit conversions, i.e.,
      payable(address(u)).
    • address(b) where b is a variable of type bytes20. One can convert b
      into the type address payable by using two explicit conversions, i.e.,
      payable(address(b)).
    • address(c) where c is a contract. Previously, the return type of this
      conversion depended on whether the contract can receive Ether (either by having a receive
      function or a payable fallback function). The conversion payable(c) has the type address payable and is only allowed when the contract c can receive Ether. In general, one can
      always convert c into the type address payable by using the following explicit
      conversion: payable(address(c)). Note that address(this) falls under the same category
      as address(c) and the same rules apply for it.
  • The chainid builtin in inline assembly is now considered view instead of pure.

  • Unary negation cannot be used on unsigned integers anymore, only on signed integers.

Interface Changes

  • The output of --combined-json has changed: JSON fields abi, devdoc, userdoc and
    storage-layout are sub-objects now. Before 0.8.0 they used to be serialised as strings.

  • The "legacy AST" has been removed (--ast-json on the commandline interface and legacyAST for standard JSON).
    Use the "compact AST" (--ast-compact-json resp. AST) as replacement.

  • The old error reporter (--old-reporter) has been removed.

How to update your code

  • If you rely on wrapping arithmetic, surround each operation with unchecked { ... }.
  • Optional: If you use SafeMath or a similar library, change x.add(y) to x + y, x.mul(y) to x * y etc.
  • Add pragma abicoder v1; if you want to stay with the old ABI coder.
  • Optionally remove pragma experimental ABIEncoderV2 or pragma abicoder v2 since it is redundant.
  • Change byte to bytes1.
  • Add intermediate explicit type conversions if required.
  • Combine c.f{gas: 10000}{value: 1}() to c.f{gas: 10000, value: 1}().
  • Change msg.sender.transfer(x) to payable(msg.sender).transfer(x) or use a stored variable of address payable type.
  • Change x**y**z to (x**y)**z.
  • Use inline assembly as a replacement for log0, ..., log4.
  • Negate unsigned integers by subtracting them from the maximum value of the type and adding 1 (e.g. type(uint256).max - x + 1, while ensuring that x is not zero)

Abi Spec (`docs/abi-spec.rst`)

.. index:: abi, application binary interface

.. _ABI:


Contract ABI Specification


Basic Design

The Contract Application Binary Interface (ABI) is the standard way to interact with contracts in the Ethereum ecosystem, both
from outside the blockchain and for contract-to-contract interaction. Data is encoded according to its type,
as described in this specification. The encoding is not self describing and thus requires a schema in order to decode.

We assume that the interface functions of a contract are strongly typed, known at compilation time and static.
We assume that all contracts will have the interface definitions of any contracts they call available at compile-time.

This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. Also, the ABI specification for libraries is :ref:slightly different <library-selectors>.

.. _abi_function_selector:
.. index:: ! selector; of a function

Function Selector

The first four bytes of the call data for a function call specifies the function to be called. It is the
first (left, high-order in big-endian) four bytes of the Keccak-256 hash of the signature of
the function. The signature is defined as the canonical expression of the basic prototype without data
location specifier, i.e.
the function name with the parenthesised list of parameter types. Parameter types are split by a single
comma — no spaces are used.

.. note::
The return type of a function is not part of this signature. In
:ref:Solidity's function overloading <overload-function> return types are not considered.
The reason is to keep function call resolution context-independent.
The :ref:JSON description of the ABI<abi_json> however contains both inputs and outputs.

Argument Encoding

Starting from the fifth byte, the encoded arguments follow. This encoding is also used in
other places, e.g. the return values and also event arguments are encoded in the same way,
without the four bytes specifying the function.

Types

Note that the library ABIs can take types different than below e.g. for non-storage structs. See :ref:library selectors <library-selectors> for details.

The following elementary types exist:

  • uint<M>: unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0. e.g. uint32, uint8, uint256.

  • int<M>: two's complement signed integer type of M bits, 0 < M <= 256, M % 8 == 0.

  • address: equivalent to uint160, except for the assumed interpretation and language typing.
    For computing the function selector, address is used.

  • uint, int: synonyms for uint256, int256 respectively. For computing the function
    selector, uint256 and int256 have to be used.

  • bool: equivalent to uint8 restricted to the values 0 and 1. For computing the function selector, bool is used.

  • fixed<M>x<N>: signed fixed-point decimal number of M bits, 8 <= M <= 256,
    M % 8 == 0, and 0 < N <= 80, which denotes the value v as v / (10 ** N).

  • ufixed<M>x<N>: unsigned variant of fixed<M>x<N>.

  • fixed, ufixed: synonyms for fixed128x18, ufixed128x18 respectively. For
    computing the function selector, fixed128x18 and ufixed128x18 have to be used.

  • bytes<M>: binary type of M bytes, 0 < M <= 32.

  • function: an address (20 bytes) followed by a function selector (4 bytes). Encoded identical to bytes24.

The following (fixed-size) array type exists:

  • <type>[M]: a fixed-length array of M elements, M >= 0, of the given type.

    .. note::

    text
    While this ABI specification can express fixed-length arrays with zero elements, they're not supported by the compiler.

The following non-fixed-size types exist:

  • bytes: dynamic sized byte sequence.

  • string: dynamic sized unicode string assumed to be UTF-8 encoded.

  • <type>[]: a variable-length array of elements of the given type.

Types can be combined to a tuple by enclosing them inside parentheses, separated by commas:

  • (T1,T2,...,Tn): tuple consisting of the types T1, ..., Tn, n >= 0

It is possible to form tuples of tuples, arrays of tuples and so on. It is also possible to form zero-tuples (where n == 0).

Mapping Solidity to ABI types

Solidity supports all the types presented above with the same names with the
exception of tuples. On the other hand, some Solidity types are not supported
by the ABI. The following table shows on the left column Solidity types that
are not part of the ABI, and on the right column the ABI types that represent
them.

+-------------------------------+-----------------------------------------------------------------------------+
| Solidity | ABI |
+===============================+=============================================================================+
|:ref:address payable<address>|address |
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:contract<contracts> |address |
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:enum<enums> |uint8 |
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:user defined value types |its underlying value type | | | |
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:struct<structs> |tuple |
+-------------------------------+-----------------------------------------------------------------------------+

.. warning::
Before version 0.8.0 enums could have more than 256 members and were represented by the
smallest integer type just big enough to hold the value of any member.

Design Criteria for the Encoding

The encoding is designed to have the following properties, which are especially useful if some arguments are nested arrays:

  1. The number of reads necessary to access a value is at most the depth of the value
    inside the argument array structure, i.e. four reads are needed to retrieve a_i[k][l][r]. In a
    previous version of the ABI, the number of reads scaled linearly with the total number of dynamic
    parameters in the worst case.

  2. The data of a variable or an array element is not interleaved with other data and it is
    relocatable, i.e. it only uses relative "addresses".

Formal Specification of the Encoding

We distinguish static and dynamic types. Static types are encoded in-place and dynamic types are
encoded at a separately allocated location after the current block.

Definition: The following types are called "dynamic":

  • bytes
  • string
  • T[] for any T
  • T[k] for any dynamic T and any k >= 0
  • (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k

All other types are called "static".

Definition: len(a) is the number of bytes in a binary string a.
The type of len(a) is assumed to be uint256.

We define enc, the actual encoding, as a mapping of values of the ABI types to binary strings such
that len(enc(X)) depends on the value of X if and only if the type of X is dynamic.

Definition: For any ABI value X, we recursively define enc(X), depending
on the type of X being

  • (T1,...,Tk) for k >= 0 and any types T1, ..., Tk

    enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k))

    where X = (X(1), ..., X(k)) and
    head and tail are defined for Ti as follows:

    if Ti is static:

    head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string)

    otherwise, i.e. if Ti is dynamic:

    head(X(i)) = enc(len( head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)) ))
    tail(X(i)) = enc(X(i))

    Note that in the dynamic case, head(X(i)) is well-defined since the lengths of
    the head parts only depend on the types and not the values. The value of head(X(i)) is the offset
    of the beginning of tail(X(i)) relative to the start of enc(X).

  • T[k] for any T and k:

    enc(X) = enc((X[0], ..., X[k-1]))

    i.e. it is encoded as if it were a tuple with k elements
    of the same type.

  • T[] where X has k elements (k is assumed to be of type uint256):

    enc(X) = enc(k) enc((X[0], ..., X[k-1]))

    i.e. it is encoded as if it were a tuple with k elements of the same type (resp. an array of static size k), prefixed with
    the number of elements.

  • bytes, of length k (which is assumed to be of type uint256):

    enc(X) = enc(k) pad_right(X), i.e. the number of bytes is encoded as a
    uint256 followed by the actual value of X as a byte sequence, followed by
    the minimum number of zero-bytes such that len(enc(X)) is a multiple of 32.

  • string:

    enc(X) = enc(enc_utf8(X)), i.e. X is UTF-8 encoded and this value is interpreted
    as of bytes type and encoded further. Note that the length used in this subsequent
    encoding is the number of bytes of the UTF-8 encoded string, not its number of characters.

  • uint<M>: enc(X) is the big-endian encoding of X, padded on the higher-order
    (left) side with zero-bytes such that the length is 32 bytes.

  • address: as in the uint160 case

  • int<M>: enc(X) is the big-endian two's complement encoding of X, padded on the higher-order (left) side with 0xff bytes for negative X and with zero-bytes for non-negative X such that the length is 32 bytes.

  • bool: as in the uint8 case, where 1 is used for true and 0 for false

  • fixed<M>x<N>: enc(X) is enc(X * 10**N) where X * 10**N is interpreted as a int256.

  • fixed: as in the fixed128x18 case

  • ufixed<M>x<N>: enc(X) is enc(X * 10**N) where X * 10**N is interpreted as a uint256.

  • ufixed: as in the ufixed128x18 case

  • bytes<M>: enc(X) is the sequence of bytes in X padded with trailing zero-bytes to a length of 32 bytes.

Note that for any X, len(enc(X)) is a multiple of 32.

Function Selector and Argument Encoding

All in all, a call to the function f with parameters a_1, ..., a_n is encoded as

function_selector(f) enc((a_1, ..., a_n))

and the return values v_1, ..., v_k of f are encoded as

enc((v_1, ..., v_k))

i.e. the values are combined into a tuple and encoded.

Examples

Given the contract:

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

contract Foo {
    function bar(bytes3[2] memory) public pure {}
    function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
    function sam(bytes memory, bool, uint[] memory) public pure {}
}

Thus, for our Foo example, if we wanted to call bar with the argument ["abc", "def"], we would pass 68 bytes total, broken down into:

  • 0xfce353f6: the Method ID. This is derived from the signature bar(bytes3[2]).
  • 0x6162630000000000000000000000000000000000000000000000000000000000: the first part of the first
    parameter, a bytes3 value "abc" (left-aligned).
  • 0x6465660000000000000000000000000000000000000000000000000000000000: the second part of the first
    parameter, a bytes3 value "def" (left-aligned).

In total:

.. code-block:: none

text
0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000

If we wanted to call baz with the parameters 69 and
true, we would pass 68 bytes total, which can be broken down into:

  • 0xcdcd77c0: the Method ID. This is derived as the first 4 bytes of the Keccak hash of
    the ASCII form of the signature baz(uint32,bool).
  • 0x0000000000000000000000000000000000000000000000000000000000000045: the first parameter,
    a uint32 value 69 padded to 32 bytes
  • 0x0000000000000000000000000000000000000000000000000000000000000001: the second parameter - boolean
    true, padded to 32 bytes

In total:

.. code-block:: none

text
0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001

It returns a single bool. If, for example, it were to return false, its output would be
the single byte array 0x0000000000000000000000000000000000000000000000000000000000000000, a single bool.

If we wanted to call sam with the arguments "dave", true and [1,2,3], we would
pass 292 bytes total, broken down into:

  • 0xa5643bf2: the Method ID. This is derived from the signature sam(bytes,bool,uint256[]). Note that uint is replaced with its canonical representation uint256.
  • 0x0000000000000000000000000000000000000000000000000000000000000060: the location of the data part of the first parameter (dynamic type), measured in bytes from the start of the arguments block. In this case, 0x60.
  • 0x0000000000000000000000000000000000000000000000000000000000000001: the second parameter: boolean true.
  • 0x00000000000000000000000000000000000000000000000000000000000000a0: the location of the data part of the third parameter (dynamic type), measured in bytes. In this case, 0xa0.
  • 0x0000000000000000000000000000000000000000000000000000000000000004: the data part of the first argument, it starts with the length of the byte array in elements, in this case, 4.
  • 0x6461766500000000000000000000000000000000000000000000000000000000: the contents of the first argument: the UTF-8 (equal to ASCII in this case) encoding of "dave", padded on the right to 32 bytes.
  • 0x0000000000000000000000000000000000000000000000000000000000000003: the data part of the third argument, it starts with the length of the array in elements, in this case, 3.
  • 0x0000000000000000000000000000000000000000000000000000000000000001: the first entry of the third parameter.
  • 0x0000000000000000000000000000000000000000000000000000000000000002: the second entry of the third parameter.
  • 0x0000000000000000000000000000000000000000000000000000000000000003: the third entry of the third parameter.

In total:

.. code-block:: none

text
0xa5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003

Use of Dynamic Types

A call to a function with the signature f(uint256,uint32[],bytes10,bytes) with values
(0x123, [0x456, 0x789], "1234567890", "Hello, world!") is encoded in the following way:

We take the first four bytes of keccak("f(uint256,uint32[],bytes10,bytes)"), i.e. 0x8be65246.
Then we encode the head parts of all four arguments. For the static types uint256 and bytes10,
these are directly the values we want to pass, whereas for the dynamic types uint32[] and bytes,
we use the offset in bytes to the start of their data area, measured from the start of the value
encoding (i.e. not counting the first four bytes containing the hash of the function signature). These are:

  • 0x0000000000000000000000000000000000000000000000000000000000000123 (0x123 padded to 32 bytes)
  • 0x0000000000000000000000000000000000000000000000000000000000000080 (offset to start of data part of second parameter, 4*32 bytes, exactly the size of the head part)
  • 0x3132333435363738393000000000000000000000000000000000000000000000 ("1234567890" padded to 32 bytes on the right)
  • 0x00000000000000000000000000000000000000000000000000000000000000e0 (offset to start of data part of fourth parameter = offset to start of data part of first dynamic parameter + size of data part of first dynamic parameter = 4*32 + 3*32 (see below))

After this, the data part of the first dynamic argument, [0x456, 0x789] follows:

  • 0x0000000000000000000000000000000000000000000000000000000000000002 (number of elements of the array, 2)
  • 0x0000000000000000000000000000000000000000000000000000000000000456 (first element)
  • 0x0000000000000000000000000000000000000000000000000000000000000789 (second element)

Finally, we encode the data part of the second dynamic argument, "Hello, world!":

  • 0x000000000000000000000000000000000000000000000000000000000000000d (number of elements (bytes in this case): 13)
  • 0x48656c6c6f2c20776f726c642100000000000000000000000000000000000000 ("Hello, world!" padded to 32 bytes on the right)

All together, the encoding is (newline after function selector and each 32-bytes for clarity):

.. code-block:: none

text
0x8be65246
  0000000000000000000000000000000000000000000000000000000000000123
  0000000000000000000000000000000000000000000000000000000000000080
  3132333435363738393000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000e0
  0000000000000000000000000000000000000000000000000000000000000002
  0000000000000000000000000000000000000000000000000000000000000456
  0000000000000000000000000000000000000000000000000000000000000789
  000000000000000000000000000000000000000000000000000000000000000d
  48656c6c6f2c20776f726c642100000000000000000000000000000000000000

Let us apply the same principle to encode the data for a function with a signature g(uint256[][],string[])
with values ([[1, 2], [3]], ["one", "two", "three"]) but start from the most atomic parts of the encoding:

First we encode the length and data of the first embedded dynamic array [1, 2] of the first root array [[1, 2], [3]]:

  • 0x0000000000000000000000000000000000000000000000000000000000000002 (number of elements in the first array, 2; the elements themselves are 1 and 2)
  • 0x0000000000000000000000000000000000000000000000000000000000000001 (first element)
  • 0x0000000000000000000000000000000000000000000000000000000000000002 (second element)

Then we encode the length and data of the second embedded dynamic array [3] of the first root array [[1, 2], [3]]:

  • 0x0000000000000000000000000000000000000000000000000000000000000001 (number of elements in the second array, 1; the element is 3)
  • 0x0000000000000000000000000000000000000000000000000000000000000003 (first element)

Then we need to find the offsets a and b for their respective dynamic arrays [1, 2] and [3].
To calculate the offsets we can take a look at the encoded data of the first root array [[1, 2], [3]]
enumerating each line in the encoding:

.. code-block:: none

text
0 - a                                                                - offset of [1, 2]
1 - b                                                                - offset of [3]
2 - 0000000000000000000000000000000000000000000000000000000000000002 - count for [1, 2]
3 - 0000000000000000000000000000000000000000000000000000000000000001 - encoding of 1
4 - 0000000000000000000000000000000000000000000000000000000000000002 - encoding of 2
5 - 0000000000000000000000000000000000000000000000000000000000000001 - count for [3]
6 - 0000000000000000000000000000000000000000000000000000000000000003 - encoding of 3

Offset a points to the start of the content of the array [1, 2] which is line
2 (64 bytes); thus a = 0x0000000000000000000000000000000000000000000000000000000000000040.

Offset b points to the start of the content of the array [3] which is line 5 (160 bytes);
thus b = 0x00000000000000000000000000000000000000000000000000000000000000a0.

Then we encode the embedded strings of the second root array:

  • 0x0000000000000000000000000000000000000000000000000000000000000003 (number of characters in word "one")
  • 0x6f6e650000000000000000000000000000000000000000000000000000000000 (utf8 representation of word "one")
  • 0x0000000000000000000000000000000000000000000000000000000000000003 (number of characters in word "two")
  • 0x74776f0000000000000000000000000000000000000000000000000000000000 (utf8 representation of word "two")
  • 0x0000000000000000000000000000000000000000000000000000000000000005 (number of characters in word "three")
  • 0x7468726565000000000000000000000000000000000000000000000000000000 (utf8 representation of word "three")

In parallel to the first root array, since strings are dynamic elements we need to find their offsets c, d and e:

.. code-block:: none

text
0 - c                                                                - offset for "one"
1 - d                                                                - offset for "two"
2 - e                                                                - offset for "three"
3 - 0000000000000000000000000000000000000000000000000000000000000003 - count for "one"
4 - 6f6e650000000000000000000000000000000000000000000000000000000000 - encoding of "one"
5 - 0000000000000000000000000000000000000000000000000000000000000003 - count for "two"
6 - 74776f0000000000000000000000000000000000000000000000000000000000 - encoding of "two"
7 - 0000000000000000000000000000000000000000000000000000000000000005 - count for "three"
8 - 7468726565000000000000000000000000000000000000000000000000000000 - encoding of "three"

Offset c points to the start of the content of the string "one" which is line 3 (96 bytes);
thus c = 0x0000000000000000000000000000000000000000000000000000000000000060.

Offset d points to the start of the content of the string "two" which is line 5 (160 bytes);
thus d = 0x00000000000000000000000000000000000000000000000000000000000000a0.

Offset e points to the start of the content of the string "three" which is line 7 (224 bytes);
thus e = 0x00000000000000000000000000000000000000000000000000000000000000e0.

Note that the encodings of the embedded elements of the root arrays are not dependent on each other
and have the same encodings for a function with a signature g(string[],uint256[][]).

Then we encode the length of the first root array:

  • 0x0000000000000000000000000000000000000000000000000000000000000002 (number of elements in the first root array, 2; the elements themselves are [1, 2] and [3])

Then we encode the length of the second root array:

  • 0x0000000000000000000000000000000000000000000000000000000000000003 (number of strings in the second root array, 3; the strings themselves are "one", "two" and "three")

Finally we find the offsets f and g for their respective root dynamic arrays [[1, 2], [3]] and
["one", "two", "three"], and assemble parts in the correct order:

.. code-block:: none

text
0x2289b18c                                                            - function signature
 0 - f                                                                - offset of [[1, 2], [3]]
 1 - g                                                                - offset of ["one", "two", "three"]
 2 - 0000000000000000000000000000000000000000000000000000000000000002 - count for [[1, 2], [3]]
 3 - 0000000000000000000000000000000000000000000000000000000000000040 - offset of [1, 2]
 4 - 00000000000000000000000000000000000000000000000000000000000000a0 - offset of [3]
 5 - 0000000000000000000000000000000000000000000000000000000000000002 - count for [1, 2]
 6 - 0000000000000000000000000000000000000000000000000000000000000001 - encoding of 1
 7 - 0000000000000000000000000000000000000000000000000000000000000002 - encoding of 2
 8 - 0000000000000000000000000000000000000000000000000000000000000001 - count for [3]
 9 - 0000000000000000000000000000000000000000000000000000000000000003 - encoding of 3
10 - 0000000000000000000000000000000000000000000000000000000000000003 - count for ["one", "two", "three"]
11 - 0000000000000000000000000000000000000000000000000000000000000060 - offset for "one"
12 - 00000000000000000000000000000000000000000000000000000000000000a0 - offset for "two"
13 - 00000000000000000000000000000000000000000000000000000000000000e0 - offset for "three"
14 - 0000000000000000000000000000000000000000000000000000000000000003 - count for "one"
15 - 6f6e650000000000000000000000000000000000000000000000000000000000 - encoding of "one"
16 - 0000000000000000000000000000000000000000000000000000000000000003 - count for "two"
17 - 74776f0000000000000000000000000000000000000000000000000000000000 - encoding of "two"
18 - 0000000000000000000000000000000000000000000000000000000000000005 - count for "three"
19 - 7468726565000000000000000000000000000000000000000000000000000000 - encoding of "three"

Offset f points to the start of the content of the array [[1, 2], [3]] which is line 2 (64 bytes);
thus f = 0x0000000000000000000000000000000000000000000000000000000000000040.

Offset g points to the start of the content of the array ["one", "two", "three"] which is line 10 (320 bytes);
thus g = 0x0000000000000000000000000000000000000000000000000000000000000140.

.. _abi_events:

Events

Events are an abstraction of the Ethereum logging/event-watching protocol. Log entries provide the contract's
address, a series of up to four topics and some arbitrary length binary data. Events leverage the existing function
ABI in order to interpret this (together with an interface spec) as a properly typed structure.

Given an event name and series of event parameters, we split them into two sub-series: those which are indexed and
those which are not.
Those which are indexed, which may number up to 3 (for non-anonymous events) or 4 (for anonymous ones), are used
alongside the Keccak hash of the event signature to form the topics of the log entry.
Those which are not indexed form the byte array of the event.

In effect, a log entry using this ABI is described as:

  • address: the address of the contract (intrinsically provided by Ethereum);
  • topics[0]: keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")") (canonical_type_of
    is a function that simply returns the canonical type of a given argument, e.g. for uint indexed foo, it would
    return uint256). This value is only present in topics[0] if the event is not declared as anonymous;
  • topics[n]: abi_encode(EVENT_INDEXED_ARGS[n - 1]) if the event is not declared as anonymous
    or abi_encode(EVENT_INDEXED_ARGS[n]) if it is (EVENT_INDEXED_ARGS is the series of EVENT_ARGS that
    are indexed);
  • data: ABI encoding of EVENT_NON_INDEXED_ARGS (EVENT_NON_INDEXED_ARGS is the series of EVENT_ARGS
    that are not indexed, abi_encode is the ABI encoding function used for returning a series of typed values
    from a function, as described above).

For all types of length at most 32 bytes, the EVENT_INDEXED_ARGS array contains
the value directly, padded or sign-extended (for signed integers) to 32 bytes, just as for regular ABI encoding.
However, for all "complex" types or types of dynamic length, including all arrays, string, bytes and structs,
EVENT_INDEXED_ARGS will contain the Keccak hash of a special in-place encoded value
(see :ref:indexed_event_encoding), rather than the encoded value directly.
This allows applications to efficiently query for values of dynamic-length types
(by setting the hash of the encoded value as the topic), but leaves applications unable
to decode indexed values they have not queried for. For dynamic-length types,
application developers face a trade-off between fast search for predetermined values
(if the argument is indexed) and legibility of arbitrary values (which requires that
the arguments not be indexed). Developers may overcome this tradeoff and achieve both
efficient search and arbitrary legibility by defining events with two arguments — one
indexed, one not — intended to hold the same value.

.. _abi_errors:
.. index:: error, selector; of an error

Errors

In case of a failure inside a contract, the contract can use a special opcode to abort execution and revert
all state changes. In addition to these effects, descriptive data can be returned to the caller.
This descriptive data is the encoding of an error and its arguments in the same way as data for a function
call.

As an example, let us consider the following contract whose transfer function always
reverts with a custom error of "insufficient balance":

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract TestToken {
    error InsufficientBalance(uint256 available, uint256 required);
    function transfer(address /*to*/, uint amount) public pure {
        revert InsufficientBalance(0, amount);
    }
}

The return data would be encoded in the same way as the function call
InsufficientBalance(0, amount) to the function InsufficientBalance(uint256,uint256),
i.e. 0xcf479181, uint256(0), uint256(amount).

The error selectors 0x00000000 and 0xffffffff are reserved for future use.

.. warning::
Never trust error data.
The error data by default bubbles up through the chain of external calls, which
means that a contract may receive an error not defined in any of the contracts
it calls directly.
Furthermore, any contract can fake any error by returning data that matches
an error signature, even if the error is not defined anywhere.

.. _abi_json:

JSON

The JSON format for a contract's interface is given by an array of function, event and error descriptions.
A function description is a JSON object with the fields:

  • type: "function", "constructor", "receive" (the :ref:"receive Ether" function <receive-ether-function>) or "fallback" (the :ref:"default" function <fallback-function>);

  • name: the name of the function;

  • inputs: an array of objects, each of which contains:

    • name: the name of the parameter.
    • type: the canonical type of the parameter (more below).
    • components: used for tuple types (more below).
  • outputs: an array of objects similar to inputs.

  • stateMutability: a string with one of the following values: pure (:ref:specified to not read blockchain state ), view (:ref:specified to not modify the blockchain state <view-functions>), nonpayable (function does not accept Ether - the default) and payable (function accepts Ether).

Constructor, receive, and fallback never have name or outputs. Receive and fallback do not have inputs either.

.. note::
Sending non-zero Ether to non-payable function will revert the transaction.

.. note::
The state mutability nonpayable is reflected in Solidity by not specifying
a state mutability modifier at all.

An event description is a JSON object with fairly similar fields:

  • type: always "event"

  • name: the name of the event.

  • inputs: an array of objects, each of which contains:

    • name: the name of the parameter.
    • type: the canonical type of the parameter (more below).
    • components: used for tuple types (more below).
    • indexed: true if the field is part of the log's topics, false if it is one of the log's data segments.
  • anonymous: true if the event was declared as anonymous.

Errors look as follows:

  • type: always "error"

  • name: the name of the error.

  • inputs: an array of objects, each of which contains:

    • name: the name of the parameter.
    • type: the canonical type of the parameter (more below).
    • components: used for tuple types (more below).

.. note::
There can be multiple errors with the same name and even with identical signature
in the JSON array; for example, if the errors originate from different
files in the smart contract or are referenced from another smart contract.
For the ABI, only the name of the error itself is relevant and not where it is
defined.

For example,

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;


contract Test {
    constructor() { b = hex"12345678901234567890123456789012"; }
    event Event(uint indexed a, bytes32 b);
    event Event2(uint indexed a, bytes32 b);
    error InsufficientBalance(uint256 available, uint256 required);
    function foo(uint a) public { emit Event(a, b); }
    bytes32 b;
}

would result in the JSON:

.. code-block:: json

text
[{
"type":"error",
"inputs": [{"name":"available","type":"uint256"},{"name":"required","type":"uint256"}],
"name":"InsufficientBalance"
}, {
"type":"event",
"inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}],
"name":"Event"
}, {
"type":"event",
"inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}],
"name":"Event2"
}, {
"type":"function",
"inputs": [{"name":"a","type":"uint256"}],
"name":"foo",
"outputs": []
}]

Handling tuple types

Despite the fact that names are intentionally not part of the ABI encoding, they do make a lot of sense to be included
in the JSON to enable displaying it to the end user. The structure is nested in the following way:

An object with members name, type and potentially components describes a typed variable.
The canonical type is determined until a tuple type is reached and the string description up
to that point is stored in type prefix with the word tuple, i.e. it will be tuple followed by
a sequence of [] and [k] with
integers k. The components of the tuple are then stored in the member components,
which is of an array type and has the same structure as the top-level object except that
indexed is not allowed there.

As an example, the code

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5 <0.9.0;
pragma abicoder v2;

contract Test {
    struct S { uint a; uint[] b; T[] c; }
    struct T { uint x; uint y; }
    function f(S memory, T memory, uint) public pure {}
    function g() public pure returns (S memory, T memory, uint) {}
}

would result in the JSON:

.. code-block:: json

text
[
  {
    "name": "f",
    "type": "function",
    "inputs": [
      {
        "name": "s",
        "type": "tuple",
        "components": [
          {
            "name": "a",
            "type": "uint256"
          },
          {
            "name": "b",
            "type": "uint256[]"
          },
          {
            "name": "c",
            "type": "tuple[]",
            "components": [
              {
                "name": "x",
                "type": "uint256"
              },
              {
                "name": "y",
                "type": "uint256"
              }
            ]
          }
        ]
      },
      {
        "name": "t",
        "type": "tuple",
        "components": [
          {
            "name": "x",
            "type": "uint256"
          },
          {
            "name": "y",
            "type": "uint256"
          }
        ]
      },
      {
        "name": "a",
        "type": "uint256"
      }
    ],
    "outputs": []
  }
]

.. _abi_packed_mode:

Strict Encoding Mode

Strict encoding mode is the mode that leads to exactly the same encoding as defined in the formal specification above.
This means that offsets have to be as small as possible while still not creating overlaps in the data areas, and thus no gaps are
allowed.

Usually, ABI decoders are written in a straightforward way by just following offset pointers, but some decoders
might enforce strict mode. The Solidity ABI decoder currently does not enforce strict mode, but the encoder
always creates data in strict mode.

Non-standard Packed Mode

Through abi.encodePacked(), Solidity supports a non-standard packed mode where:

  • types shorter than 32 bytes are concatenated directly, without padding or sign extension
  • dynamic types are encoded in-place and without the length.
  • array elements are padded, but still encoded in-place

Furthermore, structs as well as nested arrays are not supported.

As an example, the encoding of int16(-1), bytes1(0x42), uint16(0x03), string("Hello, world!") results in:

.. code-block:: none

text
0xffff42000348656c6c6f2c20776f726c6421
  ^^^^                                 int16(-1)
      ^^                               bytes1(0x42)
        ^^^^                           uint16(0x03)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^ string("Hello, world!") without a length field

More specifically:

  • During the encoding, everything is encoded in-place. This means that there is
    no distinction between head and tail, as in the ABI encoding, and the length
    of an array is not encoded.
  • The direct arguments of abi.encodePacked are encoded without padding,
    as long as they are not arrays (or string or bytes).
  • The encoding of an array is the concatenation of the
    encoding of its elements with padding.
  • Dynamically-sized types like string, bytes or uint[] are encoded
    without their length field.
  • The encoding of string or bytes does not apply padding at the end,
    unless it is part of an array or struct (then it is padded to a multiple of
    32 bytes).

In general, the encoding is ambiguous as soon as there are two dynamically-sized elements,
because of the missing length field.

If padding is needed, explicit type conversions can be used: abi.encodePacked(uint16(0x12)) == hex"0012".

Since packed encoding is not used when calling functions, there is no special support
for prepending a function selector. Since the encoding is ambiguous, there is no decoding function.

.. warning::

text
If you use ``keccak256(abi.encodePacked(a, b))`` and both ``a`` and ``b`` are dynamic types,
it is easy to craft collisions in the hash value by moving parts of ``a`` into ``b`` and
vice-versa. More specifically, ``abi.encodePacked("a", "bc") == abi.encodePacked("ab", "c")``.
If you use ``abi.encodePacked`` for signatures, authentication or data integrity, make
sure to always use the same types and check that at most one of them is dynamic.
Unless there is a compelling reason, ``abi.encode`` should be preferred.

.. _indexed_event_encoding:

Encoding of Indexed Event Parameters

Indexed event parameters that are not value types, i.e. arrays and structs are not
stored directly but instead a Keccak-256 hash of an encoding is stored. This encoding
is defined as follows:

  • the encoding of a bytes and string value is just the string contents
    without any padding or length prefix.
  • the encoding of a struct is the concatenation of the encoding of its members,
    always padded to a multiple of 32 bytes (even bytes and string).
  • the encoding of an array (both dynamically- and statically-sized) is
    the concatenation of the encoding of its elements, always padded to a multiple
    of 32 bytes (even bytes and string) and without any length prefix

In the above, as usual, a negative number is padded by sign extension and not zero padded.
bytesNN types are padded on the right while uintNN / intNN are padded on the left.

.. warning::

text
The encoding of a struct is ambiguous if it contains more than one dynamically-sized
array. Because of that, always re-check the event data and do not rely on the search result
based on the indexed parameters alone.

Analysing Compilation Output (`docs/analysing-compilation-output.rst`)

.. index:: analyse, asm

#############################
Analysing the Compiler Output
#############################

It is often useful to look at the assembly code generated by the compiler. The generated binary,
i.e., the output of solc --bin contract.sol, is generally difficult to read. It is recommended
to use the flag --asm to analyse the assembly output. Even for large contracts, looking at a
visual diff of the assembly before and after a change is often very enlightening.

Consider the following contract (named, say contract.sol):

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract C {
    function one() public pure returns (uint) {
        return 1;
    }
}

The following would be the output of solc --asm contract.sol

.. code-block:: none

text
======= contract.sol:C =======
EVM assembly:
    /* "contract.sol":0:86  contract C {... */
  mstore(0x40, 0x80)
  callvalue
  dup1
  iszero
  tag_1
  jumpi
  0x00
  dup1
  revert
tag_1:
  pop
  dataSize(sub_0)
  dup1
  dataOffset(sub_0)
  0x00
  codecopy
  0x00
  return
stop

sub_0: assembly {
        /* "contract.sol":0:86  contract C {... */
      mstore(0x40, 0x80)
      callvalue
      dup1
      iszero
      tag_1
      jumpi
      0x00
      dup1
      revert
    tag_1:
      pop
      jumpi(tag_2, lt(calldatasize, 0x04))
      shr(0xe0, calldataload(0x00))
      dup1
      0x901717d1
      eq
      tag_3
      jumpi
    tag_2:
      0x00
      dup1
      revert
        /* "contract.sol":17:84  function one() public pure returns (uint) {... */
    tag_3:
      tag_4
      tag_5
      jump	// in
    tag_4:
      mload(0x40)
      tag_6
      swap2
      swap1
      tag_7
      jump	// in
    tag_6:
      mload(0x40)
      dup1
      swap2
      sub
      swap1
      return
    tag_5:
        /* "contract.sol":53:57  uint */
      0x00
        /* "contract.sol":76:77  1 */
      0x01
        /* "contract.sol":69:77  return 1 */
      swap1
      pop
        /* "contract.sol":17:84  function one() public pure returns (uint) {... */
      swap1
      jump	// out
        /* "#utility.yul":7:125   */
    tag_10:
        /* "#utility.yul":94:118   */
      tag_12
        /* "#utility.yul":112:117   */
      dup2
        /* "#utility.yul":94:118   */
      tag_13
      jump	// in
    tag_12:
        /* "#utility.yul":89:92   */
      dup3
        /* "#utility.yul":82:119   */
      mstore
        /* "#utility.yul":72:125   */
      pop
      pop
      jump	// out
        /* "#utility.yul":131:353   */
    tag_7:
      0x00
        /* "#utility.yul":262:264   */
      0x20
        /* "#utility.yul":251:260   */
      dup3
        /* "#utility.yul":247:265   */
      add
        /* "#utility.yul":239:265   */
      swap1
      pop
        /* "#utility.yul":275:346   */
      tag_15
        /* "#utility.yul":343:344   */
      0x00
        /* "#utility.yul":332:341   */
      dup4
        /* "#utility.yul":328:345   */
      add
        /* "#utility.yul":319:325   */
      dup5
        /* "#utility.yul":275:346   */
      tag_10
      jump	// in
    tag_15:
        /* "#utility.yul":229:353   */
      swap3
      swap2
      pop
      pop
      jump	// out
        /* "#utility.yul":359:436   */
    tag_13:
      0x00
        /* "#utility.yul":425:430   */
      dup2
        /* "#utility.yul":414:430   */
      swap1
      pop
        /* "#utility.yul":404:436   */
      swap2
      swap1
      pop
      jump	// out

    auxdata: 0xa2646970667358221220a5874f19737ddd4c5d77ace1619e5160c67b3d4bedac75fce908fed32d98899864736f6c637827302e382e342d646576656c6f702e323032312e332e33302b636f6d6d69742e65613065363933380058
}

Alternatively, the above output can also be obtained from Remix <https://remix.ethereum.org/>_,
under the option "Compilation Details" after compiling a contract.

Notice that the asm output starts with the creation / constructor code. The deploy code is
provided as part of the sub object (in the above example, it is part of the sub-object sub_0).
The auxdata field corresponds to the contract :ref:metadata <encoding-of-the-metadata-hash-in-the-bytecode>. The comments in the assembly output point to the
source location. Note that #utility.yul is an internally generated file of utility functions
that can be obtained using the flags --combined-json generated-sources,generated-sources-runtime.

Similarly, the optimized assembly can be obtained with the command: solc --optimize --asm contract.sol. Often times, it is interesting to see if two different sources in Solidity result in
the same optimized code. For example, to see if the expressions (a * b) / c, a * b / c
generates the same bytecode. This can be easily done by taking a diff of the corresponding
assembly output, after potentially stripping comments that reference the source locations.

.. note::

The --asm output is not designed to be machine readable. Therefore, there may be breaking
changes on the output between minor versions of solc.


Assembly (`docs/assembly.rst`)

.. _inline-assembly:

###############
Inline Assembly
###############

.. index:: ! assembly, ! asm, ! evmasm

You can interleave Solidity statements with inline assembly in a language close
to the one of the Ethereum Virtual Machine. This gives you more fine-grained control,
which is especially useful when you are enhancing the language by writing libraries or
optimizing gas usage.

The language used for inline assembly in Solidity is called :ref:Yul <yul>
and it is documented in its own section. This section will only cover
how the inline assembly code can interface with the surrounding Solidity code.

.. warning::
Inline assembly is a way to access the Ethereum Virtual Machine
at a low level. This bypasses several important safety
features and checks of Solidity. You should only use it for
tasks that need it, and only if you are confident with using it.

An inline assembly block is marked by assembly { ... }, where the code inside
the curly braces is code in the :ref:Yul <yul> language.

The inline assembly code can access local Solidity variables as explained below.

Different inline assembly blocks share no namespace, i.e. it is not possible
to call a Yul function or access a Yul variable defined in a different inline assembly block.

Example

The following example provides library code to access the code of another contract and
load it into a bytes variable. This is possible with "plain Solidity" too, by using
<address>.code. But the point here is that reusable assembly libraries can enhance the
Solidity language without a compiler change.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

library GetCode {
    // This will report a warning - `at` will be promoted to reserved keyword
    function at(address addr) public view returns (bytes memory code) {
        assembly {
            // retrieve the size of the code, this needs assembly
            let size := extcodesize(addr)
            // allocate output byte array - this could also be done without assembly
            // by using code = new bytes(size)
            code := mload(0x40)
            // new "memory end" including padding
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // store length in memory
            mstore(code, size)
            // actually retrieve the code, this needs assembly
            extcodecopy(addr, add(code, 0x20), 0, size)
        }
    }
}

Inline assembly is also beneficial in cases where the optimizer fails to produce
efficient code, for example:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;


library VectorSum {
    // This function is less efficient because the optimizer currently fails to
    // remove the bounds checks in array access.
    function sumSolidity(uint[] memory data) public pure returns (uint sum) {
        for (uint i = 0; i < data.length; ++i)
            sum += data[i];
    }

    // We know that we only access the array in bounds, so we can avoid the check.
    // 0x20 needs to be added to an array because the first slot contains the
    // array length.
    function sumAsm(uint[] memory data) public pure returns (uint sum) {
        for (uint i = 0; i < data.length; ++i) {
            assembly {
                sum := add(sum, mload(add(add(data, 0x20), mul(i, 0x20))))
            }
        }
    }

    // Same as above, but accomplish the entire code within inline assembly.
    function sumPureAsm(uint[] memory data) public pure returns (uint sum) {
        assembly {
            // Load the length (first 32 bytes)
            let len := mload(data)

            // Skip over the length field.
            //
            // Keep temporary variable so it can be incremented in place.
            //
            // NOTE: incrementing data would result in an unusable
            //       data variable after this assembly block
            let dataElementLocation := add(data, 0x20)

            // Iterate until the bound is not met.
            for
                { let end := add(dataElementLocation, mul(len, 0x20)) }
                lt(dataElementLocation, end)
                { dataElementLocation := add(dataElementLocation, 0x20) }
            {
                sum := add(sum, mload(dataElementLocation))
            }
        }
    }
}

.. index:: selector; of a function

Access to External Variables, Functions and Libraries

You can access Solidity variables and other identifiers by using their name.

Local variables of value type are directly usable in inline assembly.
They can both be read and assigned to.

Local variables that refer to memory evaluate to the address of the variable in memory, not the value itself.
Such variables can also be assigned to, but note that an assignment will only change the pointer and not the data
and that it is your responsibility to respect Solidity's memory management.
See :ref:Conventions in Solidity <conventions-in-solidity>.

Similarly, local variables that refer to statically-sized calldata arrays or calldata structs
evaluate to the address of the variable in calldata, not the value itself.
The variable can also be assigned a new offset, but note that no validation is performed to ensure that
the variable will not point beyond calldatasize().

For external function pointers the address and the function selector can be
accessed using x.address and x.selector.
The selector consists of four right-aligned bytes.
Both values can be assigned to. For example:

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.10 <0.9.0;

contract C {
    // Assigns a new selector and address to the return variable @fun
    function combineToFunctionPointer(address newAddress, uint newSelector) public pure returns (function() external fun) {
        assembly {
            fun.selector := newSelector
            fun.address  := newAddress
        }
    }
}

For dynamic calldata arrays, you can access
their calldata offset (in bytes) and length (number of elements) using x.offset and x.length.
Both expressions can also be assigned to, but as for the static case, no validation will be performed
to ensure that the resulting data area is within the bounds of calldatasize().

For local storage variables or state variables (including transient storage) a single Yul identifier
is not sufficient, since they do not necessarily occupy a single full storage slot.
Therefore, their "address" is composed of a slot and a byte-offset
inside that slot. To retrieve the slot pointed to by the variable x, you
use x.slot, and to retrieve the byte-offset you use x.offset.
Using x itself will result in an error.

You can also assign to the .slot part of a local storage variable pointer.
For these (structs, arrays or mappings), the .offset part is always zero.
It is not possible to assign to the .slot or .offset part of a state variable,
though.

Local Solidity variables are available for assignments, for example:

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.28 <0.9.0;

// This will report a warning
contract C {
    bool transient a;
    uint b;
    function f(uint x) public returns (uint r) {
        assembly {
            // We ignore the storage slot offset, we know it is zero
            // in this special case.
            r := mul(x, sload(b.slot))
            tstore(a.slot, true)
        }
    }
}

.. warning::
If you access variables of a type that spans less than 256 bits
(for example uint64, address, or bytes16),
you cannot make any assumptions about bits not part of the
encoding of the type. Especially, do not assume them to be zero.
To be safe, always clear the data properly before you use it
in a context where this is important:
uint32 x = f(); assembly { x := and(x, 0xffffffff) /* now use x */ }
To clean signed types, you can use the signextend opcode:
assembly { signextend(<num_bytes_of_x_minus_one>, x) }

Since Solidity 0.6.0, the name of an inline assembly variable may not
shadow any declaration visible in the scope of the inline assembly block
(including variable, contract and function declarations).

Since Solidity 0.7.0, variables and functions declared inside the
inline assembly block may not contain ., but using . is
valid to access Solidity variables from outside the inline assembly block.
However, it is still valid to use dots if you use Solidity in Yul-only mode.

Things to Avoid

Inline assembly might have a quite high-level look, but it actually is extremely
low-level. Function calls, loops, ifs and switches are converted by simple
rewriting rules and after that, the only thing the assembler does for you is re-arranging
functional-style opcodes, counting stack height for
variable access and removing stack slots for assembly-local variables when the end
of their block is reached.

.. _conventions-in-solidity:

Conventions in Solidity

.. _assembly-typed-variables:

Values of Typed Variables

In contrast to EVM assembly, Solidity has types which are narrower than 256 bits,
e.g. uint24. For efficiency, most arithmetic operations ignore the fact that
types can be shorter than 256
bits, and the higher-order bits are cleaned when necessary,
i.e., shortly before they are written to memory or before comparisons are performed.
This means that if you access such a variable
from within inline assembly, you might have to manually clean the higher-order bits
first.

.. _assembly-memory-management:

Memory Management

Solidity manages memory in the following way. There is a "free memory pointer"
at position 0x40 in memory. If you want to allocate memory, use the memory
starting from where this pointer points at and update it.
There is no guarantee that the memory has not been used before and thus
you cannot assume that its contents are zero bytes.
There is no built-in mechanism to release or free allocated memory.
Solidity does not guarantee and does not require that the values in memory
are placed at positions aligned to a multiple of any value.
Here is an assembly snippet you can use for allocating memory that follows the process outlined above:

.. code-block:: yul

text
function allocate(length) -> pos {
  pos := mload(0x40)
  mstore(0x40, add(pos, length))
}

The first 64 bytes of memory can be used as "scratch space" for short-term
allocation. The 32 bytes after the free memory pointer (i.e., starting at 0x60)
are meant to be zero permanently and is used as the initial value for
empty dynamic memory arrays.
This means that the allocatable memory starts at 0x80, which is the initial value
of the free memory pointer.

Elements in memory arrays in Solidity always occupy multiples of 32 bytes (this is
even true for bytes1[], but not for bytes and string). Multi-dimensional memory
arrays are pointers to memory arrays. The length of a dynamic array is stored at the
first slot of the array and followed by the array elements.

.. warning::
Statically-sized memory arrays do not have a length field, but it might be added later
to allow better convertibility between statically and dynamically-sized arrays; so,
do not rely on this.

Memory Safety

Without the use of inline assembly, the compiler can rely on memory to remain in a well-defined
state at all times. This is especially relevant for :ref:the new code generation pipeline via Yul IR :
this code generation path can move local variables from stack to memory to avoid stack-too-deep errors and
perform additional memory optimizations, if it can rely on certain assumptions about memory use.

While we recommend to always respect Solidity's memory model, inline assembly allows you to use memory
in an incompatible way. Therefore, moving stack variables to memory and additional memory optimizations are,
by default, globally disabled in the presence of any inline assembly block that contains a memory operation
or assigns to Solidity variables in memory.

However, you can specifically annotate an assembly block to indicate that it in fact respects Solidity's memory
model as follows:

.. code-block:: solidity

text
assembly ("memory-safe") {
    ...
}

In particular, a memory-safe assembly block may only access the following memory ranges:

  • Memory allocated by yourself using a mechanism like the allocate function described above.
  • Memory allocated by Solidity, e.g. memory within the bounds of a memory array you reference.
  • The scratch space between memory offset 0 and 64 mentioned above.
  • Temporary memory that is located after the value of the free memory pointer at the beginning of the assembly block,
    i.e. memory that is "allocated" at the free memory pointer without updating the free memory pointer.

Furthermore, if the assembly block assigns to Solidity variables in memory, you need to assure that accesses to
the Solidity variables only access these memory ranges.

Since this is mainly about the optimizer, these restrictions still need to be followed, even if the assembly block
reverts or terminates. As an example, the following assembly snippet is not memory safe, because the value of
returndatasize() may exceed the 64 byte scratch space:

.. code-block:: solidity

text
assembly {
  returndatacopy(0, 0, returndatasize())
  revert(0, returndatasize())
}

On the other hand, the following code is memory safe, because memory beyond the location pointed to by the
free memory pointer can safely be used as temporary scratch space:

.. code-block:: solidity

text
assembly ("memory-safe") {
  let p := mload(0x40)
  returndatacopy(p, 0, returndatasize())
  revert(p, returndatasize())
}

Note that you do not need to update the free memory pointer if there is no following allocation,
but you can only use memory starting from the current offset given by the free memory pointer.

If the memory operations use a length of zero, it is also fine to just use any offset (not only if it falls into the scratch space):

.. code-block:: solidity

text
assembly ("memory-safe") {
  revert(0, 0)
}

Note that not only memory operations in inline assembly itself can be memory-unsafe, but also assignments to
Solidity variables of reference type in memory. For example the following is not memory-safe:

.. code-block:: solidity

text
bytes memory x;
assembly {
  x := 0x40
}
x[0x20] = 0x42;

Inline assembly that neither involves any operations that access memory nor assigns to any Solidity variables
in memory is automatically considered memory-safe and does not need to be annotated.

.. warning::
It is your responsibility to make sure that the assembly actually satisfies the memory model. If you annotate
an assembly block as memory-safe, but violate one of the memory assumptions, this will lead to incorrect and
undefined behavior that cannot easily be discovered by testing.

In case you are developing a library that is meant to be compatible across multiple versions
of Solidity, you can use a special comment to annotate an assembly block as memory-safe:

.. code-block:: solidity

text
/// @solidity memory-safe-assembly
assembly {
    ...
}

.. warning::
The memory-safe-assembly special comment is deprecated and scheduled for removal.
In new code targeting recent compilers, use the assembly block annotation.

Advanced Safe Use of Memory

Beyond the strict definition of memory-safety given above, there are cases in which you may want to use more than 64 bytes
of scratch space starting at memory offset 0. If you are careful, it can be admissible to use memory up to (and not
including) offset 0x80 and still safely declare the assembly block as memory-safe.
This is admissible under either of the following conditions:

  • By the end of the assembly block, the free memory pointer at offset 0x40 is restored to a sane value (i.e. it is either
    restored to its original value or an increment of it due to a manual memory allocation), and the memory word at offset 0x60
    is restored to a value of zero.

  • The assembly block terminates, i.e. execution can never return to high-level Solidity code. This is the case, for example,
    if your assembly block unconditionally ends in calling the revert opcode.

Furthermore, you need to be aware that the default-value of dynamic arrays in Solidity point to memory offset 0x60, so
for the duration of temporarily changing the value at memory offset 0x60, you can no longer rely on getting accurate
length values when reading dynamic arrays, until you restore the zero value at 0x60. To be more precise, we only guarantee
safety when overwriting the zero pointer, if the remainder of the assembly snippet does not interact with the memory of
high-level Solidity objects (including by reading from offsets previously stored in variables).


Brand Guide (`docs/brand-guide.rst`)

####################
Solidity Brand Guide
####################

This brand guide features information on Solidity's brand policy and
logo usage guidelines.

The Solidity Brand

The Solidity programming language is an open-source, community project
governed by a core team. The core team is part of the Argot Collective <https://argot.org/>, a non-profit that develops and maintains Solidity.
The project was originally started at and sponsored by the Ethereum Foundation <https://ethereum.foundation/>
.

This document aims to provide information about how to best use the
Solidity brand name and logo.

We encourage you to read this document carefully before using the
brand name or the logo. Your cooperation is highly appreciated!

Solidity Brand Name

"Solidity" should be used to refer to the Solidity programming language
solely.

Please do not use "Solidity":

  • To refer to any other programming language.

  • In a way that is misleading or may imply association of unrelated
    modules, tools, documentation, or other resources with the Solidity
    programming language.

  • In ways that confuse the community as to whether the Solidity
    programming language is open-source and free to use.

Solidity Logo License

.. image:: https://i.creativecommons.org/l/by/4.0/88x31.png
:width: 88
:alt: Creative Commons License

The Solidity logo is distributed and licensed under a Creative Commons Attribution 4.0 International License <https://creativecommons.org/licenses/by/4.0/>_.

This is the most permissive Creative Commons license and allows reuse
and modifications for any purpose.

You are free to:

  • Share — Copy and redistribute the material in any medium or format.

  • Adapt — Remix, transform, and build upon the material for any
    purpose, even commercially.

Under the following terms:

  • Attribution — You must give appropriate credit, provide a link to
    the license, and indicate if changes were made. You may do so in any
    reasonable manner, but not in any way that suggests that the Solidity
    core team endorses you or your use.

When using the Solidity logo, please respect the Solidity logo guidelines.

Solidity Logo Guidelines

.. image:: solidity_logo.svg
:width: 256

(Right click on the logo to download it.)

Please do not:

  • Change the ratio of the logo (do not stretch it or cut it).

  • Change the colors of the logo, unless it is absolutely necessary.

Credits

This document was, in parts, derived from the Python Software Foundation Trademark Usage Policy <https://www.python.org/psf/trademarks/>_
and the Rust Media Guide <https://www.rust-lang.org/policies/media-guide>_.


Bugs.Json (`docs/bugs.json`)

[
{
"uid": "SOL-2026-7",
"name": "YulOptimizerKnowledgeBaseStaleBookkeeping",
"summary": "The Yul optimizer could consider two memory or storage locations distinct even though their addresses were computed from different values of the same reassigned variable and coincided at runtime. This could lead to loads being replaced with outdated values and to needed stores being removed.",
"description": "The Yul optimizer steps LoadResolver and EqualStoreEliminator keep track of what was stored in memory and storage. LoadResolver uses this to replace loads and keccak256 calls with known values, and EqualStoreEliminator uses it to remove stores of a value that the location already contains. Whenever a store is encountered whose exact location cannot be determined, the optimizer has to forget what it knows about every location the store might overwrite. To decide this, the optimizer represents an address symbolically as a constant offset either from zero or from another variable (its base variable). Two addresses with the same base can then be determined to be distinct if their offsets differ (for storage) or are at least 32 bytes apart (for memory). These representations were cached per variable. The base variable, however, may be reassigned afterwards. The optimizer did not always notice and then compared an address computed from the old value of the base with an address computed from the new value as if both used the same base. As a result, it could consider two locations distinct even though they coincided at runtime, keeping a stale entry for a location that had just been overwritten. A subsequent load from that location could then be replaced with an outdated value, a subsequent store of that value to the location could be removed, and keccak256 over the location could be replaced with the hash of an outdated value. Whether the bug is triggered depends on the structure of the intermediate code these optimizer steps receive. It is therefore sensitive to the optimizer sequence and to the surrounding code, and the two locations additionally have to coincide at runtime. In optimized IR code generation, any code may be affected, including code without inline assembly. In optimized evmasm code generation, only inline assembly that does not refer to any Solidity variables or functions and compiler-generated Yul utility functions could be affected. Unoptimized code is unaffected.",
"link": "https://blog.soliditylang.org/2026/10/22/yul-optimizer-knowledge-base-stale-bookkeeping-bug/",
"introduced": "0.8.19",
"fixed": "0.8.38",
"severity": "low",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2026-6",
"name": "MisorderedNamedParametersInRequireWithCustomErrors",
"summary": "Custom error arguments passed to require using named-parameter syntax are ABI-encoded in call-site order instead of declaration order when compiling via IR.",
"description": "When a custom error was passed into the second argument of require and instantiated using named parameter syntax (e.g., require(condition, MyError({b: 1, a: 2}))), the IR-based code generator would pass the arguments to the ABI encoder in the order they appeared at the call site, without reordering them to match the error definition. The arguments were type-checked against the parameters with matching names, not the ones they were actually passed into by the codegen, so the bug would not result in a compilation error. Instead, the encoder would produce a structurally valid encoding matching the error signature but not reflecting the values used to instantiate the error. The arguments on the stack would be reordered and possibly reinterpreted as different types by the encoder. In case of reference types, the reinterpretation would result in the content being obtained from wrong offsets in memory, storage or calldata. In some cases large values misinterpreted as offsets or lengths would make the encoder revert due to running out of gas. Types that occupy more than one slot on the stack would further complicate the behavior by leading to not only reordering but also misalignment of argument boundaries. The only unaffected types were string literals, which are not being passed to the encoder through the stack. The bug was specific to custom errors passed as the second argument of require. Standalone revert ErrorName({...}) statements, event emissions, function calls, struct constructor invocations and other constructs supporting named parameters were not affected. The evmasm pipeline was also unaffected.",
"link": "https://blog.soliditylang.org/2026/09/10/misordered-named-parameters-in-require-with-custom-errors-bug/",
"introduced": "0.8.26",
"fixed": "0.8.37",
"severity": "very low",
"conditions": {
"viaIR": true
}
},
{
"uid": "SOL-2026-5",
"name": "MemoryByteArrayElementDeleteClearsWholeWord",
"summary": "Applying delete to a single element of a bytes array in memory clears not only that element but the whole 32-byte word starting at the element's location, zeroing up to 31 bytes beyond the element.",
"description": "Elements of bytes arrays in memory are packed, each occupying a single byte. When a value is assigned to such an element, the evmasm code generator correctly stores it with a single-byte MSTORE8 instruction. The code path in the evmasm pipeline implementing delete on such an element, however, wrote the zero value with a full-word MSTORE, clearing the 32 bytes starting at the element's location. The bytes following the element within the array were silently zeroed. If the element was within the last 31 bytes of the array's allocation, the write also extended past it into the area where the allocator places the next memory object, clearing the most significant bytes of that object's first word. How many elements are in reach depends on the size of the allocation: arrays created with new bytes(n) or from literals occupy their length rounded up to a multiple of 32 bytes, so only elements falling within the last 31 bytes of that rounded-up area, if any, could be affected. The results of bytes.concat, string.concat, and the abi.encode* functions, on the other hand, are placed by the evmasm pipeline in an allocation of exactly the size of their data, so the next object starts immediately after their last element and each of their last 31 elements is in reach. Assigning zero to an element (b[i] = 0) was not affected, only the delete operator, and neither were byte arrays in transient storage, storage, or calldata. The bug exists only in the evmasm pipeline. Code compiled via IR is unaffected. Optimizer settings have no influence. The defective code predates the first released version of the compiler.",
"link": "https://blog.soliditylang.org/2026/09/10/memory-byte-array-element-delete-clears-whole-word-bug/",
"fixed": "0.8.37",
"severity": "low/medium",
"conditions": {
"viaIR": false
}
},
{
"uid": "SOL-2026-4",
"name": "SpillSlotCollisionAcrossMutualRecursion",
"summary": "Local variables of two simultaneously active functions moved to fixed memory offsets by the stack limit evader may be assigned the same offset if the call graph contains mutual recursion, so that one variable is silently overwritten by the other.",
"description": "To work around the 16-slot stack access limit of the EVM, the IR-based code generator can, under some preconditions, move local variables to fixed memory offsets. Variables that can never be active at the same time may safely share an offset, so the reserved memory area is sized by a depth-first walk of the call graph that computes for every node the number of slots it and its callees need. To keep this walk from descending infinitely into recursive call chains, the slot count was initialized with zero upon entering it. This provisional zero was observable: a function reached again through a call graph cycle reported an empty footprint to its caller, the caller's count was finalized and cached on that basis, and the undercount propagated to every later caller, including functions outside the cycle. As a result, a function called by such a cycle and a function calling into it could be assigned the same memory slot even though both can be active at the same time. A relocated variable still needed after the call into the cycle returned had then been silently overwritten by the called function, producing wrong results. Triggering the bug requires the IR pipeline and a call graph in which a cycle of at least two mutually recursive functions both reaches a function needing relocation of variables to memory and is entered from a separate call chain whose own relocated variable is read again after the call towards the cycle returns. From 0.8.21 onward, it is independent of whether the optimizer is enabled.",
"link": "https://blog.soliditylang.org/2026/09/10/spill-slot-collision-across-mutual-recursion-bug/",
"introduced": "0.7.2",
"fixed": "0.8.37",
"severity": "low/medium",
"conditions": {
"viaIR": true
}
},
{
"uid": "SOL-2026-3",
"name": "InheritanceOrderReversalOnStorageEndWarning",
"summary": "Emitting a warning about storage base location being too close to the storage end unintentionally reversed the linearizedBaseContracts annotation, possibly leading to miscompilation due to reversing the order in which inheritance is resolved.",
"description": "When the compiler detects that a custom layout specifier puts contract's static storage area too close to the end of the address space, it emits a warning. To make the warning more useful, the compiler tries to point at the last storage variable in that area. For this reason it walks the linearized inheritance hierarchy in reverse (from the least to the most derived). The list is calculated once and stored in an AST annotation called linearizedBaseContracts. The direct cause of the bug was the fact that the code that reverses the list was doing it in place rather than on a copy, modifying the annotation. This effectively reversed the order of base contracts seen by any component that runs after layout checks: later phases of analysis, AST export, code generator, SMTChecker, etc. The observable effect was a reversed order of state variable initialization, constructor invocation, virtual function/modifier resolution, leading either to miscompilations or internal compiler errors, depending on the specific usage. Since the source of the bug was in the analysis stage, it was independent of the codegen pipeline or optimizer settings. The main condition necessary to trigger the bug was the presence of the warning in the output. The other is presence of language constructs whose evaluation depends on the inheritance order. While potential effects are very serious, this requirement excludes the vast majority of contracts as intentionally placing the storage variables in the last 264 slots is highly discouraged, which was actually the main reason for adding this warning.",
"link": "https://blog.soliditylang.org/2026/07/09/inheritance-order-reversal-on-storage-end-warning-bug/",
"introduced": "0.8.29",
"fixed": "0.8.36",
"severity": "medium"
},
{
"uid": "SOL-2026-2",
"name": "UnsoundSpillInMutualRecursion",
"summary": "Local variables of a function involved in mutual recursion may spuriously be moved to fixed memory offsets and overwritten across recursive calls.",
"description": "To work around the 16-slot stack access limit of the EVM, the IR-based code generator can move local variables of stack-too-deep functions to fixed memory offsets. This relocation is unsound for recursive functions: a fixed offset would be shared by all activations of the function, so a recursive call would overwrite the caller's value. The stack limit evader therefore must not relocate variables of functions that are part of a recursive call chain. To this end, the call graph was searched for cycles using a path-based depth-first search that, once a function had been fully explored and popped from the search path, short-circuited on it on any later visit. As a result, a function shared between several intersecting cycles could be reached first through a path that did not yet close a cycle through it, get marked as finished, and then be skipped when a later path would have revealed that it does lie on a cycle. Such a function was misclassified as non-recursive. When a misclassified function was complex enough for the stack limit evader to relocate some of its variables, those variables were moved to fixed memory offsets and silently corrupted on recursion, producing wrong results rather than a compile-time error. Triggering the bug requires the IR pipeline, a set of mutually recursive functions whose call graph contains intersecting cycles, at least one of the functions in an undetected part of a cycle being complex enough to require relocation to memory, and an unfortunate processing order of the functions (which depends on the hashes of their Yul names). It is independent of whether the optimizer is enabled.",
"link": "https://blog.soliditylang.org/2026/07/09/unsound-spill-in-mutual-recursion-bug/",
"introduced": "0.7.2",
"fixed": "0.8.36",
"severity": "medium",
"conditions": {
"viaIR": true
}
},
{
"uid": "SOL-2026-1",
"name": "TransientStorageClearingHelperCollision",
"summary": "Clearing both storage and transient storage variables in the same contract may result in only one of these locations being cleared.",
"description": "The IR-based code generator provides a set of Yul helper functions for basic operations, such as clearing, copying, encoding or type conversions. Not all functions are used by every contract. The codegen appends them to the generated sources individually, only when an operation that would invoke one of them is encountered. Utility functions are often specialized for different types and locations. Since Yul does not support generic functions, specialization is done by generating multiple versions of the same function, with the information distinguishing the variants embedded in their names. However, if not all the necessary bits of distinguishing information are properly accounted for, two helpers may end up with the same name, causing a collision. In this situation the codegen includes only one of them, with calls to both variants invoking it. This happened with the set_to_zero helper used when an area of transient or persistent storage needs to be cleared. The helper name was missing the location information, which resulted in a collision between the persistent and transient storage variants for the same type. This meant that contracts clearing both locations would actually clear only one, leaving the other untouched. Which location ended up being cleared depended on the order in which the code generator processed the input. The necessary condition to trigger the bug was the use of delete operator on a transient storage variable. This was due to value types being the only types supported in transient storage and delete being the only operation invoking the helper allowed on such types. The other necessary condition was clearing of persistent storage and in this case the range of affected operations was wider: operator delete, array pop() or assignment that resulted in a longer array being overwritten with a shorter one. The cleared variable itself also did not necessarily have to be of the same type. It was enough that a matching value type was nested in it. It also did not always have to be the exact same value type - clearing operations on reference types are usually performed at slot granularity, treating every slot as uint256 rather than clearing every value packed into it individually. To trigger the bug both operations had to be present within the same piece of bytecode. Independent contracts, not related through inheritance, would not affect each other this way. The presence of one operation only in creation code and the other only in deployed code would not trigger the bug either.",
"link": "https://blog.soliditylang.org/2026/02/18/transient-storage-clearing-helper-collision-bug/",
"introduced": "0.8.28",
"fixed": "0.8.34",
"severity": "high",
"conditions": {
"viaIR": true,
"evmVersion": ">=cancun"
}
},
{
"uid": "SOL-2025-1",
"name": "LostStorageArrayWriteOnSlotOverflow",
"summary": "Operations that involve clearing or copying from arrays that straddle the end of storage could result in silent data retention.",
"description": "Solidity makes it possible to define variables that extend past the last (2
256-th) slot of storage, which results in wrap-around back to slot zero. Since EVM uses 256-bit integer arithmetic, most operations on such variables just work. The only situation which requires special attention is iteration against absolute slot addresses: the invariant that the last slot belonging to a variable has the highest address does not hold. When implemented incorrectly, a loop over an array will immediately terminate if the container spans the end of storage - due to the initial position already being greater than the end position. This affected storage array clearing loops generated by both evmasm and IR pipelines. Additionally, (only in the evmasm pipeline) copying operations whose source was an array straddling the end of storage were also affected. At the language level, the buggy code would be generated for array assignment, array initialization, delete operator, .pop() and .push(). Note that a clearing loop is inserted by the compiler not only for invocations of the delete operator, but also to zero storage when overwriting a longer array with a shorter one, popping an element or even pushing an empty element to a dynamic array. Since clearing is a separate loop, it is possible for the bug to only affect it and not the copy operation it follows (which is always the case in the IR pipeline). The bug is extremely unlikely to be triggered accidentally due to the probabilistic impossibility of a short dynamic array being allocated right at the storage boundary. On the other hand, scenarios in which a user may place a static array there intentionally do not seem realistic and are limited to unusual layouts, in which a contract does not place any storage variables at slot zero (otherwise they would overlap the array).",
"link": "https://blog.soliditylang.org/2025/12/18/lost-storage-array-write-on-slot-overflow-bug/",
"introduced": "0.1.0",
"fixed": "0.8.32",
"severity": "low"
},
{
"uid": "SOL-2023-3",
"name": "VerbatimInvalidDeduplication",
"summary": "All verbatim blocks are considered identical by deduplicator and can incorrectly be unified when surrounded by identical opcodes.",
"description": "The block deduplicator is a step of the opcode-based optimizer which identifies equivalent assembly blocks and merges them into a single one. However, when blocks contained verbatim, their comparison was performed incorrectly, leading to the collapse of assembly blocks which are identical except for the contents of the verbatim items. Since verbatim is only available in Yul, compilation of Solidity sources is not affected.",
"link": "https://blog.soliditylang.org/2023/11/08/verbatim-invalid-deduplication-bug/",
"introduced": "0.8.5",
"fixed": "0.8.23",
"severity": "low"
},
{
"uid": "SOL-2023-2",
"name": "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"summary": "Optimizer sequences containing FullInliner do not preserve the evaluation order of arguments of inlined function calls in code that is not in expression-split form.",
"description": "Function call arguments in Yul are evaluated right to left. This order matters when the argument expressions have side-effects, and changing it may change contract behavior. FullInliner is an optimizer step that can replace a function call with the body of that function. The transformation involves assigning argument expressions to temporary variables, which imposes an explicit evaluation order. FullInliner was written with the assumption that this order does not necessarily have to match usual argument evaluation order because the argument expressions have no side-effects. In most circumstances this assumption is true because the default optimization step sequence contains the ExpressionSplitter step. ExpressionSplitter ensures that the code is in expression-split form, which means that function calls cannot appear nested inside expressions, and all function call arguments have to be variables. The assumption is, however, not guaranteed to be true in general. Version 0.6.7 introduced a setting allowing users to specify an arbitrary optimization step sequence, making it possible for the FullInliner to actually encounter argument expressions with side-effects, which can result in behavior differences between optimized and unoptimized bytecode. Contracts compiled without optimization or with the default optimization sequence are not affected. To trigger the bug the user has to explicitly choose compiler settings that contain a sequence with FullInliner step not preceded by ExpressionSplitter.",
"link": "https://blog.soliditylang.org/2023/07/19/full-inliner-non-expression-split-argument-evaluation-order-bug/",
"introduced": "0.6.7",
"fixed": "0.8.21",
"severity": "low",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2023-1",
"name": "MissingSideEffectsOnSelectorAccess",
"summary": "Accessing the .selector member on complex expressions leaves the expression unevaluated in the legacy code generation.",
"description": "When accessing the .selector member on an expression with side-effects, like an assignment, a function call or a conditional, the expression would not be evaluated in the legacy code generation. This would happen in expressions where the functions used in the expression were all known at compilation time, regardless of whether the whole expression could be evaluated at compilation time or not. Note that the code generated by the IR pipeline was unaffected and would behave as expected.",
"link": "https://blog.soliditylang.org/2023/07/19/missing-side-effects-on-selector-access-bug/",
"introduced": "0.6.2",
"fixed": "0.8.21",
"severity": "low",
"conditions": {
"viaIR": false
}
},
{
"uid": "SOL-2022-7",
"name": "StorageWriteRemovalBeforeConditionalTermination",
"summary": "Calling functions that conditionally terminate the external EVM call using the assembly statements return(...) or stop() may result in incorrect removals of prior storage writes.",
"description": "A call to a Yul function that conditionally terminates the external EVM call could result in prior storage writes being incorrectly removed by the Yul optimizer. This used to happen in cases in which it would have been valid to remove the store, if the Yul function in question never actually terminated the external call, and the control flow always returned back to the caller instead. Conditional termination within the same Yul block instead of within a called function was not affected. In Solidity with optimized via-IR code generation, any storage write before a function conditionally calling return(...) or stop() in inline assembly, may have been incorrectly removed, whenever it would have been valid to remove the write without the return(...) or stop(). In optimized legacy code generation, only inline assembly that did not refer to any Solidity variables and that involved conditionally-terminating user-defined assembly functions could be affected.",
"link": "https://blog.soliditylang.org/2022/09/08/storage-write-removal-before-conditional-termination/",
"introduced": "0.8.13",
"fixed": "0.8.17",
"severity": "medium/high",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2022-6",
"name": "AbiReencodingHeadOverflowWithStaticArrayCleanup",
"summary": "ABI-encoding a tuple with a statically-sized calldata array in the last component would corrupt 32 leading bytes of its first dynamically encoded component.",
"description": "When ABI-encoding a statically-sized calldata array, the compiler always pads the data area to a multiple of 32-bytes and ensures that the padding bytes are zeroed. In some cases, this cleanup used to be performed by always writing exactly 32 bytes, regardless of how many needed to be zeroed. This was done with the assumption that the data that would eventually occupy the area past the end of the array had not yet been written, because the encoder processes tuple components in the order they were given. While this assumption is mostly true, there is an important corner case: dynamically encoded tuple components are stored separately from the statically-sized ones in an area called the tail of the encoding and the tail immediately follows the head, which is where the statically-sized components are placed. The aforementioned cleanup, if performed for the last component of the head would cross into the tail and overwrite up to 32 bytes of the first component stored there with zeros. The only array type for which the cleanup could actually result in an overwrite were arrays with uint256 or bytes32 as the base element type and in this case the size of the corrupted area was always exactly 32 bytes. The problem affected tuples at any nesting level. This included also structs, which are encoded as tuples in the ABI. Note also that lists of parameters and return values of functions, events and errors are encoded as tuples.",
"link": "https://blog.soliditylang.org/2022/08/08/calldata-tuple-reencoding-head-overflow-bug/",
"introduced": "0.5.8",
"fixed": "0.8.16",
"severity": "medium",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2022-5",
"name": "DirtyBytesArrayToStorage",
"summary": "Copying bytes arrays from memory or calldata to storage may result in dirty storage values.",
"description": "Copying bytes arrays from memory or calldata to storage is done in chunks of 32 bytes even if the length is not a multiple of 32. Thereby, extra bytes past the end of the array may be copied from calldata or memory to storage. These dirty bytes may then become observable after a .push() without arguments to the bytes array in storage, i.e. such a push will not result in a zero value at the end of the array as expected. This bug only affects the legacy code generation pipeline, the new code generation pipeline via IR is not affected.",
"link": "https://blog.soliditylang.org/2022/06/15/dirty-bytes-array-to-storage-bug/",
"introduced": "0.0.1",
"fixed": "0.8.15",
"severity": "low"
},
{
"uid": "SOL-2022-4",
"name": "InlineAssemblyMemorySideEffects",
"summary": "The Yul optimizer may incorrectly remove memory writes from inline assembly blocks, that do not access solidity variables.",
"description": "The Yul optimizer considers all memory writes in the outermost Yul block that are never read from as unused and removes them. This is valid when that Yul block is the entire Yul program, which is always the case for the Yul code generated by the new via-IR pipeline. Inline assembly blocks are never optimized in isolation when using that pipeline. Instead they are optimized as a part of the whole Yul input. However, the legacy code generation pipeline (which is still the default) runs the Yul optimizer individually on an inline assembly block if the block does not refer to any local variables defined in the surrounding Solidity code. Consequently, memory writes in such inline assembly blocks are removed as well, if the written memory is never read from in the same assembly block, even if the written memory is accessed later, for example by a subsequent inline assembly block.",
"link": "https://blog.soliditylang.org/2022/06/15/inline-assembly-memory-side-effects-bug/",
"introduced": "0.8.13",
"fixed": "0.8.15",
"severity": "medium",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2022-3",
"name": "DataLocationChangeInInternalOverride",
"summary": "It was possible to change the data location of the parameters or return variables from calldata to memory and vice-versa while overriding internal and public functions. This caused invalid code to be generated when calling such a function internally through virtual function calls.",
"description": "When calling external functions, it is irrelevant if the data location of the parameters is calldata or memory, the encoding of the data does not change. Because of that, changing the data location when overriding external functions is allowed. The compiler incorrectly also allowed a change in the data location for overriding public and internal functions. Since public functions can be called internally as well as externally, this causes invalid code to be generated when such an incorrectly overridden function is called internally through the base contract. The caller provides a memory pointer, but the called function interprets it as a calldata pointer or vice-versa.",
"link": "https://blog.soliditylang.org/2022/05/17/data-location-inheritance-bug/",
"introduced": "0.6.9",
"fixed": "0.8.14",
"severity": "very low"
},
{
"uid": "SOL-2022-2",
"name": "NestedCalldataArrayAbiReencodingSizeValidation",
"summary": "ABI-reencoding of nested dynamic calldata arrays did not always perform proper size checks against the size of calldata and could read beyond calldatasize().",
"description": "Calldata validation for nested dynamic types is deferred until the first access to the nested values. Such an access may for example be a copy to memory or an index or member access to the outer type. While in most such accesses calldata validation correctly checks that the data area of the nested array is completely contained in the passed calldata (i.e. in the range [0, calldatasize()]), this check may not be performed, when ABI encoding such nested types again directly from calldata. For instance, this can happen, if a value in calldata with a nested dynamic array is passed to an external call, used in abi.encode or emitted as event. In such cases, if the data area of the nested array extends beyond calldatasize(), ABI encoding it did not revert, but continued reading values from beyond calldatasize() (i.e. zero values).",
"link": "https://blog.soliditylang.org/2022/05/17/calldata-reencode-size-check-bug/",
"introduced": "0.5.8",
"fixed": "0.8.14",
"severity": "very low"
},
{
"uid": "SOL-2022-1",
"name": "AbiEncodeCallLiteralAsFixedBytesBug",
"summary": "Literals used for a fixed length bytes parameter in abi.encodeCall were encoded incorrectly.",
"description": "For the encoding, the compiler only considered the types of the expressions in the second argument of abi.encodeCall itself, but not the parameter types of the function given as first argument. In almost all cases the abi encoding of the type of the expression matches the abi encoding of the parameter type of the given function. This is because the type checker ensures the expression is implicitly convertible to the respective parameter type. However this is not true for number literals used for fixed bytes types shorter than 32 bytes, nor for string literals used for any fixed bytes type. Number literals were encoded as numbers instead of being shifted to become left-aligned. String literals were encoded as dynamically sized memory strings instead of being converted to a left-aligned bytes value.",
"link": "https://blog.soliditylang.org/2022/03/16/encodecall-bug/",
"introduced": "0.8.11",
"fixed": "0.8.13",
"severity": "very low"
},
{
"uid": "SOL-2021-4",
"name": "UserDefinedValueTypesBug",
"summary": "User defined value types with underlying type shorter than 32 bytes used incorrect storage layout and wasted storage",
"description": "The compiler did not correctly compute the storage layout of user defined value types based on types that are shorter than 32 bytes. It would always use a full storage slot for these types, even if the underlying type was shorter. This was wasteful and might have problems with tooling or contract upgrades.",
"link": "https://blog.soliditylang.org/2021/09/29/user-defined-value-types-bug/",
"introduced": "0.8.8",
"fixed": "0.8.9",
"severity": "very low"
},
{
"uid": "SOL-2021-3",
"name": "SignedImmutables",
"summary": "Immutable variables of signed integer type shorter than 256 bits can lead to values with invalid higher order bits if inline assembly is used.",
"description": "When immutable variables of signed integer type shorter than 256 bits are read, their higher order bits were unconditionally set to zero. The correct operation would be to sign-extend the value, i.e. set the higher order bits to one if the sign bit is one. This sign-extension is performed by Solidity just prior to when it matters, i.e. when a value is stored in memory, when it is compared or when a division is performed. Because of that, to our knowledge, the only way to access the value in its unclean state is by reading it through inline assembly.",
"link": "https://blog.soliditylang.org/2021/09/29/signed-immutables-bug/",
"introduced": "0.6.5",
"fixed": "0.8.9",
"severity": "very low"
},
{
"uid": "SOL-2021-2",
"name": "ABIDecodeTwoDimensionalArrayMemory",
"summary": "If used on memory byte arrays, result of the function abi.decode can depend on the contents of memory outside of the actual byte array that is decoded.",
"description": "The ABI specification uses pointers to data areas for everything that is dynamically-sized. When decoding data from memory (instead of calldata), the ABI decoder did not properly validate some of these pointers. More specifically, it was possible to use large values for the pointers inside arrays such that computing the offset resulted in an undetected overflow. This could lead to these pointers targeting areas in memory outside of the actual area to be decoded. This way, it was possible for abi.decode to return different values for the same encoded byte array.",
"link": "https://blog.soliditylang.org/2021/04/21/decoding-from-memory-bug/",
"introduced": "0.4.16",
"fixed": "0.8.4",
"conditions": {
"ABIEncoderV2": true
},
"severity": "very low"
},
{
"uid": "SOL-2021-1",
"name": "KeccakCaching",
"summary": "The bytecode optimizer incorrectly reused previously evaluated Keccak-256 hashes. You are unlikely to be affected if you do not compute Keccak-256 hashes in inline assembly.",
"description": "Solidity's bytecode optimizer has a step that can compute Keccak-256 hashes, if the contents of the memory are known during compilation time. This step also has a mechanism to determine that two Keccak-256 hashes are equal even if the values in memory are not known during compile time. This mechanism had a bug where Keccak-256 of the same memory content, but different sizes were considered equal. More specifically, keccak256(mpos1, length1) and keccak256(mpos2, length2) in some cases were considered equal if length1 and length2, when rounded up to nearest multiple of 32 were the same, and when the memory contents at mpos1 and mpos2 can be deduced to be equal. You maybe affected if you compute multiple Keccak-256 hashes of the same content, but with different lengths inside inline assembly. You are unaffected if your code uses keccak256 with a length that is not a compile-time constant or if it is always a multiple of 32.",
"link": "https://blog.soliditylang.org/2021/03/23/keccak-optimizer-bug/",
"fixed": "0.8.3",
"conditions": {
"optimizer": true
},
"severity": "medium"
},
{
"uid": "SOL-2020-11",
"name": "EmptyByteArrayCopy",
"summary": "Copying an empty byte array (or string) from memory or calldata to storage can result in data corruption if the target array's length is increased subsequently without storing new data.",
"description": "The routine that copies byte arrays from memory or calldata to storage stores unrelated data from after the source array in the storage slot if the source array is empty. If the storage array's length is subsequently increased either by using .push() or by assigning to its .length attribute (only before 0.6.0), the newly created byte array elements will not be zero-initialized, but contain the unrelated data. You are not affected if you do not assign to .length and do not use .push() on byte arrays, or only use .push(<arg>) or manually initialize the new elements.",
"link": "https://blog.soliditylang.org/2020/10/19/empty-byte-array-copy-bug/",
"fixed": "0.7.4",
"severity": "medium"
},
{
"uid": "SOL-2020-10",
"name": "DynamicArrayCleanup",
"summary": "When assigning a dynamically-sized array with types of size at most 16 bytes in storage causing the assigned array to shrink, some parts of deleted slots were not zeroed out.",
"description": "Consider a dynamically-sized array in storage whose base-type is small enough such that multiple values can be packed into a single slot, such as uint128[]. Let us define its length to be l. When this array gets assigned from another array with a smaller length, say m, the slots between elements m and l have to be cleaned by zeroing them out. However, this cleaning was not performed properly. Specifically, after the slot corresponding to m, only the first packed value was cleaned up. If this array gets resized to a length larger than m, the indices corresponding to the unclean parts of the slot contained the original value, instead of 0. The resizing here is performed by assigning to the array length, by a push() or via inline assembly. You are not affected if you are only using .push(<arg>) or if you assign a value (even zero) to the new elements after increasing the length of the array.",
"link": "https://blog.soliditylang.org/2020/10/07/solidity-dynamic-array-cleanup-bug/",
"fixed": "0.7.3",
"severity": "medium"
},
{
"uid": "SOL-2020-9",
"name": "FreeFunctionRedefinition",
"summary": "The compiler does not flag an error when two or more free functions with the same name and parameter types are defined in a source unit or when an imported free function alias shadows another free function with a different name but identical parameter types.",
"description": "In contrast to functions defined inside contracts, free functions with identical names and parameter types did not create an error. Both definition of free functions with identical name and parameter types and an imported free function with an alias that shadows another function with a different name but identical parameter types were permitted due to which a call to either the multiply defined free function or the imported free function alias within a contract led to the execution of that free function which was defined first within the source unit. Subsequently defined identical free function definitions were silently ignored and their code generation was skipped.",
"introduced": "0.7.1",
"fixed": "0.7.2",
"severity": "low"
},
{
"uid": "SOL-2020-8",
"name": "UsingForCalldata",
"summary": "Function calls to internal library functions with calldata parameters called via using for can result in invalid data being read.",
"description": "Function calls to internal library functions using the using for mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.",
"introduced": "0.6.9",
"fixed": "0.6.10",
"severity": "very low"
},
{
"uid": "SOL-2020-7",
"name": "MissingEscapingInFormatting",
"summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.",
"description": "When ABIEncoderV2 is enabled, string literals passed directly to encoding functions or external function calls are stored as strings in the intermediate code. Characters outside the printable range are handled correctly, but backslashes are not escaped in this procedure. This leads to double backslashes being reduced to single backslashes and consequently re-interpreted as escapes potentially resulting in a different string being encoded.",
"introduced": "0.5.14",
"fixed": "0.6.8",
"severity": "very low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2020-6",
"name": "ArraySliceDynamicallyEncodedBaseType",
"summary": "Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.",
"description": "For arrays with dynamically sized base types, index range accesses that use a start expression that is non-zero will result in invalid array slices. Any index access to such array slices will result in data being read from incorrect calldata offsets. Array slices are only supported for dynamic calldata types and all problematic type require ABIEncoderV2 to be enabled.",
"introduced": "0.6.0",
"fixed": "0.6.8",
"severity": "very low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2020-5",
"name": "ImplicitConstructorCallvalueCheck",
"summary": "The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.",
"description": "Starting from Solidity 0.4.5 the creation code of contracts without explicit payable constructor is supposed to contain a callvalue check that results in contract creation reverting, if non-zero value is passed. However, this check was missing in case no explicit constructor was defined in a contract at all, but the contract has a base that does define a constructor. In these cases it is possible to send value in a contract creation transaction or using inline assembly without revert, even though the creation code is supposed to be non-payable.",
"introduced": "0.4.5",
"fixed": "0.6.8",
"severity": "very low"
},
{
"uid": "SOL-2020-4",
"name": "TupleAssignmentMultiStackSlotComponents",
"summary": "Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.",
"description": "Tuple assignments did not correctly account for tuple components that occupy multiple stack slots in case the number of stack slots differs between left-hand-side and right-hand-side. This can either happen in the presence of nested tuples or if the right-hand-side contains external function pointers or references to dynamic calldata arrays, while the left-hand-side contains an omission.",
"introduced": "0.1.6",
"fixed": "0.6.6",
"severity": "very low"
},
{
"uid": "SOL-2020-3",
"name": "MemoryArrayCreationOverflow",
"summary": "The creation of very large memory arrays can result in overlapping memory regions and thus memory corruption.",
"description": "No runtime overflow checks were performed for the length of memory arrays during creation. In cases for which the memory size of an array in bytes, i.e. the array length times 32, is larger than 2^256-1, the memory allocation will overflow, potentially resulting in overlapping memory areas. The length of the array is still stored correctly, so copying or iterating over such an array will result in out-of-gas.",
"link": "https://blog.soliditylang.org/2020/04/06/memory-creation-overflow-bug/",
"introduced": "0.2.0",
"fixed": "0.6.5",
"severity": "low"
},
{
"uid": "SOL-2020-1",
"name": "YulOptimizerRedundantAssignmentBreakContinue",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with break or continue even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.6.0",
"fixed": "0.6.1",
"severity": "medium",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2020-2",
"name": "privateCanBeOverridden",
"summary": "Private methods can be overridden by inheriting contracts.",
"description": "While private methods of base contracts are not visible and cannot be called directly from the derived contract, it is still possible to declare a function of the same name and type and thus change the behaviour of the base contract's function.",
"introduced": "0.3.0",
"fixed": "0.5.17",
"severity": "low"
},
{
"uid": "SOL-2020-1",
"name": "YulOptimizerRedundantAssignmentBreakContinue0.5",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with break or continue even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.5.8",
"fixed": "0.5.16",
"severity": "low",
"conditions": {
"yulOptimizer": true
}
},
{
"uid": "SOL-2019-10",
"name": "ABIEncoderV2LoopYulOptimizer",
"summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.",
"description": "The Yul optimizer incorrectly replaces mload and sload calls with values that have been previously written to the load location (and potentially changed in the meantime) if all of the following conditions are met: (1) there is a matching mstore or sstore call before; (2) the contents of memory or storage is only changed in a function that is called (directly or indirectly) in between the first store and the load call; (3) called function contains a for loop where the same memory location is changed in the condition or the post or body block. When used in Solidity mode, this can only happen if the experimental ABIEncoderV2 is activated and the experimental Yul optimizer has been activated manually in addition to the regular optimizer in the compiler settings.",
"introduced": "0.5.14",
"fixed": "0.5.15",
"severity": "low",
"conditions": {
"ABIEncoderV2": true,
"optimizer": true,
"yulOptimizer": true
}
},
{
"uid": "SOL-2019-9",
"name": "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"summary": "Reading from calldata structs that contain dynamically encoded, but statically-sized members can result in incorrect values.",
"description": "When a calldata struct contains a dynamically encoded, but statically-sized member, the offsets for all subsequent struct members are calculated incorrectly. All reads from such members will result in invalid values. Only calldata structs are affected, i.e. this occurs in external functions with such structs as argument. Using affected structs in storage or memory or as arguments to public functions on the other hand works correctly.",
"introduced": "0.5.6",
"fixed": "0.5.11",
"severity": "low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2019-8",
"name": "SignedArrayStorageCopy",
"summary": "Assigning an array of signed integers to a storage array of different type can lead to data corruption in that array.",
"description": "In two's complement, negative integers have their higher order bits set. In order to fit into a shared storage slot, these have to be set to zero. When a conversion is done at the same time, the bits to set to zero were incorrectly determined from the source and not the target type. This means that such copy operations can lead to incorrect values being stored.",
"link": "https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/",
"introduced": "0.4.7",
"fixed": "0.5.10",
"severity": "low/medium"
},
{
"uid": "SOL-2019-7",
"name": "ABIEncoderV2StorageArrayWithMultiSlotElement",
"summary": "Storage arrays containing structs or other statically-sized arrays are not read properly when directly encoded in external function calls or in abi.encode*.",
"description": "When storage arrays whose elements occupy more than a single storage slot are directly encoded in external function calls or using abi.encode*, their elements are read in an overlapping manner, i.e. the element pointer is not properly advanced between reads. This is not a problem when the storage data is first copied to a memory variable or if the storage array only contains value types or dynamically-sized arrays.",
"link": "https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/",
"introduced": "0.4.16",
"fixed": "0.5.10",
"severity": "low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2019-6",
"name": "DynamicConstructorArgumentsClippedABIV2",
"summary": "A contract's constructor that takes structs or arrays that contain dynamically-sized arrays reverts or decodes to invalid data.",
"description": "During construction of a contract, constructor parameters are copied from the code section to memory for decoding. The amount of bytes to copy was calculated incorrectly in case all parameters are statically-sized but contain dynamically-sized arrays as struct members or inner arrays. Such types are only available if ABIEncoderV2 is activated.",
"introduced": "0.4.16",
"fixed": "0.5.9",
"severity": "very low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2019-5",
"name": "UninitializedFunctionPointerInConstructor",
"summary": "Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.",
"description": "Uninitialized internal function pointers point to a special piece of code that causes a revert when called. Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.",
"introduced": "0.5.0",
"fixed": "0.5.8",
"severity": "very low"
},
{
"uid": "SOL-2019-5",
"name": "UninitializedFunctionPointerInConstructor_0.4.x",
"summary": "Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.",
"description": "Uninitialized internal function pointers point to a special piece of code that causes a revert when called. Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.",
"introduced": "0.4.5",
"fixed": "0.4.26",
"severity": "very low"
},
{
"uid": "SOL-2019-4",
"name": "IncorrectEventSignatureInLibraries",
"summary": "Contract types used in events in libraries cause an incorrect event signature hash",
"description": "Instead of using the type address in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.",
"introduced": "0.5.0",
"fixed": "0.5.8",
"severity": "very low"
},
{
"uid": "SOL-2019-4",
"name": "IncorrectEventSignatureInLibraries_0.4.x",
"summary": "Contract types used in events in libraries cause an incorrect event signature hash",
"description": "Instead of using the type address in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.",
"introduced": "0.3.0",
"fixed": "0.4.26",
"severity": "very low"
},
{
"uid": "SOL-2019-3",
"name": "ABIEncoderV2PackedStorage",
"summary": "Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.",
"description": "Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2. This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.",
"link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.0",
"fixed": "0.5.7",
"severity": "low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2019-3",
"name": "ABIEncoderV2PackedStorage_0.4.x",
"summary": "Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.",
"description": "Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2. This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.",
"link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.4.19",
"fixed": "0.4.26",
"severity": "low",
"conditions": {
"ABIEncoderV2": true
}
},
{
"uid": "SOL-2019-2",
"name": "IncorrectByteInstructionOptimization",
"summary": "The optimizer incorrectly handles byte opcodes whose second argument is 31 or a constant expression that evaluates to 31. This can result in unexpected values.",
"description": "The optimizer incorrectly handles byte opcodes that use the constant 31 as second argument. This can happen when performing index access on bytesNN types with a compile-time constant value (not index) of 31 or when using the byte opcode in inline assembly.",
"link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.5",
"fixed": "0.5.7",
"severity": "very low",
"conditions": {
"optimizer": true
}
},
{
"uid": "SOL-2019-1",
"name": "DoubleShiftSizeOverflow",
"summary": "Double bitwise shifts by large constants whose sum overflows 256 bits can result in unexpected values.",
"description": "Nested logical shift operations whose total shift size is 2256 or more are incorrectly optimized. This only applies to shifts by numbers of bits that are compile-time constant expressions.",
"link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.5",
"fixed": "0.5.6",
"severity": "low",
"conditions": {
"optimizer": true,
"evmVersion": ">=constantinople"
}
},
{
"uid": "SOL-2018-4",
"name": "ExpExponentCleanup",
"summary": "Using the ** operator with an exponent of type shorter than 256 bits can result in unexpected values.",
"description": "Higher order bits in the exponent are not properly cleaned before the EXP opcode is applied if the type of the exponent expression is smaller than 256 bits and not smaller than the type of the base. In that case, the result might be larger than expected if the exponent is assumed to lie within the value range of the type. Literal numbers as exponents are unaffected as are exponents or bases of type uint256.",
"link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"fixed": "0.4.25",
"severity": "medium/high",
"check": {
"regex-source": "[^/]\
\* [^/0-9 ]"
}
},
{
"uid": "SOL-2018-3",
"name": "EventStructWrongData",
"summary": "Using structs in events logged wrong data.",
"description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.",
"link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"introduced": "0.4.17",
"fixed": "0.4.25",
"severity": "very low",
"check": {
"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"
}
},
{
"uid": "SOL-2018-2",
"name": "NestedArrayFunctionCallDecoder",
"summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.",
"description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.",
"link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"introduced": "0.1.4",
"fixed": "0.4.22",
"severity": "medium",
"check": {
"regex-source": "returns[^;{]
\[\s*[^\] \t\r\n\v\f][^\]]*\]\s
\[\s*[^\] \t\r\n\v\f][^\]]\][^{;][;{]"
}
},
{
"uid": "SOL-2018-1",
"name": "OneOfTwoConstructorsSkipped",
"summary": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.",
"description": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored. There will be a compiler warning about the old-style constructor, so contracts only using new-style constructors are fine.",
"introduced": "0.4.22",
"fixed": "0.4.23",
"severity": "very low"
},
{
"uid": "SOL-2017-5",
"name": "ZeroFunctionSelector",
"summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.",
"description": "If a function has a selector consisting only of zeros, is payable and part of a contract that does not have a fallback function and at most five external functions in total, this function is called instead of the fallback function if Ether is sent to the contract without data.",
"fixed": "0.4.18",
"severity": "very low"
},
{
"uid": "SOL-2017-4",
"name": "DelegateCallReturnValue",
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successful.",
"introduced": "0.3.0",
"fixed": "0.4.15",
"severity": "low"
},
{
"uid": "SOL-2017-3",
"name": "ECRecoverMalformedInput",
"summary": "The ecrecover() builtin can return garbage for malformed input.",
"description": "The ecrecover precompile does not properly signal failure for malformed input (especially in the 'v' argument) and thus the Solidity function can return data that was previously present in the return area in memory.",
"fixed": "0.4.14",
"severity": "medium"
},
{
"uid": "SOL-2017-2",
"name": "SkipEmptyStringLiteral",
"summary": "If "" is used in a function call, the following function arguments will not be correctly passed to the function.",
"description": "If the empty string literal "" is used as an argument in a function call, it is skipped by the encoder. This has the effect that the encoding of all arguments following this is shifted left by 32 bytes and thus the function call data is corrupted.",
"fixed": "0.4.12",
"severity": "low"
},
{
"uid": "SOL-2017-1",
"name": "ConstantOptimizerSubtraction",
"summary": "In some situations, the optimizer replaces certain numbers in the code with routines that compute different numbers.",
"description": "The optimizer tries to represent any number in the bytecode by routines that compute them with less gas. For some special numbers, an incorrect routine is generated. This could allow an attacker to e.g. trick victims about a specific amount of ether, or function calls to call different functions (or none at all).",
"link": "https://blog.soliditylang.org/2017/05/03/solidity-optimizer-bug/",
"fixed": "0.4.11",
"severity": "low",
"conditions": {
"optimizer": true
}
},
{
"uid": "SOL-2016-11",
"name": "IdentityPrecompileReturnIgnored",
"summary": "Failure of the identity precompile was ignored.",
"description": "Calls to the identity contract, which is used for copying memory, ignored its return value. On the public chain, calls to the identity precompile can be made in a way that they never fail, but this might be different on private chains.",
"severity": "low",
"fixed": "0.4.7"
},
{
"uid": "SOL-2016-10",
"name": "OptimizerStateKnowledgeNotResetForJumpdest",
"summary": "The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.",
"description": "The optimizer performs symbolic execution at certain stages. At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges. Computing this common state was simplified to just use the empty state, but this implementation was not done properly. This bug can cause data corruption.",
"severity": "medium",
"introduced": "0.4.5",
"fixed": "0.4.6",
"conditions": {
"optimizer": true
}
},
{
"uid": "SOL-2016-9",
"name": "HighOrderByteCleanStorage",
"summary": "For short types, the high order bytes were not cleaned properly and could overwrite existing data.",
"description": "Types shorter than 32 bytes are packed together into the same 32 byte storage slot, but storage writes always write 32 bytes. For some types, the higher order bytes were not cleaned properly, which made it sometimes possible to overwrite a variable in storage when writing to another one.",
"link": "https://blog.soliditylang.org/2016/11/01/security-alert-solidity-variables-can-overwritten-storage/",
"severity": "high",
"introduced": "0.1.6",
"fixed": "0.4.4"
},
{
"uid": "SOL-2016-8",
"name": "OptimizerStaleKnowledgeAboutSHA3",
"summary": "The optimizer did not properly reset its knowledge about SHA3 operations resulting in some hashes (also used for storage variable positions) not being calculated correctly.",
"description": "The optimizer performs symbolic execution in order to save re-evaluating expressions whose value is already known. This knowledge was not properly reset across control flow paths and thus the optimizer sometimes thought that the result of a SHA3 operation is already present on the stack. This could result in data corruption by accessing the wrong storage slot.",
"severity": "medium",
"fixed": "0.4.3",
"conditions": {
"optimizer": true
}
},
{
"uid": "SOL-2016-7",
"name": "LibrariesNotCallableFromPayableFunctions",
"summary": "Library functions threw an exception when called from a call that received Ether.",
"description": "Library functions are protected against sending them Ether through a call. Since the DELEGATECALL opcode forwards the information about how much Ether was sent with a call, the library function incorrectly assumed that Ether was sent to the library and threw an exception.",
"severity": "low",
"introduced": "0.4.0",
"fixed": "0.4.2"
},
{
"uid": "SOL-2016-6",
"name": "SendFailsForZeroEther",
"summary": "The send function did not provide enough gas to the recipient if no Ether was sent with it.",
"description": "The recipient of an Ether transfer automatically receives a certain amount of gas from the EVM to handle the transfer. In the case of a zero-transfer, this gas is not provided which causes the recipient to throw an exception.",
"severity": "low",
"fixed": "0.4.0"
},
{
"uid": "SOL-2016-5",
"name": "DynamicAllocationInfiniteLoop",
"summary": "Dynamic allocation of an empty memory array caused an infinite loop and thus an exception.",
"description": "Memory arrays can be created provided a length. If this length is zero, code was generated that did not terminate and thus consumed all gas.",
"severity": "low",
"fixed": "0.3.6"
},
{
"uid": "SOL-2016-4",
"name": "OptimizerClearStateOnCodePathJoin",
"summary": "The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.",
"description": "The optimizer performs symbolic execution at certain stages. At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges. Computing this common state was not done correctly. This bug can cause data corruption, but it is probably quite hard to use for targeted attacks.",
"severity": "low",
"fixed": "0.3.6",
"conditions": {
"optimizer": true
}
},
{
"uid": "SOL-2016-3",
"name": "CleanBytesHigherOrderBits",
"summary": "The higher order bits of short bytesNN types were not cleaned before comparison.",
"description": "Two variables of type bytesNN were considered different if their higher order bits, which are not part of the actual value, were different. An attacker might use this to reach seemingly unreachable code paths by providing incorrectly formatted input data.",
"severity": "medium/high",
"fixed": "0.3.3"
},
{
"uid": "SOL-2016-2",
"name": "ArrayAccessCleanHigherOrderBits",
"summary": "Access to array elements for arrays of types with less than 32 bytes did not correctly clean the higher order bits, causing corruption in other array elements.",
"description": "Multiple elements of an array of values that are shorter than 17 bytes are packed into the same storage slot. Writing to a single element of such an array did not properly clean the higher order bytes and thus could lead to data corruption.",
"severity": "medium/high",
"fixed": "0.3.1"
},
{
"uid": "SOL-2016-1",
"name": "AncientCompiler",
"summary": "This compiler version is ancient and might contain several undocumented or undiscovered bugs.",
"description": "The list of bugs is only kept for compiler versions starting from 0.3.0, so older versions might contain undocumented bugs.",
"severity": "high",
"fixed": "0.3.0"
}
]


Bugs (`docs/bugs.rst`)

.. index:: Bugs

.. _known_bugs:

##################
List of Known Bugs
##################

Below, you can find a JSON-formatted list of some of the known security-relevant bugs in the
Solidity compiler. The file itself is hosted in the GitHub repository <https://github.com/argotorg/solidity/blob/develop/docs/bugs.json>_.
The list stretches back as far as version 0.3.0, bugs known to be present only
in versions preceding that are not listed.

There is another file called bugs_by_version.json <https://github.com/argotorg/solidity/blob/develop/docs/bugs_by_version.json>_,
which can be used to check which bugs affect a specific version of the compiler.

When reporting a security-relevant bug, please make sure that the behavior is unintentional and outside of documented language guarantees.
Some regularly misreported behaviors are collected in :ref:Frequently Reported Non-Bugs<frequently-reported-non-bugs>.

Contract source verification tools and also other tools interacting with
contracts should consult this list according to the following criteria:

  • It is mildly suspicious if a contract was compiled with a nightly
    compiler version instead of a released version. This list does not keep
    track of unreleased or nightly versions.
  • It is also mildly suspicious if a contract was compiled with a version that was
    not the most recent at the time the contract was created. For contracts
    created from other contracts, you have to follow the creation chain
    back to a transaction and use the date of that transaction as creation date.
  • It is highly suspicious if a contract was compiled with a compiler that
    contains a known bug and the contract was created at a time where a newer
    compiler version containing a fix was already released.

The JSON file of known bugs below is an array of objects, one for each bug,
with the following keys:

uid
Unique identifier given to the bug in the form of SOL-<year>-<number>.
It is possible that multiple entries exists with the same uid. This means
multiple version ranges are affected by the same bug.
name
Unique name given to the bug
summary
Short description of the bug
description
Detailed description of the bug
link
URL of a website with more detailed information, optional
introduced
The first published compiler version that contained the bug, optional
fixed
The first published compiler version that did not contain the bug anymore
publish
The date at which the bug became known publicly, optional
severity
Severity of the bug: very low, low, medium, high. Takes into account
discoverability in contract tests, likelihood of occurrence and
potential damage by exploits.
conditions
Conditions that have to be met to trigger the bug. The following
keys can be used:
optimizer, Boolean value which
means that the optimizer has to be switched on to enable the bug.
evmVersion, a string that indicates which EVM version compiler
settings trigger the bug. The string can contain comparison
operators. For example, ">=constantinople" means that the bug
is present when the EVM version is set to constantinople or
later.
If no conditions are given, assume that the bug is present.
check
This field contains different checks that report whether the smart contract
contains the bug or not. The first type of check are JavaScript regular
expressions that are to be matched against the source code ("source-regex")
if the bug is present. If there is no match, then the bug is very likely
not present. If there is a match, the bug might be present. For improved
accuracy, the checks should be applied to the source code after stripping
comments.
The second type of check are patterns to be checked on the compact AST of
the Solidity program ("ast-compact-json-path"). The specified search query
is a JsonPath <https://github.com/json-path/JsonPath>_ expression.
If at least one path of the Solidity AST matches the query, the bug is
likely present.

.. literalinclude:: bugs.json
:language: js


Bugs.Yaml (`docs/bugs.yaml`)

  • uid: SOL-2026-7
    name: YulOptimizerKnowledgeBaseStaleBookkeeping
    summary: >-
    The Yul optimizer could consider two memory or storage locations distinct even though their addresses were computed from different values of the same reassigned variable and coincided at runtime.
    This could lead to loads being replaced with outdated values and to needed stores being removed.
    The Yul optimizer steps LoadResolver and EqualStoreEliminator keep track of what was stored in memory and storage.
    LoadResolver uses this to replace loads and keccak256 calls with known values, and EqualStoreEliminator uses it to remove stores of a value that the location already contains.
    Whenever a store is encountered whose exact location cannot be determined, the optimizer has to forget what it knows about every location the store might overwrite.
    To decide this, the optimizer represents an address symbolically as a constant offset either from zero or from another variable (its base variable).
    Two addresses with the same base can then be determined to be distinct if their offsets differ (for storage) or are at least 32 bytes apart (for memory).
    These representations were cached per variable.
    The base variable, however, may be reassigned afterwards.
    The optimizer did not always notice and then compared an address computed from the old value of the base with an address computed from the new value as if both used the same base.
    As a result, it could consider two locations distinct even though they coincided at runtime, keeping a stale entry for a location that had just been overwritten.
    A subsequent load from that location could then be replaced with an outdated value, a subsequent store of that value to the location could be removed, and keccak256 over the location could be replaced with the hash of an outdated value.
    Whether the bug is triggered depends on the structure of the intermediate code these optimizer steps receive.
    It is therefore sensitive to the optimizer sequence and to the surrounding code, and the two locations additionally have to coincide at runtime.
    In optimized IR code generation, any code may be affected, including code without inline assembly.
    In optimized evmasm code generation, only inline assembly that does not refer to any Solidity variables or functions and compiler-generated Yul utility functions could be affected.
    Unoptimized code is unaffected.
    link: https://blog.soliditylang.org/2026/10/22/yul-optimizer-knowledge-base-stale-bookkeeping-bug/
    introduced: 0.8.19
    fixed: 0.8.38
    severity: low
    conditions:
    yulOptimizer: true

  • uid: SOL-2026-6
    name: MisorderedNamedParametersInRequireWithCustomErrors
    summary: >-
    Custom error arguments passed to require using named-parameter syntax are ABI-encoded in call-site order instead of declaration order when compiling via IR.
    When a custom error was passed into the second argument of require and instantiated using named parameter syntax (e.g., require(condition, MyError({b: 1, a: 2}))), the IR-based code generator would pass the arguments to the ABI encoder in the order they appeared at the call site, without reordering them to match the error definition.
    The arguments were type-checked against the parameters with matching names, not the ones they were actually passed into by the codegen, so the bug would not result in a compilation error.
    Instead, the encoder would produce a structurally valid encoding matching the error signature but not reflecting the values used to instantiate the error.
    The arguments on the stack would be reordered and possibly reinterpreted as different types by the encoder.
    In case of reference types, the reinterpretation would result in the content being obtained from wrong offsets in memory, storage or calldata.
    In some cases large values misinterpreted as offsets or lengths would make the encoder revert due to running out of gas.
    Types that occupy more than one slot on the stack would further complicate the behavior by leading to not only reordering but also misalignment of argument boundaries.
    The only unaffected types were string literals, which are not being passed to the encoder through the stack.
    The bug was specific to custom errors passed as the second argument of require.
    Standalone revert ErrorName({...}) statements, event emissions, function calls, struct constructor invocations and other constructs supporting named parameters were not affected.
    The evmasm pipeline was also unaffected.
    link: https://blog.soliditylang.org/2026/09/10/misordered-named-parameters-in-require-with-custom-errors-bug/
    introduced: 0.8.26
    fixed: 0.8.37
    severity: very low
    conditions:
    viaIR: true

  • uid: SOL-2026-5
    name: MemoryByteArrayElementDeleteClearsWholeWord
    summary: >-
    Applying delete to a single element of a bytes array in memory clears not only that element but the whole 32-byte word starting at the element's location, zeroing up to 31 bytes beyond the element.
    Elements of bytes arrays in memory are packed, each occupying a single byte.
    When a value is assigned to such an element, the evmasm code generator correctly stores it with a single-byte MSTORE8 instruction.
    The code path in the evmasm pipeline implementing delete on such an element, however, wrote the zero value with a full-word MSTORE, clearing the 32 bytes starting at the element's location.
    The bytes following the element within the array were silently zeroed.
    If the element was within the last 31 bytes of the array's allocation, the write also extended past it into the area where the allocator places the next memory object, clearing the most significant bytes of that object's first word.
    How many elements are in reach depends on the size of the allocation: arrays created with new bytes(n) or from literals occupy their length rounded up to a multiple of 32 bytes, so only elements falling within the last 31 bytes of that rounded-up area, if any, could be affected.
    The results of bytes.concat, string.concat, and the abi.encode* functions, on the other hand, are placed by the evmasm pipeline in an allocation of exactly the size of their data, so the next object starts immediately after their last element and each of their last 31 elements is in reach.
    Assigning zero to an element (b[i] = 0) was not affected, only the delete operator, and neither were byte arrays in transient storage, storage, or calldata.
    The bug exists only in the evmasm pipeline.
    Code compiled via IR is unaffected.
    Optimizer settings have no influence.
    The defective code predates the first released version of the compiler.
    link: https://blog.soliditylang.org/2026/09/10/memory-byte-array-element-delete-clears-whole-word-bug/
    fixed: 0.8.37
    severity: low/medium
    conditions:
    viaIR: false

  • uid: SOL-2026-4
    name: SpillSlotCollisionAcrossMutualRecursion
    summary: >-
    Local variables of two simultaneously active functions moved to fixed memory offsets by the stack limit evader may be assigned the same offset if the call graph contains mutual recursion, so that one variable is silently overwritten by the other.
    To work around the 16-slot stack access limit of the EVM, the IR-based code generator can, under some preconditions, move local variables to fixed memory offsets.
    Variables that can never be active at the same time may safely share an offset, so the reserved memory area is sized by a depth-first walk of the call graph that computes for every node the number of slots it and its callees need.
    To keep this walk from descending infinitely into recursive call chains, the slot count was initialized with zero upon entering it.
    This provisional zero was observable: a function reached again through a call graph cycle reported an empty footprint to its caller, the caller's count was finalized and cached on that basis, and the undercount propagated to every later caller, including functions outside the cycle.
    As a result, a function called by such a cycle and a function calling into it could be assigned the same memory slot even though both can be active at the same time.
    A relocated variable still needed after the call into the cycle returned had then been silently overwritten by the called function, producing wrong results.
    Triggering the bug requires the IR pipeline and a call graph in which a cycle of at least two mutually recursive functions both reaches a function needing relocation of variables to memory and is entered from a separate call chain whose own relocated variable is read again after the call towards the cycle returns.
    From 0.8.21 onward, it is independent of whether the optimizer is enabled.
    link: https://blog.soliditylang.org/2026/09/10/spill-slot-collision-across-mutual-recursion-bug/
    introduced: 0.7.2
    fixed: 0.8.37
    severity: low/medium
    conditions:
    viaIR: true

  • uid: SOL-2026-3
    name: InheritanceOrderReversalOnStorageEndWarning
    summary: >-
    Emitting a warning about storage base location being too close to the storage end unintentionally reversed the linearizedBaseContracts annotation, possibly leading to miscompilation due to reversing the order in which inheritance is resolved.
    When the compiler detects that a custom layout specifier puts contract's static storage area too close to the end of the address space, it emits a warning.
    To make the warning more useful, the compiler tries to point at the last storage variable in that area.
    For this reason it walks the linearized inheritance hierarchy in reverse (from the least to the most derived).
    The list is calculated once and stored in an AST annotation called linearizedBaseContracts.
    The direct cause of the bug was the fact that the code that reverses the list was doing it in place rather than on a copy, modifying the annotation.
    This effectively reversed the order of base contracts seen by any component that runs after layout checks: later phases of analysis, AST export, code generator, SMTChecker, etc.
    The observable effect was a reversed order of state variable initialization, constructor invocation, virtual function/modifier resolution, leading either to miscompilations or internal compiler errors, depending on the specific usage.
    Since the source of the bug was in the analysis stage, it was independent of the codegen pipeline or optimizer settings.
    The main condition necessary to trigger the bug was the presence of the warning in the output.
    The other is presence of language constructs whose evaluation depends on the inheritance order.
    While potential effects are very serious, this requirement excludes the vast majority of contracts as intentionally placing the storage variables in the last 2**64 slots is highly discouraged, which was actually the main reason for adding this warning.
    link: https://blog.soliditylang.org/2026/07/09/inheritance-order-reversal-on-storage-end-warning-bug/
    introduced: 0.8.29
    fixed: 0.8.36
    severity: medium

  • uid: SOL-2026-2
    name: UnsoundSpillInMutualRecursion
    summary: >-
    Local variables of a function involved in mutual recursion may spuriously be moved to fixed memory offsets and overwritten across recursive calls.
    To work around the 16-slot stack access limit of the EVM, the IR-based code generator can move local variables of stack-too-deep functions to fixed memory offsets.
    This relocation is unsound for recursive functions: a fixed offset would be shared by all activations of the function, so a recursive call would overwrite the caller's value.
    The stack limit evader therefore must not relocate variables of functions that are part of a recursive call chain.
    To this end, the call graph was searched for cycles using a path-based depth-first search that, once a function had been fully explored and popped from the search path, short-circuited on it on any later visit.
    As a result, a function shared between several intersecting cycles could be reached first through a path that did not yet close a cycle through it, get marked as finished, and then be skipped when a later path would have revealed that it does lie on a cycle.
    Such a function was misclassified as non-recursive.
    When a misclassified function was complex enough for the stack limit evader to relocate some of its variables, those variables were moved to fixed memory offsets and silently corrupted on recursion, producing wrong results rather than a compile-time error.
    Triggering the bug requires the IR pipeline, a set of mutually recursive functions whose call graph contains intersecting cycles, at least one of the functions in an undetected part of a cycle being complex enough to require relocation to memory, and an unfortunate processing order of the functions (which depends on the hashes of their Yul names).
    It is independent of whether the optimizer is enabled.
    link: https://blog.soliditylang.org/2026/07/09/unsound-spill-in-mutual-recursion-bug/
    introduced: 0.7.2
    fixed: 0.8.36
    severity: medium
    conditions:
    viaIR: true

  • uid: SOL-2026-1
    name: TransientStorageClearingHelperCollision
    summary: >-
    Clearing both storage and transient storage variables in the same contract may result in only one of these locations being cleared.
    The IR-based code generator provides a set of Yul helper functions for basic operations, such as clearing, copying, encoding or type conversions.
    Not all functions are used by every contract.
    The codegen appends them to the generated sources individually, only when an operation that would invoke one of them is encountered.
    Utility functions are often specialized for different types and locations.
    Since Yul does not support generic functions, specialization is done by generating multiple versions of the same function, with the information distinguishing the variants embedded in their names.
    However, if not all the necessary bits of distinguishing information are properly accounted for, two helpers may end up with the same name, causing a collision.
    In this situation the codegen includes only one of them, with calls to both variants invoking it.
    This happened with the set_to_zero helper used when an area of transient or persistent storage needs to be cleared.
    The helper name was missing the location information, which resulted in a collision between the persistent and transient storage variants for the same type.
    This meant that contracts clearing both locations would actually clear only one, leaving the other untouched.
    Which location ended up being cleared depended on the order in which the code generator processed the input.
    The necessary condition to trigger the bug was the use of delete operator on a transient storage variable.
    This was due to value types being the only types supported in transient storage and delete being the only operation invoking the helper allowed on such types.
    The other necessary condition was clearing of persistent storage and in this case the range of affected operations was wider: operator delete, array pop() or assignment that resulted in a longer array being overwritten with a shorter one.
    The cleared variable itself also did not necessarily have to be of the same type.
    It was enough that a matching value type was nested in it.
    It also did not always have to be the exact same value type - clearing operations on reference types are usually performed at slot granularity, treating every slot as uint256 rather than clearing every value packed into it individually.
    To trigger the bug both operations had to be present within the same piece of bytecode.
    Independent contracts, not related through inheritance, would not affect each other this way.
    The presence of one operation only in creation code and the other only in deployed code would not trigger the bug either.
    link: https://blog.soliditylang.org/2026/02/18/transient-storage-clearing-helper-collision-bug/
    introduced: 0.8.28
    fixed: 0.8.34
    severity: high
    conditions:
    viaIR: true
    evmVersion: '>=cancun'

  • uid: SOL-2025-1
    name: LostStorageArrayWriteOnSlotOverflow
    summary: >-
    Operations that involve clearing or copying from arrays that straddle the end of storage could result in silent data retention.
    Solidity makes it possible to define variables that extend past the last (2**256-th) slot of storage, which results in wrap-around back to slot zero.
    Since EVM uses 256-bit integer arithmetic, most operations on such variables just work.
    The only situation which requires special attention is iteration against absolute slot addresses: the invariant that the last slot belonging to a variable has the highest address does not hold.
    When implemented incorrectly, a loop over an array will immediately terminate if the container spans the end of storage - due to the initial position already being greater than the end position.
    This affected storage array clearing loops generated by both evmasm and IR pipelines.
    Additionally, (only in the evmasm pipeline) copying operations whose source was an array straddling the end of storage were also affected.
    At the language level, the buggy code would be generated for array assignment, array initialization, delete operator, .pop() and .push().
    Note that a clearing loop is inserted by the compiler not only for invocations of the delete operator, but also to zero storage when overwriting a longer array with a shorter one, popping an element or even pushing an empty element to a dynamic array.
    Since clearing is a separate loop, it is possible for the bug to only affect it and not the copy operation it follows (which is always the case in the IR pipeline).
    The bug is extremely unlikely to be triggered accidentally due to the probabilistic impossibility of a short dynamic array being allocated right at the storage boundary.
    On the other hand, scenarios in which a user may place a static array there intentionally do not seem realistic and are limited to unusual layouts, in which a contract does not place any storage variables at slot zero (otherwise they would overlap the array).
    link: https://blog.soliditylang.org/2025/12/18/lost-storage-array-write-on-slot-overflow-bug/
    introduced: 0.1.0
    fixed: 0.8.32
    severity: low

  • uid: SOL-2023-3
    name: VerbatimInvalidDeduplication
    summary: >-
    All verbatim blocks are considered identical by deduplicator and can incorrectly be unified when surrounded by identical opcodes.
    The block deduplicator is a step of the opcode-based optimizer which identifies equivalent assembly blocks and merges them into a single one.
    However, when blocks contained verbatim, their comparison was performed incorrectly, leading to the collapse of assembly blocks which are identical except for the contents of the verbatim items.
    Since verbatim is only available in Yul, compilation of Solidity sources is not affected.
    link: https://blog.soliditylang.org/2023/11/08/verbatim-invalid-deduplication-bug/
    introduced: 0.8.5
    fixed: 0.8.23
    severity: low

  • uid: SOL-2023-2
    name: FullInlinerNonExpressionSplitArgumentEvaluationOrder
    summary: >-
    Optimizer sequences containing FullInliner do not preserve the evaluation order of arguments of inlined function calls in code that is not in expression-split form.
    Function call arguments in Yul are evaluated right to left.
    This order matters when the argument expressions have side-effects, and changing it may change contract behavior.
    FullInliner is an optimizer step that can replace a function call with the body of that function.
    The transformation involves assigning argument expressions to temporary variables, which imposes an explicit evaluation order.
    FullInliner was written with the assumption that this order does not necessarily have to match usual argument evaluation order because the argument expressions have no side-effects.
    In most circumstances this assumption is true because the default optimization step sequence contains the ExpressionSplitter step.
    ExpressionSplitter ensures that the code is in expression-split form, which means that function calls cannot appear nested inside expressions, and all function call arguments have to be variables.
    The assumption is, however, not guaranteed to be true in general.
    Version 0.6.7 introduced a setting allowing users to specify an arbitrary optimization step sequence, making it possible for the FullInliner to actually encounter argument expressions with side-effects, which can result in behavior differences between optimized and unoptimized bytecode.
    Contracts compiled without optimization or with the default optimization sequence are not affected.
    To trigger the bug the user has to explicitly choose compiler settings that contain a sequence with FullInliner step not preceded by ExpressionSplitter.
    link: https://blog.soliditylang.org/2023/07/19/full-inliner-non-expression-split-argument-evaluation-order-bug/
    introduced: 0.6.7
    fixed: 0.8.21
    severity: low
    conditions:
    yulOptimizer: true

  • uid: SOL-2023-1
    name: MissingSideEffectsOnSelectorAccess
    summary: >-
    Accessing the .selector member on complex expressions leaves the expression unevaluated in the legacy code generation.
    When accessing the .selector member on an expression with side-effects, like an assignment, a function call or a conditional, the expression would not be evaluated in the legacy code generation.
    This would happen in expressions where the functions used in the expression were all known at compilation time, regardless of whether the whole expression could be evaluated at compilation time or not.
    Note that the code generated by the IR pipeline was unaffected and would behave as expected.
    link: https://blog.soliditylang.org/2023/07/19/missing-side-effects-on-selector-access-bug/
    introduced: 0.6.2
    fixed: 0.8.21
    severity: low
    conditions:
    viaIR: false

  • uid: SOL-2022-7
    name: StorageWriteRemovalBeforeConditionalTermination
    summary: >-
    Calling functions that conditionally terminate the external EVM call using the assembly statements return(...) or stop() may result in incorrect removals of prior storage writes.
    A call to a Yul function that conditionally terminates the external EVM call could result in prior storage writes being incorrectly removed by the Yul optimizer.
    This used to happen in cases in which it would have been valid to remove the store, if the Yul function in question never actually terminated the external call, and the control flow always returned back to the caller instead.
    Conditional termination within the same Yul block instead of within a called function was not affected.
    In Solidity with optimized via-IR code generation, any storage write before a function conditionally calling return(...) or stop() in inline assembly, may have been incorrectly removed, whenever it would have been valid to remove the write without the return(...) or stop().
    In optimized legacy code generation, only inline assembly that did not refer to any Solidity variables and that involved conditionally-terminating user-defined assembly functions could be affected.
    link: https://blog.soliditylang.org/2022/09/08/storage-write-removal-before-conditional-termination/
    introduced: 0.8.13
    fixed: 0.8.17
    severity: medium/high
    conditions:
    yulOptimizer: true

  • uid: SOL-2022-6
    name: AbiReencodingHeadOverflowWithStaticArrayCleanup
    summary: >-
    ABI-encoding a tuple with a statically-sized calldata array in the last component would corrupt 32 leading bytes of its first dynamically encoded component.
    When ABI-encoding a statically-sized calldata array, the compiler always pads the data area to a multiple of 32-bytes and ensures that the padding bytes are zeroed.
    In some cases, this cleanup used to be performed by always writing exactly 32 bytes, regardless of how many needed to be zeroed.
    This was done with the assumption that the data that would eventually occupy the area past the end of the array had not yet been written, because the encoder processes tuple components in the order they were given.
    While this assumption is mostly true, there is an important corner case: dynamically encoded tuple components are stored separately from the statically-sized ones in an area called the tail of the encoding and the tail immediately follows the head, which is where the statically-sized components are placed.
    The aforementioned cleanup, if performed for the last component of the head would cross into the tail and overwrite up to 32 bytes of the first component stored there with zeros.
    The only array type for which the cleanup could actually result in an overwrite were arrays with uint256 or bytes32 as the base element type and in this case the size of the corrupted area was always exactly 32 bytes.
    The problem affected tuples at any nesting level.
    This included also structs, which are encoded as tuples in the ABI.
    Note also that lists of parameters and return values of functions, events and errors are encoded as tuples.
    link: https://blog.soliditylang.org/2022/08/08/calldata-tuple-reencoding-head-overflow-bug/
    introduced: 0.5.8
    fixed: 0.8.16
    severity: medium
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2022-5
    name: DirtyBytesArrayToStorage
    summary: >-
    Copying bytes arrays from memory or calldata to storage may result in dirty storage values.
    Copying bytes arrays from memory or calldata to storage is done in chunks of 32 bytes even if the length is not a multiple of 32.
    Thereby, extra bytes past the end of the array may be copied from calldata or memory to storage.
    These dirty bytes may then become observable after a .push() without arguments to the bytes array in storage, i.e. such a push will not result in a zero value at the end of the array as expected.
    This bug only affects the legacy code generation pipeline, the new code generation pipeline via IR is not affected.
    link: https://blog.soliditylang.org/2022/06/15/dirty-bytes-array-to-storage-bug/
    introduced: 0.0.1
    fixed: 0.8.15
    severity: low

  • uid: SOL-2022-4
    name: InlineAssemblyMemorySideEffects
    summary: >-
    The Yul optimizer may incorrectly remove memory writes from inline assembly blocks, that do not access solidity variables.
    The Yul optimizer considers all memory writes in the outermost Yul block that are never read from as unused and removes them.
    This is valid when that Yul block is the entire Yul program, which is always the case for the Yul code generated by the new via-IR pipeline.
    Inline assembly blocks are never optimized in isolation when using that pipeline.
    Instead they are optimized as a part of the whole Yul input.
    However, the legacy code generation pipeline (which is still the default) runs the Yul optimizer individually on an inline assembly block if the block does not refer to any local variables defined in the surrounding Solidity code.
    Consequently, memory writes in such inline assembly blocks are removed as well, if the written memory is never read from in the same assembly block, even if the written memory is accessed later, for example by a subsequent inline assembly block.
    link: https://blog.soliditylang.org/2022/06/15/inline-assembly-memory-side-effects-bug/
    introduced: 0.8.13
    fixed: 0.8.15
    severity: medium
    conditions:
    yulOptimizer: true

  • uid: SOL-2022-3
    name: DataLocationChangeInInternalOverride
    summary: >-
    It was possible to change the data location of the parameters or return variables from calldata to memory and vice-versa while overriding internal and public functions.
    This caused invalid code to be generated when calling such a function internally through virtual function calls.
    When calling external functions, it is irrelevant if the data location of the parameters is calldata or memory, the encoding of the data does not change.
    Because of that, changing the data location when overriding external functions is allowed.
    The compiler incorrectly also allowed a change in the data location for overriding public and internal functions.
    Since public functions can be called internally as well as externally, this causes invalid code to be generated when such an incorrectly overridden function is called internally through the base contract.
    The caller provides a memory pointer, but the called function interprets it as a calldata pointer or vice-versa.
    link: https://blog.soliditylang.org/2022/05/17/data-location-inheritance-bug/
    introduced: 0.6.9
    fixed: 0.8.14
    severity: very low

  • uid: SOL-2022-2
    name: NestedCalldataArrayAbiReencodingSizeValidation
    summary: >-
    ABI-reencoding of nested dynamic calldata arrays did not always perform proper size checks against the size of calldata and could read beyond calldatasize().
    Calldata validation for nested dynamic types is deferred until the first access to the nested values.
    Such an access may for example be a copy to memory or an index or member access to the outer type.
    While in most such accesses calldata validation correctly checks that the data area of the nested array is completely contained in the passed calldata (i.e. in the range [0, calldatasize()]), this check may not be performed, when ABI encoding such nested types again directly from calldata.
    For instance, this can happen, if a value in calldata with a nested dynamic array is passed to an external call, used in abi.encode or emitted as event.
    In such cases, if the data area of the nested array extends beyond calldatasize(), ABI encoding it did not revert, but continued reading values from beyond calldatasize() (i.e. zero values).
    link: https://blog.soliditylang.org/2022/05/17/calldata-reencode-size-check-bug/
    introduced: 0.5.8
    fixed: 0.8.14
    severity: very low

  • uid: SOL-2022-1
    name: AbiEncodeCallLiteralAsFixedBytesBug
    summary: >-
    Literals used for a fixed length bytes parameter in abi.encodeCall were encoded incorrectly.
    For the encoding, the compiler only considered the types of the expressions in the second argument of abi.encodeCall itself, but not the parameter types of the function given as first argument.
    In almost all cases the abi encoding of the type of the expression matches the abi encoding of the parameter type of the given function.
    This is because the type checker ensures the expression is implicitly convertible to the respective parameter type.
    However this is not true for number literals used for fixed bytes types shorter than 32 bytes, nor for string literals used for any fixed bytes type.
    Number literals were encoded as numbers instead of being shifted to become left-aligned.
    String literals were encoded as dynamically sized memory strings instead of being converted to a left-aligned bytes value.
    link: https://blog.soliditylang.org/2022/03/16/encodecall-bug/
    introduced: 0.8.11
    fixed: 0.8.13
    severity: very low

  • uid: SOL-2021-4
    name: UserDefinedValueTypesBug
    summary: >-
    User defined value types with underlying type shorter than 32 bytes used incorrect storage layout and wasted storage
    The compiler did not correctly compute the storage layout of user defined value types based on types that are shorter than 32 bytes.
    It would always use a full storage slot for these types, even if the underlying type was shorter.
    This was wasteful and might have problems with tooling or contract upgrades.
    link: https://blog.soliditylang.org/2021/09/29/user-defined-value-types-bug/
    introduced: 0.8.8
    fixed: 0.8.9
    severity: very low

  • uid: SOL-2021-3
    name: SignedImmutables
    summary: >-
    Immutable variables of signed integer type shorter than 256 bits can lead to values with invalid higher order bits if inline assembly is used.
    When immutable variables of signed integer type shorter than 256 bits are read, their higher order bits were unconditionally set to zero.
    The correct operation would be to sign-extend the value, i.e. set the higher order bits to one if the sign bit is one.
    This sign-extension is performed by Solidity just prior to when it matters, i.e. when a value is stored in memory, when it is compared or when a division is performed.
    Because of that, to our knowledge, the only way to access the value in its unclean state is by reading it through inline assembly.
    link: https://blog.soliditylang.org/2021/09/29/signed-immutables-bug/
    introduced: 0.6.5
    fixed: 0.8.9
    severity: very low

  • uid: SOL-2021-2
    name: ABIDecodeTwoDimensionalArrayMemory
    summary: >-
    If used on memory byte arrays, result of the function abi.decode can depend on the contents of memory outside of the actual byte array that is decoded.
    The ABI specification uses pointers to data areas for everything that is dynamically-sized.
    When decoding data from memory (instead of calldata), the ABI decoder did not properly validate some of these pointers.
    More specifically, it was possible to use large values for the pointers inside arrays such that computing the offset resulted in an undetected overflow.
    This could lead to these pointers targeting areas in memory outside of the actual area to be decoded.
    This way, it was possible for abi.decode to return different values for the same encoded byte array.
    link: https://blog.soliditylang.org/2021/04/21/decoding-from-memory-bug/
    introduced: 0.4.16
    fixed: 0.8.4
    conditions:
    ABIEncoderV2: true
    severity: very low

  • uid: SOL-2021-1
    name: KeccakCaching
    summary: >-
    The bytecode optimizer incorrectly reused previously evaluated Keccak-256 hashes.
    You are unlikely to be affected if you do not compute Keccak-256 hashes in inline assembly.
    Solidity's bytecode optimizer has a step that can compute Keccak-256 hashes, if the contents of the memory are known during compilation time.
    This step also has a mechanism to determine that two Keccak-256 hashes are equal even if the values in memory are not known during compile time.
    This mechanism had a bug where Keccak-256 of the same memory content, but different sizes were considered equal.
    More specifically, keccak256(mpos1, length1) and keccak256(mpos2, length2) in some cases were considered equal if length1 and length2, when rounded up to nearest multiple of 32 were the same, and when the memory contents at mpos1 and mpos2 can be deduced to be equal.
    You maybe affected if you compute multiple Keccak-256 hashes of the same content, but with different lengths inside inline assembly.
    You are unaffected if your code uses keccak256 with a length that is not a compile-time constant or if it is always a multiple of 32.
    link: https://blog.soliditylang.org/2021/03/23/keccak-optimizer-bug/
    fixed: 0.8.3
    conditions:
    optimizer: true
    severity: medium

  • uid: SOL-2020-11
    name: EmptyByteArrayCopy
    summary: >-
    Copying an empty byte array (or string) from memory or calldata to storage can result in data corruption if the target array's length is increased subsequently without storing new data.
    The routine that copies byte arrays from memory or calldata to storage stores unrelated data from after the source array in the storage slot if the source array is empty.
    If the storage array's length is subsequently increased either by using .push() or by assigning to its .length attribute (only before 0.6.0), the newly created byte array elements will not be zero-initialized, but contain the unrelated data.
    You are not affected if you do not assign to .length and do not use .push() on byte arrays, or only use .push(<arg>) or manually initialize the new elements.
    link: https://blog.soliditylang.org/2020/10/19/empty-byte-array-copy-bug/
    fixed: 0.7.4
    severity: medium

  • uid: SOL-2020-10
    name: DynamicArrayCleanup
    summary: >-
    When assigning a dynamically-sized array with types of size at most 16 bytes in storage causing the assigned array to shrink, some parts of deleted slots were not zeroed out.
    Consider a dynamically-sized array in storage whose base-type is small enough such that multiple values can be packed into a single slot, such as uint128[].
    Let us define its length to be l.
    When this array gets assigned from another array with a smaller length, say m, the slots between elements m and l have to be cleaned by zeroing them out.
    However, this cleaning was not performed properly.
    Specifically, after the slot corresponding to m, only the first packed value was cleaned up.
    If this array gets resized to a length larger than m, the indices corresponding to the unclean parts of the slot contained the original value, instead of 0.
    The resizing here is performed by assigning to the array length, by a push() or via inline assembly.
    You are not affected if you are only using .push(<arg>) or if you assign a value (even zero) to the new elements after increasing the length of the array.
    link: https://blog.soliditylang.org/2020/10/07/solidity-dynamic-array-cleanup-bug/
    fixed: 0.7.3
    severity: medium

  • uid: SOL-2020-9
    name: FreeFunctionRedefinition
    summary: >-
    The compiler does not flag an error when two or more free functions with the same name and parameter types are defined in a source unit or when an imported free function alias shadows another free function with a different name but identical parameter types.
    In contrast to functions defined inside contracts, free functions with identical names and parameter types did not create an error.
    Both definition of free functions with identical name and parameter types and an imported free function with an alias that shadows another function with a different name but identical parameter types were permitted due to which a call to either the multiply defined free function or the imported free function alias within a contract led to the execution of that free function which was defined first within the source unit.
    Subsequently defined identical free function definitions were silently ignored and their code generation was skipped.
    introduced: 0.7.1
    fixed: 0.7.2
    severity: low

  • uid: SOL-2020-8
    name: UsingForCalldata
    summary: >-
    Function calls to internal library functions with calldata parameters called via using for can result in invalid data being read.
    Function calls to internal library functions using the using for mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call.
    Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer.
    Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption.
    An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.
    introduced: 0.6.9
    fixed: 0.6.10
    severity: very low

  • uid: SOL-2020-7
    name: MissingEscapingInFormatting
    summary: >-
    String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.
    When ABIEncoderV2 is enabled, string literals passed directly to encoding functions or external function calls are stored as strings in the intermediate code.
    Characters outside the printable range are handled correctly, but backslashes are not escaped in this procedure.
    This leads to double backslashes being reduced to single backslashes and consequently re-interpreted as escapes potentially resulting in a different string being encoded.
    introduced: 0.5.14
    fixed: 0.6.8
    severity: very low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2020-6
    name: ArraySliceDynamicallyEncodedBaseType
    summary: >-
    Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.
    For arrays with dynamically sized base types, index range accesses that use a start expression that is non-zero will result in invalid array slices.
    Any index access to such array slices will result in data being read from incorrect calldata offsets.
    Array slices are only supported for dynamic calldata types and all problematic type require ABIEncoderV2 to be enabled.
    introduced: 0.6.0
    fixed: 0.6.8
    severity: very low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2020-5
    name: ImplicitConstructorCallvalueCheck
    summary: >-
    The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.
    Starting from Solidity 0.4.5 the creation code of contracts without explicit payable constructor is supposed to contain a callvalue check that results in contract creation reverting, if non-zero value is passed.
    However, this check was missing in case no explicit constructor was defined in a contract at all, but the contract has a base that does define a constructor.
    In these cases it is possible to send value in a contract creation transaction or using inline assembly without revert, even though the creation code is supposed to be non-payable.
    introduced: 0.4.5
    fixed: 0.6.8
    severity: very low

  • uid: SOL-2020-4
    name: TupleAssignmentMultiStackSlotComponents
    summary: >-
    Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.
    Tuple assignments did not correctly account for tuple components that occupy multiple stack slots in case the number of stack slots differs between left-hand-side and right-hand-side.
    This can either happen in the presence of nested tuples or if the right-hand-side contains external function pointers or references to dynamic calldata arrays, while the left-hand-side contains an omission.
    introduced: 0.1.6
    fixed: 0.6.6
    severity: very low

  • uid: SOL-2020-3
    name: MemoryArrayCreationOverflow
    summary: >-
    The creation of very large memory arrays can result in overlapping memory regions and thus memory corruption.
    No runtime overflow checks were performed for the length of memory arrays during creation.
    In cases for which the memory size of an array in bytes, i.e. the array length times 32, is larger than 2^256-1, the memory allocation will overflow, potentially resulting in overlapping memory areas.
    The length of the array is still stored correctly, so copying or iterating over such an array will result in out-of-gas.
    link: https://blog.soliditylang.org/2020/04/06/memory-creation-overflow-bug/
    introduced: 0.2.0
    fixed: 0.6.5
    severity: low

  • uid: SOL-2020-1
    name: YulOptimizerRedundantAssignmentBreakContinue
    summary: >-
    The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used.
    You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.
    The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches.
    This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with break or continue even though they cannot be removed in other control-flow branches.
    Variables declared outside of the respective for loop are not affected.
    introduced: 0.6.0
    fixed: 0.6.1
    severity: medium
    conditions:
    yulOptimizer: true

  • uid: SOL-2020-2
    name: privateCanBeOverridden
    summary: >-
    Private methods can be overridden by inheriting contracts.
    While private methods of base contracts are not visible and cannot be called directly from the derived contract, it is still possible to declare a function of the same name and type and thus change the behaviour of the base contract's function.
    introduced: 0.3.0
    fixed: 0.5.17
    severity: low

  • uid: SOL-2020-1
    name: YulOptimizerRedundantAssignmentBreakContinue0.5
    summary: >-
    The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used.
    You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.
    The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches.
    This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with break or continue even though they cannot be removed in other control-flow branches.
    Variables declared outside of the respective for loop are not affected.
    introduced: 0.5.8
    fixed: 0.5.16
    severity: low
    conditions:
    yulOptimizer: true

  • uid: SOL-2019-10
    name: ABIEncoderV2LoopYulOptimizer
    summary: >-
    If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.
    The Yul optimizer incorrectly replaces mload and sload calls with values that have been previously written to the load location (and potentially changed in the meantime) if all of the following conditions are met: (1) there is a matching mstore or sstore call before; (2) the contents of memory or storage is only changed in a function that is called (directly or indirectly) in between the first store and the load call; (3) called function contains a for loop where the same memory location is changed in the condition or the post or body block.
    When used in Solidity mode, this can only happen if the experimental ABIEncoderV2 is activated and the experimental Yul optimizer has been activated manually in addition to the regular optimizer in the compiler settings.
    introduced: 0.5.14
    fixed: 0.5.15
    severity: low
    conditions:
    ABIEncoderV2: true
    optimizer: true
    yulOptimizer: true

  • uid: SOL-2019-9
    name: ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers
    summary: >-
    Reading from calldata structs that contain dynamically encoded, but statically-sized members can result in incorrect values.
    When a calldata struct contains a dynamically encoded, but statically-sized member, the offsets for all subsequent struct members are calculated incorrectly.
    All reads from such members will result in invalid values.
    Only calldata structs are affected, i.e. this occurs in external functions with such structs as argument.
    Using affected structs in storage or memory or as arguments to public functions on the other hand works correctly.
    introduced: 0.5.6
    fixed: 0.5.11
    severity: low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2019-8
    name: SignedArrayStorageCopy
    summary: >-
    Assigning an array of signed integers to a storage array of different type can lead to data corruption in that array.
    In two's complement, negative integers have their higher order bits set.
    In order to fit into a shared storage slot, these have to be set to zero.
    When a conversion is done at the same time, the bits to set to zero were incorrectly determined from the source and not the target type.
    This means that such copy operations can lead to incorrect values being stored.
    link: https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/
    introduced: 0.4.7
    fixed: 0.5.10
    severity: low/medium

  • uid: SOL-2019-7
    name: ABIEncoderV2StorageArrayWithMultiSlotElement
    summary: >-
    Storage arrays containing structs or other statically-sized arrays are not read properly when directly encoded in external function calls or in abi.encode*.
    When storage arrays whose elements occupy more than a single storage slot are directly encoded in external function calls or using abi.encode*, their elements are read in an overlapping manner, i.e. the element pointer is not properly advanced between reads.
    This is not a problem when the storage data is first copied to a memory variable or if the storage array only contains value types or dynamically-sized arrays.
    link: https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/
    introduced: 0.4.16
    fixed: 0.5.10
    severity: low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2019-6
    name: DynamicConstructorArgumentsClippedABIV2
    summary: >-
    A contract's constructor that takes structs or arrays that contain dynamically-sized arrays reverts or decodes to invalid data.
    During construction of a contract, constructor parameters are copied from the code section to memory for decoding.
    The amount of bytes to copy was calculated incorrectly in case all parameters are statically-sized but contain dynamically-sized arrays as struct members or inner arrays.
    Such types are only available if ABIEncoderV2 is activated.
    introduced: 0.4.16
    fixed: 0.5.9
    severity: very low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2019-5
    name: UninitializedFunctionPointerInConstructor
    summary: >-
    Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.
    Uninitialized internal function pointers point to a special piece of code that causes a revert when called.
    Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.
    introduced: 0.5.0
    fixed: 0.5.8
    severity: very low

  • uid: SOL-2019-5
    name: UninitializedFunctionPointerInConstructor_0.4.x
    summary: >-
    Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.
    Uninitialized internal function pointers point to a special piece of code that causes a revert when called.
    Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.
    introduced: 0.4.5
    fixed: 0.4.26
    severity: very low

  • uid: SOL-2019-4
    name: IncorrectEventSignatureInLibraries
    summary: >-
    Contract types used in events in libraries cause an incorrect event signature hash
    Instead of using the type address in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.
    introduced: 0.5.0
    fixed: 0.5.8
    severity: very low

  • uid: SOL-2019-4
    name: IncorrectEventSignatureInLibraries_0.4.x
    summary: >-
    Contract types used in events in libraries cause an incorrect event signature hash
    Instead of using the type address in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.
    introduced: 0.3.0
    fixed: 0.4.26
    severity: very low

  • uid: SOL-2019-3
    name: ABIEncoderV2PackedStorage
    summary: >-
    Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.
    Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2.
    This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.
    link: https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/
    introduced: 0.5.0
    fixed: 0.5.7
    severity: low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2019-3
    name: ABIEncoderV2PackedStorage_0.4.x
    summary: >-
    Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.
    Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2.
    This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.
    link: https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/
    introduced: 0.4.19
    fixed: 0.4.26
    severity: low
    conditions:
    ABIEncoderV2: true

  • uid: SOL-2019-2
    name: IncorrectByteInstructionOptimization
    summary: >-
    The optimizer incorrectly handles byte opcodes whose second argument is 31 or a constant expression that evaluates to 31.
    This can result in unexpected values.
    The optimizer incorrectly handles byte opcodes that use the constant 31 as second argument.
    This can happen when performing index access on bytesNN types with a compile-time constant value (not index) of 31 or when using the byte opcode in inline assembly.
    link: https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/
    introduced: 0.5.5
    fixed: 0.5.7
    severity: very low
    conditions:
    optimizer: true

  • uid: SOL-2019-1
    name: DoubleShiftSizeOverflow
    summary: >-
    Double bitwise shifts by large constants whose sum overflows 256 bits can result in unexpected values.
    Nested logical shift operations whose total shift size is 2**256 or more are incorrectly optimized.
    This only applies to shifts by numbers of bits that are compile-time constant expressions.
    link: https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/
    introduced: 0.5.5
    fixed: 0.5.6
    severity: low
    conditions:
    optimizer: true
    evmVersion: '>=constantinople'

  • uid: SOL-2018-4
    name: ExpExponentCleanup
    summary: >-
    Using the ** operator with an exponent of type shorter than 256 bits can result in unexpected values.
    Higher order bits in the exponent are not properly cleaned before the EXP opcode is applied if the type of the exponent expression is smaller than 256 bits and not smaller than the type of the base.
    In that case, the result might be larger than expected if the exponent is assumed to lie within the value range of the type.
    Literal numbers as exponents are unaffected as are exponents or bases of type uint256.
    link: https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/
    fixed: 0.4.25
    severity: medium/high
    check:
    regex-source: '[^/]** *[^/0-9 ]'

  • uid: SOL-2018-3
    name: EventStructWrongData
    summary: >-
    Using structs in events logged wrong data.
    If a struct is used in an event, the address of the struct is logged instead of the actual data.
    link: https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/
    introduced: 0.4.17
    fixed: 0.4.25
    severity: very low
    check:
    ast-compact-json-path: $..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName'
    && @.typeDescriptions.typeString.startsWith('struct'))]

  • uid: SOL-2018-2
    name: NestedArrayFunctionCallDecoder
    summary: >-
    Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.
    If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed.
    Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls.
    The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.
    link: https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/
    introduced: 0.1.4
    fixed: 0.4.22
    severity: medium
    check:
    regex-source: returns[^;{][\s[^] \t\r\n\v\f][^]]]\s[\s*[^] \t\r\n\v\f][^]]][^{;][;{]

  • uid: SOL-2018-1
    name: OneOfTwoConstructorsSkipped
    summary: >-
    If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.
    If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.
    There will be a compiler warning about the old-style constructor, so contracts only using new-style constructors are fine.
    introduced: 0.4.22
    fixed: 0.4.23
    severity: very low

  • uid: SOL-2017-5
    name: ZeroFunctionSelector
    summary: >-
    It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.
    If a function has a selector consisting only of zeros, is payable and part of a contract that does not have a fallback function and at most five external functions in total, this function is called instead of the fallback function if Ether is sent to the contract without data.
    fixed: 0.4.18
    severity: very low

  • uid: SOL-2017-4
    name: DelegateCallReturnValue
    summary: >-
    The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.
    The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides.
    This value is interpreted as a boolean and put onto the stack.
    This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successful.
    introduced: 0.3.0
    fixed: 0.4.15
    severity: low

  • uid: SOL-2017-3
    name: ECRecoverMalformedInput
    summary: >-
    The ecrecover() builtin can return garbage for malformed input.
    The ecrecover precompile does not properly signal failure for malformed input (especially in the 'v' argument) and thus the Solidity function can return data that was previously present in the return area in memory.
    fixed: 0.4.14
    severity: medium

  • uid: SOL-2017-2
    name: SkipEmptyStringLiteral
    summary: >-
    If "" is used in a function call, the following function arguments will not be correctly passed to the function.
    If the empty string literal "" is used as an argument in a function call, it is skipped by the encoder.
    This has the effect that the encoding of all arguments following this is shifted left by 32 bytes and thus the function call data is corrupted.
    fixed: 0.4.12
    severity: low

  • uid: SOL-2017-1
    name: ConstantOptimizerSubtraction
    summary: >-
    In some situations, the optimizer replaces certain numbers in the code with routines that compute different numbers.
    The optimizer tries to represent any number in the bytecode by routines that compute them with less gas.
    For some special numbers, an incorrect routine is generated.
    This could allow an attacker to e.g. trick victims about a specific amount of ether, or function calls to call different functions (or none at all).
    link: https://blog.soliditylang.org/2017/05/03/solidity-optimizer-bug/
    fixed: 0.4.11
    severity: low
    conditions:
    optimizer: true

  • uid: SOL-2016-11
    name: IdentityPrecompileReturnIgnored
    summary: >-
    Failure of the identity precompile was ignored.
    Calls to the identity contract, which is used for copying memory, ignored its return value.
    On the public chain, calls to the identity precompile can be made in a way that they never fail, but this might be different on private chains.
    severity: low
    fixed: 0.4.7

  • uid: SOL-2016-10
    name: OptimizerStateKnowledgeNotResetForJumpdest
    summary: >-
    The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.
    The optimizer performs symbolic execution at certain stages.
    At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges.
    Computing this common state was simplified to just use the empty state, but this implementation was not done properly.
    This bug can cause data corruption.
    severity: medium
    introduced: 0.4.5
    fixed: 0.4.6
    conditions:
    optimizer: true

  • uid: SOL-2016-9
    name: HighOrderByteCleanStorage
    summary: >-
    For short types, the high order bytes were not cleaned properly and could overwrite existing data.
    Types shorter than 32 bytes are packed together into the same 32 byte storage slot, but storage writes always write 32 bytes.
    For some types, the higher order bytes were not cleaned properly, which made it sometimes possible to overwrite a variable in storage when writing to another one.
    link: https://blog.soliditylang.org/2016/11/01/security-alert-solidity-variables-can-overwritten-storage/
    severity: high
    introduced: 0.1.6
    fixed: 0.4.4

  • uid: SOL-2016-8
    name: OptimizerStaleKnowledgeAboutSHA3
    summary: >-
    The optimizer did not properly reset its knowledge about SHA3 operations resulting in some hashes (also used for storage variable positions) not being calculated correctly.
    The optimizer performs symbolic execution in order to save re-evaluating expressions whose value is already known.
    This knowledge was not properly reset across control flow paths and thus the optimizer sometimes thought that the result of a SHA3 operation is already present on the stack.
    This could result in data corruption by accessing the wrong storage slot.
    severity: medium
    fixed: 0.4.3
    conditions:
    optimizer: true

  • uid: SOL-2016-7
    name: LibrariesNotCallableFromPayableFunctions
    summary: >-
    Library functions threw an exception when called from a call that received Ether.
    Library functions are protected against sending them Ether through a call.
    Since the DELEGATECALL opcode forwards the information about how much Ether was sent with a call, the library function incorrectly assumed that Ether was sent to the library and threw an exception.
    severity: low
    introduced: 0.4.0
    fixed: 0.4.2

  • uid: SOL-2016-6
    name: SendFailsForZeroEther
    summary: >-
    The send function did not provide enough gas to the recipient if no Ether was sent with it.
    The recipient of an Ether transfer automatically receives a certain amount of gas from the EVM to handle the transfer.
    In the case of a zero-transfer, this gas is not provided which causes the recipient to throw an exception.
    severity: low
    fixed: 0.4.0

  • uid: SOL-2016-5
    name: DynamicAllocationInfiniteLoop
    summary: >-
    Dynamic allocation of an empty memory array caused an infinite loop and thus an exception.
    Memory arrays can be created provided a length.
    If this length is zero, code was generated that did not terminate and thus consumed all gas.
    severity: low
    fixed: 0.3.6

  • uid: SOL-2016-4
    name: OptimizerClearStateOnCodePathJoin
    summary: >-
    The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.
    The optimizer performs symbolic execution at certain stages.
    At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges.
    Computing this common state was not done correctly.
    This bug can cause data corruption, but it is probably quite hard to use for targeted attacks.
    severity: low
    fixed: 0.3.6
    conditions:
    optimizer: true

  • uid: SOL-2016-3
    name: CleanBytesHigherOrderBits
    summary: >-
    The higher order bits of short bytesNN types were not cleaned before comparison.
    Two variables of type bytesNN were considered different if their higher order bits, which are not part of the actual value, were different.
    An attacker might use this to reach seemingly unreachable code paths by providing incorrectly formatted input data.
    severity: medium/high
    fixed: 0.3.3

  • uid: SOL-2016-2
    name: ArrayAccessCleanHigherOrderBits
    summary: >-
    Access to array elements for arrays of types with less than 32 bytes did not correctly clean the higher order bits, causing corruption in other array elements.
    Multiple elements of an array of values that are shorter than 17 bytes are packed into the same storage slot.
    Writing to a single element of such an array did not properly clean the higher order bytes and thus could lead to data corruption.
    severity: medium/high
    fixed: 0.3.1

  • uid: SOL-2016-1
    name: AncientCompiler
    summary: >-
    This compiler version is ancient and might contain several undocumented or undiscovered bugs.
    The list of bugs is only kept for compiler versions starting from 0.3.0, so older versions might contain undocumented bugs.
    severity: high
    fixed: 0.3.0


Bugs By Version.Json (`docs/bugs_by_version.json`)

{
"0.1.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-07-10"
},
"0.1.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-08-04"
},
"0.1.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-08-20"
},
"0.1.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-09-25"
},
"0.1.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-09-30"
},
"0.1.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-10-07"
},
"0.1.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-10-16"
},
"0.1.7": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-11-17"
},
"0.2.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2015-12-02"
},
"0.2.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2016-01-30"
},
"0.2.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits",
"AncientCompiler"
],
"released": "2016-02-17"
},
"0.3.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits",
"ArrayAccessCleanHigherOrderBits"
],
"released": "2016-03-11"
},
"0.3.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits"
],
"released": "2016-03-31"
},
"0.3.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin",
"CleanBytesHigherOrderBits"
],
"released": "2016-04-18"
},
"0.3.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin"
],
"released": "2016-05-27"
},
"0.3.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin"
],
"released": "2016-05-31"
},
"0.3.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther",
"DynamicAllocationInfiniteLoop",
"OptimizerClearStateOnCodePathJoin"
],
"released": "2016-06-10"
},
"0.3.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"SendFailsForZeroEther"
],
"released": "2016-08-10"
},
"0.4.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"LibrariesNotCallableFromPayableFunctions"
],
"released": "2016-09-08"
},
"0.4.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3",
"LibrariesNotCallableFromPayableFunctions"
],
"released": "2016-09-09"
},
"0.4.10": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction"
],
"released": "2017-03-15"
},
"0.4.11": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral"
],
"released": "2017-05-03"
},
"0.4.12": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
"released": "2017-07-03"
},
"0.4.13": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
"released": "2017-07-06"
},
"0.4.14": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue"
],
"released": "2017-07-31"
},
"0.4.15": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-08-08"
},
"0.4.16": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-08-24"
},
"0.4.17": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-09-21"
},
"0.4.18": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"NestedArrayFunctionCallDecoder"
],
"released": "2017-10-18"
},
"0.4.19": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"NestedArrayFunctionCallDecoder"
],
"released": "2017-11-30"
},
"0.4.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage",
"OptimizerStaleKnowledgeAboutSHA3"
],
"released": "2016-09-17"
},
"0.4.20": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"NestedArrayFunctionCallDecoder"
],
"released": "2018-02-14"
},
"0.4.21": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"NestedArrayFunctionCallDecoder"
],
"released": "2018-03-07"
},
"0.4.22": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData",
"OneOfTwoConstructorsSkipped"
],
"released": "2018-04-16"
},
"0.4.23": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData"
],
"released": "2018-04-19"
},
"0.4.24": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x",
"ExpExponentCleanup",
"EventStructWrongData"
],
"released": "2018-05-16"
},
"0.4.25": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ABIEncoderV2PackedStorage_0.4.x"
],
"released": "2018-09-12"
},
"0.4.26": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2"
],
"released": "2019-04-29"
},
"0.4.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"HighOrderByteCleanStorage"
],
"released": "2016-10-25"
},
"0.4.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored"
],
"released": "2016-10-31"
},
"0.4.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored",
"OptimizerStateKnowledgeNotResetForJumpdest"
],
"released": "2016-11-21"
},
"0.4.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
"IdentityPrecompileReturnIgnored"
],
"released": "2016-11-22"
},
"0.4.7": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction"
],
"released": "2016-12-15"
},
"0.4.8": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction"
],
"released": "2017-01-13"
},
"0.4.9": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"UninitializedFunctionPointerInConstructor_0.4.x",
"IncorrectEventSignatureInLibraries_0.4.x",
"ExpExponentCleanup",
"NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction"
],
"released": "2017-01-31"
},
"0.5.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage"
],
"released": "2018-11-13"
},
"0.5.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage"
],
"released": "2018-12-03"
},
"0.5.10": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers"
],
"released": "2019-06-25"
},
"0.5.11": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-08-12"
},
"0.5.12": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-10-01"
},
"0.5.13": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-11-14"
},
"0.5.14": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2LoopYulOptimizer"
],
"released": "2019-12-09"
},
"0.5.15": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-12-17"
},
"0.5.16": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden"
],
"released": "2020-01-02"
},
"0.5.17": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow"
],
"released": "2020-03-17"
},
"0.5.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage"
],
"released": "2018-12-19"
},
"0.5.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage"
],
"released": "2019-01-22"
},
"0.5.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage"
],
"released": "2019-02-12"
},
"0.5.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage",
"IncorrectByteInstructionOptimization",
"DoubleShiftSizeOverflow"
],
"released": "2019-03-05"
},
"0.5.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries",
"ABIEncoderV2PackedStorage",
"IncorrectByteInstructionOptimization"
],
"released": "2019-03-13"
},
"0.5.7": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"DirtyBytesArrayToStorage",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2",
"UninitializedFunctionPointerInConstructor",
"IncorrectEventSignatureInLibraries"
],
"released": "2019-03-26"
},
"0.5.8": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
"DynamicConstructorArgumentsClippedABIV2"
],
"released": "2019-04-30"
},
"0.5.9": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"privateCanBeOverridden",
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement"
],
"released": "2019-05-28"
},
"0.6.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow",
"YulOptimizerRedundantAssignmentBreakContinue"
],
"released": "2019-12-17"
},
"0.6.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow"
],
"released": "2020-01-02"
},
"0.6.10": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-06-11"
},
"0.6.11": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-07-07"
},
"0.6.12": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-07-22"
},
"0.6.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow"
],
"released": "2020-01-27"
},
"0.6.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow"
],
"released": "2020-02-18"
},
"0.6.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents",
"MemoryArrayCreationOverflow"
],
"released": "2020-03-10"
},
"0.6.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck",
"TupleAssignmentMultiStackSlotComponents"
],
"released": "2020-04-06"
},
"0.6.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck"
],
"released": "2020-04-09"
},
"0.6.7": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"MissingEscapingInFormatting",
"ArraySliceDynamicallyEncodedBaseType",
"ImplicitConstructorCallvalueCheck"
],
"released": "2020-05-04"
},
"0.6.8": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-05-14"
},
"0.6.9": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"UsingForCalldata"
],
"released": "2020-06-04"
},
"0.7.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-07-28"
},
"0.7.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup",
"FreeFunctionRedefinition"
],
"released": "2020-09-02"
},
"0.7.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy",
"DynamicArrayCleanup"
],
"released": "2020-09-28"
},
"0.7.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching",
"EmptyByteArrayCopy"
],
"released": "2020-10-07"
},
"0.7.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2020-10-19"
},
"0.7.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2020-11-18"
},
"0.7.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2020-12-16"
},
"0.8.0": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2020-12-16"
},
"0.8.1": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2021-01-27"
},
"0.8.10": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation"
],
"released": "2021-11-09"
},
"0.8.11": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"AbiEncodeCallLiteralAsFixedBytesBug"
],
"released": "2021-12-20"
},
"0.8.12": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"AbiEncodeCallLiteralAsFixedBytesBug"
],
"released": "2022-02-16"
},
"0.8.13": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"InlineAssemblyMemorySideEffects",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation"
],
"released": "2022-03-16"
},
"0.8.14": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"InlineAssemblyMemorySideEffects"
],
"released": "2022-05-17"
},
"0.8.15": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup"
],
"released": "2022-06-15"
},
"0.8.16": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination"
],
"released": "2022-08-08"
},
"0.8.17": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess"
],
"released": "2022-09-08"
},
"0.8.18": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess"
],
"released": "2023-02-01"
},
"0.8.19": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess"
],
"released": "2023-02-22"
},
"0.8.2": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory",
"KeccakCaching"
],
"released": "2021-03-02"
},
"0.8.20": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess"
],
"released": "2023-05-10"
},
"0.8.21": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication"
],
"released": "2023-07-19"
},
"0.8.22": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication"
],
"released": "2023-10-25"
},
"0.8.23": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2023-11-08"
},
"0.8.24": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-01-25"
},
"0.8.25": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-03-14"
},
"0.8.26": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-05-21"
},
"0.8.27": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-09-04"
},
"0.8.28": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2024-10-09"
},
"0.8.29": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2025-03-12"
},
"0.8.3": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables",
"ABIDecodeTwoDimensionalArrayMemory"
],
"released": "2021-03-23"
},
"0.8.30": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2025-05-07"
},
"0.8.31": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision",
"LostStorageArrayWriteOnSlotOverflow"
],
"released": "2025-12-03"
},
"0.8.32": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision"
],
"released": "2025-12-18"
},
"0.8.33": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion",
"TransientStorageClearingHelperCollision"
],
"released": "2025-12-18"
},
"0.8.34": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion"
],
"released": "2026-02-18"
},
"0.8.35": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"InheritanceOrderReversalOnStorageEndWarning",
"UnsoundSpillInMutualRecursion"
],
"released": "2026-04-29"
},
"0.8.36": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping",
"MisorderedNamedParametersInRequireWithCustomErrors",
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion"
],
"released": "2026-07-09"
},
"0.8.37": {
"bugs": [
"YulOptimizerKnowledgeBaseStaleBookkeeping"
],
"released": "2026-09-10"
},
"0.8.4": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables"
],
"released": "2021-04-21"
},
"0.8.5": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables"
],
"released": "2021-06-10"
},
"0.8.6": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables"
],
"released": "2021-06-22"
},
"0.8.7": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"SignedImmutables"
],
"released": "2021-08-11"
},
"0.8.8": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation",
"UserDefinedValueTypesBug",
"SignedImmutables"
],
"released": "2021-09-27"
},
"0.8.9": {
"bugs": [
"MemoryByteArrayElementDeleteClearsWholeWord",
"SpillSlotCollisionAcrossMutualRecursion",
"UnsoundSpillInMutualRecursion",
"LostStorageArrayWriteOnSlotOverflow",
"VerbatimInvalidDeduplication",
"FullInlinerNonExpressionSplitArgumentEvaluationOrder",
"MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
"NestedCalldataArrayAbiReencodingSizeValidation"
],
"released": "2021-09-29"
}
}


Cheatsheet (`docs/cheatsheet.rst`)


Cheatsheet


.. index:: operator;precedence

Order of Precedence of Operators

.. include:: types/operator-precedence-table.rst

.. index:: abi;decode, abi;encode, abi;encodePacked, abi;encodeWithSelector, abi;encodeCall, abi;encodeWithSignature

ABI Encoding and Decoding Functions

  • abi.decode(bytes memory encodedData, (...)) returns (...): :ref:ABI <ABI>-decodes
    the provided data. The types are given in parentheses as second argument.
    Example: (uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))
  • abi.encode(...) returns (bytes memory): :ref:ABI <ABI>-encodes the given arguments
  • abi.encodePacked(...) returns (bytes memory): Performs :ref:packed encoding <abi_packed_mode> of
    the given arguments. Note that this encoding can be ambiguous!
  • abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory): :ref:ABI <ABI>-encodes
    the given arguments starting from the second and prepends the given four-byte selector
  • abi.encodeCall(function functionPointer, (...)) returns (bytes memory): ABI-encodes a call to functionPointer with the arguments found in the
    tuple. Performs a full type-check, ensuring the types match the function signature. Result equals abi.encodeWithSelector(functionPointer.selector, ...)
  • abi.encodeWithSignature(string memory signature, ...) returns (bytes memory): Equivalent
    to abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)

.. index:: bytes;concat, string;concat

Members of ``bytes`` and ``string``

  • bytes.concat(...) returns (bytes memory): :ref:Concatenates variable number of arguments to one byte array

  • string.concat(...) returns (string memory): :ref:Concatenates variable number of arguments to one string array<string-concat>

.. index:: address;balance, address;codehash, address;send, address;code, address;transfer

Members of ``address``

  • <address>.balance (uint256): balance of the :ref:address in Wei
  • <address>.code (bytes memory): code at the :ref:address (can be empty)
  • <address>.codehash (bytes32): the codehash of the :ref:address
  • <address>.call(bytes memory) returns (bool, bytes memory): issue low-level CALL with the given payload,
    returns success condition and return data
  • <address>.delegatecall(bytes memory) returns (bool, bytes memory): issue low-level DELEGATECALL with the given payload,
    returns success condition and return data
  • <address>.staticcall(bytes memory) returns (bool, bytes memory): issue low-level STATICCALL with the given payload,
    returns success condition and return data
  • <address payable>.send(uint256 amount) returns (bool): send given amount of Wei to :ref:address,
    returns false on failure (deprecated)
  • <address payable>.transfer(uint256 amount): send given amount of Wei to :ref:address, throws on failure (deprecated)

.. index:: blockhash, blobhash, block, block;basefee, block;blobbasefee, block;chainid, block;coinbase, block;difficulty, block;gaslimit, block;number, block;prevrandao, block;slotnum, block;timestamp
.. index:: gasleft, msg;data, msg;sender, msg;sig, msg;value, tx;gasprice, tx;origin

Block and Transaction Properties

  • blockhash(uint blockNumber) returns (bytes32): hash of the given block - only works for 256 most recent blocks
  • blobhash(uint index) returns (bytes32): versioned hash of the index-th blob associated with the current transaction.
    A versioned hash consists of a single byte representing the version (currently 0x01), followed by the last 31 bytes
    of the SHA256 hash of the KZG commitment (EIP-4844 <https://eips.ethereum.org/EIPS/eip-4844>_).
    Returns zero if no blob with the given index exists.
  • block.basefee (uint): current block's base fee (EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>_ and EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>_)
  • block.blobbasefee (uint): current block's blob base fee (EIP-7516 <https://eips.ethereum.org/EIPS/eip-7516>_ and EIP-4844 <https://eips.ethereum.org/EIPS/eip-4844>_)
  • block.chainid (uint): current chain id
  • block.coinbase (address payable): current block miner's address
  • block.difficulty (uint): current block difficulty (EVM < Paris). For other EVM versions it behaves as a deprecated alias for block.prevrandao that will be removed in the next breaking release
  • block.gaslimit (uint): current block gaslimit
  • block.number (uint): current block number
  • block.prevrandao (uint): random number provided by the beacon chain (EVM >= Paris) (see EIP-4399 <https://eips.ethereum.org/EIPS/eip-4399>_ )
  • block.slotnum (uint64): current beacon chain slot number (EVM >= Amsterdam) (see EIP-7843 <https://eips.ethereum.org/EIPS/eip-7843>_ )
  • block.timestamp (uint): current block timestamp in seconds since Unix epoch
  • gasleft() returns (uint256): remaining gas
  • msg.data (bytes): complete calldata
  • msg.sender (address): sender of the message (current call)
  • msg.sig (bytes4): first four bytes of the calldata (i.e. function identifier)
  • msg.value (uint): number of wei sent with the message
  • tx.gasprice (uint): gas price of the transaction
  • tx.origin (address): sender of the transaction (full call chain)

.. index:: assert, require, revert

Validations and Assertions

  • assert(bool condition): abort execution and revert state changes if condition is false (use for internal error)
  • require(bool condition): abort execution and revert state changes if condition is false (use
    for malformed input or error in external component)
  • require(bool condition, string memory message): abort execution and revert state changes if
    condition is false (use for malformed input or error in external component). Also provide error message.
  • revert(): abort execution and revert state changes
  • revert(string memory message): abort execution and revert state changes providing an explanatory string

.. index:: cryptography, keccak256, sha256, ripemd160, ecrecover, addmod, mulmod, erc7201

Mathematical and Cryptographic Functions

  • keccak256(bytes memory) returns (bytes32): compute the Keccak-256 hash of the input
  • sha256(bytes memory) returns (bytes32): compute the SHA-256 hash of the input
  • ripemd160(bytes memory) returns (bytes20): compute the RIPEMD-160 hash of the input
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address): recover address associated with
    the public key from elliptic curve signature, return zero on error
  • addmod(uint x, uint y, uint k) returns (uint): compute (x + y) % k where the addition is performed with
    arbitrary precision and does not wrap around at 2**256. Assert that k != 0 starting from version 0.5.0.
  • mulmod(uint x, uint y, uint k) returns (uint): compute (x * y) % k where the multiplication is performed
    with arbitrary precision and does not wrap around at 2**256. Assert that k != 0 starting from version 0.5.0.
  • erc7201(string memory id) returns (uint): compute the base slot of an erc7201 storage namespace.
    Can be used in compile time context.

.. index:: this, super, selfdestruct

  • this (current contract's type): the current contract, explicitly convertible to address or address payable
  • super: a contract one level higher in the inheritance hierarchy
  • selfdestruct(address payable recipient): send all funds to the given address and (only on EVMs before Cancun or when invoked within the transaction creating the contract) destroy the contract.

.. index:: type;name, type;creationCode, type;runtimeCode, type;interfaceId, type;min, type;max

Type Information

  • type(C).name (string): the name of the contract
  • type(C).creationCode (bytes memory): creation bytecode of the given contract, see :ref:Type Information<meta-type>.
  • type(C).runtimeCode (bytes memory): runtime bytecode of the given contract, see :ref:Type Information<meta-type>.
  • type(I).interfaceId (bytes4): value containing the EIP-165 interface identifier of the given interface, see :ref:Type Information<meta-type>.
  • type(T).min (T): the minimum value representable by the integer type T, see :ref:Type Information<meta-type>.
  • type(T).max (T): the maximum value representable by the integer type T, see :ref:Type Information<meta-type>.

.. index:: visibility, public, private, external, internal

Function Visibility Specifiers

.. code-block:: solidity
:force:

text
function myFunction() <visibility specifier> returns (bool) {
    return true;
}
  • public: visible externally and internally (creates a :ref:getter function<getter-functions> for storage/state variables)
  • private: only visible in the current contract
  • external: only visible externally (only for functions) - i.e. can only be message-called (via this.func)
  • internal: only visible internally

.. index:: modifiers, pure, view, payable, constant, anonymous, indexed

Modifiers

  • pure for functions: Disallows modification or access of state.
  • view for functions: Disallows modification of state.
  • payable for functions: Allows them to receive Ether together with a call.
  • constant for state variables: Disallows assignment (except initialization), does not occupy storage slot.
  • immutable for state variables: Allows assignment at construction time and is constant when deployed. Is stored in code.
  • anonymous for events: Does not store event signature as topic.
  • indexed for event parameters: Stores the parameter as topic.
  • virtual for functions and modifiers: Allows the function's or modifier's
    behavior to be changed in derived contracts.
  • override: States that this function, modifier or public state variable changes
    the behavior of a function or modifier in a base contract.

Common Patterns (`docs/common-patterns.rst`)

###############
Common Patterns
###############

.. index:: withdrawal

.. _withdrawal_pattern:


Withdrawal from Contracts


The recommended method of sending funds after an effect
is using the withdrawal pattern. Although the most intuitive
method of sending Ether, as a result of an effect, is a
direct transfer call, this is not recommended as it
introduces a potential security risk. You may read
more about this on the :ref:security_considerations page.

The following is an example of the withdrawal pattern in practice in
a contract where the goal is to send the most of some compensation, e.g. Ether, to the
contract in order to become the "richest", inspired by
King of the Ether <https://www.kingoftheether.com/>_.

In the following contract, if you are no longer the richest,
you receive the funds of the person who is now the richest.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract WithdrawalContract {
    address public richest;
    uint public mostSent;

    mapping(address => uint) pendingWithdrawals;

    /// The amount of Ether sent was not higher than
    /// the currently highest amount.
    error NotEnoughEther();

    constructor() payable {
        richest = msg.sender;
        mostSent = msg.value;
    }

    function becomeRichest() public payable {
        if (msg.value <= mostSent) revert NotEnoughEther();
        pendingWithdrawals[richest] += msg.value;
        richest = msg.sender;
        mostSent = msg.value;
    }

    function withdraw() public {
        uint amount = pendingWithdrawals[msg.sender];
        // Remember to zero the pending refund before
        // sending to prevent reentrancy attacks
        pendingWithdrawals[msg.sender] = 0;
        (bool success, ) = payable(msg.sender).call{value: amount}("");
        require(success);
    }
}

This is as opposed to the more intuitive sending pattern:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract SendContract {
    address payable public richest;
    uint public mostSent;

    /// The amount of Ether sent was not higher than
    /// the currently highest amount.
    error NotEnoughEther();

    constructor() payable {
        richest = payable(msg.sender);
        mostSent = msg.value;
    }

    function becomeRichest() public payable {
        if (msg.value <= mostSent) revert NotEnoughEther();
        // This line can cause problems (explained below).
        (bool success, ) = richest.call{value: msg.value}("");
        require(success);
        richest = payable(msg.sender);
        mostSent = msg.value;
    }
}

Notice that, in this example, an attacker could trap the
contract into an unusable state by causing richest to be
the address of a contract that has a receive or fallback function
which fails (e.g. by using revert() or by just
consuming more than the 2300 gas stipend transferred to them). That way,
whenever transfer is called to deliver funds to the
"poisoned" contract, it will fail and thus also becomeRichest
will fail, with the contract being stuck forever.

In contrast, if you use the "withdraw" pattern from the first example,
the attacker can only cause his or her own withdraw to fail and not the
rest of the contract's workings.

.. index:: access;restricting


Restricting Access


Restricting access is a common pattern for contracts.
Note that you can never restrict any human or computer
from reading the content of your transactions or
your contract's state. You can make it a bit harder
by using encryption, but if your contract is supposed
to read the data, so will everyone else.

You can restrict read access to your contract's state
by other contracts. That is actually the default
unless you declare your state variables public.

Furthermore, you can restrict who can make modifications
to your contract's state or call your contract's
functions and this is what this section is about.

.. index:: function;modifier

The use of function modifiers makes these
restrictions highly readable.

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract AccessRestriction {
    // These will be assigned at the construction
    // phase, where `msg.sender` is the account
    // creating this contract.
    address public owner = msg.sender;
    uint public creationTime = block.timestamp;

    // Now follows a list of errors that
    // this contract can generate together
    // with a textual explanation in special
    // comments.

    /// Sender not authorized for this
    /// operation.
    error Unauthorized();

    /// Function called too early.
    error TooEarly();

    /// Not enough Ether sent with function call.
    error NotEnoughEther();

    // Modifiers can be used to change
    // the body of a function.
    // If this modifier is used, it will
    // prepend a check that only passes
    // if the function is called from
    // a certain address.
    modifier onlyBy(address account)
    {
        if (msg.sender != account)
            revert Unauthorized();
        // Do not forget the "_;"! It will
        // be replaced by the actual function
        // body when the modifier is used.
        _;
    }

    /// Make `newOwner` the new owner of this
    /// contract.
    function changeOwner(address newOwner)
        public
        onlyBy(owner)
    {
        owner = newOwner;
    }

    modifier onlyAfter(uint time) {
        if (block.timestamp < time)
            revert TooEarly();
        _;
    }

    /// Erase ownership information.
    /// May only be called 6 weeks after
    /// the contract has been created.
    function disown()
        public
        onlyBy(owner)
        onlyAfter(creationTime + 6 weeks)
    {
        delete owner;
    }

    // This modifier requires a certain
    // fee being associated with a function call.
    // If the caller sent too much, he or she is
    // refunded, but only after the function body.
    // This was dangerous before Solidity version 0.4.0,
    // where it was possible to skip the part after `_;`.
    modifier costs(uint amount) {
        if (msg.value < amount)
            revert NotEnoughEther();

        _;
        if (msg.value > amount) {
            (bool success, ) = payable(msg.sender).call{value: msg.value - amount}("");
            require(success);
        }
    }

    function forceOwnerChange(address newOwner)
        public
        payable
        costs(200 ether)
    {
        owner = newOwner;
        // just some example condition
        if (uint160(owner) & 0 == 1)
            // This did not refund for Solidity
            // before version 0.4.0.
            return;
        // refund overpaid fees
    }
}

A more specialised way in which access to function
calls can be restricted will be discussed
in the next example.

.. index:: state machine


State Machine


Contracts often act as a state machine, which means
that they have certain stages in which they behave
differently or in which different functions can
be called. A function call often ends a stage
and transitions the contract into the next stage
(especially if the contract models interaction).
It is also common that some stages are automatically
reached at a certain point in time.

An example for this is a blind auction contract which
starts in the stage "accepting blinded bids", then
transitions to "revealing bids" which is ended by
"determine auction outcome".

.. index:: function;modifier

Function modifiers can be used in this situation
to model the states and guard against
incorrect usage of the contract.

Example

In the following example,
the modifier atStage ensures that the function can
only be called at a certain stage.

Automatic timed transitions
are handled by the modifier timedTransitions, which
should be used for all functions.

.. note::
Modifier Order Matters.
If atStage is combined
with timedTransitions, make sure that you mention
it after the latter, so that the new stage is
taken into account.

Finally, the modifier transitionNext can be used
to automatically go to the next stage when the
function finishes.

.. note::
Modifier May be Skipped.
This only applies to Solidity before version 0.4.0:
Since modifiers are applied by simply replacing
code and not by using a function call,
the code in the transitionNext modifier
can be skipped if the function itself uses
return. If you want to do that, make sure
to call nextStage manually from those functions.
Starting with version 0.4.0, modifier code
will run even if the function explicitly returns.

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract StateMachine {
    enum Stages {
        AcceptingBlindedBids,
        RevealBids,
        AnotherStage,
        AreWeDoneYet,
        Finished
    }
    /// Function cannot be called at this time.
    error FunctionInvalidAtThisStage();

    // This is the current stage.
    Stages public stage = Stages.AcceptingBlindedBids;

    uint public creationTime = block.timestamp;

    modifier atStage(Stages stage_) {
        if (stage != stage_)
            revert FunctionInvalidAtThisStage();
        _;
    }

    function nextStage() internal {
        stage = Stages(uint(stage) + 1);
    }

    // Perform timed transitions. Be sure to mention
    // this modifier first, otherwise the guards
    // will not take the new stage into account.
    modifier timedTransitions() {
        if (stage == Stages.AcceptingBlindedBids &&
                    block.timestamp >= creationTime + 10 days)
            nextStage();
        if (stage == Stages.RevealBids &&
                block.timestamp >= creationTime + 12 days)
            nextStage();
        // The other stages transition by transaction
        _;
    }

    // Order of the modifiers matters here!
    function bid()
        public
        payable
        timedTransitions
        atStage(Stages.AcceptingBlindedBids)
    {
        // We will not implement that here
    }

    function reveal()
        public
        timedTransitions
        atStage(Stages.RevealBids)
    {
    }

    // This modifier goes to the next stage
    // after the function is done.
    modifier transitionNext()
    {
        _;
        nextStage();
    }

    function g()
        public
        timedTransitions
        atStage(Stages.AnotherStage)
        transitionNext
    {
    }

    function h()
        public
        timedTransitions
        atStage(Stages.AreWeDoneYet)
        transitionNext
    {
    }

    function i()
        public
        timedTransitions
        atStage(Stages.Finished)
    {
    }
}

Contracts (`docs/contracts.rst`)

.. index:: ! contract

.. _contracts:

##########
Contracts
##########

Contracts in Solidity are similar to classes in object-oriented languages. They
contain persistent data in state variables, and functions that can modify these
variables. Calling a function on a different contract (instance) will perform
an EVM function call and thus switch the context such that state variables
in the calling contract are
inaccessible. A contract and its functions need to be called for anything to happen.
There is no "cron" concept in Ethereum to call a function at a particular event automatically.

.. include:: contracts/creating-contracts.rst

.. include:: contracts/visibility-and-getters.rst

.. include:: contracts/function-modifiers.rst

.. include:: contracts/transient-storage.rst

.. include:: contracts/constant-state-variables.rst
.. include:: contracts/custom-storage-layout.rst
.. include:: contracts/functions.rst

.. include:: contracts/events.rst
.. include:: contracts/errors.rst

.. include:: contracts/inheritance.rst

.. include:: contracts/abstract-contracts.rst
.. include:: contracts/interfaces.rst

.. include:: contracts/libraries.rst

.. include:: contracts/using-for.rst


Contributing (`docs/contributing.rst`)

############
Contributing
############

Help is always welcome and there are plenty of options to contribute to Solidity.

In particular, we appreciate support in the following areas:

  • Reporting issues.
  • Fixing and responding to Solidity's GitHub issues <https://github.com/argotorg/solidity/issues>, especially those tagged as
    "good first issue" <https://github.com/argotorg/solidity/labels/good%20first%20issue>
    which are
    meant as introductory issues for external contributors.
  • Improving the documentation.
  • Translating <https://github.com/solidity-docs>_ the documentation into more languages.
  • Responding to questions from other users on StackExchange <https://ethereum.stackexchange.com>_ and the Solidity Matrix Chat <https://matrix.to/#/#ethereum\_solidity:gitter.im>_.
  • Getting involved in the language design process by proposing language changes or new features in the Solidity forum <https://forum.soliditylang.org/>_ and providing feedback.

To get started, you can try :ref:building-from-source in order to familiarize
yourself with the components of Solidity and the build process. Also, it may be
useful to become well-versed at writing smart-contracts in Solidity.

Please note that this project is released with a Contributor Code of Conduct <https://raw.githubusercontent.com/ethereum/solidity/develop/CODE_OF_CONDUCT.md>_. By participating in this project — in the issues, pull requests, or Matrix channels — you agree to abide by its terms.

Team Calls

If you have issues or pull requests to discuss, or are interested in hearing what
the team and contributors are working on, you can join our public team call:

  • Wednesdays at 3PM CET/CEST.

The call takes place on Jitsi <https://meet.solidity.org>_.

New topics can be freely added to the agenda <https://notes.argot.org/@solidity-design-call-agenda>_
and will be scheduled for discussion on the nearest call.

How to Report Issues

To report an issue, please use the
GitHub issues tracker <https://github.com/argotorg/solidity/issues>_. When
reporting issues, please mention the following details:

  • Solidity version.
  • Source code (if applicable).
  • Operating system.
  • Steps to reproduce the issue.
  • Actual vs. expected behavior.

Reducing the source code that caused the issue to a bare minimum is always
very helpful, and sometimes even clarifies a misunderstanding.

For technical discussions about language design, a post in the
Solidity forum <https://forum.soliditylang.org/>_ is the correct place (see :ref:solidity_language_design).

Workflow for Pull Requests

In order to contribute, please fork off of the develop branch and make your
changes there. Your commit messages should detail why you made your change
in addition to what you did (unless it is a tiny change).

If you need to pull in any changes from develop after making your fork (for
example, to resolve potential merge conflicts), please avoid using git merge
and instead, git rebase your branch. This will help us review your change
more easily.

Additionally, if you are writing a new feature, please ensure you add appropriate
test cases under test/ (see below).

However, if you are making a larger change, please consult with the Solidity Development Matrix channel <https://matrix.to/#/#ethereum\_solidity-dev:gitter.im>_ (different from the one mentioned above — this one is
focused on compiler and language development instead of language usage) first.

New features and bugfixes should be added to the Changelog.md file: please
follow the style of previous entries, when applicable.

Finally, please make sure you respect the coding style <https://github.com/argotorg/solidity/blob/develop/CODING_STYLE.md>_
for this project. Also, even though we do CI testing, please test your code and
ensure that it builds locally before submitting a pull request.

We highly recommend going through our review checklist <https://github.com/argotorg/solidity/blob/develop/ReviewChecklist.md>_ before submitting the pull request.
We thoroughly review every PR and will help you get it right, but there are many common problems that can be easily avoided, making the review much smoother.

Thank you for your help!

AI-Assisted Contributions

We do not ban the use of AI tools, but we hold all contributions to the same high standard
regardless of how they are produced, and we require full transparency about their use.

Submitting AI-generated code means you have reviewed it, understand it, can explain it, and have
tested it as thoroughly as if you had written it by hand.

If you used AI tools to generate code, tests, or documentation in any part of your contribution,
disclosure in the pull request is mandatory.
If we determine that a PR contains undisclosed AI-generated content, we may close it.

Running the Compiler Tests

Prerequisites

For running all compiler tests you may want to optionally install a few
dependencies (evmone <https://github.com/ipsilon/evmone/releases>,
z3 <https://github.com/Z3Prover/z3>
, Eldarica <https://github.com/uuverifiers/eldarica/>,
cvc5 <https://github.com/cvc5/cvc5>
).

On macOS systems, some of the testing scripts expect GNU coreutils to be installed.
This can be easiest accomplished using Homebrew: brew install coreutils.

On Windows systems, make sure that you have a privilege to create symlinks,
otherwise several tests may fail.
Administrators should have that privilege, but you may also
grant it to other users <https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links#policy-management>_
or
enable Developer Mode <https://learn.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development>_.

Running the Tests

Solidity includes different types of tests, most of them bundled into the
Boost C++ Test Framework <https://www.boost.org/doc/libs/release/libs/test/doc/html/index.html>_ application soltest.
Running build/test/soltest or its wrapper scripts/soltest.sh is sufficient for most changes.

The ./scripts/tests.sh script executes most Solidity tests automatically,
including those bundled into the Boost C++ Test Framework <https://www.boost.org/doc/libs/release/libs/test/doc/html/index.html>_
application soltest (or its wrapper scripts/soltest.sh), as well as command-line tests and
compilation tests.

The test system automatically tries to discover the location of
the evmone <https://github.com/ipsilon/evmone/releases>_ for running the semantic tests.

The evmone library must be located in the deps or deps/lib directory relative to the
current working directory, to its parent or its parent's parent. Alternatively, an explicit location
for the evmone shared object can be specified via the ETH_EVMONE environment variable.

evmone is needed mainly for running semantic and gas tests.
If you do not have it installed, you can skip these tests by passing the --no-semantic-tests
flag to scripts/soltest.sh.

The evmone library should end with the file name
extension .so on Linux, .dll on Windows systems and .dylib on macOS.

For running SMT tests, the z3 executable must be present in PATH.
A few SMT tests use Eldarica instead of z3.
These require its executable (eld) to be present in PATH for the tests to pass.
However, if Eldarica is not found, these tests will be automatically skipped.

If z3 is not present on your system, you should disable the
SMT tests by exporting SMT_FLAGS=--no-smt before running ./scripts/tests.sh or
running ./scripts/soltest.sh --no-smt.
These tests are libsolidity/smtCheckerTests.

.. note::

text
To get a list of all unit tests run by Soltest, run ``./build/test/soltest --list_content=HRF``.

For quicker results you can run a subset of, or specific tests.

To run a subset of tests, you can use filters:
./scripts/soltest.sh -t TestSuite/TestName,
where TestName can be a wildcard *.

Or, for example, to run all the tests for the yul disambiguator:
./scripts/soltest.sh -t "yulOptimizerTests/disambiguator/*" --no-smt.

./build/test/soltest --help has extensive help on all of the options available.

See especially:

  • show_progress (-p) <https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/show_progress.html>_ to show test completion,
  • run_test (-t) <https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/run_test.html>_ to run specific tests cases, and
  • report-level (-r) <https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/report_level.html>_ give a more detailed report.

.. note::

text
Those working in a Windows environment wanting to run the above basic sets
without z3. Using Git Bash, you use: ``./build/test/Release/soltest.exe -- --no-smt``.
If you are running this in plain Command Prompt, use ``.\build\test\Release\soltest.exe -- --no-smt``.

If you want to debug using GDB, make sure you build differently than the "usual".
For example, you could run the following command in your build folder:

.. code-block:: bash

cmake -DCMAKE_BUILD_TYPE=Debug ..
make

This creates symbols so that when you debug a test using the --debug flag,
you have access to functions and variables in which you can break or print with.

The CI runs additional tests (including solc-js and testing third party Solidity
frameworks) that require compiling the Emscripten target.

Writing and Running Syntax Tests

Syntax tests check that the compiler generates the correct error messages for invalid code
and properly accepts valid code.
They are stored in individual files inside the tests/libsolidity/syntaxTests folder.
These files must contain annotations, stating the expected result(s) of the respective test.
The test suite compiles and checks them against the given expectations.

For example: ./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol

.. code-block:: solidity

text
contract test {
    uint256 variable;
    uint128 variable;
}
// ----
// DeclarationError: (36-52): Identifier already declared.

A syntax test must contain at least the contract under test itself, followed by the separator // ----. The comments that follow the separator are used to describe the
expected compiler errors or warnings. The number range denotes the location in the source where the error occurred.
If you want the contract to compile without any errors or warning you can leave
out the separator and the comments that follow it.

In the above example, the state variable variable was declared twice, which is not allowed. This results in a DeclarationError stating that the identifier was already declared.

The isoltest tool is used for these tests and you can find it under ./build/test/tools/. It is an interactive tool which allows
editing of failing contracts using your preferred text editor. Let's try to break this test by removing the second declaration of variable:

.. code-block:: solidity

text
contract test {
    uint256 variable;
}
// ----
// DeclarationError: (36-52): Identifier already declared.

Running ./build/test/tools/isoltest again results in a test failure:

.. code-block:: text

text
syntaxTests/double_stateVariable_declaration.sol: FAIL
    Contract:
        contract test {
            uint256 variable;
        }

    Expected result:
        DeclarationError: (36-52): Identifier already declared.
    Obtained result:
        Success

isoltest prints the expected result next to the obtained result, and also
provides a way to edit, update or skip the current contract file, or quit the application.

It offers several options for failing tests:

  • edit: isoltest tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command-line (as isoltest --editor /path/to/editor), in the environment variable EDITOR or just /usr/bin/editor (in that order).
  • update: Updates the expectations for contract under test. This updates the annotations by removing unmet expectations and adding missing expectations. The test is then run again.
  • skip: Skips the execution of this particular test.
  • quit: Quits isoltest.

All of these options apply to the current contract, except quit which stops the entire testing process.

Automatically updating the test above changes it to

.. code-block:: solidity

text
contract test {
    uint256 variable;
}
// ----

and re-run the test. It now passes again:

.. code-block:: text

text
Re-running test case...
syntaxTests/double_stateVariable_declaration.sol: OK

.. note::

text
Choose a name for the contract file that explains what it tests, e.g. ``double_variable_declaration.sol``.
Do not put more than one contract into a single file, unless you are testing inheritance or cross-contract calls.
Each file should test one aspect of your new feature.

Command-line Tests

Our suite of end-to-end command-line tests checks the behaviour of the compiler binary as a whole
in various scenarios.
These tests are located in test/cmdlineTests/ <https://github.com/argotorg/solidity/tree/develop/test/cmdlineTests>_,
one per subdirectory, and can be executed using the cmdlineTests.sh script.

By default the script runs all available tests.
You can also provide one or more file name patterns <https://www.gnu.org/software/bash/manual/bash.html#Filename-Expansion>_,
in which case only the tests matching at least one pattern will be executed.
It is also possible to exclude files matching a specific pattern by prefixing it with --exclude.

By default the script assumes that a solc binary is available inside the build/ subdirectory
inside the working copy.
If you build the compiler outside of the source tree, you can use the SOLIDITY_BUILD_DIR environment
variable to specify a different location for the build directory.

Example:

.. code-block:: bash

text
export SOLIDITY_BUILD_DIR=~/solidity/build/
test/cmdlineTests.sh "standard_*" "*_yul_*" --exclude "standard_yul_*"

The commands above will run tests from directories starting with test/cmdlineTests/standard_ and
subdirectories of test/cmdlineTests/ that have _yul_ somewhere in the name,
but no test whose name starts with standard_yul_ will be executed.
It will also assume that the file solidity/build/solc/solc inside your home directory is the
compiler binary (unless you are on Windows -- then solidity/build/solc/Release/solc.exe).

There are several kinds of command-line tests:

  • Standard JSON test: contains at least an input.json file.
    In general may contain:

    • input.json: input file to be passed to the --standard-json option on the command line.
    • output.json: expected Standard JSON output.
    • args: extra command-line arguments passed to solc.
  • CLI test: contains at least an input.* file (other than input.json).
    In general may contain:

    • input.*: a single input file, whose name will be supplied to solc on the command line.
      Usually input.sol or input.yul.
    • args: extra command-line arguments passed to solc.
    • stdin: content to be passed to solc via standard input.
    • output: expected content of the standard output.
    • err: expected content of the standard error output.
    • exit: expected exit code. If not provided, zero is expected.
  • Script test: contains a test.* file.
    In general may contain:

    • test.*: a single script to run, usually test.sh or test.py.
      The script must be executable.

Running the Fuzzer via AFL

Fuzzing is a technique that runs programs on more or less random inputs to find exceptional execution
states (segmentation faults, exceptions, etc). Modern fuzzers are clever and run a directed search
inside the input. We have a specialized binary called solfuzzer which takes source code as input
and fails whenever it encounters an internal compiler error, segmentation fault or similar, but
does not fail if e.g., the code contains an error. This way, fuzzing tools can find internal problems in the compiler.

We mainly use AFL <https://lcamtuf.coredump.cx/afl/>_ for fuzzing. You need to download and
install the AFL packages from your repositories (afl, afl-clang) or build them manually.
Next, build Solidity (or just the solfuzzer binary) with AFL as your compiler:

.. code-block:: bash

text
cd build
# if needed
make clean
cmake .. -DCMAKE_C_COMPILER=path/to/afl-gcc -DCMAKE_CXX_COMPILER=path/to/afl-g++
make solfuzzer

At this stage, you should be able to see a message similar to the following:

.. code-block:: text

text
Scanning dependencies of target solfuzzer
[ 98%] Building CXX object test/tools/CMakeFiles/solfuzzer.dir/fuzzer.cpp.o
afl-cc 2.52b by <[email protected]>
afl-as 2.52b by <[email protected]>
[+] Instrumented 1949 locations (64-bit, non-hardened mode, ratio 100%).
[100%] Linking CXX executable solfuzzer

If the instrumentation messages did not appear, try switching the cmake flags pointing to AFL's clang binaries:

.. code-block:: bash

text
# if previously failed
make clean
cmake .. -DCMAKE_C_COMPILER=path/to/afl-clang -DCMAKE_CXX_COMPILER=path/to/afl-clang++
make solfuzzer

Otherwise, upon execution the fuzzer halts with an error saying binary is not instrumented:

.. code-block:: text

text
afl-fuzz 2.52b by <[email protected]>
... (truncated messages)
[*] Validating target binary...

[-] Looks like the target binary is not instrumented! The fuzzer depends on
    compile-time instrumentation to isolate interesting test cases while
    mutating the input data. For more information, and for tips on how to
    instrument binaries, please see /usr/share/doc/afl-doc/docs/README.

    When source code is not available, you may be able to leverage QEMU
    mode support. Consult the README for tips on how to enable this.
    (It is also possible to use afl-fuzz as a traditional, "dumb" fuzzer.
    For that, you can use the -n option - but expect much worse results.)

[-] PROGRAM ABORT : No instrumentation detected
         Location : check_binary(), afl-fuzz.c:6920

Next, you need some example source files. This makes it much easier for the fuzzer
to find errors. You can either copy some files from the syntax tests or extract test files
from the documentation or the other tests:

.. code-block:: bash

text
mkdir /tmp/test_cases
cd /tmp/test_cases
# extract from tests:
path/to/solidity/scripts/isolate_tests.py path/to/solidity/test/libsolidity/SolidityEndToEndTest.cpp
# extract from documentation:
path/to/solidity/scripts/isolate_tests.py path/to/solidity/docs

The AFL documentation states that the corpus (the initial input files) should not be
too large. The files themselves should not be larger than 1 kB and there should be
at most one input file per functionality, so better start with a small number of.
There is also a tool called afl-cmin that can trim input files
that result in similar behavior of the binary.

Now run the fuzzer (the -m extends the size of memory to 60 MB):

.. code-block:: bash

text
afl-fuzz -m 60 -i /tmp/test_cases -o /tmp/fuzzer_reports -- /path/to/solfuzzer

The fuzzer creates source files that lead to failures in /tmp/fuzzer_reports.
Often it finds many similar source files that produce the same error. You can
use the tool scripts/uniqueErrors.sh to filter out the unique errors.

Whiskers

Whiskers is a string templating system similar to Mustache <https://mustache.github.io>_. It is used by the
compiler in various places to aid readability, and thus maintainability and verifiability, of the code.

The syntax comes with a substantial difference to Mustache. The template markers {{ and }} are
replaced by < and > in order to aid parsing and avoid conflicts with :ref:yul
(The symbols < and > are invalid in inline assembly, while { and } are used to delimit blocks).
Another limitation is that lists are only resolved one depth and they do not recurse. This may change in the future.

A rough specification is the following:

Any occurrence of <name> is replaced by the string-value of the supplied variable name without any
escaping and without iterated replacements. An area can be delimited by <#name>...</name>. It is replaced
by as many concatenations of its contents as there were sets of variables supplied to the template system,
each time replacing any ```` items by their respective value. Top-level variables can also be used
inside such areas.

There are also conditionals of the form <?name>...<!name>...</name>, where template replacements
continue recursively either in the first or the second segment depending on the value of the boolean
parameter name. If <?+name>...<!+name>...</+name> is used, then the check is whether
the string parameter name is non-empty.

.. _documentation-style:

Documentation Style Guide

In the following section you find style recommendations specifically focusing on documentation
contributions to Solidity.

English Language

Use International English, unless using project or brand names. Try to reduce the usage of
local slang and references, making your language as clear to all readers as possible.
Below are some references to help:

  • Simplified technical English <https://en.wikipedia.org/wiki/Simplified_Technical_English>_
  • International English <https://en.wikipedia.org/wiki/International_English>_

.. note::

text
While the official Solidity documentation is written in English, there are community contributed :ref:`translations`
in other languages available. Please refer to the `translation guide <https://github.com/solidity-docs#solidity-documentation-translation-guide>`_
for information on how to contribute to the community translations.

Title Case for Headings

Use title case <https://titlecase.com>_ for headings. This means capitalise all principal words in
titles, but not articles, conjunctions, and prepositions unless they start the
title.

For example, the following are all correct:

  • Title Case for Headings.
  • For Headings Use Title Case.
  • Local and State Variable Names.
  • Order of Layout.

Expand Contractions

Use expanded contractions for words, for example:

  • "Do not" instead of "Don't".
  • "Can not" instead of "Can't".

Active and Passive Voice

Active voice is typically recommended for tutorial style documentation as it
helps the reader understand who or what is performing a task. However, as the
Solidity documentation is a mixture of tutorials and reference content, passive
voice is sometimes more applicable.

As a summary:

  • Use passive voice for technical reference, for example language definition and internals of the Ethereum VM.
  • Use active voice when describing recommendations on how to apply an aspect of Solidity.

For example, the below is in passive voice as it specifies an aspect of Solidity:

Functions can be declared pure in which case they promise not to read
from or modify the state.

For example, the below is in active voice as it discusses an application of Solidity:

When invoking the compiler, you can specify how to discover the first element
of a path, and also path prefix remappings.

Common Terms

  • "Function parameters" and "return variables", not input and output parameters.

Code Examples

A CI process tests all code block formatted code examples that begin with pragma solidity, contract, library
or interface using the ./test/cmdlineTests.sh script when you create a PR. If you are adding new code examples,
ensure they work and pass tests before creating the PR.

Ensure that all code examples begin with a pragma version that spans the largest where the contract code is valid.
For example pragma solidity >=0.4.0 <0.9.0;.

Running Documentation Tests

Make sure your contributions pass our documentation tests by running ./docs/docs.sh that installs dependencies
needed for documentation and checks for any problems such as broken links or syntax issues.

.. _solidity_language_design:

Solidity Language Design

To actively get involved in the language design process and to share your ideas concerning the future of Solidity,
please join the Solidity forum <https://forum.soliditylang.org/>_.

The Solidity forum serves as the place to propose and discuss new language features and their implementation in
the early stages of ideation or modifications of existing features.

As soon as proposals get more tangible, their
implementation will also be discussed in the Solidity GitHub repository <https://github.com/argotorg/solidity>_
in the form of issues.

In addition to the forum and issue discussions, we regularly host language design discussion calls in which selected
topics, issues or feature implementations are debated in detail. The invitation to those calls is shared via the forum.

We are also sharing feedback surveys and other content that is relevant to language design in the forum.

If you want to know where the team is standing in terms of implementing new features, you can follow the implementation status in the Solidity GitHub project <https://github.com/orgs/argotorg/projects/38>.
Issues in the design backlog need further specification and will either be discussed in a language design call or in a regular team call. You can
see the upcoming changes for the next breaking release by changing from the default branch (develop) to the breaking branch <https://github.com/argotorg/solidity/tree/breaking>
.

For ad-hoc cases and questions, you can reach out to us via the Solidity-dev Gitter channel <https://gitter.im/ethereum/solidity-dev>_ — a
dedicated chatroom for conversations around the Solidity compiler and language development.

We are happy to hear your thoughts on how we can improve the language design process to be even more collaborative and transparent.


Control Structures (`docs/control-structures.rst`)

##################################
Expressions and Control Structures
##################################

.. index:: ! parameter, parameter;input, parameter;output, function parameter, parameter;function, return variable, variable;return, return

.. index:: if, else, while, do/while, for, break, continue, return, switch, goto

Control Structures

Most of the control structures known from curly-braces languages are available in Solidity:

There is: if, else, while, do, for, break, continue, return, with
the usual semantics known from C or JavaScript.

Solidity also supports exception handling in the form of try/catch-statements,
but only for :ref:external function calls <external-function-calls> and
contract creation calls. Errors can be created using the :ref:revert statement <revert-statement>.

Parentheses can not be omitted for conditionals, but curly braces can be omitted
around single-statement bodies.

Note that there is no type conversion from non-boolean to boolean types as
there is in C and JavaScript, so if (1) { ... } is not valid
Solidity.

.. index:: ! function;call, function;internal, function;external

.. _function-calls:

Function Calls

.. _internal-function-calls:

Internal Function Calls

Functions of the current contract can be called directly ("internally"), also recursively, as seen in
this nonsensical example:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

// This will report a warning
contract C {
    function g(uint a) public pure returns (uint ret) { return a + f(); }
    function f() internal pure returns (uint ret) { return g(7) + f(); }
}

These function calls are translated into simple jumps inside the EVM. This has
the effect that the current memory is not cleared, i.e. passing memory references
to internally-called functions is very efficient. Only functions of the same
contract instance can be called internally.

You should still avoid excessive recursion, as every internal function call
uses up at least one stack slot and there are only 1024 slots available.

.. _external-function-calls:

External Function Calls

Functions can also be called using the this.g(8); and c.g(2); notation, where
c is a contract instance and g is a function belonging to c.
Calling the function g via either way results in it being called "externally", using a
message call and not directly via jumps.
Please note that function calls on this cannot be used in the constructor,
as the actual contract has not been created yet.

Functions of other contracts have to be called externally. For an external call,
all function arguments have to be copied to memory.

.. note::
A function call from one contract to another does not create its own transaction,
it is a message call as part of the overall transaction.

When calling functions of other contracts, you can specify the amount of Wei or
gas sent with the call with the special options {value: 10, gas: 10000}.
Note that it is discouraged to specify gas values explicitly, since the gas costs
of opcodes can change in the future. Any Wei you send to the contract is added
to the total balance of that contract:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(InfoFeed addr) public { feed = addr; }
    function callFeed() public { feed.info{value: 10, gas: 800}(); }
}

You need to use the modifier payable with the info function because
otherwise, the value option would not be available.

.. warning::
Be careful that feed.info{value: 10, gas: 800} only locally sets the
value and amount of gas sent with the function call, and the
parentheses at the end perform the actual call. So
feed.info{value: 10, gas: 800} does not call the function and
the value and gas settings are lost, only
feed.info{value: 10, gas: 800}() performs the function call.

.. warning::
Due to the fact that the EVM considers a call to a non-existing contract to
always succeed, Solidity uses the extcodesize opcode to check that
the contract that is about to be called actually exists (it contains code)
and causes an exception if it does not. This check is skipped if the return
data will be decoded after the call and thus the ABI decoder will catch the
case of a non-existing contract.

text
This check is not performed in case of :ref:`low-level calls <address_related>` which
operate on addresses rather than contract instances.

.. warning::
Be careful when using high-level calls to
:ref:precompiled contracts ,
since the compiler considers them non-existing according to the
above logic even though they execute code and can return data.

.. note::
Since the version 0.8.10, the compiler does not check extcodesize on
high-level external calls if return data is expected, because an empty code
will be unable to return data, and the ABI decoder will revert.
As a consequence, this allows high-level external calls to precompiled
contracts, since they can return data despite having no code
associated with their addresses.

text
Read about :ref:`precompiled contracts ` and
:ref:`low-level calls <address_related>`
for more information.

Function calls also cause exceptions if the called contract itself
throws an exception or goes out of gas.

.. warning::
Any interaction with another contract imposes a potential danger, especially
if the source code of the contract is not known in advance. The
current contract hands over control to the called contract and that may potentially
do just about anything. Even if the called contract inherits from a known parent contract,
the inheriting contract is only required to have a correct interface. The
implementation of the contract, however, can be completely arbitrary and thus,
pose a danger. In addition, be prepared in case it calls into other contracts of
your system or even back into the calling contract before the first
call returns. This means
that the called contract can change state variables of the calling contract
via its functions. Write your functions in a way that, for example, calls to
external functions happen after any changes to state variables in your contract
so your contract is not vulnerable to a reentrancy exploit.

.. note::
Before Solidity 0.6.2, the recommended way to specify the value and gas was to
use f.value(x).gas(g)(). This was deprecated in Solidity 0.6.2 and is no
longer possible since Solidity 0.7.0.

Function Calls with Named Parameters

Function call arguments can be given by name, in any order,
if they are enclosed in { } as can be seen in the following
example. The argument list has to coincide by name with the list of
parameters from the function declaration, but can be in arbitrary order.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;

contract C {
    mapping(uint => uint) data;

    function f() public {
        set({value: 2, key: 3});
    }

    function set(uint key, uint value) public {
        data[key] = value;
    }
}

Omitted Names in Function Definitions

The names of parameters and return values in the function declaration can be omitted.
Those items with omitted names will still be present on the stack, but they are
inaccessible by name. An omitted return value name
can still return a value to the caller by use of the return statement.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract C {
    // omitted name for parameter
    function func(uint k, uint) public pure returns(uint) {
        return k;
    }
}

.. index:: ! new, contracts;creating

.. _creating-contracts:

Creating Contracts via ``new``

A contract can create other contracts using the new keyword. The full
code of the contract being created has to be known when the creating contract
is compiled so recursive creation-dependencies are not possible.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract D {
    uint public x;
    constructor(uint a) payable {
        x = a;
    }
}

contract C {
    D d = new D(4); // will be executed as part of C's constructor

    function createD(uint arg) public {
        D newD = new D(arg);
        newD.x();
    }

    function createAndEndowD(uint arg, uint amount) public payable {
        // Send ether along with the creation
        D newD = new D{value: amount}(arg);
        newD.x();
    }
}

As seen in the example, it is possible to send Ether while creating
an instance of D using the value option, but it is not possible
to limit the amount of gas.
If the creation fails (due to out-of-stack, not enough balance or other problems),
an exception is thrown.

.. _salted-contract-creations:

Salted contract creations / create2

When creating a contract, the address of the contract is computed from
the address of the creating contract and a counter that is increased with
each contract creation.

If you specify the option salt (a bytes32 value), then contract creation will
use a different mechanism to come up with the address of the new contract:

It will compute the address from the address of the creating contract,
the given salt value, the (creation) bytecode of the created contract and the constructor
arguments.

In particular, the counter ("nonce") is not used. This allows for more flexibility
in creating contracts: You are able to derive the address of the
new contract before it is created. Furthermore, you can rely on this address
also in case the creating
contracts creates other contracts in the meantime.

The main use-case here is contracts that act as judges for off-chain interactions,
which only need to be created if there is a dispute.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract D {
    uint public x;
    constructor(uint a) {
        x = a;
    }
}

contract C {
    function createDSalted(bytes32 salt, uint arg) public {
        // This complicated expression just tells you how the address
        // can be pre-computed. It is just there for illustration.
        // You actually only need ``new D{salt: salt}(arg)``.
        address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
            bytes1(0xff),
            address(this),
            salt,
            keccak256(abi.encodePacked(
                type(D).creationCode,
                abi.encode(arg)
            ))
        )))));

        D d = new D{salt: salt}(arg);
        require(address(d) == predictedAddress);
    }
}

.. warning::
There are some peculiarities in relation to salted creation. A contract can be
re-created at the same address after having been destroyed. Yet, it is possible
for that newly created contract to have a different deployed bytecode even
though the creation bytecode has been the same (which is a requirement because
otherwise the address would change). This is due to the fact that the constructor
can query external state that might have changed between the two creations
and incorporate that into the deployed bytecode before it is stored.

.. _order-of-evaluation:

Order of Evaluation of Expressions

The evaluation order of expressions is not specified (more formally, the order
in which the children of one node in the expression tree are evaluated is not
specified, but they are of course evaluated before the node itself). It is only
guaranteed that statements are executed in order and short-circuiting for
boolean expressions is done.

.. index:: ! assignment

Assignment

.. index:: ! assignment;destructuring

.. _destructuring-assignments:

Destructuring Assignments and Returning Multiple Values

Solidity internally allows tuple types, i.e. a list of objects
of potentially different types whose number is a constant at
compile-time. Those tuples can be used to return multiple values at the same time.
These can then either be assigned to newly declared variables
or to pre-existing variables (or LValues in general).

Tuples are not proper types in Solidity, they can only be used to form syntactic
groupings of expressions.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

contract C {
    uint index;

    function f() public pure returns (uint, bool, uint) {
        return (7, true, 2);
    }

    function g() public {
        // Variables declared with type and assigned from the returned tuple,
        // not all elements have to be specified (but the number must match).
        (uint x, , uint y) = f();
        // Common trick to swap values -- does not work for non-value storage types.
        (x, y) = (y, x);
        // Components can be left out (also for variable declarations).
        (index, , ) = f(); // Sets the index to 7
    }
}

It is not possible to mix variable declarations and non-declaration assignments,
i.e. the following is not valid: (x, uint y) = (1, 2);

.. note::
Prior to version 0.5.0 it was possible to assign to tuples of smaller size, either
filling up on the left or on the right side (which ever was empty). This is
now disallowed, so both sides have to have the same number of components.

.. warning::
Be careful when assigning to multiple variables at the same time when
reference types are involved, because it could lead to unexpected
copying behavior.

Complications for Arrays and Structs

The semantics of assignments are more complicated for non-value types like arrays and structs,
including bytes and string, see :ref:Data location and assignment behavior <data-location-assignment> for details.

In the example below the call to g(x) has no effect on x because it creates
an independent copy of the storage value in memory. However, h(x) successfully modifies x
because only a reference and not a copy is passed.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract C {
    uint[20] x;

    function f() public {
        g(x);
        h(x);
    }

    function g(uint[20] memory y) internal pure {
        y[2] = 3;
    }

    function h(uint[20] storage y) internal {
        y[3] = 4;
    }
}

.. index:: ! scoping, declarations, default value

.. _default-value:

Scoping and Declarations

A variable which is declared will have an initial default
value whose byte-representation is all zeros.
The "default values" of variables are the typical "zero-state"
of whatever the type is. For example, the default value for a bool
is false. The default value for the uint or int
types is 0. For statically-sized arrays and bytes1 to
bytes32, each individual
element will be initialized to the default value corresponding
to its type. For dynamically-sized arrays, bytes
and string, the default value is an empty array or string.
For the enum type, the default value is its first member.

Scoping in Solidity follows the widespread scoping rules of C99
(and many other languages): Variables are visible from the point right after their declaration
until the end of the smallest { }-block that contains the declaration.
As an exception to this rule, variables declared in the
initialization part of a for-loop are only visible until the end of the for-loop.

Variables that are parameter-like (function parameters, modifier parameters,
catch parameters, ...) are visible inside the code block that follows -
the body of the function/modifier for a function and modifier parameter and the catch block
for a catch parameter.

Variables and other items declared outside of a code block, for example functions, contracts,
user-defined types, etc., are visible even before they were declared. This means you can
use state variables before they are declared and call functions recursively.

As a consequence, the following examples will compile without warnings, since
the two variables have the same name but disjoint scopes.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract C {
    function minimalScoping() pure public {
        {
            uint same;
            same = 1;
        }

        {
            uint same;
            same = 3;
        }
    }
}

As a special example of the C99 scoping rules, note that in the following,
the first assignment to x will actually assign the outer and not the inner variable.
In any case, you will get a warning about the outer variable being shadowed.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
// This will report a warning
contract C {
    function f() pure public returns (uint) {
        uint x = 1;
        {
            x = 2; // this will assign to the outer variable
            uint x;
        }
        return x; // x has value 2
    }
}

.. warning::
Before version 0.5.0 Solidity followed the same scoping rules as
JavaScript, that is, a variable declared anywhere within a function would be in scope
for the entire function, regardless where it was declared. The following example shows a code snippet that used
to compile but leads to an error starting from version 0.5.0.

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
// This will not compile
contract C {
    function f() pure public returns (uint) {
        x = 2;
        uint x;
        return x;
    }
}

.. index:: ! safe math, safemath, checked, unchecked
.. _unchecked:

Checked or Unchecked Arithmetic

An overflow or underflow is the situation where the resulting value of an arithmetic operation,
when executed on an unrestricted integer, falls outside the range of the result type.

Prior to Solidity 0.8.0, arithmetic operations would always wrap in case of
under- or overflow leading to widespread use of libraries that introduce
additional checks.

Since Solidity 0.8.0, all arithmetic operations revert on over- and underflow by default,
thus making the use of these libraries unnecessary.

To obtain the previous behavior, an unchecked block can be used:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract C {
    function f(uint a, uint b) pure public returns (uint) {
        // This subtraction will wrap on underflow.
        unchecked { return a - b; }
    }
    function g(uint a, uint b) pure public returns (uint) {
        // This subtraction will revert on underflow.
        return a - b;
    }
}

The call to f(2, 3) will return 2**256-1, while g(2, 3) will cause
a failing assertion.

The unchecked block can be used everywhere inside a block, but not as a replacement
for a block. It also cannot be nested.

The setting only affects the statements that are syntactically inside the block.
Functions called from within an unchecked block do not inherit the property.

.. note::
To avoid ambiguity, you cannot use _; inside an unchecked block.

The following operators will cause a failing assertion on overflow or underflow
and will wrap without an error if used inside an unchecked block:

++, --, +, binary -, unary -, *, /, %, **

+=, -=, *=, /=, %=

.. warning::
It is not possible to disable the check for division by zero
or modulo by zero using the unchecked block.

.. note::
Bitwise operators do not perform overflow or underflow checks.
This is particularly visible when using bitwise shifts (<<, >>, <<=, >>=) in
place of integer division and multiplication by a power of 2.
For example type(uint256).max << 3 does not revert even though type(uint256).max * 8 would.

.. note::
The second statement in int x = type(int).min; -x; will result in an overflow
because the negative range can hold one more value than the positive range.

Explicit type conversions will always truncate and never cause a failing assertion
with the exception of a conversion from an integer to an enum type.

.. index:: ! exception, ! throw, ! assert, ! require, ! revert, ! errors

.. _assert-and-require:

Error handling: Assert, Require, Revert and Exceptions

Solidity uses state-reverting exceptions to handle errors.
Such an exception undoes all changes made to the
state in the current call (and all its sub-calls) and
flags an error to the caller.

When exceptions happen in a sub-call, they "bubble up" (i.e.,
exceptions are rethrown) automatically unless they are caught in
a try/catch statement. Exceptions to this rule are send
and the low-level functions call, delegatecall and
staticcall: they return false as their first return value in case
of an exception instead of "bubbling up".

.. warning::
The low-level functions call, delegatecall and
staticcall return true as their first return value
if the account called is non-existent, as part of the design
of the EVM. Account existence must be checked prior to calling if needed.

Exceptions can contain error data that is passed back to the caller
in the form of :ref:error instances <errors>.
The built-in errors Error(string) and Panic(uint256) are
used by special functions, as explained below. Error is used for "regular" error conditions
while Panic is used for errors that should not be present in bug-free code.

.. _assert-and-require-statements:

Panic via ``assert`` and Error via ``require``

The convenience functions assert and require can be used to check for conditions and throw an exception
if the condition is not met.

The assert function creates an error of type Panic(uint256).
The same error is created by the compiler in certain situations as listed below.

Assert should only be used to test for internal
errors, and to check invariants. Properly functioning code should
never create a Panic, not even on invalid external input.
If this happens, then there
is a bug in your contract which you should fix. Language analysis
tools can evaluate your contract to identify the conditions and
function calls which will cause a Panic.

A Panic exception is generated in the following situations.
The error code supplied with the error data indicates the kind of panic.

#. 0x00: Used for generic compiler inserted panics.
#. 0x01: If you call assert with an argument that evaluates to false.
#. 0x11: If an arithmetic operation results in underflow or overflow outside of an unchecked { ... } block.
#. 0x12; If you divide or modulo by zero (e.g. 5 / 0 or 23 % 0).
#. 0x21: If you convert a value that is too big or negative into an enum type.
#. 0x22: If you access a storage byte array that is incorrectly encoded.
#. 0x31: If you call .pop() on an empty array.
#. 0x32: If you access an array, bytesN or an array slice at an out-of-bounds or negative index (i.e. x[i] where i >= x.length or i < 0).
#. 0x41: If you allocate too much memory or create an array that is too large.
#. 0x51: If you call a zero-initialized variable of internal function type.

The require function provides three overloads:

  1. require(bool) which will revert without any data (not even an error selector).
  2. require(bool, string) which will revert with an Error(string).
  3. require(bool, error) which will revert with the custom, user supplied error provided as the second argument.

.. note::
require arguments are evaluated unconditionally, so take special care to make sure that
they are not expressions with unexpected side-effects.
For example, in require(condition, CustomError(f())); and require(condition, f());,
function f() will be called regardless of whether the supplied condition is true or false.

An Error(string) exception (or an exception without data) is generated
by the compiler in the following situations:

#. Calling require(x) where x evaluates to false.
#. If you use revert() or revert("description").
#. If you perform an external function call targeting a contract that contains no code.
#. If your contract receives Ether via a public function without
payable modifier (including the constructor and the fallback function).
#. If your contract receives Ether via a public getter function.

For the following cases, the error data from the external call
(if provided) is forwarded. This means that it can either cause
an Error or a Panic (or whatever else was given):

#. If a .transfer() fails.
#. If you call a function via a message call but it does not finish
properly (i.e., it runs out of gas, has no matching function, or
throws an exception itself), except when a low level operation
call, send, delegatecall, callcode or staticcall
is used. The low level operations never throw exceptions but
indicate failures by returning false.
#. If you create a contract using the new keyword but the contract
creation :ref:does not finish properly<creating-contracts>.

You can optionally provide a message string or a custom error to require, but not to assert.

.. note::
If you do not provide a string or custom error argument to require, it will revert
with empty error data, not even including the error selector.

The following example shows how you can use require to check conditions on inputs
and assert for internal error checking.

.. code-block:: solidity
:force:

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

contract Sharer {
    function sendHalf(address payable addr) public payable returns (uint balance) {
        require(msg.value % 2 == 0, "Even value required.");
        uint balanceBeforeTransfer = address(this).balance;
        (bool success, ) = addr.call{value: msg.value / 2}("");
        require(success);
        // Since require will stop execution and revert if success is false,
        // there should be no way for us to still have half of the Ether.
        assert(address(this).balance == balanceBeforeTransfer - msg.value / 2);
        return address(this).balance;
    }
}

Internally, Solidity performs a revert operation (instruction
0xfd). This causes
the EVM to revert all changes made to the state. The reason for reverting
is that there is no safe way to continue execution, because an expected effect
did not occur. Because we want to keep the atomicity of transactions, the
safest action is to revert all changes and make the whole transaction
(or at least call) without effect.

In both cases, the caller can react on such failures using try/catch, but
the changes in the callee will always be reverted.

.. note::

text
Panic exceptions used to use the ``invalid`` opcode before Solidity 0.8.0,
which consumed all gas available to the call.
Exceptions that use ``require`` used to consume all gas until before the Metropolis release.

.. _revert-statement:

``revert``

A direct revert can be triggered using the revert statement and the revert function.

The revert statement takes a custom error as direct argument without parentheses:

text
revert CustomError(arg1, arg2);

For backward-compatibility reasons, there is also the revert() function, which uses parentheses
and accepts a string:

text
revert();
revert("description");

The error data will be passed back to the caller and can be caught there.
Using revert() causes a revert without any error data while revert("description")
will create an Error(string) error.

Using a custom error instance will usually be much cheaper than a string description,
because you can use the name of the error to describe it, which is encoded in only
four bytes. A longer description can be supplied via NatSpec which does not incur
any costs.

The following example shows how to use an error string and a custom error instance
together with revert and the equivalent require:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract VendingMachine {
    address owner;
    error Unauthorized();
    function buy(uint amount) public payable {
        if (amount > msg.value / 2 ether)
            revert("Not enough Ether provided.");
        // Alternative way to do it:
        require(
            amount <= msg.value / 2 ether,
            "Not enough Ether provided."
        );
        // Perform the purchase.
    }
    function withdraw() public {
        if (msg.sender != owner)
            revert Unauthorized();

        (bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
        require(success);
    }
}

The two ways if (!condition) revert(...); and require(condition, ...); are
equivalent as long as the arguments to revert and require do not have side-effects,
for example if they are just strings.

.. note::
The require function is evaluated just as any other function.
This means that all arguments are evaluated before the function itself is executed.
In particular, in require(condition, f()) the function f is executed even if
condition is true.

The provided string is :ref:abi-encoded <ABI> as if it were a call to a function Error(string).
In the above example, revert("Not enough Ether provided."); returns the following hexadecimal as error return data:

.. code::

text
0x08c379a0                                                         // Function selector for Error(string)
0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset
0x000000000000000000000000000000000000000000000000000000000000001a // String length
0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data

The provided message can be retrieved by the caller using try/catch as shown below.

.. note::
There used to be a keyword called throw with the same semantics as revert() which
was deprecated in version 0.4.13 and removed in version 0.5.0.

.. _try-catch:

``try``/``catch``

A failure in an external call can be caught using a try/catch statement, as follows:

.. code-block:: solidity

text
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.1;

interface DataFeed { function getData(address token) external returns (uint value); }

contract FeedConsumer {
    DataFeed feed;
    uint errorCount;
    function rate(address token) public returns (uint value, bool success) {
        // Permanently disable the mechanism if there are
        // more than 10 errors.
        require(errorCount < 10);
        try feed.getData(token) returns (uint v) {
            return (v, true);
        } catch Error(string memory /*reason*/) {
            // This is executed in case
            // revert was called inside getData
            // and a reason string was provided.
            errorCount++;
            return (0, false);
        } catch Panic(uint /*errorCode*/) {
            // This is executed in case of a panic,
            // i.e. a serious error like division by zero
            // or overflow. The error code can be used
            // to determine the kind of error.
            errorCount++;
            return (0, false);
        } catch (bytes memory /*lowLevelData*/) {
            // This is executed in case revert() was used.
            errorCount++;
            return (0, false);
        }
    }
}

The try keyword has to be followed by an expression representing an external function call
or a contract creation (new ContractName()).
Errors inside the expression are not caught (for example if it is a complex expression
that also involves internal function calls), only a revert happening inside the external
call itself. The returns part (which is optional) that follows declares return variables
matching the types returned by the external call. In case there was no error,
these variables are assigned and the contract's execution continues inside the
first success block. If the end of the success block is reached, execution continues after the catch blocks.

Solidity supports different kinds of catch blocks depending on the
type of error:

  • catch Error(string memory reason) { ... }: This catch clause is executed if the error was caused by revert("reasonString") or
    require(false, "reasonString") (or an internal error that causes such an
    exception).

  • catch Panic(uint errorCode) { ... }: If the error was caused by a panic, i.e. by a failing assert, division by zero,
    invalid array access, arithmetic overflow and others, this catch clause will be run.

  • catch (bytes memory lowLevelData) { ... }: This clause is executed if the error signature
    does not match any other clause, if there was an error while decoding the error
    message, or
    if no error data was provided with the exception.
    The declared variable provides access to the low-level error data in that case.

  • catch { ... }: If you are not interested in the error data, you can just use
    catch { ... } (even as the only catch clause) instead of the previous clause.

It is planned to support other types of error data in the future.
The strings Error and Panic are currently parsed as is and are not treated as identifiers.

In order to catch all error cases, you have to have at least the clause
catch { ...} or the clause catch (bytes memory lowLevelData) { ... }.

The variables declared in the returns and the catch clause are only
in scope in the block that follows.

.. note::

text
If an error happens during the decoding of the return data
inside a try/catch-statement, this causes an exception in the currently
executing contract and because of that, it is not caught in the catch clause.
If there is an error during decoding of ``catch Error(string memory reason)``
and there is a low-level catch clause, this error is caught there.

.. note::

text
If execution reaches a catch-block, then the state-changing effects of
the external call have been reverted. If execution reaches
the success block, the effects were not reverted.
If the effects have been reverted, then execution either continues
in a catch block or the execution of the try/catch statement itself
reverts (for example due to decoding failures as noted above or
due to not providing a low-level catch clause).

.. note::
The reason behind a failed call can be manifold. Do not assume that
the error message is coming directly from the called contract:
The error might have happened deeper down in the call chain and the
called contract just forwarded it. Also, it could be due to an
out-of-gas situation and not a deliberate error condition:
The caller always retains at least 1/64th of the gas in a call and thus
even if the called contract goes out of gas, the caller still
has some gas left.


Credits And Attribution (`docs/credits-and-attribution.rst`)

.. This page is meant to be linked to from the footer.

:orphan:

#######################
Credits and Attribution
#######################

Website icons

.. |icon-share-solid| image:: _static/img/solid-share-arrow.svg
.. _share icon: https://fontawesome.com/v5.15/icons/share?style=solid
.. _Font Awesome Free License: https://fontawesome.com/license/free

+-------------------------+-----------------------------------------------------------------------+
| Icon | Attribution |
+=========================+=======================================================================+
| |icon-share-solid| | - Source: share icon_ from Font Awesome 5.15.0. |
| | - License: Font Awesome Free License_ (CC BY 4.0). |
+-------------------------+-----------------------------------------------------------------------+


Frequently Reported Non Bugs (`docs/frequently-reported-non-bugs.rst`)

.. _frequently-reported-non-bugs:

############################
Frequently Reported Non-Bugs
############################

The behaviors listed below are reported as compiler bugs on a regular basis,
but are either intentional, documented, or explicitly not guaranteed by the language.

The list of actual bugs is tracked in the :ref:list of known bugs<known_bugs>.

Non-canonical ABI-encoded calldata is accepted

Offsets that point backwards, overlap, or leave gaps are not necessarily rejected,
and trailing data past the encoded arguments is ignored.
The Solidity decoder does not enforce :ref:strict encoding mode<abi_packed_mode>;
the invariant we uphold is that decoding must not read beyond calldatasize().

Different results between the evmasm and the IR pipeline

The two pipelines have some semantic differences.
Known and intentional divergences are listed in :ref:Solidity IR-based Codegen Changes,
in particular :ref:cleanup behavior differs.

Order of evaluation

The :ref:evaluation order of expressions is unspecified<order-of-evaluation> and this includes the components
of tuple assignments and returns (see also :ref:Tuples are not proper types<destructuring-assignments>).
Only statement order and short-circuiting of boolean operators are guaranteed.
Note that :ref:assignments involving reference types<data-location-assignment> copy or alias depending on
data location, which is documented behavior and not an aliasing bug by itself.

Stale references into storage

A reference to a storage array element can be left dangling by anything that resizes or relocates the
containing array, for example a .pop(), a .push() that switches a bytes array
:ref:from short to long layout, or an assignment to the array itself as in (s[0], s) = (x, y).
Writing through such a reference is not rejected and may write outside the data area of the array.

This is :ref:documented behavior<dangling-storage-references>, and code containing dangling
references is explicitly considered to have undefined behavior.


Grammar (`docs/grammar.rst`)


Language Grammar


.. syntax:autogrammar:: SolidityParser.g4
:root-rule: SolidityParser.sourceUnit
:undocumented:
:cc-to-dash:

.. syntax:autogrammar:: SolidityLexer.g4
:root-rule: SolidityParser.sourceUnit
:fragments:
:cc-to-dash:


Index (`docs/index.rst`)

Solidity

Solidity is an object-oriented, high-level language for implementing smart contracts.
Smart contracts are programs that govern the behavior of accounts within the Ethereum state.

Solidity is a curly-bracket language <https://en.wikipedia.org/wiki/List_of_programming_languages_by_type#Curly_bracket_languages>_ designed to target the Ethereum Virtual Machine (EVM).
It is influenced by C++, Python, and JavaScript.
You can find more details about which languages Solidity has been inspired by in the :doc:language influences <language-influences> section.

Solidity is statically typed, supports inheritance, libraries, and complex user-defined types, among other features.

With Solidity, you can create contracts for uses such as voting, crowdfunding, blind auctions, and multi-signature wallets.

When deploying contracts, you should use the latest released version of Solidity.
Apart from exceptional cases, only the latest version receives
security fixes <https://github.com/argotorg/solidity/security/policy#supported-versions>.
Furthermore, breaking changes, as well as new features, are introduced regularly.
We currently use a 0.y.z version number to indicate this fast pace of change <https://semver.org/#spec-item-4>
.

.. warning::

The Solidity 0.8.x release introduced a lot of breaking changes.
Make sure you read :doc:the full list <080-breaking-changes>.

Ideas for improving Solidity or this documentation are always welcome,
read our :doc:contributors guide <contributing> for more details.

.. Hint::

You can download this documentation as PDF, HTML or Epub
by clicking on the versions flyout menu in the bottom-right corner and selecting the preferred download format.

Getting Started

1. Understand the Smart Contract Basics

If you are new to the concept of smart contracts, we recommend you to get started by digging into the "Introduction to Smart Contracts" section, which covers the following:

  • :ref:A simple example smart contract <simple-smart-contract> written in Solidity.
  • :ref:Blockchain Basics .
  • :ref:The Ethereum Virtual Machine .

2. Get to Know Solidity

Once you are accustomed to the basics, we recommend you read the :doc:"Solidity by Example" <solidity-by-example>
and “Language Description” sections to understand the core concepts of the language.

3. Install the Solidity Compiler

There are various ways to install the Solidity compiler,
simply choose your preferred option and follow the steps outlined on the :ref:installation page .

.. hint::
You can try out code examples directly in your browser with the
Remix IDE <https://remix.ethereum.org>_.
Remix is a web browser-based IDE that allows you to write, deploy and administer Solidity smart contracts,
without the need to install Solidity locally.

.. warning::
As humans write software, it can have bugs.
Therefore, you should follow established software development best practices when writing your smart contracts.
This includes code review, testing, audits, and correctness proofs.
Smart contract users are sometimes more confident with code than their authors,
and blockchains and smart contracts have their own unique issues to watch out for,
so before working on production code, make sure you read the :ref:security_considerations section.

4. Learn More

If you want to learn more about building decentralized applications on Ethereum,
the Ethereum Developer Resources <https://ethereum.org/en/developers/>_ can help you with further general documentation around Ethereum,
and a wide selection of tutorials, tools, and development frameworks.

If you have any questions, you can try searching for answers or asking on the
Ethereum StackExchange <https://ethereum.stackexchange.com/>,
or our Matrix channel <https://matrix.to/#/#ethereum\_solidity:gitter.im>
.

.. _translations:

Translations

Community contributors help translate this documentation into several languages.
Note that they have varying degrees of completeness and up-to-dateness.
The English version stands as a reference.

You can switch between languages by clicking on the flyout menu in the bottom-right corner
and selecting the preferred language.

  • Chinese <https://docs.soliditylang.org/zh-cn/latest/>_
  • French <https://docs.soliditylang.org/fr/latest/>_
  • Indonesian <https://github.com/solidity-docs/id-indonesian>_
  • Japanese <https://github.com/solidity-docs/ja-japanese>_
  • Korean <https://github.com/solidity-docs/ko-korean>_
  • Persian <https://github.com/solidity-docs/fa-persian>_
  • Russian <https://github.com/solidity-docs/ru-russian>_
  • Spanish <https://github.com/solidity-docs/es-spanish>_
  • Turkish <https://docs.soliditylang.org/tr/latest/>_

.. note::

We set up a GitHub organization and translation workflow to help streamline the community efforts.
Please refer to the translation guide in the solidity-docs org <https://github.com/solidity-docs>_
for information on how to start a new language or contribute to the community translations.

Contents

:ref:Keyword Index <genindex>, :ref:Search Page <search>

.. toctree::
:maxdepth: 2
:caption: Basics

introduction-to-smart-contracts.rst
solidity-by-example.rst
installing-solidity.rst

.. toctree::
:maxdepth: 2
:caption: Language Description

layout-of-source-files.rst
structure-of-a-contract.rst
types.rst
units-and-global-variables.rst
control-structures.rst
contracts.rst
assembly.rst
cheatsheet.rst
grammar.rst

.. toctree::
:maxdepth: 2
:caption: Compiler

using-the-compiler.rst
analysing-compilation-output.rst
ir-breaking-changes.rst

.. toctree::
:maxdepth: 2
:caption: Internals

internals/layout_in_storage.rst
internals/layout_in_memory.rst
internals/layout_in_calldata.rst
internals/variable_cleanup.rst
internals/source_mappings.rst
internals/optimizer.rst
metadata.rst
abi-spec.rst

.. toctree::
:maxdepth: 2
:caption: Advisory content

security-considerations.rst
bugs.rst
frequently-reported-non-bugs.rst
050-breaking-changes.rst
060-breaking-changes.rst
070-breaking-changes.rst
080-breaking-changes.rst

.. toctree::
:maxdepth: 2
:caption: Additional Material

natspec-format.rst
smtchecker.rst
yul.rst
path-resolution.rst

.. toctree::
:maxdepth: 2
:caption: Resources

style-guide.rst
common-patterns.rst
resources.rst
contributing.rst
language-influences.rst
brand-guide.rst


Installing Solidity (`docs/installing-solidity.rst`)

.. index:: ! installing

.. _installing-solidity:

################################
Installing the Solidity Compiler
################################

Versioning

Solidity versions follow Semantic Versioning <https://semver.org>_. In
addition, patch-level releases with major release 0 (i.e. 0.x.y) will not
contain breaking changes. That means code that compiles with version 0.x.y
can be expected to compile with 0.x.z where z > y.

In addition to releases, we provide prereleases and nightly development builds to make it
easy for developers to try out upcoming features and provide early feedback.
Note that such builds contain bleeding-edge code from the development branch and are not guaranteed
to be of the same quality as full releases.
Despite our best efforts, they might contain undocumented and/or broken changes that will not
become a part of an actual release. They are not meant for production use.

When deploying contracts, you should use the latest released version of Solidity. This
is because breaking changes, as well as new features and bug fixes are introduced regularly.
We currently use a 0.x version number to indicate this fast pace of change <https://semver.org/#spec-item-4>_.

Remix

We recommend Remix for small contracts and for quickly learning Solidity.

Access Remix online <https://remix.ethereum.org/>, you do not need to install anything.
If you want to use it without connection to the Internet, download Remix Desktop from the releases page <https://github.com/remix-project-org/remix-desktop/releases/>
.
Remix is also a convenient option for testing nightly builds
without installing multiple Solidity versions.

Further options on this page detail installing command-line Solidity compiler software
on your computer. Choose a command-line compiler if you are working on a larger contract
or if you require more compilation options.

.. _solcjs:

npm / Node.js

Use npm for a convenient and portable way to install solcjs, a Solidity compiler. The
solcjs program has fewer features than the ways to access the compiler described
further down this page. The
:ref:commandline-compiler documentation assumes you are using
the full-featured compiler, solc. The usage of solcjs is documented inside its own
repository <https://github.com/argotorg/solc-js>_.

Note: The solc-js project is derived from the C++
solc by using Emscripten, which means that both use the same compiler source code.
solc-js can be used in JavaScript projects directly (such as Remix).
Please refer to the solc-js repository for instructions.

.. code-block:: bash

text
npm install solc

.. note::

text
The command-line executable is named ``solcjs``.

The command-line options of ``solcjs`` are not compatible with ``solc`` and tools (such as ``geth``)
expecting the behavior of ``solc`` will not work with ``solcjs``.

Docker

Docker images of Solidity builds are available using the solc <https://github.com/argotorg/solidity/pkgs/container/solc>_ image from the argotorg organization on ghcr.io.
Use the stable tag for the latest released version, and nightly for potentially unstable changes in the develop branch.

The Docker image runs the compiler executable so that you can pass all compiler arguments to it.
For example, the command below pulls the stable version of the solc image (if you do not have it already),
and runs it in a new container, passing the --help argument.

.. code-block:: bash

text
docker run ghcr.io/argotorg/solc:stable --help

.. note::

text
Specific compiler versions are supported as the Docker image tag such as ``ghcr.io/argotorg/solc:0.8.23``.
We will be passing the ``stable`` tag here instead of specific version tag to ensure that users get
the latest version by default and avoid the issue of an out-of-date version.

To use the Docker image to compile Solidity files on the host machine, mount a
local folder for input and output, and specify the contract to compile. For example:

.. code-block:: bash

text
docker run \
    --volume "/tmp/some/local/path/:/sources/" \
    ghcr.io/argotorg/solc:stable \
        /sources/Contract.sol \
        --abi \
        --bin \
        --output-dir /sources/output/

You can also use the standard JSON interface (which is recommended when using the compiler with tooling).
When using this interface, it is not necessary to mount any directories as long as the JSON input is
self-contained (i.e. it does not refer to any external files that would have to be
:ref:loaded by the import callback ).

.. code-block:: bash

text
docker run ghcr.io/argotorg/solc:stable --standard-json < input.json > output.json

Linux Packages

We provide :ref:standalone binaries <static-binaries> of the compiler that should run on most
distributions without any additional installation steps.

Ubuntu packages for versions up to 0.8.30 are available in the
ethereum/ethereum PPA <https://launchpad.net/~ethereum/+archive/ubuntu/ethereum>_.
However, we have discontinued this distribution method and future versions will not be added there.

Some Linux distributions provide their own packages.
These packages are not directly maintained by us but usually kept up-to-date by the respective
package maintainers.

Unofficial, community-maintained scripts for building and installing the compiler are also
available for some distributions:

  • Arch Linux / (AUR):

    • solidity <https://aur.archlinux.org/packages/solidity>_ (builds from source),
    • solidity-bin <https://aur.archlinux.org/packages/solidity-bin>_ (uses our standalone binaries).
  • Nix:

    • solc.nix <https://github.com/hellwolf/solc.nix>_ (builds from source).

.. note::

text
Please be aware that these scripts are produced and maintained by users and not vetted in any
way by the distro maintainers.
Exercise caution when using them.

There is also a snap package <https://snapcraft.io/solc>, however, it is currently unmaintained.
It is installable in all the supported Linux distros <https://snapcraft.io/docs/reference/administration/distribution-support/>
. To
install the latest stable version of solc:

.. code-block:: bash

text
sudo snap install solc

If you want to help testing the latest development version of Solidity
with the most recent changes, please use the following:

.. code-block:: bash

text
sudo snap install solc --edge

.. note::

text
The ``solc`` snap uses strict confinement. This is the most secure mode for snap packages
but it comes with limitations, like accessing only the files in your ``/home`` and ``/media`` directories.
For more information, go to `Demystifying Snap Confinement <https://snapcraft.io/blog/demystifying-snap-confinement>`_.

macOS Packages

We distribute the Solidity compiler through Homebrew
as a build-from-source version. Pre-built bottles are
currently not supported.

.. code-block:: bash

text
brew update
brew upgrade
brew tap ethereum/ethereum
brew install solidity

To install the most recent 0.4.x / 0.5.x version of Solidity you can also use brew install solidity@4
and brew install solidity@5, respectively.

If you need a specific version of Solidity you can install a
Homebrew formula directly from Github.

View
solidity.rb commits on GitHub <https://github.com/ethereum/homebrew-ethereum/commits/master/solidity.rb>_.

Copy the commit hash of the version you want and check it out on your machine.

.. code-block:: bash

text
git clone https://github.com/ethereum/homebrew-ethereum.git
cd homebrew-ethereum
git checkout <your-hash-goes-here>

Install it using brew:

.. code-block:: bash

text
brew unlink solidity
# eg. Install 0.4.8
brew install solidity.rb

.. _static-binaries:

Static Binaries

We maintain a repository containing static builds of past and current compiler versions for all
supported platforms at solc-bin_. This is also the location where you can find the nightly builds.

The repository is not only a quick and easy way for end users to get binaries ready to be used
out-of-the-box but it is also meant to be friendly to third-party tools:

  • The content is mirrored to https://binaries.soliditylang.org where it can be easily downloaded over
    HTTPS without any authentication, rate limiting or the need to use git.
  • Content is served with correct Content-Type headers and lenient CORS configuration so that it
    can be directly loaded by tools running in the browser.
  • Binaries do not require installation or unpacking (exception for older Windows builds
    bundled with necessary DLLs).
  • We strive for a high level of backward-compatibility. Files, once added, are not removed or moved
    without providing a symlink/redirect at the old location. They are also never modified
    in place and should always match the original checksum. The only exception would be broken or
    unusable files with the potential to cause more harm than good if left as is.
  • Files are served over both HTTP and HTTPS. As long as you obtain the file list in a secure way
    (via git, HTTPS, IPFS or just have it cached locally) and verify hashes of the binaries
    after downloading them, you do not have to use HTTPS for the binaries themselves.

The same binaries are in most cases available on the Solidity release page on GitHub_. The
difference is that we do not generally update old releases on the GitHub release page. This means
that we do not rename them if the naming convention changes and we do not add builds for platforms
that were not supported at the time of release. This only happens in solc-bin.

The solc-bin repository contains several top-level directories, each representing a single platform.
Each one includes a list.json file listing the available binaries. For example in
emscripten-wasm32/list.json you will find the following information about version 0.7.4:

.. code-block:: json

text
{
  "path": "solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js",
  "version": "0.7.4",
  "build": "commit.3f05b770",
  "longVersion": "0.7.4+commit.3f05b770",
  "keccak256": "0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3",
  "sha256": "0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2",
  "urls": [
    "dweb:/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS"
  ]
}

This means that:

  • You can find the binary in the same directory under the name
    solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js <https://github.com/argotorg/solc-bin/blob/gh-pages/emscripten-wasm32/solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js>_.
    Note that the file might be a symlink, and you will need to resolve it yourself if you are not using
    git to download it or your file system does not support symlinks.
  • The binary is also mirrored at https://binaries.soliditylang.org/emscripten-wasm32/solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js.
    In this case git is not necessary and symlinks are resolved transparently, either by serving a copy
    of the file or returning a HTTP redirect.
  • The file is also available on IPFS at QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS_.
    Please, be aware that the order of items in the urls array is not predetermined or guaranteed and users should not rely on it.
  • You can verify the integrity of the binary by comparing its keccak256 hash to
    0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3. The hash can be computed
    on the command-line using keccak256sum utility provided by sha3sum_ or keccak256() function from ethereumjs-util_ in JavaScript.
  • You can also verify the integrity of the binary by comparing its sha256 hash to
    0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2.

.. warning::

Due to the strong backwards compatibility requirement the repository contains some legacy elements
but you should avoid using them when writing new tools:

  • Use emscripten-wasm32/ (with a fallback to emscripten-asmjs/) instead of bin/ if
    you want the best performance. Until version 0.6.1 we only provided asm.js binaries.
    Starting with 0.6.2 we switched to WebAssembly builds_ with much better performance. We have
    rebuilt the older versions for wasm but the original asm.js files remain in bin/.
    The new ones had to be placed in a separate directory to avoid name clashes.
  • Use emscripten-asmjs/ and emscripten-wasm32/ instead of bin/ and wasm/ directories
    if you want to be sure whether you are downloading a wasm or an asm.js binary.
  • Use list.json instead of list.js and list.txt. The JSON list format contains all
    the information from the old ones and more.

.. warning::

  • The solc-bin.ethereum.org domain is no longer supported. Going forward,
    we recommend any tools which are still using it as the source of Solidity binaries
    to switch to binaries.soliditylang.org.

.. warning::

text
The binaries are also available at https://argotorg.github.io/solc-bin/ but this page
stopped being updated just after the release of version 0.7.2, will not receive any new releases
or nightly builds for any platform and does not serve the new directory structure, including
non-emscripten builds.

If you are using it, please switch to https://binaries.soliditylang.org, which is a drop-in
replacement. This allows us to make changes to the underlying hosting in a transparent way and
minimize disruption. Unlike the ``argotorg.github.io`` domain, which we do not have any control
over, ``binaries.soliditylang.org`` is guaranteed to work and maintain the same URL structure
in the long-term.

.. _IPFS: https://ipfs.io
.. _solc-bin: https://github.com/argotorg/solc-bin/
.. _Solidity release page on GitHub: https://github.com/argotorg/solidity/releases
.. _sha3sum: https://github.com/maandree/sha3sum
.. _keccak256() function from ethereumjs-util: https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/modules/_hash_.md#const-keccak256
.. _WebAssembly builds: https://emscripten.org/docs/compiling/WebAssembly.html
.. _QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS: https://gateway.ipfs.io/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS

.. _building-from-source:

Building from Source

Prerequisites - All Operating Systems

The following are dependencies for all builds of Solidity:

.. Note: This has to be kept in sync with scripts/ci/install_and_check_minimum_requirements.sh.

+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
+===================================+=======================================================+
| CMake_ (version 3.21.3+) | Cross-platform build file generator. |
+-----------------------------------+-------------------------------------------------------+
| Boost_ (version 1.83+) | C++ libraries. |
+-----------------------------------+-------------------------------------------------------+
| Git_ | Command-line tool for retrieving source code. |
+-----------------------------------+-------------------------------------------------------+
| z3_ (version 4.8.16+, Optional) | For use with SMT checker. |
+-----------------------------------+-------------------------------------------------------+

.. _Git: https://git-scm.com/download
.. _Boost: https://www.boost.org
.. _CMake: https://cmake.org/download/
.. _z3: https://github.com/Z3Prover/z3

.. note::
Solidity versions prior to 0.5.10 can fail to correctly link against Boost versions 1.70+.
A possible workaround is to temporarily rename /lib/cmake/Boost-1.70.0
prior to running the cmake command to configure Solidity.

text
Starting from 0.5.10 linking against Boost 1.70+ should work without manual intervention.

.. note::
The default build configuration requires a specific Z3 version (the latest one at the time the
code was last updated). Changes introduced between Z3 releases often result in slightly different
(but still valid) results being returned. Our SMT tests do not account for these differences and
will likely fail with a different version than the one they were written for. This does not mean
that a build using a different version is faulty. If you pass -DSTRICT_Z3_VERSION=OFF option
to CMake, you can build with any version that satisfies the requirement given in the table above.
If you do this, however, please remember to pass the --no-smt option to scripts/tests.sh
to skip the SMT tests.

.. note::
By default the build is performed in pedantic mode, which enables extra warnings and tells the
compiler to treat all warnings as errors.
This forces developers to fix warnings as they arise, so they do not accumulate "to be fixed later".
If you are only interested in creating a release build and do not intend to modify the source code
to deal with such warnings, you can pass -DPEDANTIC=OFF option to CMake to disable this mode.
Doing this is not recommended for general use but may be necessary when using a toolchain we are
not testing with or trying to build an older version with newer tools.
If you encounter such warnings, please consider
reporting them <https://github.com/argotorg/solidity/issues/new>_.

Minimum Compiler Versions
^^^^^^^^^^^^^^^^^^^^^^^^^

The following C++ compilers and their minimum versions can build the Solidity codebase:

.. Note: Minimum versions for GCC and Clang are based on availability in Ubuntu 24.04.

  • GCC <https://gcc.gnu.org>_, version 13.3+
  • Clang <https://clang.llvm.org/>_, version 19.1.1+
  • MSVC <https://visualstudio.microsoft.com/vs/>_, version 2022+

Prerequisites - macOS

For macOS builds, ensure that you have the latest version of
Xcode installed <https://developer.apple.com/xcode/resources/>.
This contains the Clang C++ compiler <https://en.wikipedia.org/wiki/Clang>
, the
Xcode IDE <https://en.wikipedia.org/wiki/Xcode>_ and other Apple development
tools that are required for building C++ applications on OS X.
If you are installing Xcode for the first time, or have just installed a new
version then you will need to agree to the license before you can do
command-line builds:

.. code-block:: bash

text
sudo xcodebuild -license accept

Our OS X build script uses the Homebrew <https://brew.sh>_
package manager for installing external dependencies.
Here's how to uninstall Homebrew <https://docs.brew.sh/FAQ#how-do-i-uninstall-homebrew>_,
if you ever want to start again from scratch.

Prerequisites - Windows

You need to install the following dependencies for Windows builds of Solidity:

+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
+===================================+=======================================================+
| Visual Studio 2022 Build Tools_ | C++ compiler |
+-----------------------------------+-------------------------------------------------------+
| Visual Studio 2022_ (Optional) | C++ compiler and dev environment. |
+-----------------------------------+-------------------------------------------------------+
| Boost_ (version 1.77+) | C++ libraries. |
+-----------------------------------+-------------------------------------------------------+

If you already have one IDE and only need the compiler and libraries,
you could install Visual Studio 2022 Build Tools.

Visual Studio 2022 provides both IDE and necessary compiler and libraries.
So if you have not got an IDE and prefer