diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000000..c0c139b7e8
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,18 @@
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+
+sphinx:
+ builder: html
+ configuration: docs/conf.py
+
+formats:
+ - pdf
+ - epub
+
+python:
+ install:
+ - requirements: docs/requirements.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b43f244949..b78269a3d6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.13.0)
-set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The the path to the cmake directory")
+set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The path to the cmake directory")
list(APPEND CMAKE_MODULE_PATH ${ETH_CMAKE_DIR})
# Set the build type, if none was specified.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
+ if(EXISTS "${PROJECT_SOURCE_DIR}/.git")
set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
else()
set(DEFAULT_BUILD_TYPE "Release")
@@ -21,7 +21,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.8.18")
+set(PROJECT_VERSION "0.8.29")
# OSX target needed in order to support std::visit
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
@@ -34,19 +34,34 @@ endif()
option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
option(SOLC_STATIC_STDLIBS "Link solc against static versions of libgcc and libstdc++ on supported platforms" OFF)
-option(STRICT_Z3_VERSION "Use the latest version of Z3" ON)
+option(STRICT_Z3_VERSION "Require the exact version of Z3 solver expected by our test suite." ON)
option(PEDANTIC "Enable extra warnings and pedantic build flags. Treat all warnings as errors." ON)
option(PROFILE_OPTIMIZER_STEPS "Output performance metrics for the optimiser steps." OFF)
+option(
+ IGNORE_VENDORED_DEPENDENCIES
+ "Ignore libraries provided as submodules of the repository and allow CMake to look for \
+them in the typical locations, including system-wide dirs."
+ OFF
+)
+option(
+ ONLY_BUILD_SOLIDITY_LIBRARIES
+ "Only build library targets that can be statically linked against. Do not build executables or tests."
+ OFF
+)
+mark_as_advanced(PROFILE_OPTIMIZER_STEPS)
+mark_as_advanced(IGNORE_VENDORED_DEPENDENCIES)
+mark_as_advanced(ONLY_BUILD_SOLIDITY_LIBRARIES)
# Setup cccache.
include(EthCcache)
# Let's find our dependencies
include(EthDependencies)
-include(fmtlib)
-include(jsoncpp)
-include(range-v3)
-include_directories(SYSTEM ${JSONCPP_INCLUDE_DIR})
+if (NOT IGNORE_VENDORED_DEPENDENCIES)
+ include(fmtlib)
+ include(nlohmann-json)
+ include(range-v3)
+endif()
find_package(Threads)
@@ -66,24 +81,24 @@ include(EthUtils)
# Create license.h from LICENSE.txt and template
# Converting to char array is required due to MSVC's string size limit.
-file(READ ${CMAKE_SOURCE_DIR}/LICENSE.txt LICENSE_TEXT HEX)
+file(READ ${PROJECT_SOURCE_DIR}/LICENSE.txt LICENSE_TEXT HEX)
string(REGEX MATCHALL ".." LICENSE_TEXT "${LICENSE_TEXT}")
string(REGEX REPLACE ";" ",\n\t0x" LICENSE_TEXT "${LICENSE_TEXT}")
set(LICENSE_TEXT "0x${LICENSE_TEXT}")
-configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/license.h)
+configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/license.h.in" include/license.h)
include(EthOptions)
configure_project(TESTS)
-set(LATEST_Z3_VERSION "4.11.2")
-set(MINIMUM_Z3_VERSION "4.8.0")
+set(TESTED_Z3_VERSION "4.12.1")
+set(MINIMUM_Z3_VERSION "4.8.16")
find_package(Z3)
if (${Z3_FOUND})
if (${STRICT_Z3_VERSION})
- if (NOT ("${Z3_VERSION_STRING}" VERSION_EQUAL ${LATEST_Z3_VERSION}))
+ if (NOT ("${Z3_VERSION_STRING}" VERSION_EQUAL ${TESTED_Z3_VERSION}))
message(
FATAL_ERROR
- "SMTChecker tests require Z3 ${LATEST_Z3_VERSION} for all tests to pass.\n\
+ "SMTChecker tests require Z3 ${TESTED_Z3_VERSION} for all tests to pass.\n\
Build with -DSTRICT_Z3_VERSION=OFF if you want to use a different version. \
You can also use -DUSE_Z3=OFF to build without Z3. In both cases use --no-smt when running tests."
)
@@ -122,15 +137,11 @@ elseif (${Z3_FOUND})
message("Z3 SMT solver found. This enables optional SMT checking with Z3.")
endif()
-find_package(CVC4 QUIET)
-if (${CVC4_FOUND})
- add_definitions(-DHAVE_CVC4)
- message("CVC4 SMT solver found. This enables optional SMT checking with CVC4.")
-endif()
+find_program(CVC5_PATH cvc5)
-if (NOT (${Z3_FOUND} OR ${CVC4_FOUND}))
+if (NOT (${Z3_FOUND} OR CVC5_PATH))
message("No SMT solver found (or it has been forcefully disabled). Optional SMT checking will not be available.\
- \nPlease install Z3 or CVC4 or remove the option disabling them (USE_Z3, USE_CVC4).")
+ \nPlease install Z3 or cvc5 or remove the option disabling them (USE_Z3).")
endif()
add_subdirectory(libsolutil)
@@ -140,12 +151,16 @@ add_subdirectory(libevmasm)
add_subdirectory(libyul)
add_subdirectory(libsolidity)
add_subdirectory(libsolc)
-add_subdirectory(tools)
+add_subdirectory(libstdlib)
-if (NOT EMSCRIPTEN)
- add_subdirectory(solc)
-endif()
+if (NOT ONLY_BUILD_SOLIDITY_LIBRARIES)
+ add_subdirectory(tools)
-if (TESTS AND NOT EMSCRIPTEN)
- add_subdirectory(test)
+ if (NOT EMSCRIPTEN)
+ add_subdirectory(solc)
+ endif()
+
+ if (TESTS AND NOT EMSCRIPTEN)
+ add_subdirectory(test)
+ endif()
endif()
diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst
index 3f41ac860a..a40bbcf6e9 100644
--- a/docs/050-breaking-changes.rst
+++ b/docs/050-breaking-changes.rst
@@ -137,7 +137,7 @@ For most of the topics the compiler will provide suggestions.
``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
+* For clarity reasons, the command-line interface now requires ``-`` if the
standard input is used as source.
Deprecated Elements
@@ -147,18 +147,18 @@ 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
+Command-line and JSON Interfaces
--------------------------------
-* The command line option ``--formal`` (used to generate Why3 output for
+* 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
+* 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
+* The ``--clone-bin`` and ``--combined-json clone-bin`` command-line options
were removed.
* Remappings with empty prefix are disallowed.
diff --git a/docs/060-breaking-changes.rst b/docs/060-breaking-changes.rst
index 4f5571d54a..e7c93057f6 100644
--- a/docs/060-breaking-changes.rst
+++ b/docs/060-breaking-changes.rst
@@ -12,7 +12,7 @@ For the full list check
Changes the Compiler Might not Warn About
=========================================
-This section lists changes where the behaviour of your code might
+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
@@ -105,23 +105,23 @@ 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
+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
~~~~~~~~~~~~~~~~~~
-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 the deprecated old error reporter.
+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 `_ hash of the metadata file to the end of the bytecode by default
(for details, see documentation on :doc:`contract metadata `). Before 0.6.0, the compiler appended the
-`Swarm `_ hash by default, and in order to still support this behaviour,
-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.
+`Swarm `_ 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` and effect the metadata JSON generated by the compiler.
diff --git a/docs/080-breaking-changes.rst b/docs/080-breaking-changes.rst
index b322d2a489..9d1f3347b6 100644
--- a/docs/080-breaking-changes.rst
+++ b/docs/080-breaking-changes.rst
@@ -10,18 +10,18 @@ For the full list check
Silent Changes of the Semantics
===============================
-This section lists changes where existing code changes its behaviour without
+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 behaviour.
+ 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 behaviour using ``pragma abicoder v1;``.
+ 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.
@@ -57,7 +57,7 @@ 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 behaviour in
+* 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
@@ -106,7 +106,7 @@ This section lists changes that might cause existing contracts to not compile an
* The global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4`` have been removed.
- These are low-level functions that were largely unused. Their behaviour can be accessed from inline assembly.
+ 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.
@@ -155,7 +155,7 @@ Interface Changes
``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.
+ Use the "compact AST" (``--ast-compact-json`` resp. ``AST``) as replacement.
* The old error reporter (``--old-reporter``) has been removed.
@@ -173,4 +173,4 @@ How to update your code
- 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)
+- 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)
diff --git a/docs/Makefile b/docs/Makefile
index 3cc98f6990..01660bd388 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -34,7 +34,6 @@ help:
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@@ -116,12 +115,6 @@ latexpdf:
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-latexpdfja:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through platex and dvipdfmx..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000000..a3b5f25aed
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,23 @@
+# Solidity Language Docs
+
+## Local environment setup
+
+1. Install python https://www.python.org/downloads/
+1. 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
diff --git a/docs/_static/css/custom-dark.css b/docs/_static/css/custom-dark.css
new file mode 100644
index 0000000000..044a8f800d
--- /dev/null
+++ b/docs/_static/css/custom-dark.css
@@ -0,0 +1,595 @@
+
+
+/* DARK MODE STYLING */
+
+/* code directives */
+
+:root[style*=dark] .method dt,
+:root[style*=dark] .class dt,
+:root[style*=dark] .data dt,
+:root[style*=dark] .attribute dt,
+:root[style*=dark] .function dt,
+:root[style*=dark] .classmethod dt,
+:root[style*=dark] .exception dt,
+:root[style*=dark] .descclassname,
+:root[style*=dark] .descname {
+ background-color: #2d2d2d !important;
+}
+
+:root[style*=dark] .rst-content dl:not(.docutils) dt {
+ background-color: #0008;
+ border-top: solid 3px #fff2;
+ border-left: solid 3px #fff2;
+}
+
+:root[style*=dark] em.property {
+ color: #888888;
+}
+
+
+/* tables */
+
+:root[style*=dark] .rst-content table.docutils td {
+ border: 0px;
+}
+
+:root[style*=dark] .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
+ background-color: #0002;
+}
+
+:root[style*=dark] .rst-content pre {
+ background: none;
+}
+
+/* inlined code highlights */
+
+:root[style*=dark] .xref,
+:root[style*=dark] .py-meth {
+ color: #aaddff !important;
+ font-weight: normal !important;
+}
+
+/* highlight color search text */
+
+:root[style*=dark] .rst-content .highlighted {
+ background: #ff5722;
+ box-shadow: 0 0 0 2px #f0978b;
+}
+
+/* notes, warnings, hints */
+
+:root[style*=dark] .hint .admonition-title {
+ background: #2aa87c !important;
+}
+
+:root[style*=dark] .warning .admonition-title {
+ background: #cc4444 !important;
+}
+
+:root[style*=dark] .admonition-title {
+ background: #3a7ca8 !important;
+}
+
+:root[style*=dark] .admonition,
+:root[style*=dark] .note {
+ background-color: #0008 !important;
+}
+
+
+/* table of contents */
+
+:root[style*=dark] .sidebar {
+ background-color: #191919 !important;
+}
+
+:root[style*=dark] .sidebar-title {
+ background-color: #2b2b2b !important;
+}
+
+:root[style*=dark] .wy-menu-vertical code.docutils.literal.notranslate {
+ background: none !important;
+ border: none !important;
+}
+
+
+:root[style*=dark] .toc-backref {
+ color: grey !important;
+}
+
+:root[style*=dark] .highlight {
+ background: #0008;
+ color: #f8f8f2
+}
+
+:root[style*=dark] .highlight .c {
+ color: #888
+}
+
+
+/* Comment */
+
+:root[style*=dark] .highlight .err {
+ color: #960050;
+ background-color: #1e0010
+}
+
+
+/* Error */
+
+:root[style*=dark] .highlight .k {
+ color: #66d9ef
+}
+
+
+/* Keyword */
+
+:root[style*=dark] .highlight .l {
+ color: #ae81ff
+}
+
+
+/* Literal */
+
+:root[style*=dark] .highlight .n {
+ color: #f8f8f2
+}
+
+
+/* Name */
+
+:root[style*=dark] .highlight .o {
+ color: #f92672
+}
+
+
+/* Operator */
+
+:root[style*=dark] .highlight .p {
+ color: #f8f8f2
+}
+
+
+/* Punctuation */
+
+:root[style*=dark] .highlight .ch {
+ color: #888
+}
+
+
+/* Comment.Hashbang */
+
+:root[style*=dark] .highlight .cm {
+ color: #888
+}
+
+
+/* Comment.Multiline */
+
+:root[style*=dark] .highlight .cp {
+ color: #888
+}
+
+
+/* Comment.Preproc */
+
+:root[style*=dark] .highlight .cpf {
+ color: #888
+}
+
+
+/* Comment.PreprocFile */
+
+:root[style*=dark] .highlight .c1 {
+ color: #888
+}
+
+
+/* Comment.Single */
+
+:root[style*=dark] .highlight .cs {
+ color: #888
+}
+
+
+/* Comment.Special */
+
+:root[style*=dark] .highlight .gd {
+ color: #f92672
+}
+
+
+/* Generic.Deleted */
+
+:root[style*=dark] .highlight .ge {
+ font-style: italic
+}
+
+
+/* Generic.Emph */
+
+:root[style*=dark] .highlight .gi {
+ color: #a6e22e
+}
+
+
+/* Generic.Inserted */
+
+:root[style*=dark] .highlight .gs {
+ font-weight: bold
+}
+
+
+/* Generic.Strong */
+
+:root[style*=dark] .highlight .gu {
+ color: #888
+}
+
+
+/* Generic.Subheading */
+
+:root[style*=dark] .highlight .kc {
+ color: #66d9ef
+}
+
+
+/* Keyword.Constant */
+
+:root[style*=dark] .highlight .kd {
+ color: #66d9ef
+}
+
+
+/* Keyword.Declaration */
+
+:root[style*=dark] .highlight .kn {
+ color: #f92672
+}
+
+
+/* Keyword.Namespace */
+
+:root[style*=dark] .highlight .kp {
+ color: #66d9ef
+}
+
+
+/* Keyword.Pseudo */
+
+:root[style*=dark] .highlight .kr {
+ color: #66d9ef
+}
+
+
+/* Keyword.Reserved */
+
+:root[style*=dark] .highlight .kt {
+ color: #66d9ef
+}
+
+
+/* Keyword.Type */
+
+:root[style*=dark] .highlight .ld {
+ color: #e6db74
+}
+
+
+/* Literal.Date */
+
+:root[style*=dark] .highlight .m {
+ color: #ae81ff
+}
+
+
+/* Literal.Number */
+
+:root[style*=dark] .highlight .s {
+ color: #e6db74
+}
+
+
+/* Literal.String */
+
+:root[style*=dark] .highlight .na {
+ color: #a6e22e
+}
+
+
+/* Name.Attribute */
+
+:root[style*=dark] .highlight .nb {
+ color: #f8f8f2
+}
+
+
+/* Name.Builtin */
+
+:root[style*=dark] .highlight .nc {
+ color: #a6e22e
+}
+
+
+/* Name.Class */
+
+:root[style*=dark] .highlight .no {
+ color: #66d9ef
+}
+
+
+/* Name.Constant */
+
+:root[style*=dark] .highlight .nd {
+ color: #a6e22e
+}
+
+
+/* Name.Decorator */
+
+:root[style*=dark] .highlight .ni {
+ color: #f8f8f2
+}
+
+
+/* Name.Entity */
+
+:root[style*=dark] .highlight .ne {
+ color: #a6e22e
+}
+
+
+/* Name.Exception */
+
+:root[style*=dark] .highlight .nf {
+ color: #a6e22e
+}
+
+
+/* Name.Function */
+
+:root[style*=dark] .highlight .nl {
+ color: #f8f8f2
+}
+
+
+/* Name.Label */
+
+:root[style*=dark] .highlight .nn {
+ color: #f8f8f2
+}
+
+
+/* Name.Namespace */
+
+:root[style*=dark] .highlight .nx {
+ color: #a6e22e
+}
+
+
+/* Name.Other */
+
+:root[style*=dark] .highlight .py {
+ color: #f8f8f2
+}
+
+
+/* Name.Property */
+
+:root[style*=dark] .highlight .nt {
+ color: #f92672
+}
+
+
+/* Name.Tag */
+
+:root[style*=dark] .highlight .nv {
+ color: #f8f8f2
+}
+
+
+/* Name.Variable */
+
+:root[style*=dark] .highlight .ow {
+ color: #f92672
+}
+
+
+/* Operator.Word */
+
+:root[style*=dark] .highlight .w {
+ color: #f8f8f2
+}
+
+
+/* Text.Whitespace */
+
+:root[style*=dark] .highlight .mb {
+ color: #ae81ff
+}
+
+
+/* Literal.Number.Bin */
+
+:root[style*=dark] .highlight .mf {
+ color: #ae81ff
+}
+
+
+/* Literal.Number.Float */
+
+:root[style*=dark] .highlight .mh {
+ color: #ae81ff
+}
+
+
+/* Literal.Number.Hex */
+
+:root[style*=dark] .highlight .mi {
+ color: #ae81ff
+}
+
+
+/* Literal.Number.Integer */
+
+:root[style*=dark] .highlight .mo {
+ color: #ae81ff
+}
+
+
+/* Literal.Number.Oct */
+
+:root[style*=dark] .highlight .sa {
+ color: #e6db74
+}
+
+
+/* Literal.String.Affix */
+
+:root[style*=dark] .highlight .sb {
+ color: #e6db74
+}
+
+
+/* Literal.String.Backtick */
+
+:root[style*=dark] .highlight .sc {
+ color: #e6db74
+}
+
+
+/* Literal.String.Char */
+
+:root[style*=dark] .highlight .dl {
+ color: #e6db74
+}
+
+
+/* Literal.String.Delimiter */
+
+:root[style*=dark] .highlight .sd {
+ color: #e6db74
+}
+
+
+/* Literal.String.Doc */
+
+:root[style*=dark] .highlight .s2 {
+ color: #e6db74
+}
+
+
+/* Literal.String.Double */
+
+:root[style*=dark] .highlight .se {
+ color: #ae81ff
+}
+
+
+/* Literal.String.Escape */
+
+:root[style*=dark] .highlight .sh {
+ color: #e6db74
+}
+
+
+/* Literal.String.Heredoc */
+
+:root[style*=dark] .highlight .si {
+ color: #e6db74
+}
+
+
+/* Literal.String.Interpol */
+
+:root[style*=dark] .highlight .sx {
+ color: #e6db74
+}
+
+
+/* Literal.String.Other */
+
+:root[style*=dark] .highlight .sr {
+ color: #e6db74
+}
+
+
+/* Literal.String.Regex */
+
+:root[style*=dark] .highlight .s1 {
+ color: #e6db74
+}
+
+
+/* Literal.String.Single */
+
+:root[style*=dark] .highlight .ss {
+ color: #e6db74
+}
+
+
+/* Literal.String.Symbol */
+
+:root[style*=dark] .highlight .bp {
+ color: #f8f8f2
+}
+
+
+/* Name.Builtin.Pseudo */
+
+:root[style*=dark] .highlight .fm {
+ color: #a6e22e
+}
+
+
+/* Name.Function.Magic */
+
+:root[style*=dark] .highlight .vc {
+ color: #f8f8f2
+}
+
+
+/* Name.Variable.Class */
+
+:root[style*=dark] .highlight .vg {
+ color: #f8f8f2
+}
+
+
+/* Name.Variable.Global */
+
+:root[style*=dark] .highlight .vi {
+ color: #f8f8f2
+}
+
+
+/* Name.Variable.Instance */
+
+:root[style*=dark] .highlight .vm {
+ color: #f8f8f2
+}
+
+
+/* Name.Variable.Magic */
+
+:root[style*=dark] .highlight .il {
+ color: #ae81ff
+}
+
+
+/* Grammar */
+
+:root[style*=dark] .railroad-diagram {
+ fill: white;
+}
+
+:root[style*=dark] .railroad-diagram path {
+ stroke: white;
+}
+
+:root[style*=dark] .railroad-diagram rect {
+ stroke: white;
+}
+
+:root[style*=dark] .a4 .sig-name {
+ background-color: transparent !important;
+}
diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css
index 4ff53f3a7b..25ab265443 100644
--- a/docs/_static/css/custom.css
+++ b/docs/_static/css/custom.css
@@ -1,23 +1,185 @@
+/* ROOT DECLARATIONS */
+:root {
+ /* Text */
+ --color-a: #2B247C;
+ --color-b: #672AC8;
+ --color-c: #5554D9;
+ --color-d: #9F94E8;
+ --color-e: #AEC0F1;
+ --color-f: #E6E3EC;
+ /* Background */
+
+ --white: #FAF8FF;
+ --black: #110C4E;
+ --menu-bg: #2B247C06;
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+
+ --navHeight: 4.5rem;
+ --sideWidth: 300px;
+ --maxWidth: 80rem;
+ --desktopInlinePadding: 2rem;
+ --mobileInlinePadding: 1rem;
+ --currentVersionHeight: 45px;
+
+ text-rendering: geometricPrecision;
+ -webkit-font-smoothing: antialiased;
+}
+
+a,
+button {
+ border-radius: 0;
+}
+
+:root[style*=dark] {
+ --color-a: #E6E3EC !important;
+ --color-b: #AEC0F1 !important;
+ --color-c: #9F94E8 !important;
+ --color-d: #5554D9 !important;
+ --color-e: #672AC8 !important;
+ --color-f: #2B247C !important;
+
+ --white: #110C4E !important;
+ --black: #FAF8FF !important;
+ --menu-bg: #E6E3EC06 !important;
+}
+
+html,
+body,
+.unified-header::before,
+.wy-nav-side,
+.rst-versions,
+code,
+div,
+input[type=text],
+a,
+.wy-grid-for-nav {
+ transition: background 150ms ease-in-out;
+}
+
+html,
+body,
+.wy-grid-for-nav {
+ background-color: var(--color-f) !important;
+}
+
+body {
+ font-family: "Overpass", sans-serif;
+}
+
+a {
+ color: var(--color-c);
+}
+
+a, section {
+ scroll-margin-top: calc(var(--navHeight) + 2rem);
+}
+
+hr {
+ margin-block: 2rem;
+ border-color: var(--color-d) !important;
+}
+
+
+/* HEADER STYLES */
+h1 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 44px;
+ color: var(--color-a) !important;
+ line-height: 1.1;
+ text-wrap: balance;
+ margin-top: 4rem;
+ margin-bottom: 1.5rem;
+}
+
+section:first-of-type h1:first-of-type {
+ font-family: 'Overpass mono', monospace;
+ font-size: 48px;
+ margin-top: 3rem;
+ margin-bottom: 5rem;
+}
+
+h2 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 38px;
+ color: var(--color-a) !important;
+ line-height: 46px;
+ text-wrap: balance;
+ margin-top: 4rem;
+ margin-bottom: 1.5rem;
+}
+
+*:not([role=navigation])>p[role=heading]>span,
+h3 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 32px;
+ color: var(--color-a) !important;
+ line-height: 46px;
+ text-wrap: balance;
+ margin-top: 4rem;
+ margin-bottom: 1.5rem;
+}
+
+h4 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 32px;
+ color: var(--color-a) !important;
+ line-height: 46px;
+ text-wrap: balance;
+ margin-top: 3rem;
+ margin-bottom: 1.5rem;
+}
+
+h5 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 18px;
+ color: var(--color-a) !important;
+ line-height: 1.4;
+ text-wrap: balance;
+}
+
+h6 {
+ font-family: 'Overpass', sans-serif;
+ font-weight: 700;
+ font-size: 16px;
+ color: var(--color-a) !important;
+ line-height: 1.4;
+ text-wrap: balance;
+}
+
+span.pre,
pre {
- white-space: pre-wrap; /* css-3 */
- white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
- white-space: -pre-wrap; /* Opera 4-6 */
- white-space: -o-pre-wrap; /* Opera 7 */
+ /* css-3 */
+ white-space: pre-wrap;
+ /* Mozilla, since 1999 */
+ white-space: -moz-pre-wrap;
+ /* Opera 4-6 */
+ white-space: -pre-wrap;
+ /* Opera 7 */
+ white-space: -o-pre-wrap;
word-wrap: break-word;
+ font-family: 'Overpass Mono', monospace;
}
-.wy-table-responsive table td, .wy-table-responsive table th {
+small,
+small * {
+ font-size: 12px;
+}
+
+.wy-table-responsive table td,
+.wy-table-responsive table th {
white-space: normal;
}
+
.rst-content table.docutils td {
vertical-align: top;
}
/* links */
-.rst-content a:not(:visited) {
- color: #002fa7;
-}
-
.rst-content .highlighted {
background: #eac545;
}
@@ -27,60 +189,638 @@ pre {
background: #fafafa;
}
-.wy-side-nav-search img.logo {
- width: 100px !important;
- padding: 0;
+/* project version (displayed under project logo) */
+.wy-side-nav-search>div.version {
+ color: var(--color-b);
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ text-align: start;
}
-.wy-side-nav-search > a {
- padding: 0;
+/* Link to Remix IDE shown next to code snippets */
+.rst-content p.remix-link-container {
+ display: block;
+ text-align: right;
margin: 0;
+ line-height: 1em;
}
-/* project version (displayed under project logo) */
-.wy-side-nav-search .version {
- color: #272525 !important;
+.rst-content .remix-link-container a.remix-link {
+ font-size: 0.7em;
+ padding: 0.1em 0.5em;
+ background: transparent;
+ color: var(--color-a) !important;
+ border: 1px solid var(--color-a);
+ text-decoration: none;
}
-/* menu section headers */
-.wy-menu .caption {
- color: #65afff !important;
+.rst-content div.highlight-solidity,
+.rst-content div.highlight-yul {
+ margin-top: 0;
}
-/* Link to Remix IDE shown next to code snippets */
-p.remix-link-container {
+/* CUSTOMIZATION UPDATES */
+
+.wy-nav-content-wrap,
+.wy-nav-content {
+ background: transparent !important;
+}
+
+.wy-side-nav-search {
+ background-color: transparent !important;
+ color: var(--color-a) !important;
+ box-shadow: 0 4 4 0 var(--color-a);
+ border-bottom: 1px solid var(--color-d) !important;
+}
+
+.wy-side-nav-search svg {
+ color: var(--color-a) !important;
+}
+
+.wy-nav-top {
+ background-color: transparent !important;
+ color: var(--color-a) !important;
+}
+
+.wy-nav-top a {
+ color: var(--color-a) !important;
+}
+
+.wy-breadcrumbs a.icon-home:before {
+ content: "Documentation";
+ font-family: "Overpass", sans-serif;
+}
+
+.rst-content table.docutils thead {
+ color: var(--color-a);
+}
+
+code.docutils.literal.notranslate {
+ padding: 2px 4px;
+ font-size: 0.875em;
+ font-family: "Overpass Mono", monospace;
+ background: var(--white);
+ color: var(--color-c);
+ border: 0px;
+}
+
+dt code.docutils.literal.notranslate {
+ background: none;
+}
+
+.wy-nav-content {
+ color: var(--color-a);
+}
+
+/* .rst-content a:not(:visited) { */
+/* color: var(--color-b) !important; */
+/* } */
+
+.rst-content a:visited {
+ color: var(--color-c) !important;
+}
+
+.rst-content a {
+ text-decoration: underline;
+}
+
+.rst-content a:where(:focus, :focus-visible, :hover) {
+ color: var(--color-d) !important;
+}
+
+.wy-side-scroll a {
+ color: var(--color-a);
+ background: transparent;
+ font-size: 1rem;
+ line-height: 125%;
+}
+
+.wy-menu-vertical li.current a,
+.wy-menu-vertical li.current li a,
+.wy-menu-vertical li.current li a code {
+ border: none;
+ color: var(--color-a);
+}
+
+ul.current ul,
+.wy-menu-vertical li.current a:hover,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,
+.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,
+.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,
+.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,
+.wy-menu-vertical li.current {
+ background: var(--menu-bg) !important;
+}
+
+.wy-menu.wy-menu-vertical>ul {
+ margin-bottom: 3rem;
+}
+
+.wy-menu.wy-menu-vertical>p {
+ color: var(--color-c);
+}
+
+.wy-menu-vertical li.on a,
+.wy-menu-vertical li.current>a {
+ background: var(--menu-bg) !important;
+ border-bottom: 0px !important;
+ border-top: 0px !important;
+}
+
+.btn {
+ border-radius: 0;
+ text-decoration: none !important;
+}
+
+.wy-breadcrumbs-aside a,
+.wy-breadcrumbs-aside a:visited,
+a.fa.fa-github,
+a.fa.fa-github:visited,
+a.fa.fa-github:not(:visited),
+a.btn.btn-neutral:visited,
+a.btn.btn-neutral:not(:visited),
+a.btn.btn-neutral {
+ background: transparent !important;
+ color: var(--color-a) !important;
+ border: 2px solid var(--color-a) !important;
+ text-decoration: none;
+}
+
+.rst-content .remix-link-container a.remix-link:hover,
+.wy-breadcrumbs-aside a:hover,
+a.fa.fa-github:hover,
+a.btn.btn-neutral:hover {
+ background: var(--white) !important;
+ color: var(--color-b) !important;
+ border-color: var(--color-b) !important;
+}
+
+footer .rst-footer-buttons {
+ display: flex;
+ justify-content: center;
+ gap: 2rem;
+}
+
+/**
+ * Customization for the unified layout
+ */
+
+/* Site wrapper, and two children: header and rest */
+.unified-wrapper {
position: relative;
- right: -100%; /* Positioned next to the the top-right corner of the code block following it. */
+ display: flex;
+ flex-direction: column;
+ inset: 0;
+ max-width: var(--maxWidth);
+ margin-inline: auto;
+}
+
+/* Site header */
+.unified-header {
+ position: fixed;
+ top: 0;
+ inset-inline: 0;
+ z-index: 99999;
+ display: flex;
+ align-items: center;
+ box-shadow: var(--shadow);
}
-a.remix-link {
- position: absolute; /* Remove it from normal flow not to affect the original position of the snippet. */
- top: 0.5em;
- width: 3.236em; /* Size of the margin (= right-side padding in .wy-nav-content in the current theme). */
+.unified-header .inner-header {
+ display: flex;
+ margin-inline: auto;
+ width: 100%;
+ max-width: var(--maxWidth);
+ align-items: center;
+ justify-content: space-between;
+ padding-inline: var(--desktopInlinePadding);
+ padding-block: 1rem;
}
-a.remix-link .link-icon {
- background: url("../img/solid-share-arrow.svg") no-repeat;
+.unified-header::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ opacity: 95%;
+ background: var(--color-f);
+ z-index: -1;
+ backdrop-filter: blur(3px);
+}
+
+.unified-header .home-link {
display: block;
- width: 1.5em;
- height: 1.5em;
- margin: auto;
+ text-decoration: none;
+ width: 25px;
+ height: 40px;
}
-a.remix-link .link-text {
- display: none; /* Visible only on hover. */
- width: 3.3em; /* Narrow enough to get two lines of text. */
- margin: auto;
- text-align: center;
- font-size: 0.8em;
- line-height: normal;
- color: black;
+.unified-header .home-link:hover .solidity-logo {
+ transform: scale(1.1);
+ transition: transform 100ms ease-in-out;
}
-a.remix-link:hover {
+.unified-header img.solidity-logo {
+ transform: scale(1);
+ transition: transform 100ms ease-in-out;
+ width: 100%;
+ height: 100%;
+}
+
+.unified-header .nav-bar {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+}
+
+.unified-header .nav-bar .nav-button-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+}
+
+.unified-header .nav-link {
+ display: inline-block;
+ padding-inline: 8px;
+ padding-block: 4px;
+ font-size: 14px;
+ font-family: 'Overpass Mono', monospace;
+ text-decoration: none;
+ color: var(--color-a);
+ letter-spacing: -0.02em;
+ font-weight: 400;
+ box-sizing: content-box;
+ border-bottom: 1px solid transparent;
+ white-space: nowrap;
+}
+
+.unified-header .nav-link.active {
+ background: var(--white);
+}
+
+.unified-header .nav-link:hover {
+ color: var(--color-c);
+ border-bottom: 1px solid var(--color-c);
+}
+
+/* Rest: Flex-row, with two children: side bar, and content */
+.unified-wrapper .wy-grid-for-nav {
+ position: relative !important;
+ display: flex;
+ margin-inline: auto;
+}
+
+/* First child: Side bar */
+.unified-wrapper .wy-grid-for-nav nav.wy-nav-side {
+ position: fixed;
+ display: flex;
+ flex-direction: column;
+ background: var(--color-f);
+ color: var(--color-a);
+ padding-bottom: unset !important;
+ z-index: 10 !important;
+ min-height: unset !important;
+ width: var(--sideWidth) !important;
+ top: var(--navHeight);
+ bottom: 0;
+ left: auto;
+ overflow: auto;
+}
+
+.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll {
+ position: static !important;
+ width: unset !important;
+ overflow: unset !important;
+ height: unset !important;
+ padding-bottom: 2rem;
+}
+
+.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll .wy-side-nav-search {
+ margin: 0 !important;
+ width: var(--sideWidth) !important;
+}
+
+.wy-nav-side,
+.wy-side-scroll,
+.wy-side-nav-search,
+.my-menu {
+ width: 100% !important;
+}
+
+.wy-nav-side input[type=text] {
+ font-family: "Overpass", sans-serif;
+ border-radius: 0;
+ border-color: var(--color-d);
+ background: var(--white);
+ box-shadow: none;
+ color: var(--color-a);
+}
+
+.wy-nav-side input[type=text]::placeholder {
+ font-family: "Overpass", sans-serif;
+ color: var(--color-e);
+ font-size: 16px;
+ position: relative;
+ top: 4px;
+}
+
+/* Second child: Content */
+.unified-wrapper .wy-grid-for-nav .wy-nav-content {
+ width: 100%;
+ max-width: unset !important; /* override */
+ padding-inline: var(--desktopInlinePadding);
+ margin-inline-start: var(--sideWidth);
+ margin-top: var(--navHeight);
+}
+
+.unified-wrapper .wy-grid-for-nav .wy-nav-content .rst-content {
+ max-width: min(70ch, calc(100vw - 2 * var(--desktopInlinePadding) - var(--sideWidth)));
+ margin-inline: auto;
+}
+
+.unified-wrapper.menu-open .backdrop {
opacity: 0.5;
}
-a.remix-link:hover .link-text {
+.unified-wrapper .wy-nav-side,
+.unified-wrapper .rst-versions {
+ left: auto;
+
+}
+
+.unified-wrapper .backdrop {
+ opacity: 0;
+ transition: opacity 200ms ease-in-out;
+}
+
+@media (max-width: 768px) {
+ h2 {
+ margin-top: 3rem;
+ margin-bottom: 1rem;
+ }
+
+ h3 {
+ margin-top: 3rem;
+ margin-bottom: 1rem;
+ }
+
+ h4 {
+ margin-top: 2rem;
+ margin-bottom: 1rem;
+ }
+
+ /* Menu closed styles */
+ .unified-header .nav-link {
+ display: none;
+ }
+
+ .unified-header .inner-header {
+ padding-inline: var(--mobileInlinePadding);
+ }
+
+ .unified-wrapper .wy-grid-for-nav nav.wy-nav-side {
+ transform: translateX(-100%);
+ transition: transform 200ms ease-in-out;
+ }
+
+ /* Menu open styles */
+ .unified-wrapper.menu-open nav.wy-nav-side {
+ transform: translateX(0);
+ transition: transform 200ms ease-in-out;
+ }
+
+ .unified-wrapper.menu-open .rst-versions {
+ position: sticky;
+ bottom: 0;
+ width: 100%;
+ }
+
+ .unified-wrapper.menu-open .backdrop {
+ display: block;
+ position: fixed;
+ inset: 0;
+ opacity: 1;
+ transition: opacity 200ms ease-in-out;
+ z-index: 5;
+ background: #0006;
+ }
+
+ a.skip-to-content {
+ display: none;
+ }
+
+ .wy-nav-content {
+ margin-inline-start: 0 !important;
+ }
+
+ .rst-content {
+ max-width: 100% !important;
+ }
+
+ .wy-side-scroll {
+ padding-bottom: 0 !important;
+ }
+}
+
+ul.search .context {
+ color: var(--color-a) !important;
+}
+
+.rst-versions {
+ background: var(--color-f);
+}
+
+.rst-versions.shift-up {
+ height: unset !important;
+ max-height: unset !important;
+ overflow-y: unset !important;
+}
+
+.rst-content dl:not(.docutils) dt {
+ color: var(--color-a);
+ background-color: #fff8;
+ border-top: solid 3px #0002;
+ border-inline-start: solid 3px #0002;
+ padding: 2px 6px;
+}
+
+.rst-versions .rst-current-version {
+ border-color: var(--color-d) !important;
+}
+
+.rst-current-version *,
+.rst-current-version .fa:before,
+.rst-current-version .fa-element {
+ color: var(--color-b) !important;
+}
+
+.rst-current-version dt,
+.rst-current-version dd,
+.rst-current-version dd a,
+.rst-other-versions dl:last-of-type dt,
+.rst-other-versions dl:last-of-type dd,
+.rst-other-versions dl:last-of-type dd a {
+ font-size: 14px !important;
+}
+
+.rst-other-versions {
+ background: var(--white) !important;
+ color: var(--color-a) !important;
+ max-height: calc(100vh - var(--navHeight) - var(--currentVersionHeight));
+ overflow-y: scroll;
+}
+
+.rst-other-versions a {
+ text-decoration: underline;
+ color: var(--color-c) !important;
+}
+
+.rst-other-versions dt {
+ color: var(--color-a) !important;
+}
+
+.rst-other-versions dl {
+ margin-bottom: 1.5rem !important;
+}
+
+.rst-other-versions dl:last-of-type {
+ margin-top: 2rem !important;
+}
+
+/* Bottom Search */
+.wy-nav-side input[type=text],
+.rst-other-versions dl:last-of-type dd {
+ width: 100%;
+}
+
+.rst-other-versions dl:last-of-type dt {
+ color: var(--color-b) !important;
+}
+
+.rst-other-versions dl:last-of-type div[style*=padding],
+.rst-other-versions dl dd:first-of-type a {
+ padding-inline-start: 0 !important;
+}
+
+button.toctree-expand {
+ color: var(--black) !important;
+}
+
+/* Light/dark color mode toggle 🌓 */
+button.color-toggle {
+ display: inline-flex;
+ appearance: none;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ user-select: none;
+ outline: none;
+ height: 28px;
+ width: 28px;
+ background: none;
+ border: none;
+ padding: 6px;
+ margin: 6px;
+ transition-duration: 200ms;
+ transition-property: background-color,
+ color,
+ fill,
+ stroke,
+ opacity;
+}
+
+button.color-toggle:focus-visible {
+ outline: 2px solid var(--color-c);
+ color: var(--color-c);
+}
+
+button.color-toggle:hover {
+ color: var(--color-c);
+ background: #0002;
+}
+
+button.color-toggle .color-toggle-icon {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ display: inline-block;
+ line-height: 1em;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ vertical-align: middle;
+ /* color: var(--color-a); */
+}
+
+
+button.mobile-menu-button {
+ display: none;
+}
+
+@media (max-width: 768px) {
+ nav.wy-nav-top {
+ display: none;
+ }
+
+ button.mobile-menu-button {
+ display: flex;
+ }
+}
+
+
+.hidden {
+ display: none;
+}
+
+#search-results .search li:first-child,
+#search-results .search li {
+ border-color: var(--color-d);
+}
+
+#search-results .search li:last-child {
+ border: 0px;
+}
+
+.forum-link::after {
+ content: ' ↗';
+ font-size: 14px;
+ font-family: 'Overpass Mono', monospace;
+}
+
+.wy-breadcrumbs>li {
+ padding-top: 8px;
+}
+
+.wy-breadcrumbs-aside a {
+ padding: 0.5rem 0.75rem;
+ font-size: 12px;
+ font-family: "'Overpass'", sans-serif;
+ font-weight: 700;
+}
+
+a.skip-to-content:visited,
+a.skip-to-content:not(:visited),
+a.skip-to-content {
display: block;
+ pointer-events: none;
+ width: fit-content;
+ opacity: 0;
+ transition: opacity 200ms ease-in-out;
+ padding: 2px 4px;
+ font-size: 14px;
+ margin-inline-end: auto;
+ margin-inline-start: 1.5rem;
+ color: var(--color-a);
+ white-space: nowrap;
}
+
+a.skip-to-content:focus {
+ opacity: 1;
+ transition: opacity 200ms ease-in-out;
+}
+
+#content {
+ scroll-margin-top: 6rem;
+ scroll-behavior: smooth;
+}
\ No newline at end of file
diff --git a/docs/_static/css/dark.css b/docs/_static/css/dark.css
deleted file mode 100644
index a87ff09ebe..0000000000
--- a/docs/_static/css/dark.css
+++ /dev/null
@@ -1,635 +0,0 @@
-/* links */
-
-.rst-content a:not(:visited) {
- color: #aaddff !important;
-}
-
-/* code directives */
-
-.method dt,
-.class dt,
-.data dt,
-.attribute dt,
-.function dt,
-.classmethod dt,
-.exception dt,
-.descclassname,
-.descname {
- background-color: #2d2d2d !important;
-}
-
-.rst-content dl:not(.docutils) dt {
- color: #aaddff;
- background-color: #2d2d2d;
- border-top: solid 3px #525252;
- border-left: solid 3px #525252;
-}
-
-em.property {
- color: #888888;
-}
-
-
-/* tables */
-
-.rst-content table.docutils thead {
- color: #ddd;
-}
-
-.rst-content table.docutils td {
- border: 0px;
-}
-
-.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
- background-color: #5a5a5a;
-}
-
-.rst-content pre {
- background: none;
-}
-
-/* inlined code highlights */
-
-.xref,
-.py-meth,
-.rst-content a code {
- color: #aaddff !important;
- font-weight: normal !important;
-}
-
-.rst-content code {
- color: #eee !important;
- font-weight: normal !important;
-}
-
-code.literal {
- background-color: #2d2d2d !important;
- border: 1px solid #6d6d6d !important;
-}
-
-code.docutils.literal.notranslate {
- color: #ddd;
-}
-
-/* highlight color search text */
-
-.rst-content .highlighted {
- background: #ff5722;
- box-shadow: 0 0 0 2px #f0978b;
-}
-
-/* notes, warnings, hints */
-
-.hint .admonition-title {
- background: #2aa87c !important;
-}
-
-.warning .admonition-title {
- background: #cc4444 !important;
-}
-
-.admonition-title {
- background: #3a7ca8 !important;
-}
-
-.admonition,
-.note {
- background-color: #2d2d2d !important;
-}
-
-
-/* table of contents */
-
-.wy-nav-content-wrap {
- background-color: rgba(0, 0, 0, 0.6) !important;
-}
-
-.sidebar {
- background-color: #191919 !important;
-}
-
-.sidebar-title {
- background-color: #2b2b2b !important;
-}
-
-.wy-menu-vertical a {
- color: #ddd;
-}
-
-.wy-menu-vertical code.docutils.literal.notranslate {
- color: #404040;
- background: none !important;
- border: none !important;
-}
-
-.wy-nav-content {
- background: #3c3c3c;
- color: #dddddd;
-}
-
-.wy-menu-vertical li.on a,
-.wy-menu-vertical li.current>a {
- background: #a3a3a3;
- border-bottom: 0px !important;
- border-top: 0px !important;
-}
-
-.wy-menu-vertical li.current {
- background: #b3b3b3;
-}
-
-.toc-backref {
- color: grey !important;
-}
-
-.highlight .hll {
- background-color: #49483e
-}
-
-.highlight {
- background: #222;
- color: #f8f8f2
-}
-
-.highlight .c {
- color: #888
-}
-
-
-/* Comment */
-
-.highlight .err {
- color: #960050;
- background-color: #1e0010
-}
-
-
-/* Error */
-
-.highlight .k {
- color: #66d9ef
-}
-
-
-/* Keyword */
-
-.highlight .l {
- color: #ae81ff
-}
-
-
-/* Literal */
-
-.highlight .n {
- color: #f8f8f2
-}
-
-
-/* Name */
-
-.highlight .o {
- color: #f92672
-}
-
-
-/* Operator */
-
-.highlight .p {
- color: #f8f8f2
-}
-
-
-/* Punctuation */
-
-.highlight .ch {
- color: #888
-}
-
-
-/* Comment.Hashbang */
-
-.highlight .cm {
- color: #888
-}
-
-
-/* Comment.Multiline */
-
-.highlight .cp {
- color: #888
-}
-
-
-/* Comment.Preproc */
-
-.highlight .cpf {
- color: #888
-}
-
-
-/* Comment.PreprocFile */
-
-.highlight .c1 {
- color: #888
-}
-
-
-/* Comment.Single */
-
-.highlight .cs {
- color: #888
-}
-
-
-/* Comment.Special */
-
-.highlight .gd {
- color: #f92672
-}
-
-
-/* Generic.Deleted */
-
-.highlight .ge {
- font-style: italic
-}
-
-
-/* Generic.Emph */
-
-.highlight .gi {
- color: #a6e22e
-}
-
-
-/* Generic.Inserted */
-
-.highlight .gs {
- font-weight: bold
-}
-
-
-/* Generic.Strong */
-
-.highlight .gu {
- color: #888
-}
-
-
-/* Generic.Subheading */
-
-.highlight .kc {
- color: #66d9ef
-}
-
-
-/* Keyword.Constant */
-
-.highlight .kd {
- color: #66d9ef
-}
-
-
-/* Keyword.Declaration */
-
-.highlight .kn {
- color: #f92672
-}
-
-
-/* Keyword.Namespace */
-
-.highlight .kp {
- color: #66d9ef
-}
-
-
-/* Keyword.Pseudo */
-
-.highlight .kr {
- color: #66d9ef
-}
-
-
-/* Keyword.Reserved */
-
-.highlight .kt {
- color: #66d9ef
-}
-
-
-/* Keyword.Type */
-
-.highlight .ld {
- color: #e6db74
-}
-
-
-/* Literal.Date */
-
-.highlight .m {
- color: #ae81ff
-}
-
-
-/* Literal.Number */
-
-.highlight .s {
- color: #e6db74
-}
-
-
-/* Literal.String */
-
-.highlight .na {
- color: #a6e22e
-}
-
-
-/* Name.Attribute */
-
-.highlight .nb {
- color: #f8f8f2
-}
-
-
-/* Name.Builtin */
-
-.highlight .nc {
- color: #a6e22e
-}
-
-
-/* Name.Class */
-
-.highlight .no {
- color: #66d9ef
-}
-
-
-/* Name.Constant */
-
-.highlight .nd {
- color: #a6e22e
-}
-
-
-/* Name.Decorator */
-
-.highlight .ni {
- color: #f8f8f2
-}
-
-
-/* Name.Entity */
-
-.highlight .ne {
- color: #a6e22e
-}
-
-
-/* Name.Exception */
-
-.highlight .nf {
- color: #a6e22e
-}
-
-
-/* Name.Function */
-
-.highlight .nl {
- color: #f8f8f2
-}
-
-
-/* Name.Label */
-
-.highlight .nn {
- color: #f8f8f2
-}
-
-
-/* Name.Namespace */
-
-.highlight .nx {
- color: #a6e22e
-}
-
-
-/* Name.Other */
-
-.highlight .py {
- color: #f8f8f2
-}
-
-
-/* Name.Property */
-
-.highlight .nt {
- color: #f92672
-}
-
-
-/* Name.Tag */
-
-.highlight .nv {
- color: #f8f8f2
-}
-
-
-/* Name.Variable */
-
-.highlight .ow {
- color: #f92672
-}
-
-
-/* Operator.Word */
-
-.highlight .w {
- color: #f8f8f2
-}
-
-
-/* Text.Whitespace */
-
-.highlight .mb {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Bin */
-
-.highlight .mf {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Float */
-
-.highlight .mh {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Hex */
-
-.highlight .mi {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Integer */
-
-.highlight .mo {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Oct */
-
-.highlight .sa {
- color: #e6db74
-}
-
-
-/* Literal.String.Affix */
-
-.highlight .sb {
- color: #e6db74
-}
-
-
-/* Literal.String.Backtick */
-
-.highlight .sc {
- color: #e6db74
-}
-
-
-/* Literal.String.Char */
-
-.highlight .dl {
- color: #e6db74
-}
-
-
-/* Literal.String.Delimiter */
-
-.highlight .sd {
- color: #e6db74
-}
-
-
-/* Literal.String.Doc */
-
-.highlight .s2 {
- color: #e6db74
-}
-
-
-/* Literal.String.Double */
-
-.highlight .se {
- color: #ae81ff
-}
-
-
-/* Literal.String.Escape */
-
-.highlight .sh {
- color: #e6db74
-}
-
-
-/* Literal.String.Heredoc */
-
-.highlight .si {
- color: #e6db74
-}
-
-
-/* Literal.String.Interpol */
-
-.highlight .sx {
- color: #e6db74
-}
-
-
-/* Literal.String.Other */
-
-.highlight .sr {
- color: #e6db74
-}
-
-
-/* Literal.String.Regex */
-
-.highlight .s1 {
- color: #e6db74
-}
-
-
-/* Literal.String.Single */
-
-.highlight .ss {
- color: #e6db74
-}
-
-
-/* Literal.String.Symbol */
-
-.highlight .bp {
- color: #f8f8f2
-}
-
-
-/* Name.Builtin.Pseudo */
-
-.highlight .fm {
- color: #a6e22e
-}
-
-
-/* Name.Function.Magic */
-
-.highlight .vc {
- color: #f8f8f2
-}
-
-
-/* Name.Variable.Class */
-
-.highlight .vg {
- color: #f8f8f2
-}
-
-
-/* Name.Variable.Global */
-
-.highlight .vi {
- color: #f8f8f2
-}
-
-
-/* Name.Variable.Instance */
-
-.highlight .vm {
- color: #f8f8f2
-}
-
-
-/* Name.Variable.Magic */
-
-.highlight .il {
- color: #ae81ff
-}
-
-
-/* Literal.Number.Integer.Long */
-
-
-/* Link to Remix IDE shown over code snippets */
-a.remix-link {
- filter: invert(1); /* The icon is black. In dark mode we want it white. */
-}
diff --git a/docs/_static/css/fonts.css b/docs/_static/css/fonts.css
new file mode 100644
index 0000000000..1a987a6da1
--- /dev/null
+++ b/docs/_static/css/fonts.css
@@ -0,0 +1,2 @@
+@import url("https://fonts.cdnfonts.com/css/overpass");
+@import url("https://fonts.cdnfonts.com/css/overpass-mono");
\ No newline at end of file
diff --git a/docs/_static/css/pygments.css b/docs/_static/css/pygments.css
new file mode 100644
index 0000000000..0e640681de
--- /dev/null
+++ b/docs/_static/css/pygments.css
@@ -0,0 +1,399 @@
+pre {
+ line-height: 125%;
+}
+
+td.linenos .normal {
+ color: inherit;
+ background-color: transparent;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+span.linenos {
+ color: inherit;
+ background-color: transparent;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+td.linenos .special {
+ color: #000000;
+ background-color: #ffffc0;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+span.linenos.special {
+ color: #000000;
+ background-color: #ffffc0;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.highlight .hll {
+ background-color: #ffffcc
+}
+
+.highlight {
+ background: #eeffcc;
+}
+
+.highlight .c {
+ color: #408090;
+ font-style: italic
+}
+
+/* Comment */
+.highlight .err {
+ border: 1px solid #FF0000
+}
+
+/* Error */
+.highlight .k {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Keyword */
+.highlight .o {
+ color: #666666
+}
+
+/* Operator */
+.highlight .ch {
+ color: #408090;
+ font-style: italic
+}
+
+/* Comment.Hashbang */
+.highlight .cm {
+ color: #408090;
+ font-style: italic
+}
+
+/* Comment.Multiline */
+.highlight .cp {
+ color: #007020
+}
+
+/* Comment.Preproc */
+.highlight .cpf {
+ color: #408090;
+ font-style: italic
+}
+
+/* Comment.PreprocFile */
+.highlight .c1 {
+ color: #408090;
+ font-style: italic
+}
+
+/* Comment.Single */
+.highlight .cs {
+ color: #408090;
+ background-color: #fff0f0
+}
+
+/* Comment.Special */
+.highlight .gd {
+ color: #A00000
+}
+
+/* Generic.Deleted */
+.highlight .ge {
+ font-style: italic
+}
+
+/* Generic.Emph */
+.highlight .gr {
+ color: #FF0000
+}
+
+/* Generic.Error */
+.highlight .gh {
+ color: #000080;
+ font-weight: bold
+}
+
+/* Generic.Heading */
+.highlight .gi {
+ color: #00A000
+}
+
+/* Generic.Inserted */
+.highlight .go {
+ color: #333333
+}
+
+/* Generic.Output */
+.highlight .gp {
+ color: #c65d09;
+ font-weight: bold
+}
+
+/* Generic.Prompt */
+.highlight .gs {
+ font-weight: bold
+}
+
+/* Generic.Strong */
+.highlight .gu {
+ color: #800080;
+ font-weight: bold
+}
+
+/* Generic.Subheading */
+.highlight .gt {
+ color: #0044DD
+}
+
+/* Generic.Traceback */
+.highlight .kc {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Keyword.Constant */
+.highlight .kd {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Keyword.Declaration */
+.highlight .kn {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Keyword.Namespace */
+.highlight .kp {
+ color: #007020
+}
+
+/* Keyword.Pseudo */
+.highlight .kr {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Keyword.Reserved */
+.highlight .kt {
+ color: #902000
+}
+
+/* Keyword.Type */
+.highlight .m {
+ color: #208050
+}
+
+/* Literal.Number */
+.highlight .s {
+ color: #4070a0
+}
+
+/* Literal.String */
+.highlight .na {
+ color: #4070a0
+}
+
+/* Name.Attribute */
+.highlight .nb {
+ color: #007020
+}
+
+/* Name.Builtin */
+.highlight .nc {
+ color: #0e84b5;
+ font-weight: bold
+}
+
+/* Name.Class */
+.highlight .no {
+ color: #60add5
+}
+
+/* Name.Constant */
+.highlight .nd {
+ color: #555555;
+ font-weight: bold
+}
+
+/* Name.Decorator */
+.highlight .ni {
+ color: #d55537;
+ font-weight: bold
+}
+
+/* Name.Entity */
+.highlight .ne {
+ color: #007020
+}
+
+/* Name.Exception */
+.highlight .nf {
+ color: #06287e
+}
+
+/* Name.Function */
+.highlight .nl {
+ color: #002070;
+ font-weight: bold
+}
+
+/* Name.Label */
+.highlight .nn {
+ color: #0e84b5;
+ font-weight: bold
+}
+
+/* Name.Namespace */
+.highlight .nt {
+ color: #062873;
+ font-weight: bold
+}
+
+/* Name.Tag */
+.highlight .nv {
+ color: #bb60d5
+}
+
+/* Name.Variable */
+.highlight .ow {
+ color: #007020;
+ font-weight: bold
+}
+
+/* Operator.Word */
+.highlight .w {
+ color: #bbbbbb
+}
+
+/* Text.Whitespace */
+.highlight .mb {
+ color: #208050
+}
+
+/* Literal.Number.Bin */
+.highlight .mf {
+ color: #208050
+}
+
+/* Literal.Number.Float */
+.highlight .mh {
+ color: #208050
+}
+
+/* Literal.Number.Hex */
+.highlight .mi {
+ color: #208050
+}
+
+/* Literal.Number.Integer */
+.highlight .mo {
+ color: #208050
+}
+
+/* Literal.Number.Oct */
+.highlight .sa {
+ color: #4070a0
+}
+
+/* Literal.String.Affix */
+.highlight .sb {
+ color: #4070a0
+}
+
+/* Literal.String.Backtick */
+.highlight .sc {
+ color: #4070a0
+}
+
+/* Literal.String.Char */
+.highlight .dl {
+ color: #4070a0
+}
+
+/* Literal.String.Delimiter */
+.highlight .sd {
+ color: #4070a0;
+ font-style: italic
+}
+
+/* Literal.String.Doc */
+.highlight .s2 {
+ color: #4070a0
+}
+
+/* Literal.String.Double */
+.highlight .se {
+ color: #4070a0;
+ font-weight: bold
+}
+
+/* Literal.String.Escape */
+.highlight .sh {
+ color: #4070a0
+}
+
+/* Literal.String.Heredoc */
+.highlight .si {
+ color: #70a0d0;
+ font-style: italic
+}
+
+/* Literal.String.Interpol */
+.highlight .sx {
+ color: #c65d09
+}
+
+/* Literal.String.Other */
+.highlight .sr {
+ color: #235388
+}
+
+/* Literal.String.Regex */
+.highlight .s1 {
+ color: #4070a0
+}
+
+/* Literal.String.Single */
+.highlight .ss {
+ color: #517918
+}
+
+/* Literal.String.Symbol */
+.highlight .bp {
+ color: #007020
+}
+
+/* Name.Builtin.Pseudo */
+.highlight .fm {
+ color: #06287e
+}
+
+/* Name.Function.Magic */
+.highlight .vc {
+ color: #bb60d5
+}
+
+/* Name.Variable.Class */
+.highlight .vg {
+ color: #bb60d5
+}
+
+/* Name.Variable.Global */
+.highlight .vi {
+ color: #bb60d5
+}
+
+/* Name.Variable.Instance */
+.highlight .vm {
+ color: #bb60d5
+}
+
+/* Name.Variable.Magic */
+.highlight .il {
+ color: #208050
+}
+
+/* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/docs/_static/css/toggle.css b/docs/_static/css/toggle.css
index add134f6c2..d525ab62a7 100644
--- a/docs/_static/css/toggle.css
+++ b/docs/_static/css/toggle.css
@@ -9,6 +9,13 @@ input[type=checkbox] {
padding: 10px;
display: flex;
justify-content: space-between;
+ background-color: var(--color-f);
+ border-top: 1px solid var(--color-c);
+}
+
+.fa-caret-down,
+.fa-book {
+ color: var(--color-a) !important;
}
.rst-versions .rst-current-version .fa-book,
@@ -76,8 +83,11 @@ html.transition *:after {
transition-delay: 0 !important;
}
-nav.wy-nav-side {
- /* The default padding of 2em is too small and the "Keyword Index" link gets obscured
- * by the version toggle. */
- padding-bottom: 3em;
+.wy-menu-vertical a:hover {
+ background-color: #0002;
}
+
+body {
+ font-weight: 300;
+ letter-spacing: 0.5px;
+}
\ No newline at end of file
diff --git a/docs/_static/img/favicon.ico b/docs/_static/img/favicon.ico
new file mode 100644
index 0000000000..a2b8f877a3
Binary files /dev/null and b/docs/_static/img/favicon.ico differ
diff --git a/docs/_static/img/favicon.png b/docs/_static/img/favicon.png
new file mode 100644
index 0000000000..3991d87e98
Binary files /dev/null and b/docs/_static/img/favicon.png differ
diff --git a/docs/_static/img/hamburger-dark.svg b/docs/_static/img/hamburger-dark.svg
new file mode 100644
index 0000000000..26d9fed9df
--- /dev/null
+++ b/docs/_static/img/hamburger-dark.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/docs/_static/img/hamburger-light.svg b/docs/_static/img/hamburger-light.svg
new file mode 100644
index 0000000000..d5d0d0aed2
--- /dev/null
+++ b/docs/_static/img/hamburger-light.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/docs/_static/img/logo-dark.svg b/docs/_static/img/logo-dark.svg
new file mode 100644
index 0000000000..92a12a9fed
--- /dev/null
+++ b/docs/_static/img/logo-dark.svg
@@ -0,0 +1,8 @@
+
diff --git a/docs/_static/img/logo.svg b/docs/_static/img/logo.svg
new file mode 100644
index 0000000000..19391843b4
--- /dev/null
+++ b/docs/_static/img/logo.svg
@@ -0,0 +1,8 @@
+
diff --git a/docs/_static/img/moon.svg b/docs/_static/img/moon.svg
new file mode 100644
index 0000000000..607dc1b47f
--- /dev/null
+++ b/docs/_static/img/moon.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/docs/_static/img/sun.svg b/docs/_static/img/sun.svg
new file mode 100644
index 0000000000..f86fd22b2d
--- /dev/null
+++ b/docs/_static/img/sun.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/docs/_static/js/constants.js b/docs/_static/js/constants.js
new file mode 100644
index 0000000000..67fa16cdb0
--- /dev/null
+++ b/docs/_static/js/constants.js
@@ -0,0 +1,38 @@
+// Site URL
+const SITE_URL = "https://docs.soliditylang.org"
+const { origin, pathname } = location;
+const pathSplit = pathname.split("/");
+const rootPath = origin.includes(SITE_URL) && pathSplit.length > 3 ? pathSplit.splice(1, 2).join("/") : ''
+const ROOT_URL = `${origin}/${rootPath}`;
+
+// Color mode constants
+const [DARK, LIGHT] = ["dark", "light"];
+const LIGHT_LOGO_PATH = `${ROOT_URL}/_static/img/logo.svg`;
+const DARK_LOGO_PATH = `${ROOT_URL}/_static/img/logo-dark.svg`;
+const SUN_ICON_PATH = `${ROOT_URL}/_static/img/sun.svg`;
+const MOON_ICON_PATH = `${ROOT_URL}/_static/img/moon.svg`;
+const LIGHT_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-light.svg`;
+const DARK_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-dark.svg`;
+const COLOR_TOGGLE_ICON_CLASS = "color-toggle-icon";
+const SOLIDITY_LOGO_CLASS = "solidity-logo";
+const LS_COLOR_SCHEME = "color-scheme";
+
+// Solidity navigation constants
+const SOLIDITY_HOME_URL = "https://soliditylang.org";
+const BLOG_URL = `${SOLIDITY_HOME_URL}/blog`;
+const DOCS_URL = "/";
+const USE_CASES_PATH = `${SOLIDITY_HOME_URL}/use-cases`;
+const CONTRIBUTE_PATH = `/en/latest/contributing.html`;
+const ABOUT_PATH = `${SOLIDITY_HOME_URL}/about`;
+const FORUM_URL = "https://forum.soliditylang.org/";
+const NAV_LINKS = [
+ { name: "Blog", href: BLOG_URL },
+ { name: "Documentation", href: DOCS_URL },
+ { name: "Use cases", href: USE_CASES_PATH },
+ { name: "Contribute", href: CONTRIBUTE_PATH },
+ { name: "About", href: ABOUT_PATH },
+ { name: "Forum", href: FORUM_URL },
+];
+
+const MOBILE_MENU_TOGGLE_CLASS = "shift";
+const WRAPPER_CLASS = "unified-wrapper";
diff --git a/docs/_static/js/initialize.js b/docs/_static/js/initialize.js
new file mode 100644
index 0000000000..1c3be8aadd
--- /dev/null
+++ b/docs/_static/js/initialize.js
@@ -0,0 +1,265 @@
+const getLogoSrc = (isDark) => (isDark ? DARK_LOGO_PATH : LIGHT_LOGO_PATH);
+
+const getModeIconSrc = (isDark) => (isDark ? SUN_ICON_PATH : MOON_ICON_PATH);
+
+const getMenuIconSrc = (isDark) =>
+ isDark ? DARK_HAMBURGER_PATH : LIGHT_HAMBURGER_PATH;
+
+function addFooterNote() {
+ const contentInfo = document.querySelector("div[role=contentinfo]");
+ const footerNote = document.createElement("p");
+ footerNote.classList.add("footer-note");
+ footerNote.innerHTML =
+ 'Customized with ❤️ by the ethereum.org team.';
+ contentInfo.parentNode.insertBefore(footerNote, contentInfo.nextSibling);
+}
+
+function rearrangeDom() {
+ const bodyDivs = document.querySelectorAll("body>div");
+ bodyDivs.forEach((div) => div.remove());
+ const wrapperDiv = document.createElement("div");
+ wrapperDiv.classList.add(WRAPPER_CLASS);
+ bodyDivs.forEach((div) => wrapperDiv.appendChild(div));
+ document.body.prepend(wrapperDiv);
+
+ const rstVersions = document.querySelector(".rst-versions");
+ const wyNavSide = document.querySelector("nav.wy-nav-side");
+ // NOTE: Since RTD migration to addons, `.rst-versions` is no longer present in the DOM.
+ // The following code is kept for compatibility with older versions.
+ // See: https://github.com/readthedocs/readthedocs.org/issues/11474
+ if (rstVersions && wyNavSide) {
+ rstVersions.remove();
+ wyNavSide.appendChild(rstVersions);
+ }
+ const backdrop = document.createElement("div");
+ backdrop.classList.add("backdrop");
+ wrapperDiv.appendChild(backdrop);
+
+ const content = document.querySelector(".wy-nav-content");
+ if (content) {
+ content.id = "content";
+ document.querySelector("section.wy-nav-content-wrap")?.remove();
+ document.querySelector(".wy-grid-for-nav")?.appendChild(content);
+ }
+}
+
+function buildHeader() {
+ const isDarkMode = localStorage.getItem(LS_COLOR_SCHEME) == DARK;
+
+ const header = document.createElement("div");
+ header.classList.add("unified-header");
+ document.querySelector(`.${WRAPPER_CLASS}`).prepend(header);
+
+ const innerHeader = document.createElement("div");
+ innerHeader.classList.add("inner-header");
+ header.appendChild(innerHeader);
+
+ const homeLink = document.createElement("a");
+ homeLink.classList.add("home-link");
+ homeLink.href = SOLIDITY_HOME_URL;
+ homeLink.ariaLabel = "Solidity home";
+ innerHeader.appendChild(homeLink);
+
+ const logo = document.createElement("img");
+ logo.classList.add(SOLIDITY_LOGO_CLASS);
+ logo.src = getLogoSrc(isDarkMode);
+ logo.alt = "Solidity logo";
+ homeLink.appendChild(logo);
+
+ const skipToContent = document.createElement("a");
+ skipToContent.classList.add("skip-to-content");
+ skipToContent.href = "#content";
+ skipToContent.innerText = "{skip to content}";
+ innerHeader.appendChild(skipToContent);
+
+ const navBar = document.createElement("nav");
+ navBar.classList.add("nav-bar");
+ innerHeader.appendChild(navBar);
+
+ const linkElements = NAV_LINKS.map(({ name, href }) => {
+ const link = document.createElement("a");
+ link.classList.add("nav-link");
+ link.setAttribute("key", name);
+ link.setAttribute("href", href);
+ link.setAttribute("aria-label", name);
+ if (href === FORUM_URL) {
+ link.classList.add("forum-link");
+ link.setAttribute("target", "_blank");
+ link.setAttribute("rel", "noopener noreferrer");
+ }
+ link.innerText = name;
+ return link;
+ });
+ linkElements.forEach((link) => navBar.appendChild(link));
+
+ // Flex wrapper for color mode and mobile menu buttons
+ const navButtonContainer = document.createElement("div");
+ navButtonContainer.classList.add("nav-button-container");
+ navBar.appendChild(navButtonContainer);
+
+ // Build color toggle
+ const toggleIcon = document.createElement("img");
+ toggleIcon.classList.add(COLOR_TOGGLE_ICON_CLASS);
+ toggleIcon.src = getModeIconSrc(isDarkMode);
+ toggleIcon.alt = "Color mode toggle icon";
+ toggleIcon.setAttribute("aria-hidden", "true");
+ toggleIcon.setAttribute("key", "toggle icon");
+ const colorModeButton = document.createElement("button");
+ colorModeButton.classList.add("color-toggle");
+ colorModeButton.setAttribute("type", "button");
+ colorModeButton.setAttribute("aria-label", "Toggle light dark mode");
+ colorModeButton.setAttribute("key", "color mode button");
+ colorModeButton.addEventListener("click", toggleColorMode);
+ colorModeButton.appendChild(toggleIcon);
+ navButtonContainer.appendChild(colorModeButton);
+
+ // Build mobile hamburger menu
+ const menuIcon = document.createElement("img");
+ menuIcon.classList.add(COLOR_TOGGLE_ICON_CLASS);
+ menuIcon.src = getMenuIconSrc(isDarkMode);
+ menuIcon.alt = "Toggle menu";
+ menuIcon.setAttribute("aria-hidden", "true");
+ menuIcon.setAttribute("key", "menu icon");
+ const menuButton = document.createElement("button");
+ menuButton.classList.add("color-toggle");
+ menuButton.classList.add("mobile-menu-button");
+ menuButton.setAttribute("type", "button");
+ menuButton.setAttribute("aria-label", "Toggle menu");
+ menuButton.setAttribute("key", "menu button");
+ menuButton.addEventListener("click", toggleMenu);
+ menuButton.appendChild(menuIcon);
+ navButtonContainer.appendChild(menuButton);
+}
+
+const updateActiveNavLink = () => {
+ const navLinks = document.querySelectorAll(".unified-header .nav-link");
+ navLinks.forEach((link) => {
+ const href = link.getAttribute("href");
+ if (document.documentURI.includes("contributing.html")) {
+ link.classList[href.includes("contributing.html") ? "add" : "remove"](
+ "active"
+ );
+ } else {
+ link.classList[document.documentURI.includes(href) ? "add" : "remove"](
+ "active"
+ );
+ }
+ });
+};
+
+document.addEventListener("locationchange", updateActiveNavLink);
+
+function updateGitHubEditPath() {
+ // Replaces the version number in the GitHub edit path with "develop" if it exists.
+ // This is to ensure that the edit path always points to the `develop` branch instead of the specific version branch.
+ // Note that it will fail silently if the anchor element is not found, i.e. the page is not editable or
+ // if the sphinx_rtd_theme is updated to a version that changes the anchor element.
+ // See: https://github.com/readthedocs/sphinx_rtd_theme/blob/a1c2147b17cbf0e57b7d7a6450ad4d9a5ff362cf/sphinx_rtd_theme/breadcrumbs.html#L35
+ // TODO: We should consider a more robust way to handle this in the future.
+ const gitHubEditAnchor = document.querySelector(".wy-breadcrumbs-aside > a");
+ if (!gitHubEditAnchor) return;
+
+ const url = new URL(gitHubEditAnchor.href);
+ const split = url.pathname.split("/");
+ const versionIndex = split.indexOf("blob") + 1;
+ split[versionIndex] = "develop";
+ url.pathname = split.join("/");
+ gitHubEditAnchor.setAttribute("href", url.toString());
+ gitHubEditAnchor.setAttribute("target", "_blank");
+ gitHubEditAnchor.setAttribute("rel", "noopener noreferrer");
+}
+
+function initialize() {
+ // Rearrange DOM elements for styling
+ rearrangeDom();
+
+ // Check localStorage for existing color scheme preference
+ var prefersDark = localStorage.getItem(LS_COLOR_SCHEME) == DARK;
+ // Check link for search param "color"... it may be "light" or "dark"
+ var urlParams = new URLSearchParams(window.location.search);
+ if (urlParams.size > 0) {
+ // This is used for color mode continuity between the main Solidity Lang site and the docs
+ var colorSchemeParam = urlParams.get("color");
+ // If present, overwrite prefersDark accordingly
+ if (colorSchemeParam) {
+ prefersDark = colorSchemeParam == DARK;
+ }
+
+ // Remove "color" search param from URL
+ const { location, title } = document;
+ const { pathname, origin, search, hash } = location;
+ const newSearchParams = new URLSearchParams(search);
+ newSearchParams.delete("color");
+ const sanitizedSearch =
+ newSearchParams.size < 1 ? "" : "?" + newSearchParams.toString();
+ window.history.replaceState(
+ origin,
+ title,
+ pathname + sanitizedSearch + hash
+ );
+ }
+
+ // In case none existed, establish localStorage color scheme preference
+ var mode = prefersDark ? DARK : LIGHT;
+ localStorage.setItem(LS_COLOR_SCHEME, mode);
+
+ // Select the root element and set the style attribute to denote color-scheme attribute
+ document
+ .querySelector(":root")
+ .setAttribute("style", `--color-scheme: ${mode}`);
+
+ // NOTE: Since RTD migration to addons, the elements below are no longer present in the DOM.
+ // The following code is kept for compatibility with older versions.
+ // Remove old input and RTD logo anchor element
+ document.querySelector("input[name=mode]")?.remove();
+ document.querySelector("label[for=switch]")?.remove();
+ document.querySelector(".wy-side-nav-search > a")?.remove();
+
+ // Add footer note
+ addFooterNote();
+
+ // Build header
+ buildHeader();
+
+ // Close menu
+ toggleMenu({ force: false });
+
+ // Update active nav link
+ updateActiveNavLink();
+
+ // Update GitHub edit path to direct to `develop` branch
+ updateGitHubEditPath();
+}
+
+document.addEventListener("DOMContentLoaded", initialize);
+
+const handleClick = (e) => {
+ if (e.target.closest(".backdrop")) {
+ toggleMenu({ force: false });
+ }
+
+ if (e.target.closest("a")) {
+ const target = e.target.closest("a");
+ const href = target.getAttribute("href");
+ if (href.includes(SOLIDITY_HOME_URL)) {
+ const url = new URL(href);
+ const params = new URLSearchParams(url.search);
+ params.set("color", localStorage.getItem(LS_COLOR_SCHEME));
+ url.search = params.toString();
+ target.setAttribute("href", url.toString());
+ }
+ }
+};
+document.addEventListener("click", handleClick);
+
+const handleKeyDown = (e) => {
+ if (e.metaKey && e.key === "k") {
+ document.querySelector("#rtd-search-form input")?.focus();
+ } else if (e.key === "Escape") {
+ toggleMenu({ force: false });
+ }
+ if (e.metaKey && e.code === "Backslash") {
+ toggleColorMode();
+ }
+};
+document.addEventListener("keydown", handleKeyDown);
diff --git a/docs/_static/js/toggle.js b/docs/_static/js/toggle.js
index 780ea9ee71..6ea2dd1f80 100644
--- a/docs/_static/js/toggle.js
+++ b/docs/_static/js/toggle.js
@@ -1,39 +1,47 @@
-document.addEventListener('DOMContentLoaded', function() {
+function toggleColorMode() {
+ // Check localStorage for previous color scheme preference, assign the opposite
+ var newMode = localStorage.getItem(LS_COLOR_SCHEME) == DARK ? LIGHT : DARK;
- function toggleCssMode(isDay) {
- var mode = (isDay ? "Day" : "Night");
- localStorage.setItem("css-mode", mode);
+ // Update localStorage with new color scheme preference
+ localStorage.setItem(LS_COLOR_SCHEME, newMode);
- var url_root = DOCUMENTATION_OPTIONS.URL_ROOT == "./" ? "" : DOCUMENTATION_OPTIONS.URL_ROOT;
- var daysheet = $(`link[href="${url_root}_static/pygments.css"]`)[0].sheet;
- daysheet.disabled = !isDay;
+ // Update the root element with the new color scheme preference
+ document
+ .querySelector(":root")
+ .setAttribute("style", `--color-scheme: ${newMode}`);
- var nightsheet = $(`link[href="${url_root}_static/css/dark.css"]`)[0];
- if (!isDay && nightsheet === undefined) {
- var element = document.createElement("link");
- element.setAttribute("rel", "stylesheet");
- element.setAttribute("type", "text/css");
- element.setAttribute("href", `${url_root}_static/css/dark.css`);
- document.getElementsByTagName("head")[0].appendChild(element);
- return;
- }
- if (nightsheet !== undefined) {
- nightsheet.sheet.disabled = isDay;
- }
- }
-
- var initial = localStorage.getItem("css-mode") != "Night";
- var checkbox = document.querySelector('input[name=mode]');
+ // Update logo
+ document
+ .querySelector(`img.${SOLIDITY_LOGO_CLASS}`)
+ .setAttribute("src", newMode === LIGHT ? LIGHT_LOGO_PATH : DARK_LOGO_PATH);
- toggleCssMode(initial);
- checkbox.checked = initial;
+ // Update color mode toggle icon
+ document
+ .querySelector(`img.${COLOR_TOGGLE_ICON_CLASS}`)
+ .setAttribute("src", newMode === LIGHT ? MOON_ICON_PATH : SUN_ICON_PATH);
- checkbox.addEventListener('change', function() {
- document.documentElement.classList.add('transition');
- window.setTimeout(() => {
- document.documentElement.classList.remove('transition');
- }, 1000)
- toggleCssMode(this.checked);
- })
+ // Update hamburger menu icon color
+ document
+ .querySelector("button.mobile-menu-button img")
+ .setAttribute(
+ "src",
+ newMode === LIGHT ? LIGHT_HAMBURGER_PATH : DARK_HAMBURGER_PATH
+ );
+}
-});
\ No newline at end of file
+function toggleMenu(options = {}) {
+ const handleClassToggle = ({ classList }, className) => {
+ if (typeof options.force !== "undefined") {
+ classList.toggle(className, options.force);
+ } else {
+ classList.toggle(className);
+ }
+ };
+ document
+ .querySelectorAll('[data-toggle="rst-versions"]')
+ .forEach((e) => handleClassToggle(e, MOBILE_MENU_TOGGLE_CLASS));
+ document
+ .querySelectorAll('[data-toggle="wy-nav-shift"]')
+ .forEach((e) => handleClassToggle(e, MOBILE_MENU_TOGGLE_CLASS));
+ handleClassToggle(document.querySelector(`.${WRAPPER_CLASS}`), "menu-open");
+}
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 7906d75ffe..91da5127c5 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -16,7 +16,7 @@ as described in this specification. The encoding is not self describing and thus
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.
+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 `.
.. _abi_function_selector:
.. index:: ! selector; of a function
@@ -47,6 +47,8 @@ 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 ` for details.
+
The following elementary types exist:
- ``uint``: unsigned integer type of ``M`` bits, ``0 < M <= 256``, ``M % 8 == 0``. e.g. ``uint32``, ``uint8``, ``uint256``.
@@ -252,7 +254,21 @@ Given the contract:
}
-Thus, for our ``Foo`` example if we wanted to call ``baz`` with the parameters ``69`` and
+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
+
+ 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
@@ -271,20 +287,6 @@ In total:
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 ``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
-
- 0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000
-
If we wanted to call ``sam`` with the arguments ``"dave"``, ``true`` and ``[1,2,3]``, we would
pass 292 bytes total, broken down into:
@@ -311,7 +313,7 @@ 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 ``sha3("f(uint256,uint32[],bytes10,bytes)")``, i.e. ``0x8be65246``.
+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
@@ -563,7 +565,7 @@ A function description is a JSON object with the fields:
blockchain state `), ``view`` (:ref:`specified to not modify the blockchain
state `), ``nonpayable`` (function does not accept Ether - the default) and ``payable`` (function accepts Ether).
-Constructor and fallback function never have ``name`` or ``outputs``. Fallback function doesn't have ``inputs`` either.
+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.
@@ -581,7 +583,7 @@ An event description is a JSON object with fairly similar fields:
* ``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 one of the log's data segment.
+ * ``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``.
diff --git a/docs/analysing-compilation-output.rst b/docs/analysing-compilation-output.rst
index 892b18b957..183f773223 100644
--- a/docs/analysing-compilation-output.rst
+++ b/docs/analysing-compilation-output.rst
@@ -11,7 +11,7 @@ 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
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
diff --git a/docs/assembly.rst b/docs/assembly.rst
index b527ffbafd..a0a9d06dc7 100644
--- a/docs/assembly.rst
+++ b/docs/assembly.rst
@@ -9,7 +9,8 @@ Inline Assembly
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.
+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 `
and it is documented in its own section. This section will only cover
@@ -162,7 +163,7 @@ their calldata offset (in bytes) and length (number of elements) using ``x.offse
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, a single Yul identifier
+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
@@ -180,15 +181,18 @@ Local Solidity variables are available for assignments, for example:
:force:
// SPDX-License-Identifier: GPL-3.0
- pragma solidity >=0.7.0 <0.9.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 view returns (uint r) {
+ 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)
}
}
}
@@ -362,7 +366,7 @@ in memory is automatically considered memory-safe and does not need to be annota
.. 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 behaviour that cannot easily be discovered by testing.
+ 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:
@@ -375,4 +379,25 @@ of Solidity, you can use a special comment to annotate an assembly block as memo
}
Note that we will disallow the annotation via comment in a future breaking release; so, if you are not concerned with
-backwards-compatibility with older compiler versions, prefer using the dialect string.
+backward-compatibility with older compiler versions, prefer using the dialect string.
+
+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).
diff --git a/docs/brand-guide.rst b/docs/brand-guide.rst
index 5601b16a8e..cf471c5e3c 100644
--- a/docs/brand-guide.rst
+++ b/docs/brand-guide.rst
@@ -67,7 +67,7 @@ When using the Solidity logo, please respect the Solidity logo guidelines.
Solidity Logo Guidelines
========================
-.. image:: logo.svg
+.. image:: solidity_logo.svg
:width: 256
*(Right click on the logo to download it.)*
diff --git a/docs/bugs.json b/docs/bugs.json
index 9c9780c935..c853f95edd 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -1,4 +1,40 @@
[
+ {
+ "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",
diff --git a/docs/bugs.rst b/docs/bugs.rst
index 75a23e4999..f7f18e9a7f 100644
--- a/docs/bugs.rst
+++ b/docs/bugs.rst
@@ -7,7 +7,7 @@ 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
+Solidity compiler. The file itself is hosted in the `GitHub repository
`_.
The list stretches back as far as version 0.3.0, bugs known to be present only
in versions preceding that are not listed.
@@ -68,7 +68,7 @@ conditions
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
+ 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
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index 4e7bca56b3..2c3b6487ae 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -1422,6 +1422,8 @@
},
"0.6.10": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1436,6 +1438,8 @@
},
"0.6.11": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1450,6 +1454,8 @@
},
"0.6.12": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1464,6 +1470,7 @@
},
"0.6.2": {
"bugs": [
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1481,6 +1488,7 @@
},
"0.6.3": {
"bugs": [
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1498,6 +1506,7 @@
},
"0.6.4": {
"bugs": [
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1515,6 +1524,7 @@
},
"0.6.5": {
"bugs": [
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1532,6 +1542,7 @@
},
"0.6.6": {
"bugs": [
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1548,6 +1559,8 @@
},
"0.6.7": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1564,6 +1577,8 @@
},
"0.6.8": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"NestedCalldataArrayAbiReencodingSizeValidation",
@@ -1577,6 +1592,8 @@
},
"0.6.9": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1592,6 +1609,8 @@
},
"0.7.0": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1606,6 +1625,8 @@
},
"0.7.1": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1621,6 +1642,8 @@
},
"0.7.2": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1635,6 +1658,8 @@
},
"0.7.3": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1648,6 +1673,8 @@
},
"0.7.4": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1660,6 +1687,8 @@
},
"0.7.5": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1672,6 +1701,8 @@
},
"0.7.6": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1684,6 +1715,8 @@
},
"0.8.0": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1696,6 +1729,8 @@
},
"0.8.1": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1708,6 +1743,9 @@
},
"0.8.10": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1717,6 +1755,9 @@
},
"0.8.11": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1727,6 +1768,9 @@
},
"0.8.12": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1737,6 +1781,9 @@
},
"0.8.13": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
@@ -1748,6 +1795,9 @@
},
"0.8.14": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
@@ -1757,6 +1807,9 @@
},
"0.8.15": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination",
"AbiReencodingHeadOverflowWithStaticArrayCleanup"
],
@@ -1764,16 +1817,41 @@
},
"0.8.16": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"StorageWriteRemovalBeforeConditionalTermination"
],
"released": "2022-08-08"
},
"0.8.17": {
- "bugs": [],
+ "bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess"
+ ],
"released": "2022-09-08"
},
+ "0.8.18": {
+ "bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess"
+ ],
+ "released": "2023-02-01"
+ },
+ "0.8.19": {
+ "bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess"
+ ],
+ "released": "2023-02-22"
+ },
"0.8.2": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1784,8 +1862,54 @@
],
"released": "2021-03-02"
},
+ "0.8.20": {
+ "bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess"
+ ],
+ "released": "2023-05-10"
+ },
+ "0.8.21": {
+ "bugs": [
+ "VerbatimInvalidDeduplication"
+ ],
+ "released": "2023-07-19"
+ },
+ "0.8.22": {
+ "bugs": [
+ "VerbatimInvalidDeduplication"
+ ],
+ "released": "2023-10-25"
+ },
+ "0.8.23": {
+ "bugs": [],
+ "released": "2023-11-08"
+ },
+ "0.8.24": {
+ "bugs": [],
+ "released": "2024-01-25"
+ },
+ "0.8.25": {
+ "bugs": [],
+ "released": "2024-03-14"
+ },
+ "0.8.26": {
+ "bugs": [],
+ "released": "2024-05-21"
+ },
+ "0.8.27": {
+ "bugs": [],
+ "released": "2024-09-04"
+ },
+ "0.8.28": {
+ "bugs": [],
+ "released": "2024-10-09"
+ },
"0.8.3": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1797,6 +1921,8 @@
},
"0.8.4": {
"bugs": [
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1807,6 +1933,9 @@
},
"0.8.5": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1817,6 +1946,9 @@
},
"0.8.6": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1827,6 +1959,9 @@
},
"0.8.7": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1837,6 +1972,9 @@
},
"0.8.8": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
@@ -1848,6 +1986,9 @@
},
"0.8.9": {
"bugs": [
+ "VerbatimInvalidDeduplication",
+ "FullInlinerNonExpressionSplitArgumentEvaluationOrder",
+ "MissingSideEffectsOnSelectorAccess",
"AbiReencodingHeadOverflowWithStaticArrayCleanup",
"DirtyBytesArrayToStorage",
"DataLocationChangeInInternalOverride",
diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst
index 412678953e..79aa6e65d5 100644
--- a/docs/cheatsheet.rst
+++ b/docs/cheatsheet.rst
@@ -2,16 +2,17 @@
Cheatsheet
**********
-.. index:: operator; precedence
+.. index:: operator;precedence
Order of Precedence of Operators
================================
+
.. include:: types/operator-precedence-table.rst
-.. index:: assert, block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, codehash, send
+.. index:: abi;decode, abi;encode, abi;encodePacked, abi;encodeWithSelector, abi;encodeCall, abi;encodeWithSignature
-Global Variables
-================
+ABI Encoding and Decoding Functions
+===================================
- ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI `-decodes
the provided data. The types are given in parentheses as second argument.
@@ -22,19 +23,58 @@ Global Variables
- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: :ref:`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, (...))``
+ 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`
+
+.. index:: address;balance, address;codehash, address;send, address;code, address;transfer
+
+Members of ``address``
+======================
+
+- ``.balance`` (``uint256``): balance of the :ref:`address` in Wei
+- ``.code`` (``bytes memory``): code at the :ref:`address` (can be empty)
+- ``.codehash`` (``bytes32``): the codehash of the :ref:`address`
+- ``.call(bytes memory) returns (bool, bytes memory)``: issue low-level ``CALL`` with the given payload,
+ returns success condition and return data
+- ``.delegatecall(bytes memory) returns (bool, bytes memory)``: issue low-level ``DELEGATECALL`` with the given payload,
+ returns success condition and return data
+- ``.staticcall(bytes memory) returns (bool, bytes memory)``: issue low-level ``STATICCALL`` with the given payload,
+ returns success condition and return data
+- ``.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`,
+ returns ``false`` on failure
+- ``.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
+
+.. index:: blockhash, blobhash, block, block;basefee, block;blobbasefee, block;chainid, block;coinbase, block;difficulty, block;gaslimit, block;number, block;prevrandao, 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 `_).
+ Returns zero if no blob with the given index exists.
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 `_ and `EIP-1559 `_)
+- ``block.blobbasefee`` (``uint``): current block's blob base fee (`EIP-7516 `_ and `EIP-4844 `_)
- ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address
-- ``block.difficulty`` (``uint``): current block difficulty
+- ``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 `_ )
- ``block.timestamp`` (``uint``): current block timestamp in seconds since Unix epoch
- ``gasleft() returns (uint256)``: remaining gas
- ``msg.data`` (``bytes``): complete calldata
@@ -43,6 +83,12 @@ Global Variables
- ``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)
@@ -50,7 +96,12 @@ Global Variables
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
-- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks
+
+.. index:: cryptography, keccak256, sha256, ripemd160, ecrecover, addmod, mulmod
+
+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
@@ -60,15 +111,21 @@ Global Variables
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.
+
+.. index:: this, super, selfdestruct
+
+Contract-related
+================
+
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address`` or ``address payable``
-- ``super``: the contract one level higher in the inheritance hierarchy
-- ``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given address
-- ``.balance`` (``uint256``): balance of the :ref:`address` in Wei
-- ``.code`` (``bytes memory``): code at the :ref:`address` (can be empty)
-- ``.codehash`` (``bytes32``): the codehash of the :ref:`address`
-- ``.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`,
- returns ``false`` on failure
-- ``.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
+- ``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`.
- ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`.
@@ -103,12 +160,12 @@ 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 initialisation), does not occupy storage slot.
-- ``immutable`` for state variables: Allows exactly one assignment at construction time and is constant afterwards. Is stored in code.
+- ``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
- behaviour to be changed in derived contracts.
+ behavior to be changed in derived contracts.
- ``override``: States that this function, modifier or public state variable changes
- the behaviour of a function or modifier in a base contract.
+ the behavior of a function or modifier in a base contract.
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index 1793ebd2f2..cbc219b53b 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -18,7 +18,7 @@ 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 money to the
+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 `_.
@@ -34,7 +34,7 @@ you receive the funds of the person who is now the richest.
address public richest;
uint public mostSent;
- mapping (address => uint) pendingWithdrawals;
+ mapping(address => uint) pendingWithdrawals;
/// The amount of Ether sent was not higher than
/// the currently highest amount.
@@ -55,7 +55,7 @@ you receive the funds of the person who is now the richest.
function withdraw() public {
uint amount = pendingWithdrawals[msg.sender];
// Remember to zero the pending refund before
- // sending to prevent re-entrancy attacks
+ // sending to prevent reentrancy attacks
pendingWithdrawals[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
diff --git a/docs/conf.py b/docs/conf.py
index 10aa406f28..f57a3b5b90 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -31,10 +31,60 @@ def setup(sphinx):
sphinx.add_lexer('Solidity', SolidityLexer)
sphinx.add_lexer('Yul', YulLexer)
+ sphinx.add_css_file('css/fonts.css')
sphinx.add_css_file('css/custom.css')
+ sphinx.add_css_file('css/custom-dark.css')
+ sphinx.add_css_file('css/pygments.css')
+
+# -- RTD GitHub configuration ---------------------------------------------
+
+# Taken from:
+# https://github.com/readthedocs/readthedocs.org/blob/e366e7fc8649fbcf1b6d06ecc12c5f7766144c46/readthedocs/projects/constants.py#L350
+GITHUB_REGEXS = [
+ re.compile(r"github.com/(.+)/(.+)(?:\.git){1}$"),
+ # This must come before the one without a / to make sure we don't capture the /
+ re.compile(r"github.com/(.+)/(.+)/"),
+ re.compile(r"github.com/(.+)/(.+)"),
+ re.compile(r"github.com:(.+)/(.+)\.git$"),
+]
-# -- General configuration ------------------------------------------------
+# Taken and adapted from:
+# https://github.com/readthedocs/readthedocs.org/blob/e366e7fc8649fbcf1b6d06ecc12c5f7766144c46/readthedocs/builds/utils.py#L24
+def get_github_username_repo(url):
+ if "github" in url:
+ for regex in GITHUB_REGEXS:
+ match = regex.search(url)
+ if match:
+ return match.groups()
+ return (None, None)
+
+display_github = False
+# NOTE: RTD_DISPLAY_GITHUB, RTD_GITHUB_USER and RTD_GITHUB_REPO are set in the RTD project settings
+github_user = os.getenv("RTD_GITHUB_USER")
+github_repo = os.getenv("RTD_GITHUB_REPO")
+
+if github_user and github_repo:
+ display_github = True
+else:
+ git_clone_url = os.getenv("READTHEDOCS_GIT_CLONE_URL")
+ if git_clone_url:
+ github_user, github_repo = get_github_username_repo(git_clone_url)
+ if github_user and github_repo:
+ display_github = True
+
+display_github_env = os.getenv("RTD_DISPLAY_GITHUB")
+if display_github_env:
+ display_github = display_github_env.lower() == "true"
+
+html_context = {
+ "display_github": display_github,
+ "github_user": github_user,
+ "github_repo": github_repo,
+ "github_version": os.getenv("READTHEDOCS_VERSION", "develop"),
+ "conf_py_path": "/docs/",
+}
+# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
@@ -45,6 +95,7 @@ def setup(sphinx):
'sphinx_a4doc',
'html_extra_template_renderer',
'remix_code_links',
+ 'sphinx.ext.imgconverter',
]
a4_base_path = os.path.dirname(__file__) + '/grammar'
@@ -63,7 +114,7 @@ def setup(sphinx):
# General information about the project.
project = 'Solidity'
-project_copyright = '2016-2021, Ethereum'
+project_copyright = '2016-2024, The Solidity Authors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -131,7 +182,6 @@ def setup(sphinx):
# documentation.
html_theme_options = {
'logo_only': True,
- 'style_nav_header_background': '#65afff',
'display_version': True,
}
@@ -147,12 +197,12 @@ def setup(sphinx):
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-html_logo = "logo.svg"
+# html_logo = "logo.svg"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+html_favicon = "_static/img/favicon.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -161,7 +211,7 @@ def setup(sphinx):
html_css_files = ["css/toggle.css"]
-html_js_files = ["js/toggle.js"]
+html_js_files = ["js/constants.js", "js/initialize.js", "js/toggle.js"]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@@ -209,7 +259,7 @@ def setup(sphinx):
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+html_show_sphinx = False
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
diff --git a/docs/contracts.rst b/docs/contracts.rst
index aee26c95af..588b1da00d 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -20,6 +20,8 @@ There is no "cron" concept in Ethereum to call a function at a particular event
.. include:: contracts/function-modifiers.rst
+.. include:: contracts/transient-storage.rst
+
.. include:: contracts/constant-state-variables.rst
.. include:: contracts/functions.rst
diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst
index 2e94397b12..4e96987354 100644
--- a/docs/contracts/constant-state-variables.rst
+++ b/docs/contracts/constant-state-variables.rst
@@ -13,8 +13,9 @@ for ``immutable``, it can still be assigned at construction time.
It is also possible to define ``constant`` variables at the file level.
-The compiler does not reserve a storage slot for these variables, and every occurrence is
-replaced by the respective value.
+Every occurrence of such a variable in the source is replaced by its underlying value
+and the compiler does not reserve a storage slot for it.
+It cannot be assigned a slot in transient storage using the ``transient`` keyword either.
Compared to regular state variables, the gas costs of constant and immutable variables
are much lower. For a constant variable, the expression assigned to it is copied to
@@ -30,19 +31,23 @@ Not all types for constants and immutables are implemented at this time. The onl
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
- pragma solidity >=0.7.4;
+ pragma solidity ^0.8.21;
uint constant X = 32**22 + 8;
contract C {
string constant TEXT = "abc";
bytes32 constant MY_HASH = keccak256("abc");
- uint immutable decimals;
+ uint immutable decimals = 18;
uint immutable maxBalance;
address immutable owner = msg.sender;
constructor(uint decimals_, address ref) {
- decimals = decimals_;
+ if (decimals_ != 0)
+ // Immutables are only immutable when deployed.
+ // At construction time they can be assigned to any number of times.
+ decimals = decimals_;
+
// Assignments to immutables can even access the environment.
maxBalance = ref.balance;
}
@@ -74,25 +79,34 @@ Immutable
=========
Variables declared as ``immutable`` are a bit less restricted than those
-declared as ``constant``: Immutable variables can be assigned an arbitrary
-value in the constructor of the contract or at the point of their declaration.
-They can be assigned only once and can, from that point on, be read even during
-construction time.
+declared as ``constant``: Immutable variables can be assigned a
+value at construction time.
+The value can be changed at any time before deployment and then it becomes permanent.
+
+One additional restriction is that immutables can only be assigned to inside expressions for which
+there is no possibility of being executed after creation.
+This excludes all modifier definitions and functions other than constructors.
+
+There are no restrictions on reading immutable variables.
+The read is even allowed to happen before the variable is written to for the first time because variables in
+Solidity always have a well-defined initial value.
+For this reason it is also allowed to never explicitly assign a value to an immutable.
+
+.. warning::
+ When accessing immutables at construction time, please keep the :ref:`initialization order
+ ` in mind.
+ Even if you provide an explicit initializer, some expressions may end up being evaluated before
+ that initializer, especially when they are at a different level in inheritance hierarchy.
+
+.. note::
+ Before Solidity 0.8.21 initialization of immutable variables was more restrictive.
+ Such variables had to be initialized exactly once at construction time and could not be read
+ before then.
The contract creation code generated by the compiler will modify the
contract's runtime code before it is returned by replacing all references
to immutables with the values assigned to them. This is important if
you are comparing the
runtime code generated by the compiler with the one actually stored in the
-blockchain.
-
-.. note::
- Immutables that are assigned at their declaration are only considered
- initialized once the constructor of the contract is executing.
- This means you cannot initialize immutables inline with a value
- that depends on another immutable. You can do this, however,
- inside the constructor of the contract.
-
- This is a safeguard against different interpretations about the order
- of state variable initialization and constructor execution, especially
- with regards to inheritance.
+blockchain. The compiler outputs where these immutables are located in the deployed bytecode
+in the ``immutableReferences`` field of the :ref:`compiler JSON standard output `.
diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst
index f574a5a6aa..8eb4e5f56c 100644
--- a/docs/contracts/creating-contracts.rst
+++ b/docs/contracts/creating-contracts.rst
@@ -8,7 +8,7 @@ Contracts can be created "from outside" via Ethereum transactions or from within
IDEs, such as `Remix `_, make the creation process seamless using UI elements.
-One way to create contracts programmatically on Ethereum is via the JavaScript API `web3.js `_.
+One way to create contracts programmatically on Ethereum is via the JavaScript API `web3.js `_.
It has a function called `web3.eth.Contract `_
to facilitate contract creation.
diff --git a/docs/contracts/errors.rst b/docs/contracts/errors.rst
index 19577a3872..d345b4eacf 100644
--- a/docs/contracts/errors.rst
+++ b/docs/contracts/errors.rst
@@ -1,22 +1,25 @@
-.. index:: ! error, revert, ! selector; of an error
+.. index:: ! error, revert, require, ! selector; of an error
.. _errors:
-*******************************
-Errors and the Revert Statement
-*******************************
+*************
+Custom Errors
+*************
Errors in Solidity provide a convenient and gas-efficient way to explain to the
user why an operation failed. They can be defined inside and outside of contracts (including interfaces and libraries).
They have to be used together with the :ref:`revert statement `
-which causes
-all changes in the current call to be reverted and passes the error data back to the
-caller.
+or the :ref:`require function `.
+In the case of ``revert`` statements, or ``require`` calls where the condition is evaluated to be false,
+all changes in the current call are reverted, and the error data passed back to the caller.
+
+The example below shows custom error usage with the ``revert`` statement in function ``transferWithRevertError``,
+as well as the newer approach with ``require`` in function ``transferWithRequireError``.
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
- pragma solidity ^0.8.4;
+ pragma solidity ^0.8.27;
/// Insufficient balance for transfer. Needed `required` but only
/// `available` available.
@@ -26,7 +29,7 @@ caller.
contract TestToken {
mapping(address => uint) balance;
- function transfer(address to, uint256 amount) public {
+ function transferWithRevertError(address to, uint256 amount) public {
if (amount > balance[msg.sender])
revert InsufficientBalance({
available: balance[msg.sender],
@@ -35,12 +38,22 @@ caller.
balance[msg.sender] -= amount;
balance[to] += amount;
}
+ function transferWithRequireError(address to, uint256 amount) public {
+ require(amount <= balance[msg.sender], InsufficientBalance(balance[msg.sender], amount));
+ balance[msg.sender] -= amount;
+ balance[to] += amount;
+ }
// ...
}
+Another important detail to mention when it comes to using ``require`` with custom errors, is that memory
+allocation for the error-based revert reason will only happen in the reverting case, which, along with
+optimization of constants and string literals makes this about as gas-efficient as the
+``if (!condition) revert CustomError(args)`` pattern.
+
Errors cannot be overloaded or overridden but are inherited.
The same error can be defined in multiple places as long as the scopes are distinct.
-Instances of errors can only be created using ``revert`` statements.
+Instances of errors can only be created using ``revert`` statements, or as the second argument to ``require`` functions.
The error creates data that is then passed to the caller with the revert operation
to either return to the off-chain component or catch it in a :ref:`try/catch statement `.
@@ -65,8 +78,7 @@ The selector consists of the first four bytes of the keccak256-hash of the signa
only the name of the error is relevant, not the contract or file where it is defined.
The statement ``require(condition, "description");`` would be equivalent to
-``if (!condition) revert Error("description")`` if you could define
-``error Error(string)``.
+``if (!condition) revert Error("description")`` if you could define ``error Error(string)``.
Note, however, that ``Error`` is a built-in type and cannot be defined in user-supplied code.
Similarly, a failing ``assert`` or similar conditions will revert with an error
diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst
index 8618e7524b..8c73c31603 100644
--- a/docs/contracts/events.rst
+++ b/docs/contracts/events.rst
@@ -9,12 +9,13 @@ Events
Solidity events give an abstraction on top of the EVM's logging functionality.
Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.
-Events are inheritable members of contracts. When you call them, they cause the
+Events can be defined at file level or as inheritable members of contracts (including interfaces and libraries).
+When you call them, they cause the
arguments to be stored in the transaction's log - a special data structure
-in the blockchain. These logs are associated with the address of the contract,
+in the blockchain. These logs are associated with the address of the contract that emitted them,
are incorporated into the blockchain, and stay there as long as a block is
accessible (forever as of now, but this might
-change with Serenity). The Log and its event data is not accessible from within
+change in the future). The Log and its event data is not accessible from within
contracts (not even from the contract that created them).
It is possible to request a Merkle proof for logs, so if
@@ -151,6 +152,6 @@ The output of the above looks like the following (trimmed):
Additional Resources for Understanding Events
=============================================
-- `Javascript documentation `_
+- `JavaScript documentation `_
- `Example usage of events `_
- `How to access them in js `_
diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst
index f231195448..2fd0357db0 100644
--- a/docs/contracts/function-modifiers.rst
+++ b/docs/contracts/function-modifiers.rst
@@ -6,7 +6,7 @@
Function Modifiers
******************
-Modifiers can be used to change the behaviour of functions in a declarative way.
+Modifiers can be used to change the behavior of functions in a declarative way.
For example,
you can use a modifier to automatically check a condition prior to executing the function.
@@ -40,16 +40,6 @@ if they are marked ``virtual``. For details, please see
}
}
- contract destructible is owned {
- // This contract inherits the `onlyOwner` modifier from
- // `owned` and applies it to the `destroy` function, which
- // causes that calls to `destroy` only have an effect if
- // they are made by the stored owner.
- function destroy() public onlyOwner {
- selfdestruct(owner);
- }
- }
-
contract priced {
// Modifiers can receive arguments:
modifier costs(uint price) {
@@ -59,8 +49,8 @@ if they are marked ``virtual``. For details, please see
}
}
- contract Register is priced, destructible {
- mapping (address => bool) registeredAddresses;
+ contract Register is priced, owned {
+ mapping(address => bool) registeredAddresses;
uint price;
constructor(uint initialPrice) { price = initialPrice; }
@@ -72,6 +62,9 @@ if they are marked ``virtual``. For details, please see
registeredAddresses[msg.sender] = true;
}
+ // This contract inherits the `onlyOwner` modifier from
+ // the `owned` contract. As a result, calls to `changePrice` will
+ // only take effect if they are made by the stored owner.
function changePrice(uint price_) public onlyOwner {
price = price_;
}
@@ -131,7 +124,7 @@ variables are set to their :ref:`default values` just as if the f
body.
The ``_`` symbol can appear in the modifier multiple times. Each occurrence is replaced with
-the function body.
+the function body, and the function returns the return value of the final occurrence.
Arbitrary expressions are allowed for modifier arguments and in this context,
all symbols visible from the function are visible in the modifier. Symbols
diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst
index 902ad1ce5a..a3a2755388 100644
--- a/docs/contracts/functions.rst
+++ b/docs/contracts/functions.rst
@@ -1,4 +1,4 @@
-.. index:: ! functions
+.. index:: ! functions, ! function;free
.. _functions:
@@ -174,7 +174,7 @@ Functions can be declared ``view`` in which case they promise not to modify the
The following statements are considered modifying the state:
-#. Writing to state variables.
+#. Writing to state variables (storage and transient storage).
#. :ref:`Emitting events `.
#. :ref:`Creating other contracts `.
#. Using ``selfdestruct``.
@@ -226,7 +226,7 @@ This means that reading from ``immutable`` variables can be a non-pure operation
In addition to the list of state modifying statements explained above, the following are considered reading from the state:
-#. Reading from state variables.
+#. Reading from state variables (storage and transient storage).
#. Accessing ``address(this).balance`` or ``.balance``.
#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``).
#. Calling any function not marked ``pure``.
@@ -250,7 +250,7 @@ Reverting a state change is not considered a "state modification", as only chang
state made previously in code that did not have the ``view`` or ``pure`` restriction
are reverted and that code has the option to catch the ``revert`` and not pass it on.
-This behaviour is also in line with the ``STATICCALL`` opcode.
+This behavior is also in line with the ``STATICCALL`` opcode.
.. warning::
It is not possible to prevent functions from reading the state at the level
@@ -267,7 +267,7 @@ This behaviour is also in line with the ``STATICCALL`` opcode.
.. note::
Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state.
- It is a compile-time type check, which can be circumvented doing invalid explicit conversions
+ It is a compile-time type check, which can be circumvented by doing invalid explicit conversions
between contract types, because the compiler can verify that the type of the contract does
not do state-changing operations, but it cannot check that the contract that will be called
at runtime is actually of that type.
@@ -277,7 +277,7 @@ This behaviour is also in line with the ``STATICCALL`` opcode.
Special Functions
=================
-.. index:: ! receive ether function, function;receive ! receive
+.. index:: ! receive ether function, function;receive, ! receive
.. _receive-ether-function:
diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst
index a33a36d27b..fccfee6095 100644
--- a/docs/contracts/inheritance.rst
+++ b/docs/contracts/inheritance.rst
@@ -41,26 +41,26 @@ Details are given in the following example.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
-
contract Owned {
- constructor() { owner = payable(msg.sender); }
address payable owner;
+ constructor() { owner = payable(msg.sender); }
}
-
// Use `is` to derive from another contract. Derived
// contracts can access all non-private members including
// internal functions and state variables. These cannot be
// accessed externally via `this`, though.
- contract Destructible is Owned {
+ contract Emittable is Owned {
+ event Emitted();
+
// The keyword `virtual` means that the function can change
- // its behaviour in derived classes ("overriding").
- function destroy() virtual public {
- if (msg.sender == owner) selfdestruct(owner);
+ // its behavior in derived classes ("overriding").
+ function emitEvent() virtual public {
+ if (msg.sender == owner)
+ emit Emitted();
}
}
-
// These abstract contracts are only provided to make the
// interface known to the compiler. Note the function
// without body. If a contract does not implement all
@@ -69,37 +69,35 @@ Details are given in the following example.
function lookup(uint id) public virtual returns (address adr);
}
-
abstract contract NameReg {
function register(bytes32 name) public virtual;
function unregister() public virtual;
}
-
// Multiple inheritance is possible. Note that `Owned` is
- // also a base class of `Destructible`, yet there is only a single
+ // also a base class of `Emittable`, yet there is only a single
// instance of `Owned` (as for virtual inheritance in C++).
- contract Named is Owned, Destructible {
+ contract Named is Owned, Emittable {
constructor(bytes32 name) {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).register(name);
}
// Functions can be overridden by another function with the same name and
- // the same number/types of inputs. If the overriding function has different
+ // the same number/types of inputs. If the overriding function has different
// types of output parameters, that causes an error.
// Both local and message-based function calls take these overrides
// into account.
// If you want the function to override, you need to use the
// `override` keyword. You need to specify the `virtual` keyword again
// if you want this function to be overridden again.
- function destroy() public virtual override {
+ function emitEvent() public virtual override {
if (msg.sender == owner) {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).unregister();
// It is still possible to call a specific
// overridden function.
- Destructible.destroy();
+ Emittable.emitEvent();
}
}
}
@@ -108,22 +106,22 @@ Details are given in the following example.
// If a constructor takes an argument, it needs to be
// provided in the header or modifier-invocation-style at
// the constructor of the derived contract (see below).
- contract PriceFeed is Owned, Destructible, Named("GoldFeed") {
+ contract PriceFeed is Owned, Emittable, Named("GoldFeed") {
+ uint info;
+
function updateInfo(uint newInfo) public {
if (msg.sender == owner) info = newInfo;
}
// Here, we only specify `override` and not `virtual`.
// This means that contracts deriving from `PriceFeed`
- // cannot change the behaviour of `destroy` anymore.
- function destroy() public override(Destructible, Named) { Named.destroy(); }
+ // cannot change the behavior of `emitEvent` anymore.
+ function emitEvent() public override(Emittable, Named) { Named.emitEvent(); }
function get() public view returns(uint r) { return info; }
-
- uint info;
}
-Note that above, we call ``Destructible.destroy()`` to "forward" the
-destruction request. The way this is done is problematic, as
+Note that above, we call ``Emittable.emitEvent()`` to "forward" the
+emit event request. The way this is done is problematic, as
seen in the following example:
.. code-block:: solidity
@@ -131,68 +129,109 @@ seen in the following example:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
- contract owned {
- constructor() { owner = payable(msg.sender); }
+ contract Owned {
address payable owner;
+ constructor() { owner = payable(msg.sender); }
}
- contract Destructible is owned {
- function destroy() public virtual {
- if (msg.sender == owner) selfdestruct(owner);
+ contract Emittable is Owned {
+ event Emitted();
+
+ function emitEvent() virtual public {
+ if (msg.sender == owner) {
+ emit Emitted();
+ }
}
}
- contract Base1 is Destructible {
- function destroy() public virtual override { /* do cleanup 1 */ Destructible.destroy(); }
+ contract Base1 is Emittable {
+ event Base1Emitted();
+ function emitEvent() public virtual override {
+ /* Here, we emit an event to simulate some Base1 logic */
+ emit Base1Emitted();
+ Emittable.emitEvent();
+ }
}
- contract Base2 is Destructible {
- function destroy() public virtual override { /* do cleanup 2 */ Destructible.destroy(); }
+ contract Base2 is Emittable {
+ event Base2Emitted();
+ function emitEvent() public virtual override {
+ /* Here, we emit an event to simulate some Base2 logic */
+ emit Base2Emitted();
+ Emittable.emitEvent();
+ }
}
contract Final is Base1, Base2 {
- function destroy() public override(Base1, Base2) { Base2.destroy(); }
+ event FinalEmitted();
+ function emitEvent() public override(Base1, Base2) {
+ /* Here, we emit an event to simulate some Final logic */
+ emit FinalEmitted();
+ Base2.emitEvent();
+ }
}
-A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it
+A call to ``Final.emitEvent()`` will call ``Base2.emitEvent`` because we specify it
explicitly in the final override, but this function will bypass
-``Base1.destroy``. The way around this is to use ``super``:
+``Base1.emitEvent``, resulting in the following sequence of events:
+``FinalEmitted -> Base2Emitted -> Emitted``, instead of the expected sequence:
+``FinalEmitted -> Base2Emitted -> Base1Emitted -> Emitted``.
+The way around this is to use ``super``:
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
- contract owned {
- constructor() { owner = payable(msg.sender); }
+ contract Owned {
address payable owner;
+ constructor() { owner = payable(msg.sender); }
}
- contract Destructible is owned {
- function destroy() virtual public {
- if (msg.sender == owner) selfdestruct(owner);
+ contract Emittable is Owned {
+ event Emitted();
+
+ function emitEvent() virtual public {
+ if (msg.sender == owner) {
+ emit Emitted();
+ }
}
}
- contract Base1 is Destructible {
- function destroy() public virtual override { /* do cleanup 1 */ super.destroy(); }
+ contract Base1 is Emittable {
+ event Base1Emitted();
+ function emitEvent() public virtual override {
+ /* Here, we emit an event to simulate some Base1 logic */
+ emit Base1Emitted();
+ super.emitEvent();
+ }
}
- contract Base2 is Destructible {
- function destroy() public virtual override { /* do cleanup 2 */ super.destroy(); }
+ contract Base2 is Emittable {
+ event Base2Emitted();
+ function emitEvent() public virtual override {
+ /* Here, we emit an event to simulate some Base2 logic */
+ emit Base2Emitted();
+ super.emitEvent();
+ }
}
contract Final is Base1, Base2 {
- function destroy() public override(Base1, Base2) { super.destroy(); }
+ event FinalEmitted();
+ function emitEvent() public override(Base1, Base2) {
+ /* Here, we emit an event to simulate some Final logic */
+ emit FinalEmitted();
+ super.emitEvent();
+ }
}
-If ``Base2`` calls a function of ``super``, it does not simply
+If ``Final`` calls a function of ``super``, it does not simply
call this function on one of its base contracts. Rather, it
calls this function on the next base contract in the final
-inheritance graph, so it will call ``Base1.destroy()`` (note that
+inheritance graph, so it will call ``Base1.emitEvent()`` (note that
the final inheritance sequence is -- starting with the most
-derived contract: Final, Base2, Base1, Destructible, owned).
+derived contract: Final, Base2, Base1, Emittable, Owned).
The actual function that is called when using super is
not known in the context of the class where it is used,
although its type is known. This is similar for ordinary
@@ -291,7 +330,7 @@ and ends at a contract mentioning a function with that signature
that does not override.
If you do not mark a function that overrides as ``virtual``, derived
-contracts can no longer change the behaviour of that function.
+contracts can no longer change the behavior of that function.
.. note::
@@ -396,7 +435,7 @@ Constructors
A constructor is an optional function declared with the ``constructor`` keyword
which is executed upon contract creation, and where you can run contract
-initialisation code.
+initialization code.
Before the constructor code is executed, state variables are initialised to
their specified value if you initialise them inline, or their :ref:`default value` if you do not.
@@ -434,11 +473,11 @@ You can use internal parameters in a constructor (for example storage pointers).
the contract has to be marked :ref:`abstract `, because these parameters
cannot be assigned valid values from outside but only through the constructors of derived contracts.
-.. warning ::
+.. warning::
Prior to version 0.4.22, constructors were defined as functions with the same name as the contract.
This syntax was deprecated and is not allowed anymore in version 0.5.0.
-.. warning ::
+.. warning::
Prior to version 0.7.0, you had to specify the visibility of constructors as either
``internal`` or ``public``.
@@ -485,7 +524,7 @@ One way is directly in the inheritance list (``is Base(7)``). The other is in
the way a modifier is invoked as part of
the derived constructor (``Base(y * y)``). The first way to
do it is more convenient if the constructor argument is a
-constant and defines the behaviour of the contract or
+constant and defines the behavior of the contract or
describes it. The second way has to be used if the
constructor arguments of the base depend on those of the
derived contract. Arguments have to be given either in the
@@ -588,9 +627,11 @@ One area where inheritance linearization is especially important and perhaps not
Inheriting Different Kinds of Members of the Same Name
======================================================
-It is an error when any of the following pairs in a contract have the same name due to inheritance:
- - a function and a modifier
- - a function and an event
- - an event and a modifier
+The only situations where, due to inheritance, a contract may contain multiple definitions sharing
+the same name are:
-As an exception, a state variable getter can override an external function.
+- Overloading of functions.
+- Overriding of virtual functions.
+- Overriding of external virtual functions by state variable getters.
+- Overriding of virtual modifiers.
+- Overloading of events.
diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst
index cc71cf64e6..a3085667b7 100644
--- a/docs/contracts/interfaces.rst
+++ b/docs/contracts/interfaces.rst
@@ -65,7 +65,7 @@ inheritance.
Types defined inside interfaces and other contract-like structures
can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``.
-.. warning:
+.. warning::
Interfaces have supported ``enum`` types since :doc:`Solidity version 0.5.0 <050-breaking-changes>`, make
sure the pragma version specifies this version as a minimum.
diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst
index 7256ebe031..a3c04ba064 100644
--- a/docs/contracts/libraries.rst
+++ b/docs/contracts/libraries.rst
@@ -196,7 +196,7 @@ It is possible to obtain the address of a library by converting
the library type to the ``address`` type, i.e. using ``address(LibraryName)``.
As the compiler does not know the address where the library will be deployed, the compiled hex code
-will contain placeholders of the form ``__$30bbc0abd4d6364515865950d3e0d10953$__``. The placeholder
+will contain placeholders of the form ``__$30bbc0abd4d6364515865950d3e0d10953$__`` `(format was different `_. The placeholder
is a 34 character prefix of the hex encoding of the keccak256 hash of the fully qualified library
name, which would be for example ``libraries/bigint.sol:BigInt`` if the library was stored in a file
called ``bigint.sol`` in a ``libraries/`` directory. Such bytecode is incomplete and should not be
diff --git a/docs/contracts/transient-storage.rst b/docs/contracts/transient-storage.rst
new file mode 100644
index 0000000000..b2d0be2922
--- /dev/null
+++ b/docs/contracts/transient-storage.rst
@@ -0,0 +1,172 @@
+.. index:: ! transient storage, ! transient, tstore, tload
+
+.. _transient-storage:
+
+*****************
+Transient Storage
+*****************
+
+Transient storage is another data location besides memory, storage, calldata
+(and return-data and code) which was introduced alongside its respective opcodes
+``TSTORE`` and ``TLOAD`` by `EIP-1153 `_.
+This new data location behaves as a key-value store similar to storage with the main
+difference being that data in transient storage is not permanent, but is scoped to
+the current transaction only, after which it will be reset to zero.
+Since the content of transient storage has very limited lifetime and size,
+it does not need to be stored permanently as a part of state
+and the associated gas costs are much lower than in case of storage.
+EVM version ``cancun`` or newer is required for transient storage to be available.
+
+Transient storage variables cannot be initialized in place, i.e., they cannot be assigned
+to upon declaration, since the value would be cleared at the end of the creation transaction,
+rendering the initialization ineffective.
+Transient variables will be :ref:`default value` initialized depending on
+their underlying type.
+``constant`` and ``immutable`` variables conflict with transient storage, since
+their values are either inlined or directly stored in code.
+
+Transient storage variables have completely independent address space from storage,
+so that the order of transient state variables does not affect the layout of storage
+state variables and vice-versa.
+They do need distinct names though because all state variables share the same namespace.
+It is also important to note that the values in transient storage are packed in the
+same fashion as those in persistent storage.
+See :ref:`Storage Layout ` for more information.
+
+Besides that, transient variables can have visibility as well and ``public`` ones will
+have a getter function generated automatically as usual.
+
+Note that, currently, such use of ``transient`` as a data location is only allowed for
+:ref:`value type ` state variable declarations.
+Reference types, such as arrays, mappings and structs, as well as local or parameter
+variables are not yet supported.
+
+An expected canonical use case for transient storage is cheaper reentrancy locks,
+which can be readily implemented with the opcodes as showcased next.
+
+.. code-block:: solidity
+
+ // SPDX-License-Identifier: GPL-3.0
+ pragma solidity ^0.8.28;
+
+ contract Generosity {
+ mapping(address => bool) sentGifts;
+ bool transient locked;
+
+ modifier nonReentrant {
+ require(!locked, "Reentrancy attempt");
+ locked = true;
+ _;
+ // Unlocks the guard, making the pattern composable.
+ // After the function exits, it can be called again, even in the same transaction.
+ locked = false;
+ }
+
+ function claimGift() nonReentrant public {
+ require(address(this).balance >= 1 ether);
+ require(!sentGifts[msg.sender]);
+ (bool success, ) = msg.sender.call{value: 1 ether}("");
+ require(success);
+
+ // In a reentrant function, doing this last would open up the vulnerability
+ sentGifts[msg.sender] = true;
+ }
+ }
+
+Transient storage is private to the contract that owns it, in the same way as persistent storage.
+Only owning contract frames may access their transient storage, and when they do, all the frames access the same transient store.
+
+Transient storage is part of the EVM state and is subject to the same mutability enforcements
+as persistent storage. As such, any read access to it is not ``pure`` and writing access is not ``view``.
+
+If the ``TSTORE`` opcode is called within the context of a ``STATICCALL``,
+it will result in an exception instead of performing the modification.
+``TLOAD`` is allowed within the context of a ``STATICCALL``.
+
+When transient storage is used in the context of ``DELEGATECALL`` or ``CALLCODE``,
+then the owning contract of the transient storage is the contract that issued ``DELEGATECALL``
+or ``CALLCODE`` instruction (the caller) as with persistent storage.
+When transient storage is used in the context of ``CALL`` or ``STATICCALL``,
+then the owning contract of the transient storage is the contract that is the target
+of the ``CALL`` or ``STATICCALL`` instruction (the callee).
+
+.. note::
+ In the case of ``DELEGATECALL``, since references to transient storage variables
+ are currently not supported, it is not possible to pass those into library calls.
+ In libraries, access to transient storage is only possible using inline assembly.
+
+If a frame reverts, all writes to transient storage that took place between entry
+to the frame and the return are reverted, including those that took place in inner calls.
+The caller of an external call may employ a ``try ... catch`` block to prevent reverts
+bubbling up from the inner calls.
+
+*********************************************************************
+Composability of Smart Contracts and the Caveats of Transient Storage
+*********************************************************************
+
+Given the caveats mentioned in the specification of EIP-1153,
+in order to preserve the composability of your smart contract,
+utmost care is recommended for more advanced use cases of transient storage.
+
+For smart contracts, composability is a very important design principle to achieve self-contained behaviour,
+such that multiple calls into individual smart contracts can be composed to more complex applications.
+So far the EVM largely guaranteed composable behaviour, since multiple calls into a smart contract
+within a complex transaction are virtually indistinguishable from multiple calls to the contract
+stretched over several transactions. However, transient storage allows a violation of this principle,
+and incorrect use may lead to complex bugs that only surface when used across several calls.
+
+Let's illustrate the problem with a simple example:
+
+.. code-block:: solidity
+
+ // SPDX-License-Identifier: GPL-3.0
+ pragma solidity ^0.8.28;
+
+ contract MulService {
+ uint transient multiplier;
+ function setMultiplier(uint mul) external {
+ multiplier = mul;
+ }
+
+ function multiply(uint value) external view returns (uint) {
+ return value * multiplier;
+ }
+ }
+
+and a sequence of external calls:
+
+.. code-block:: solidity
+
+ setMultiplier(42);
+ multiply(1);
+ multiply(2);
+
+If the example used memory or storage to store the multiplier, it would be fully composable.
+It would not matter whether you split the sequence into separate transactions or grouped them in some way.
+You would always get the same result: after ``multiplier`` is set to ``42``, the subsequent calls
+would return ``42`` and ``84`` respectively.
+This enables use cases such as batching calls from multiple transactions
+together to reduce gas costs.
+Transient storage potentially breaks such use cases since composability can no longer be taken for granted.
+In the example, if the calls are not executed in the same transaction, then ``multiplier``
+is reset and the next calls to function ``multiply`` would always return ``0``.
+
+As another example, since transient storage is constructed as a relatively cheap key-value store,
+a smart contract author may be tempted to use transient storage as a replacement for in-memory mappings
+without keeping track of the modified keys in the mapping and thereby without clearing the mapping
+at the end of the call.
+This, however, can easily lead to unexpected behaviour in complex transactions,
+in which values set by a previous call into the contract within the same transaction remain.
+
+The use of transient storage for reentrancy locks that are cleared at the end of the call frame
+into the contract, is safe.
+However, be sure to resist the temptation to save the 100 gas used for resetting the
+reentrancy lock, since failing to do so, will restrict your contract to only one call
+within a transaction, preventing its use in complex composed transactions,
+which have been a cornerstone for complex applications on chain.
+
+It is recommend to generally always clear transient storage completely at the end of a call
+into your smart contract to avoid these kinds of issues and to simplify
+the analysis of the behaviour of your contract within complex transactions.
+Check the `Security Considerations section of EIP-1153 `_
+for further details.
\ No newline at end of file
diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst
index 20299e1a4b..a05cb277c6 100644
--- a/docs/contracts/using-for.rst
+++ b/docs/contracts/using-for.rst
@@ -1,4 +1,4 @@
-.. index:: ! using for, library
+.. index:: ! using for, library, ! operator;user-defined, function;free
.. _using-for:
@@ -6,37 +6,87 @@
Using For
*********
-The directive ``using A for B;`` can be used to attach
-functions (``A``) as member functions to any type (``B``).
-These functions will receive the object they are called on
+The directive ``using A for B`` can be used to attach
+functions (``A``) as operators to user-defined value types
+or as member functions to any type (``B``).
+The member functions receive the object they are called on
as their first parameter (like the ``self`` variable in Python).
+The operator functions receive operands as parameters.
It is valid either at file level or inside a contract,
at contract level.
The first part, ``A``, can be one of:
-- A list of file-level or library functions (e.g. ``using {f, g, h, L.t} for uint;``) -
- only those functions will be attached to the type as member functions.
- Note that private library functions can only be specified when ``using for`` is inside the library.
-- The name of a library (e.g. ``using L for uint;``) -
- all non-private functions of the library are attached to the type.
+- A list of functions, optionally with an operator name assigned (e.g.
+ ``using {f, g as +, h, L.t} for uint``).
+ If no operator is specified, the function can be either a library function or a free function and
+ is attached to the type as a member function.
+ Otherwise it must be a free function and it becomes the definition of that operator on the type.
+- The name of a library (e.g. ``using L for uint``) -
+ all non-private functions of the library are attached to the type
+ as member functions
At file level, the second part, ``B``, has to be an explicit type (without data location specifier).
Inside contracts, you can also use ``*`` in place of the type (e.g. ``using L for *;``),
which has the effect that all functions of the library ``L``
are attached to *all* types.
-If you specify a library, *all* functions in the library get attached,
+If you specify a library, *all* non-private functions in the library get attached,
even those where the type of the first parameter does not
match the type of the object. The type is checked at the
point the function is called and function overload
resolution is performed.
-If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint;``),
+If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint``),
then the type (``uint``) has to be implicitly convertible to the
first parameter of each of these functions. This check is
performed even if none of these functions are called.
+Note that private library functions can only be specified when ``using for`` is inside a library.
+
+If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a
+:ref:`user-defined value type ` and the definition must be a ``pure`` function.
+Operator definitions must be global.
+The following operators can be defined this way:
+
++------------+----------+---------------------------------------------+
+| Category | Operator | Possible signatures |
++============+==========+=============================================+
+| Bitwise | ``&`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``|`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``^`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``~`` | ``function (T) pure returns (T)`` |
++------------+----------+---------------------------------------------+
+| Arithmetic | ``+`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``-`` | ``function (T, T) pure returns (T)`` |
+| + +---------------------------------------------+
+| | | ``function (T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``*`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``/`` | ``function (T, T) pure returns (T)`` |
+| +----------+---------------------------------------------+
+| | ``%`` | ``function (T, T) pure returns (T)`` |
++------------+----------+---------------------------------------------+
+| Comparison | ``==`` | ``function (T, T) pure returns (bool)`` |
+| +----------+---------------------------------------------+
+| | ``!=`` | ``function (T, T) pure returns (bool)`` |
+| +----------+---------------------------------------------+
+| | ``<`` | ``function (T, T) pure returns (bool)`` |
+| +----------+---------------------------------------------+
+| | ``<=`` | ``function (T, T) pure returns (bool)`` |
+| +----------+---------------------------------------------+
+| | ``>`` | ``function (T, T) pure returns (bool)`` |
+| +----------+---------------------------------------------+
+| | ``>=`` | ``function (T, T) pure returns (bool)`` |
++------------+----------+---------------------------------------------+
+
+Note that unary and binary ``-`` need separate definitions.
+The compiler will choose the right definition based on how the operator is invoked.
The ``using A for B;`` directive is active only within the current
scope (either the contract or the current module/source unit),
@@ -46,7 +96,7 @@ outside of the contract or module in which it is used.
When the directive is used at file level and applied to a
user-defined type which was defined at file level in the same file,
the word ``global`` can be added at the end. This will have the
-effect that the functions are attached to the type everywhere
+effect that the functions and operators are attached to the type everywhere
the type is available (including other files), not only in the
scope of the using statement.
@@ -150,3 +200,37 @@ if you pass memory or value types, a copy will be performed, even in case of the
``self`` variable. The only situation where no copy will be performed
is when storage reference variables are used or when internal library
functions are called.
+
+Another example shows how to define a custom operator for a user-defined type:
+
+.. code-block:: solidity
+
+ // SPDX-License-Identifier: GPL-3.0
+ pragma solidity ^0.8.19;
+
+ type UFixed16x2 is uint16;
+
+ using {
+ add as +,
+ div as /
+ } for UFixed16x2 global;
+
+ uint32 constant SCALE = 100;
+
+ function add(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) {
+ return UFixed16x2.wrap(UFixed16x2.unwrap(a) + UFixed16x2.unwrap(b));
+ }
+
+ function div(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) {
+ uint32 a32 = UFixed16x2.unwrap(a);
+ uint32 b32 = UFixed16x2.unwrap(b);
+ uint32 result32 = a32 * SCALE / b32;
+ require(result32 <= type(uint16).max, "Divide overflow");
+ return UFixed16x2.wrap(uint16(a32 * SCALE / b32));
+ }
+
+ contract Math {
+ function avg(UFixed16x2 a, UFixed16x2 b) public pure returns (UFixed16x2) {
+ return (a + b) / UFixed16x2.wrap(200);
+ }
+ }
diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst
index 8932c5079b..5bf46dea55 100644
--- a/docs/contracts/visibility-and-getters.rst
+++ b/docs/contracts/visibility-and-getters.rst
@@ -200,12 +200,12 @@ The next example is more complex:
struct Data {
uint a;
bytes3 b;
- mapping (uint => uint) map;
+ mapping(uint => uint) map;
uint[3] c;
uint[] d;
bytes e;
}
- mapping (uint => mapping(bool => Data[])) public data;
+ mapping(uint => mapping(bool => Data[])) public data;
}
It generates a function of the following form. The mapping and arrays (with the
diff --git a/docs/contributing.rst b/docs/contributing.rst
index da949c1369..bb88d12016 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -28,11 +28,11 @@ 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 calls:
+the team and contributors are working on, you can join our public team call:
-- Mondays and Wednesdays at 3PM CET/CEST.
+- Wednesdays at 3PM CET/CEST.
-Both calls take place on `Jitsi `_.
+The call takes place on `Jitsi `_.
How to Report Issues
====================
@@ -45,7 +45,7 @@ reporting issues, please mention the following details:
* Source code (if applicable).
* Operating system.
* Steps to reproduce the issue.
-* Actual vs. expected behaviour.
+* 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.
@@ -93,8 +93,8 @@ Prerequisites
For running all compiler tests you may want to optionally install a few
dependencies (`evmone `_,
-`libz3 `_, and
-`libhera `_).
+`libz3 `_, `Eldarica `_,
+`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``.
@@ -102,9 +102,9 @@ 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 `_
+`grant it to other users `_
or
-`enable Developer Mode `_.
+`enable Developer Mode `_.
Running the Tests
-----------------
@@ -115,7 +115,7 @@ Running ``build/test/soltest`` or its wrapper ``scripts/soltest.sh`` is sufficie
The ``./scripts/tests.sh`` script executes most Solidity tests automatically,
including those bundled into the `Boost C++ Test Framework `_
-application ``soltest`` (or its wrapper ``scripts/soltest.sh``), as well as command line tests and
+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
@@ -129,24 +129,21 @@ for the ``evmone`` shared object can be specified via the ``ETH_EVMONE`` environ
If you do not have it installed, you can skip these tests by passing the ``--no-semantic-tests``
flag to ``scripts/soltest.sh``.
-Running Ewasm tests is disabled by default and can be explicitly enabled
-via ``./scripts/soltest.sh --ewasm`` and requires `hera `_
-to be found by ``soltest``.
-The mechanism for locating the ``hera`` library is the same as for ``evmone``, except that the
-variable for specifying an explicit location is called ``ETH_HERA``.
-
-The ``evmone`` and ``hera`` libraries should both end with the file name
+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 ``libz3`` library must be installed and locatable
by ``cmake`` during compiler configure stage.
+A few SMT tests use ``Eldarica`` instead of ``Z3``.
+``Eldarica`` is a runtime dependency, its executable (``eld``) must be present in ``PATH`` for the tests to pass.
+However, if ``Eldarica`` is not found, these tests will be automatically skipped.
If the ``libz3`` library is not installed 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`` and ``libsolidity/smtCheckerTestsJSON``.
+These tests are ``libsolidity/smtCheckerTests``.
-.. note ::
+.. note::
To get a list of all unit tests run by Soltest, run ``./build/test/soltest --list_content=HRF``.
@@ -167,7 +164,7 @@ See especially:
- `run_test (-t) `_ to run specific tests cases, and
- `report-level (-r) `_ give a more detailed report.
-.. note ::
+.. note::
Those working in a Windows environment wanting to run the above basic sets
without libz3. Using Git Bash, you use: ``./build/test/Release/soltest.exe -- --no-smt``.
@@ -175,6 +172,7 @@ See especially:
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 ..
@@ -245,7 +243,7 @@ provides a way to edit, update or skip the current contract file, or quit the ap
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).
+- ``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``.
@@ -275,6 +273,62 @@ and re-run the test. It now passes again:
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/ `_,
+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 `_,
+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
+
+ 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
==========================
@@ -356,7 +410,7 @@ The AFL documentation states that the corpus (the initial input files) should no
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 behaviour of the binary.
+that result in similar behavior of the binary.
Now run the fuzzer (the ``-m`` extends the size of memory to 60 MB):
@@ -403,13 +457,12 @@ contributions to Solidity.
English Language
----------------
-Use English, with British English spelling preferred, 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:
+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 `_
* `International English `_
-* `British English spelling `_
-
.. note::
@@ -503,7 +556,7 @@ topics, issues or feature implementations are debated in detail. The invitation
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 or implementing new features, you can follow the implementation status in the `Solidity Github project `_.
+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 `_.
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 `_.
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 18a522217f..238d261152 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -173,7 +173,6 @@ parameters from the function declaration, but can be in arbitrary order.
function set(uint key, uint value) public {
data[key] = value;
}
-
}
Omitted Names in Function Definitions
@@ -366,13 +365,13 @@ i.e. the following is not valid: ``(x, uint y) = (1, 2);``
.. warning::
Be careful when assigning to multiple variables at the same time when
reference types are involved, because it could lead to unexpected
- copying behaviour.
+ 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 behaviour ` for details.
+including ``bytes`` and ``string``, see :ref:`Data location and assignment behavior ` 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``
@@ -511,7 +510,7 @@ 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 behaviour, an ``unchecked`` block can be used:
+To obtain the previous behavior, an ``unchecked`` block can be used:
.. code-block:: solidity
@@ -595,6 +594,8 @@ 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``
----------------------------------------------
@@ -626,21 +627,20 @@ The error code supplied with the error data indicates the kind of panic.
#. 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 either creates an error without any data or
-an error of type ``Error(string)``. It
-should be used to ensure valid conditions
-that cannot be detected until execution time.
-This includes conditions on inputs
-or return values from calls to external contracts.
+The ``require`` function provides three overloads:
-.. note::
+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.
- It is currently not possible to use custom errors in combination
- with ``require``. Please use ``if (!condition) revert CustomError();`` instead.
+.. 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:
+by the compiler in the following situations:
#. Calling ``require(x)`` where ``x`` evaluates to ``false``.
#. If you use ``revert()`` or ``revert("description")``.
@@ -651,7 +651,7 @@ in the following situations:
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):
+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
@@ -663,10 +663,10 @@ an `Error` or a `Panic` (or whatever else was given):
#. If you create a contract using the ``new`` keyword but the contract
creation :ref:`does not finish properly`.
-You can optionally provide a message string for ``require``, but not for ``assert``.
+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 argument to ``require``, it will revert
+ 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.
@@ -686,7 +686,7 @@ and ``assert`` for internal error checking.
addr.transfer(msg.value / 2);
// Since transfer throws an exception on failure and
// cannot call back here, there should be no way for us to
- // still have half of the money.
+ // still have half of the Ether.
assert(address(this).balance == balanceBeforeTransfer - msg.value / 2);
return address(this).balance;
}
@@ -720,7 +720,7 @@ The ``revert`` statement takes a custom error as direct argument without parenth
revert CustomError(arg1, arg2);
-For backwards-compatibility reasons, there is also the ``revert()`` function, which uses parentheses
+For backward-compatibility reasons, there is also the ``revert()`` function, which uses parentheses
and accepts a string:
revert();
diff --git a/docs/docs.sh b/docs/docs.sh
index f2c5667612..abe4921e30 100755
--- a/docs/docs.sh
+++ b/docs/docs.sh
@@ -31,5 +31,8 @@ set -euo pipefail
script_dir="$(dirname "$0")"
cd "${script_dir}"
-pip3 install -r requirements.txt --upgrade --upgrade-strategy eager
+# TODO `--ignore-installed` now fixes an issue where pip tries to uninstall a Debian installed package, but is unable to
+# TODO since Debian has decided to not use the RECORD file, which then breaks pip.
+# TODO https://github.com/pypa/pip/issues/11631 and https://bugs.launchpad.net/ubuntu/+source/wheel/+bug/2063151
+pip3 install -r requirements.txt --ignore-installed --upgrade --upgrade-strategy eager
sphinx-build -nW -b html -d _build/doctrees . _build/html
diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst
index 3c7b3dcc69..47e19033f9 100644
--- a/docs/examples/blind-auction.rst
+++ b/docs/examples/blind-auction.rst
@@ -16,11 +16,11 @@ Simple Open Auction
===================
The general idea of the following simple auction contract is that everyone can
-send their bids during a bidding period. The bids already include sending money
-/ Ether in order to bind the bidders to their bid. If the highest bid is
-raised, the previous highest bidder gets their money back. After the end of
+send their bids during a bidding period. The bids already include sending some compensation,
+e.g. Ether, in order to bind the bidders to their bid. If the highest bid is
+raised, the previous highest bidder gets their Ether back. After the end of
the bidding period, the contract has to be called manually for the beneficiary
-to receive their money - contracts cannot activate themselves.
+to receive their Ether - contracts cannot activate themselves.
.. code-block:: solidity
@@ -92,19 +92,19 @@ to receive their money - contracts cannot activate themselves.
revert AuctionAlreadyEnded();
// If the bid is not higher, send the
- // money back (the revert statement
+ // Ether back (the revert statement
// will revert all changes in this
// function execution including
- // it having received the money).
+ // it having received the Ether).
if (msg.value <= highestBid)
revert BidNotHighEnough(highestBid);
if (highestBid != 0) {
- // Sending back the money by simply using
+ // Sending back the Ether by simply using
// highestBidder.send(highestBid) is a security risk
// because it could execute an untrusted contract.
// It is always safer to let the recipients
- // withdraw their money themselves.
+ // withdraw their Ether themselves.
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
@@ -182,7 +182,7 @@ the contract checks that the hash value is the same as the one provided during
the bidding period.
Another challenge is how to make the auction **binding and blind** at the same
-time: The only way to prevent the bidder from just not sending the money after
+time: The only way to prevent the bidder from just not sending the Ether after
they won the auction is to make them send it together with the bid. Since value
transfers cannot be blinded in Ethereum, anyone can see the value.
diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst
index 7ade926572..9a3ad845ce 100644
--- a/docs/examples/micropayment.rst
+++ b/docs/examples/micropayment.rst
@@ -36,7 +36,7 @@ Creating the signature
Alice does not need to interact with the Ethereum network
to sign the transaction, the process is completely offline.
In this tutorial, we will sign messages in the browser
-using `web3.js `_ and
+using `web3.js `_ and
`MetaMask `_, using the method described in `EIP-712 `_,
as it provides a number of other security benefits.
@@ -55,7 +55,7 @@ as it provides a number of other security benefits.
What to Sign
------------
-For a contract that fulfils payments, the signed message must include:
+For a contract that fulfills payments, the signed message must include:
1. The recipient's address.
2. The amount to be transferred.
@@ -80,13 +80,17 @@ the contract's address itself will be accepted. You can find
an example of this in the first two lines of the ``claimPayment()``
function of the full contract at the end of this section.
+Furthermore, instead of destroying the contract by calling ``selfdestruct``,
+which is currently deprecated, we will disable the contract's functionalities by freezing it,
+resulting in the reversion of any call after it being frozen.
+
Packing arguments
-----------------
Now that we have identified what information to include in the signed message,
we are ready to put the message together, hash it, and sign it. For simplicity,
we concatenate the data. The `ethereumjs-abi `_
-library provides a function called ``soliditySHA3`` that mimics the behaviour of
+library provides a function called ``soliditySHA3`` that mimics the behavior of
Solidity's ``keccak256`` function applied to arguments encoded using ``abi.encodePacked``.
Here is a JavaScript function that creates the proper signature for the ``ReceiverPays`` example:
@@ -144,29 +148,54 @@ The full contract
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
- contract ReceiverPays {
- address owner = msg.sender;
+ contract Owned {
+ address payable owner;
+ constructor() {
+ owner = payable(msg.sender);
+ }
+ }
+
+ contract Freezable is Owned {
+ bool private _frozen = false;
+
+ modifier notFrozen() {
+ require(!_frozen, "Inactive Contract.");
+ _;
+ }
+
+ function freeze() internal {
+ if (msg.sender == owner)
+ _frozen = true;
+ }
+ }
+
+ contract ReceiverPays is Freezable {
mapping(uint256 => bool) usedNonces;
constructor() payable {}
- function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) external {
+ function claimPayment(uint256 amount, uint256 nonce, bytes memory signature)
+ external
+ notFrozen
+ {
require(!usedNonces[nonce]);
usedNonces[nonce] = true;
// this recreates the message that was signed on the client
bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this)));
-
require(recoverSigner(message, signature) == owner);
-
payable(msg.sender).transfer(amount);
}
- /// destroy the contract and reclaim the leftover funds.
- function shutdown() external {
+ /// freeze the contract and reclaim the leftover funds.
+ function shutdown()
+ external
+ notFrozen
+ {
require(msg.sender == owner);
- selfdestruct(payable(msg.sender));
+ freeze();
+ payable(msg.sender).transfer(address(this).balance);
}
/// signature methods.
@@ -195,7 +224,6 @@ The full contract
returns (address)
{
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
-
return ecrecover(message, v, r, s);
}
@@ -304,7 +332,7 @@ Closing the Payment Channel
When Bob is ready to receive his funds, it is time to
close the payment channel by calling a ``close`` function on the smart contract.
Closing the channel pays the recipient the Ether they are owed and
-destroys the contract, sending any remaining Ether back to Alice. To
+deactivates the contract by freezing it, sending any remaining Ether back to Alice. To
close the channel, Bob needs to provide a message signed by Alice.
The smart contract must verify that the message contains a valid signature from the sender.
@@ -319,7 +347,7 @@ they could provide a message with a lower amount and cheat the recipient out of
The function verifies the signed message matches the given parameters.
If everything checks out, the recipient is sent their portion of the Ether,
-and the sender is sent the rest via a ``selfdestruct``.
+and the sender is sent the remaining funds via a ``transfer``.
You can see the ``close`` function in the full contract.
Channel Expiration
@@ -341,10 +369,24 @@ The full contract
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
- contract SimplePaymentChannel {
- address payable public sender; // The account sending payments.
- address payable public recipient; // The account receiving the payments.
- uint256 public expiration; // Timeout in case the recipient never closes.
+
+ contract Frozeable {
+ bool private _frozen = false;
+
+ modifier notFrozen() {
+ require(!_frozen, "Inactive Contract.");
+ _;
+ }
+
+ function freeze() internal {
+ _frozen = true;
+ }
+ }
+
+ contract SimplePaymentChannel is Frozeable {
+ address payable public sender; // The account sending payments.
+ address payable public recipient; // The account receiving the payments.
+ uint256 public expiration; // Timeout in case the recipient never closes.
constructor (address payable recipientAddress, uint256 duration)
payable
@@ -357,16 +399,23 @@ The full contract
/// the recipient can close the channel at any time by presenting a
/// signed amount from the sender. the recipient will be sent that amount,
/// and the remainder will go back to the sender
- function close(uint256 amount, bytes memory signature) external {
+ function close(uint256 amount, bytes memory signature)
+ external
+ notFrozen
+ {
require(msg.sender == recipient);
require(isValidSignature(amount, signature));
recipient.transfer(amount);
- selfdestruct(sender);
+ freeze();
+ sender.transfer(address(this).balance);
}
/// the sender can extend the expiration at any time
- function extend(uint256 newExpiration) external {
+ function extend(uint256 newExpiration)
+ external
+ notFrozen
+ {
require(msg.sender == sender);
require(newExpiration > expiration);
@@ -375,9 +424,13 @@ The full contract
/// if the timeout is reached without the recipient closing the channel,
/// then the Ether is released back to the sender.
- function claimTimeout() external {
+ function claimTimeout()
+ external
+ notFrozen
+ {
require(block.timestamp >= expiration);
- selfdestruct(sender);
+ freeze();
+ sender.transfer(address(this).balance);
}
function isValidSignature(uint256 amount, bytes memory signature)
@@ -386,14 +439,12 @@ The full contract
returns (bool)
{
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
-
// check that the signature is from the payment sender
return recoverSigner(message, signature) == sender;
}
/// All functions below this are just taken from the chapter
/// 'creating and verifying signatures' chapter.
-
function splitSignature(bytes memory sig)
internal
pure
@@ -409,7 +460,6 @@ The full contract
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
-
return (v, r, s);
}
@@ -419,7 +469,6 @@ The full contract
returns (address)
{
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
-
return ecrecover(message, v, r, s);
}
@@ -433,7 +482,7 @@ The full contract
.. note::
The function ``splitSignature`` does not use all security
checks. A real implementation should use a more rigorously tested library,
- such as openzepplin's `version `_ of this code.
+ such as openzeppelin's `version `_ of this code.
Verifying Payments
------------------
diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst
index 697699ae6e..9ae2849cb4 100644
--- a/docs/examples/modular.rst
+++ b/docs/examples/modular.rst
@@ -7,7 +7,7 @@ Modular Contracts
A modular approach to building your contracts helps you reduce the complexity
and improve the readability which will help to identify bugs and vulnerabilities
during development and code review.
-If you specify and control the behaviour of each module in isolation, the
+If you specify and control the behavior of each module in isolation, the
interactions you have to consider are only those between the module specifications
and not every other moving part of the contract.
In the example below, the contract uses the ``move`` method
@@ -34,7 +34,7 @@ and the sum of all balances is an invariant across the lifetime of the contract.
contract Token {
mapping(address => uint256) balances;
using Balances for *;
- mapping(address => mapping (address => uint256)) allowed;
+ mapping(address => mapping(address => uint256)) allowed;
event Transfer(address from, address to, uint amount);
event Approval(address owner, address spender, uint amount);
diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst
index e42b017fb6..a2651af238 100644
--- a/docs/examples/safe-remote.rst
+++ b/docs/examples/safe-remote.rst
@@ -6,18 +6,18 @@ Safe Remote Purchase
Purchasing goods remotely currently requires multiple parties that need to trust each other.
The simplest configuration involves a seller and a buyer. The buyer would like to receive
-an item from the seller and the seller would like to get money (or an equivalent)
+an item from the seller and the seller would like to get some compensation, e.g. Ether,
in return. The problematic part is the shipment here: There is no way to determine for
sure that the item arrived at the buyer.
There are multiple ways to solve this problem, but all fall short in one or the other way.
In the following example, both parties have to put twice the value of the item into the
-contract as escrow. As soon as this happened, the money will stay locked inside
+contract as escrow. As soon as this happened, the Ether will stay locked inside
the contract until the buyer confirms that they received the item. After that,
the buyer is returned the value (half of their deposit) and the seller gets three
times the value (their deposit plus the value). The idea behind
this is that both parties have an incentive to resolve the situation or otherwise
-their money is locked forever.
+their Ether is locked forever.
This contract of course does not solve the problem, but gives an overview of how
you can use state machine-like constructs inside a contract.
diff --git a/docs/ext/remix_code_links.py b/docs/ext/remix_code_links.py
index 2fc15ddda0..55fc0ef5c2 100644
--- a/docs/ext/remix_code_links.py
+++ b/docs/ext/remix_code_links.py
@@ -22,23 +22,16 @@ def remix_code_url(source_code, language, solidity_version):
# NOTE: base64 encoded data may contain +, = and / characters. Remix seems to handle them just
# fine without any escaping.
base64_encoded_source = base64.b64encode(source_code.encode('utf-8')).decode('ascii')
- return f"https://remix.ethereum.org/?language={language}&version={solidity_version}&code={base64_encoded_source}"
+ return f"https://remix.ethereum.org/?#language={language}&version={solidity_version}&code={base64_encoded_source}"
def build_remix_link_node(url):
- link_icon_node = docutils.nodes.inline()
- link_icon_node.set_class('link-icon')
-
- link_text_node = docutils.nodes.inline(text="open in Remix")
- link_text_node.set_class('link-text')
-
- reference_node = docutils.nodes.reference('', '', internal=False, refuri=url)
- reference_node.set_class('remix-link')
- reference_node += [link_icon_node, link_text_node]
+ reference_node = docutils.nodes.reference('', 'open in Remix', internal=False, refuri=url, target='_blank')
+ reference_node['classes'].append('remix-link')
paragraph_node = docutils.nodes.paragraph()
- paragraph_node.set_class('remix-link-container')
- paragraph_node += reference_node
+ paragraph_node['classes'].append('remix-link-container')
+ paragraph_node.append(reference_node)
return paragraph_node
@@ -49,22 +42,24 @@ def insert_remix_link(app, doctree, solidity_version):
for literal_block_node in doctree.traverse(docutils.nodes.literal_block):
assert 'language' in literal_block_node.attributes
language = literal_block_node.attributes['language'].lower()
- if language in ['solidity', 'yul']:
- text_nodes = list(literal_block_node.traverse(docutils.nodes.Text))
- assert len(text_nodes) == 1
-
- remix_url = remix_code_url(text_nodes[0], language, solidity_version)
- url_length = len(remix_url.encode('utf-8'))
- if url_length > MAX_SAFE_URL_LENGTH:
- logger.warning(
- "Remix URL generated from the code snippet exceeds the maximum safe URL length "
- " (%d > %d bytes).",
- url_length,
- MAX_SAFE_URL_LENGTH,
- location=(literal_block_node.source, literal_block_node.line),
- )
-
- insert_node_before(literal_block_node, build_remix_link_node(remix_url))
+ if language not in ['solidity', 'yul']:
+ continue
+
+ text_nodes = list(literal_block_node.traverse(docutils.nodes.Text))
+ assert len(text_nodes) == 1
+
+ remix_url = remix_code_url(text_nodes[0], language, solidity_version)
+ url_length = len(remix_url.encode('utf-8'))
+ if url_length > MAX_SAFE_URL_LENGTH:
+ logger.warning(
+ "Remix URL generated from the code snippet exceeds the maximum safe URL length "
+ " (%d > %d bytes).",
+ url_length,
+ MAX_SAFE_URL_LENGTH,
+ location=(literal_block_node.source, literal_block_node.line),
+ )
+
+ insert_node_before(literal_block_node, build_remix_link_node(remix_url))
def setup(app):
diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4
index c47dc411cd..f994c331d5 100644
--- a/docs/grammar/SolidityLexer.g4
+++ b/docs/grammar/SolidityLexer.g4
@@ -62,7 +62,7 @@ New: 'new';
/**
* Unit denomination for numbers.
*/
-NumberUnit: 'wei' | 'gwei' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years';
+SubDenomination: 'wei' | 'gwei' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years';
Override: 'override';
Payable: 'payable';
Pragma: 'pragma' -> pushMode(PragmaMode);
@@ -85,11 +85,13 @@ SignedIntegerType:
Storage: 'storage';
String: 'string';
Struct: 'struct';
+Transient: 'transient'; // not a real keyword
True: 'true';
Try: 'try';
Type: 'type';
Ufixed: 'ufixed' | ('ufixed' [1-9][0-9]+ 'x' [1-9][0-9]+);
Unchecked: 'unchecked';
+Unicode: 'unicode';
/**
* Sized unsigned integer types.
* uint is an alias of uint256.
@@ -198,9 +200,7 @@ fragment EscapeSequence:
/**
* A single quoted string literal allowing arbitrary unicode characters.
*/
-UnicodeStringLiteral:
- 'unicode"' DoubleQuotedUnicodeStringCharacter* '"'
- | 'unicode\'' SingleQuotedUnicodeStringCharacter* '\'';
+UnicodeStringLiteral: 'unicode' (('"' DoubleQuotedUnicodeStringCharacter* '"') | ('\'' SingleQuotedUnicodeStringCharacter* '\''));
//@doc:inline
fragment DoubleQuotedUnicodeStringCharacter: ~["\r\n\\] | EscapeSequence;
//@doc:inline
@@ -222,6 +222,14 @@ fragment EvenHexDigits: HexCharacter HexCharacter ('_'? HexCharacter HexCharacte
//@doc:inline
fragment HexCharacter: [0-9A-Fa-f];
+/**
+ * Scanned but not used by any rule, i.e, disallowed.
+ * solc parser considers number starting with '0', not immediately followed by '.' or 'x' as
+ * octal, even if non octal digits '8' and '9' are present.
+ */
+OctalNumber: '0' DecimalDigits ('.' DecimalDigits)?;
+
+
/**
* A decimal number literal consists of decimal digits that may be delimited by underscores and
* an optional positive or negative exponent.
@@ -232,6 +240,12 @@ DecimalNumber: (DecimalDigits | (DecimalDigits? '.' DecimalDigits)) ([eE] '-'? D
fragment DecimalDigits: [0-9] ('_'? [0-9])* ;
+/**
+ * This is needed to avoid successfully parsing a number followed by a string with no whitespace between.
+ */
+DecimalNumberFollowedByIdentifier: DecimalNumber Identifier;
+
+
/**
* An identifier in solidity has to start with a letter, a dollar-sign or an underscore and
* may additionally contain numbers after the first symbol.
@@ -285,14 +299,14 @@ YulEVMBuiltin:
'stop' | 'add' | 'sub' | 'mul' | 'div' | 'sdiv' | 'mod' | 'smod' | 'exp' | 'not'
| 'lt' | 'gt' | 'slt' | 'sgt' | 'eq' | 'iszero' | 'and' | 'or' | 'xor' | 'byte'
| 'shl' | 'shr' | 'sar' | 'addmod' | 'mulmod' | 'signextend' | 'keccak256'
- | 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'msize' | 'gas'
+ | 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'tload' | 'tstore'| 'msize' | 'gas'
| 'address' | 'balance' | 'selfbalance' | 'caller' | 'callvalue' | 'calldataload'
| 'calldatasize' | 'calldatacopy' | 'extcodesize' | 'extcodecopy' | 'returndatasize'
- | 'returndatacopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode'
+ | 'returndatacopy' | 'mcopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode'
| 'delegatecall' | 'staticcall' | 'return' | 'revert' | 'selfdestruct' | 'invalid'
| 'log0' | 'log1' | 'log2' | 'log3' | 'log4' | 'chainid' | 'origin' | 'gasprice'
- | 'blockhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty' | 'gaslimit'
- | 'basefee';
+ | 'blockhash' | 'blobhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty'
+ | 'prevrandao' | 'gaslimit' | 'basefee' | 'blobbasefee';
YulLBrace: '{' -> pushMode(YulMode);
YulRBrace: '}' -> popMode;
diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4
index 3068749895..a344fad544 100644
--- a/docs/grammar/SolidityParser.g4
+++ b/docs/grammar/SolidityParser.g4
@@ -22,6 +22,7 @@ sourceUnit: (
| enumDefinition
| userDefinedValueTypeDefinition
| errorDefinition
+ | eventDefinition
)* EOF;
//@doc: inline
@@ -152,7 +153,7 @@ stateMutability: Pure | View | Payable;
*/
overrideSpecifier: Override (LParen overrides+=identifierPath (Comma overrides+=identifierPath)* RParen)?;
/**
- * The definition of contract, library and interface functions.
+ * The definition of contract, library, interface or free functions.
* Depending on the context in which the function is defined, further restrictions may apply,
* e.g. functions in interfaces have to be unimplemented, i.e. may not contain a body block.
*/
@@ -161,7 +162,7 @@ locals[
boolean visibilitySet = false,
boolean mutabilitySet = false,
boolean virtualSet = false,
- boolean overrideSpecifierSet = false
+ boolean overrideSpecifierSet = false,
]
:
Function (identifier | Fallback | Receive)
@@ -175,6 +176,7 @@ locals[
)*
(Returns LParen returnParameters=parameterList RParen)?
(Semicolon | body=block);
+
/**
* The definition of a modifier.
* Note that within the body block of a modifier, the underscore cannot be used as identifier,
@@ -249,7 +251,7 @@ structMember: type=typeName name=identifier Semicolon;
/**
* Definition of an enum. Can occur at top-level within a source unit or within a contract, library or interface.
*/
-enumDefinition: Enum name=identifier LBrace enumValues+=identifier (Comma enumValues+=identifier)* RBrace;
+enumDefinition: Enum name=identifier LBrace enumValues+=identifier (Comma enumValues+=identifier)* RBrace;
/**
* Definition of a user defined value type. Can occur at top-level within a source unit or within a contract, library or interface.
*/
@@ -260,7 +262,7 @@ userDefinedValueTypeDefinition:
* The declaration of a state variable.
*/
stateVariableDeclaration
-locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean overrideSpecifierSet = false]
+locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean overrideSpecifierSet = false, boolean locationSet = false]
:
type=typeName
(
@@ -270,6 +272,7 @@ locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean
| {!$constantnessSet}? Constant {$constantnessSet = true;}
| {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;}
| {!$constantnessSet}? Immutable {$constantnessSet = true;}
+ | {!$locationSet}? Transient {$locationSet = true;}
)*
name=identifier
(Assign initialValue=expression)?
@@ -311,11 +314,38 @@ errorDefinition:
LParen (parameters+=errorParameter (Comma parameters+=errorParameter)*)? RParen
Semicolon;
+/**
+ * Operators that users are allowed to implement for some types with `using for`.
+ */
+userDefinableOperator:
+ BitAnd
+ | BitNot
+ | BitOr
+ | BitXor
+ | Add
+ | Div
+ | Mod
+ | Mul
+ | Sub
+ | Equal
+ | GreaterThan
+ | GreaterThanOrEqual
+ | LessThan
+ | LessThanOrEqual
+ | NotEqual;
+
/**
* Using directive to attach library functions and free functions to types.
* Can occur within contracts and libraries and at the file level.
*/
-usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? Semicolon;
+usingDirective:
+ Using (
+ identifierPath
+ | (LBrace usingAliases (Comma usingAliases)* RBrace)
+ ) For (Mul | typeName) Global? Semicolon;
+
+usingAliases: identifierPath (As userDefinableOperator)?;
+
/**
* A type name can be an elementary type, a function type, a mapping type, a user-defined type
* (e.g. a contract or struct) or an array type.
@@ -347,7 +377,7 @@ dataLocation: Memory | Storage | Calldata;
*/
expression:
expression LBrack index=expression? RBrack # IndexAccess
- | expression LBrack start=expression? Colon end=expression? RBrack # IndexRangeAccess
+ | expression LBrack startIndex=expression? Colon endIndex=expression? RBrack # IndexRangeAccess
| expression Period (identifier | Address) # MemberAccess
| expression LBrace (namedArgument (Comma namedArgument)*)? RBrace # FunctionCallOptions
| expression callArgumentList # FunctionCall
@@ -368,12 +398,13 @@ expression:
| expression Or expression # OrOperation
| expression Conditional expression Colon expression # Conditional
| expression assignOp expression # Assignment
- | New typeName # NewExpression
+ | New typeName # NewExpr
| tupleExpression # Tuple
| inlineArrayExpression # InlineArray
- | (
+ | (
identifier
| literal
+ | literalWithSubDenomination
| elementaryTypeName[false]
) # PrimaryExpression
;
@@ -389,9 +420,12 @@ inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack;
/**
* Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers.
*/
-identifier: Identifier | From | Error | Revert | Global;
+identifier: Identifier | From | Error | Revert | Global | Transient;
literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral;
+
+literalWithSubDenomination: numberLiteral SubDenomination;
+
booleanLiteral: True | False;
/**
* A full string literal consists of either one or several consecutive quoted strings.
@@ -409,7 +443,8 @@ unicodeStringLiteral: UnicodeStringLiteral+;
/**
* Number literals can be decimal or hexadecimal numbers with an optional unit.
*/
-numberLiteral: (DecimalNumber | HexNumber) NumberUnit?;
+numberLiteral: DecimalNumber | HexNumber;
+
/**
* A curly-braced block of statements. Opens its own scope.
*/
@@ -504,7 +539,7 @@ variableDeclarationTuple:
variableDeclarationStatement: ((variableDeclaration (Assign expression)?) | (variableDeclarationTuple Assign expression)) Semicolon;
expressionStatement: expression Semicolon;
-mappingType: Mapping LParen key=mappingKeyType DoubleArrow value=typeName RParen;
+mappingType: Mapping LParen key=mappingKeyType name=identifier? DoubleArrow value=typeName name=identifier? RParen;
/**
* Only elementary types or user defined types are viable as mapping keys.
*/
diff --git a/docs/index.rst b/docs/index.rst
index 3cb27eaeda..f1608890d7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,38 +1,35 @@
Solidity
========
-Solidity is an object-oriented, high-level language for implementing smart
-contracts. Smart contracts are programs which govern the behaviour of accounts
-within the Ethereum state.
+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 `_ 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 ` section.
+Solidity is a `curly-bracket language `_ 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 ` section.
-Solidity is statically typed, supports inheritance, libraries and complex
-user-defined types among other features.
+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.
+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
+When deploying contracts, you should use the latest released version of Solidity.
+Apart from exceptional cases, only the latest version receives
`security fixes `_.
-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 `_.
+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 `_.
.. warning::
- Solidity recently released the 0.8.x version that introduced a lot of breaking
- changes. Make sure you read :doc:`the full list <080-breaking-changes>`.
+ Solidity recently released the 0.8.x version that 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 ` for more details.
.. Hint::
- You can download this documentation as PDF, HTML or Epub by clicking on the versions
- flyout menu in the bottom-left corner and selecting the preferred download format.
+ You can download this documentation as PDF, HTML or Epub
+ by clicking on the versions flyout menu in the bottom-left corner and selecting the preferred download format.
Getting Started
@@ -40,8 +37,7 @@ 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:
+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 ` written in Solidity.
* :ref:`Blockchain Basics `.
@@ -59,29 +55,27 @@ simply choose your preferred option and follow the steps outlined on the :ref:`i
.. hint::
You can try out code examples directly in your browser with the
- `Remix IDE `_. 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.
+ `Remix IDE `_.
+ 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. 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.
+ 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 `_
-can help you with further general documentation around Ethereum, and a wide selection of tutorials,
-tools and development frameworks.
+If you want to learn more about building decentralized applications on Ethereum,
+the `Ethereum Developer Resources `_ 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 `_, or
-our `Gitter channel `_.
+`Ethereum StackExchange `_,
+or our `Gitter channel `_.
.. _translations:
@@ -89,13 +83,13 @@ 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.
+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-left corner
and selecting the preferred language.
-* `Chinese `_
+* `Chinese `_
* `French `_
* `Indonesian `_
* `Japanese `_
@@ -103,12 +97,12 @@ and selecting the preferred language.
* `Persian `_
* `Russian `_
* `Spanish `_
-* `Turkish `_
+* `Turkish `_
.. 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 `_
+ 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 `_
for information on how to start a new language or contribute to the community translations.
Contents
@@ -121,8 +115,8 @@ Contents
:caption: Basics
introduction-to-smart-contracts.rst
- installing-solidity.rst
solidity-by-example.rst
+ installing-solidity.rst
.. toctree::
:maxdepth: 2
@@ -161,21 +155,31 @@ Contents
.. toctree::
:maxdepth: 2
- :caption: Additional Material
+ :caption: Advisory content
+ security-considerations.rst
+ 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
- security-considerations.rst
smtchecker.rst
- resources.rst
- path-resolution.rst
yul.rst
+ path-resolution.rst
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Resources
+
style-guide.rst
common-patterns.rst
- bugs.rst
+ resources.rst
contributing.rst
- brand-guide.rst
language-influences.rst
+ brand-guide.rst
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 9a613d75d3..5473dbb524 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -10,12 +10,12 @@ Versioning
==========
Solidity versions follow `Semantic Versioning `_. In
-addition, patch level releases with major release 0 (i.e. 0.x.y) will not
+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 **nightly development builds** with the
-intention of making it easy for developers to try out upcoming features and
+In addition to releases, we provide **nightly development builds** to make
+it easy for developers to try out upcoming features and
provide early feedback. Note, however, that while the nightly builds are usually
very stable, they contain bleeding-edge code from the development branch and are
not guaranteed to be always working. Despite our best efforts, they might
@@ -33,12 +33,12 @@ Remix
`Access Remix online `_, you do not need to install anything.
If you want to use it without connection to the Internet, go to
-https://github.com/ethereum/remix-live/tree/gh-pages and download the ``.zip`` file as
-explained on that page. Remix is also a convenient option for testing nightly builds
+https://github.com/ethereum/remix-live/tree/gh-pages#readme and follow the instructions on that page.
+Remix is also a convenient option for testing nightly builds
without installing multiple Solidity versions.
-Further options on this page detail installing commandline Solidity compiler software
-on your computer. Choose a commandline compiler if you are working on a larger contract
+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:
@@ -54,7 +54,7 @@ the full-featured compiler, ``solc``. The usage of ``solcjs`` is documented insi
`repository `_.
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` 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.
@@ -64,18 +64,18 @@ Please refer to the solc-js repository for instructions.
.. note::
- The commandline executable is named ``solcjs``.
+ The command-line executable is named ``solcjs``.
- The commandline options of ``solcjs`` are not compatible with ``solc`` and tools (such as ``geth``)
- expecting the behaviour of ``solc`` will not work with ``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`` image from the ``ethereum`` organisation.
-Use the ``stable`` tag for the latest released version, and ``nightly`` for potentially unstable changes in the develop branch.
+Docker images of Solidity builds are available using the ``solc`` image from the ``ethereum`` organization.
+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 you can pass all compiler arguments to it.
+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.
@@ -83,21 +83,27 @@ and runs it in a new container, passing the ``--help`` argument.
docker run ethereum/solc:stable --help
-You can also specify release build versions in the tag, for example, for the 0.5.4 release.
+You can specify release build versions in the tag. For example:
.. code-block:: bash
- docker run ethereum/solc:0.5.4 --help
+ docker run ethereum/solc:stable --help
+
+Note
-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.
+Specific compiler versions are supported as the Docker image tag such as `ethereum/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
docker run -v /local/path:/sources ethereum/solc:stable -o /sources/output --abi --bin /sources/Contract.sol
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
+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 `).
@@ -130,13 +136,15 @@ The nightly version can be installed using these commands:
sudo apt-get install solc
Furthermore, 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.
+maintained by us but usually kept up-to-date by the respective package maintainers.
-For example, Arch Linux has packages for the latest development version:
+For example, Arch Linux has packages for the latest development version as AUR packages: `solidity `_
+and `solidity-bin `_.
-.. code-block:: bash
+.. note::
- pacman -S solidity
+ Please be aware that `AUR `_ packages
+ are user-produced content and unofficial packages. Exercise caution when using them.
There is also a `snap package `_, however, it is **currently unmaintained**.
It is installable in all the `supported Linux distros `_. To
@@ -181,7 +189,7 @@ If you need a specific version of Solidity you can install a
Homebrew formula directly from Github.
View
-`solidity.rb commits on Github `_.
+`solidity.rb commits on GitHub `_.
Copy the commit hash of the version you want and check it out on your machine.
@@ -212,23 +220,23 @@ out-of-the-box but it is also meant to be friendly to third-party tools:
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 (with the exception of older Windows builds
+- Binaries do not require installation or unpacking (exception for older Windows builds
bundled with necessary DLLs).
-- We strive for a high level of backwards-compatibility. Files, once added, are not removed or moved
+- 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 a potential to cause more harm than good if left as is.
+ 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
+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 contains a ``list.json`` file listing the available binaries. For example in
+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
@@ -241,7 +249,6 @@ Each one contains a ``list.json`` file listing the available binaries. For examp
"keccak256": "0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3",
"sha256": "0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2",
"urls": [
- "bzzr://16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1",
"dweb:/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS"
]
}
@@ -256,10 +263,10 @@ This means that:
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`_.
-- The file might in future be available on Swarm at `16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1`_.
+ 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
+ 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``.
@@ -297,20 +304,17 @@ This means that:
in the long-term.
.. _IPFS: https://ipfs.io
-.. _Swarm: https://swarm-gateways.net/bzz:/swarm.eth
.. _solc-bin: https://github.com/ethereum/solc-bin/
-.. _Solidity release page on github: https://github.com/ethereum/solidity/releases
+.. _Solidity release page on GitHub: https://github.com/ethereum/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
-.. _16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1: https://swarm-gateways.net/bzz:/16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1/
.. _building-from-source:
Building from Source
====================
-
Prerequisites - All Operating Systems
-------------------------------------
@@ -319,19 +323,17 @@ The following are dependencies for all builds of Solidity:
+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
+===================================+=======================================================+
-| `CMake`_ (version 3.13+) | Cross-platform build file generator. |
+| `CMake`_ (version 3.21.3+ on | Cross-platform build file generator. |
+| Windows, 3.13+ otherwise) | |
+-----------------------------------+-------------------------------------------------------+
| `Boost`_ (version 1.77+ on | C++ libraries. |
-| Windows, 1.65+ otherwise) | |
+| Windows, 1.67+ otherwise) | |
+-----------------------------------+-------------------------------------------------------+
| `Git`_ | Command-line tool for retrieving source code. |
+-----------------------------------+-------------------------------------------------------+
-| `z3`_ (version 4.8+, Optional) | For use with SMT checker. |
-+-----------------------------------+-------------------------------------------------------+
-| `cvc4`_ (Optional) | For use with SMT checker. |
+| `z3`_ (version 4.8.16+, Optional) | For use with SMT checker. |
+-----------------------------------+-------------------------------------------------------+
-.. _cvc4: https://cvc4.cs.stanford.edu/web/
.. _Git: https://git-scm.com/download
.. _Boost: https://www.boost.org
.. _CMake: https://cmake.org/download/
@@ -340,7 +342,7 @@ The following are dependencies for all builds of Solidity:
.. 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.
+ prior to running the cmake command to configure Solidity.
Starting from 0.5.10 linking against Boost 1.70+ should work without manual intervention.
@@ -378,7 +380,7 @@ Prerequisites - macOS
---------------------
For macOS builds, ensure that you have the latest version of
-`Xcode installed `_.
+`Xcode installed `_.
This contains the `Clang C++ compiler `_, the
`Xcode IDE `_ and other Apple development
tools that are required for building C++ applications on OS X.
@@ -428,7 +430,7 @@ in Visual Studio 2019 Build Tools or Visual Studio 2019:
* C++/CLI support
.. _Visual Studio 2019: https://www.visualstudio.com/vs/
-.. _Visual Studio 2019 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019
+.. _Visual Studio 2019 Build Tools: https://visualstudio.microsoft.com/vs/older-downloads/#visual-studio-2019-and-other-products
We have a helper script which you can use to install all required external dependencies:
@@ -448,7 +450,7 @@ To clone the source code, execute the following command:
git clone --recursive https://github.com/ethereum/solidity.git
cd solidity
-If you want to help developing Solidity,
+If you want to help develop Solidity,
you should fork Solidity and add your personal fork as a second remote:
.. code-block:: bash
@@ -456,14 +458,14 @@ you should fork Solidity and add your personal fork as a second remote:
git remote add personal git@github.com:[username]/solidity.git
.. note::
- This method will result in a prerelease build leading to e.g. a flag
+ This method will result in a pre-release build leading to e.g. a flag
being set in each bytecode produced by such a compiler.
If you want to re-build a released Solidity compiler, then
- please use the source tarball on the github release page:
+ please use the source tarball on the GitHub release page:
https://github.com/ethereum/solidity/releases/download/v0.X.Y/solidity_0.X.Y.tar.gz
- (not the "Source code" provided by github).
+ (not the "Source code" provided by GitHub).
Command-Line Build
------------------
@@ -525,24 +527,23 @@ If you are interested what CMake options are available run ``cmake .. -LH``.
SMT Solvers
-----------
-Solidity can be built against SMT solvers and will do so by default if
-they are found in the system. Each solver can be disabled by a `cmake` option.
+Solidity can be built against Z3 SMT solver and will do so by default if
+it is found in the system. Z3 can be disabled by a ``cmake`` option.
*Note: In some cases, this can also be a potential workaround for build failures.*
-Inside the build folder you can disable them, since they are enabled by default:
+Inside the build folder you can disable Z3, since it is enabled by default:
.. code-block:: bash
- # disables only Z3 SMT Solver.
+ # disables Z3 SMT Solver.
cmake .. -DUSE_Z3=OFF
- # disables only CVC4 SMT Solver.
- cmake .. -DUSE_CVC4=OFF
+.. note::
- # disables both Z3 and CVC4
- cmake .. -DUSE_CVC4=OFF -DUSE_Z3=OFF
+ Solidity can optionally use other solvers, namely ``cvc5`` and ``Eldarica``,
+ but their presence is checked only at runtime, they are not needed for the build to succeed.
The Version String in Detail
============================
@@ -579,4 +580,4 @@ Example:
4. A breaking change is introduced --> version is bumped to 0.5.0.
5. The 0.5.0 release is made.
-This behaviour works well with the :ref:`version pragma `.
+This behavior works well with the :ref:`version pragma `.
diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst
index 53670eeb85..557a0a0e20 100644
--- a/docs/internals/layout_in_storage.rst
+++ b/docs/internals/layout_in_storage.rst
@@ -1,11 +1,17 @@
-.. index:: storage, state variable, mapping
+.. index:: storage, state variable, mapping, transient storage
-************************************
-Layout of State Variables in Storage
-************************************
+**********************************************************
+Layout of State Variables in Storage and Transient Storage
+**********************************************************
.. _storage-inplace-encoding:
+.. note::
+ The rules described in this section apply for both storage and transient storage data locations.
+ The layouts are completely independent and don't interfere with each other's variable locations.
+ Thus storage and transient storage state variables can be safely interleaved without any side effects.
+ Only value types are supported for transient storage.
+
State variables of contracts are stored in storage in a compact way such
that multiple values sometimes use the same storage slot.
Except for dynamically-sized arrays and mappings (see below), data is stored
@@ -147,7 +153,7 @@ JSON Output
.. _storage-layout-top-level:
-The storage layout of a contract can be requested via
+The storage (or transient storage) layout of a contract can be requested via
the :ref:`standard JSON interface `. The output is a JSON object containing two keys,
``storage`` and ``types``. The ``storage`` object is an array where each
element has the following form:
@@ -208,18 +214,18 @@ of types), arrays have its ``base`` type, and structs list their ``members`` in
the same format as the top-level ``storage`` (see :ref:`above
`).
-.. note ::
+.. note::
The JSON output format of a contract's storage layout is still considered experimental
and is subject to change in non-breaking releases of Solidity.
-The following example shows a contract and its storage layout, containing
-value and reference types, types that are encoded packed, and nested types.
+The following example shows a contract and both its storage and transient storage layout,
+containing value and reference types, types that are encoded packed, and nested types.
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
- pragma solidity >=0.4.0 <0.9.0;
+ pragma solidity ^0.8.28;
contract A {
struct S {
uint128 a;
@@ -229,15 +235,22 @@ value and reference types, types that are encoded packed, and nested types.
}
uint x;
- uint y;
+ uint transient y;
+ uint w;
+ uint transient z;
+
S s;
address addr;
- mapping (uint => mapping (address => bool)) map;
+ address transient taddr;
+ mapping(uint => mapping(address => bool)) map;
uint[] array;
string s1;
bytes b1;
}
+Storage Layout
+--------------
+
.. code-block:: json
{
@@ -251,15 +264,15 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_uint256"
},
{
- "astId": 17,
+ "astId": 19,
"contract": "fileA:A",
- "label": "y",
+ "label": "w",
"offset": 0,
"slot": "1",
"type": "t_uint256"
},
{
- "astId": 20,
+ "astId": 24,
"contract": "fileA:A",
"label": "s",
"offset": 0,
@@ -267,7 +280,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_struct(S)13_storage"
},
{
- "astId": 22,
+ "astId": 26,
"contract": "fileA:A",
"label": "addr",
"offset": 0,
@@ -275,7 +288,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_address"
},
{
- "astId": 28,
+ "astId": 34,
"contract": "fileA:A",
"label": "map",
"offset": 0,
@@ -283,7 +296,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))"
},
{
- "astId": 31,
+ "astId": 37,
"contract": "fileA:A",
"label": "array",
"offset": 0,
@@ -291,7 +304,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_array(t_uint256)dyn_storage"
},
{
- "astId": 33,
+ "astId": 39,
"contract": "fileA:A",
"label": "s1",
"offset": 0,
@@ -299,7 +312,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_string_storage"
},
{
- "astId": 35,
+ "astId": 41,
"contract": "fileA:A",
"label": "b1",
"offset": 0,
@@ -405,3 +418,49 @@ value and reference types, types that are encoded packed, and nested types.
}
}
}
+
+Transient Storage Layout
+------------------------
+
+.. code-block:: json
+
+ {
+ "storage": [
+ {
+ "astId": 17,
+ "contract": "fileA:A",
+ "label": "y",
+ "offset": 0,
+ "slot": "0",
+ "type": "t_uint256"
+ },
+ {
+ "astId": 21,
+ "contract": "fileA:A",
+ "label": "z",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_uint256"
+ },
+ {
+ "astId": 28,
+ "contract": "fileA:A",
+ "label": "taddr",
+ "offset": 0,
+ "slot": "2",
+ "type": "t_address"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "encoding": "inplace",
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_uint256": {
+ "encoding": "inplace",
+ "label": "uint256",
+ "numberOfBytes": "32"
+ }
+ }
+ }
\ No newline at end of file
diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst
index 11f55e0e3a..604560554a 100644
--- a/docs/internals/optimizer.rst
+++ b/docs/internals/optimizer.rst
@@ -5,8 +5,11 @@
The Optimizer
*************
-The Solidity compiler uses two different optimizer modules: The "old" optimizer
-that operates at the opcode level and the "new" optimizer that operates on Yul IR code.
+The Solidity compiler involves optimizations at three different levels (in order of execution):
+
+- Optimizations during code generation based on a direct analysis of Solidity code.
+- Optimizing transformations on the Yul IR code.
+- Optimizations at the opcode level.
The opcode-based optimizer applies a set of `simplification rules `_
to opcodes. It also combines equal code sets and removes unused code.
@@ -20,6 +23,17 @@ the function calls. Similarly, if a function is
side-effect free and its result is multiplied by zero, you can remove the function
call completely.
+The codegen-based optimizer affects the initial low-level code produced from the Solidity input.
+In the legacy pipeline, the bytecode is generated immediately and most of the optimizations of this
+kind are implicit and not configurable, the only exception being an optimization which changes the
+order of literals in binary operations.
+The IR-based pipeline takes a different approach and produces Yul IR closely matching the structure
+of the Solidity code, with nearly all optimizations deferred to the Yul optimizer module.
+In that case codegen-level optimization is done only in very limited cases which are difficult to
+handle in Yul IR, but are straightforward with the high-level information from analysis phase at hand.
+An example of such an optimization is the bypass of checked arithmetic when incrementing the counter
+in certain idiomatic ``for`` loops.
+
Currently, the parameter ``--optimize`` activates the opcode-based optimizer for the
generated bytecode and the Yul optimizer for the Yul code generated internally, for example for ABI coder v2.
One can use ``solc --ir-optimized --optimize`` to produce an
@@ -27,9 +41,15 @@ optimized Yul IR for a Solidity source. Similarly, one can use ``solc --strict-a
for a stand-alone Yul mode.
.. note::
- The `peephole optimizer `_ and the inliner are always
+ Some optimizer steps, such as, for example, the `peephole optimizer `_
+ and the :ref:`unchecked loop increment optimizer ` are always
enabled by default and can only be turned off via the :ref:`Standard JSON `.
+.. note::
+ An empty optimizer sequence, i.e ``:``, is accepted even without ``--optimize`` in order to fully disable
+ the user-supplied portion of the Yul :ref:`optimizer sequence `, as by default,
+ even when the optimizer is not turned on, the :ref:`unused pruner ` step will be run.
+
You can find more details on both optimizer modules and their optimization steps below.
Benefits of Optimizing Solidity Code
@@ -275,11 +295,11 @@ backtracking.
All components of the Yul-based optimizer module are explained below.
The following transformation steps are the main components:
-- SSA Transform
-- Common Subexpression Eliminator
-- Expression Simplifier
-- Redundant Assign Eliminator
-- Full Inliner
+- SSATransform
+- CommonSubexpressionEliminator
+- ExpressionSimplifier
+- UnusedAssignEliminator
+- FullInliner
.. _optimizer-steps:
@@ -293,7 +313,7 @@ on the individual steps and their sequence below.
Abbreviation Full name
============ ===============================
``f`` :ref:`block-flattener`
-``l`` :ref:`circular-reference-pruner`
+``l`` :ref:`circular-references-pruner`
``c`` :ref:`common-subexpression-eliminator`
``C`` :ref:`conditional-simplifier`
``U`` :ref:`conditional-unsimplifier`
@@ -315,12 +335,11 @@ Abbreviation Full name
``T`` :ref:`literal-rematerialiser`
``L`` :ref:`load-resolver`
``M`` :ref:`loop-invariant-code-motion`
-``r`` :ref:`redundant-assign-eliminator`
-``R`` :ref:`reasoning-based-simplifier` - highly experimental
``m`` :ref:`rematerialiser`
-``V`` :ref:`SSA-reverser`
-``a`` :ref:`SSA-transform`
+``V`` :ref:`ssa-reverser`
+``a`` :ref:`ssa-transform`
``t`` :ref:`structural-simplifier`
+``r`` :ref:`unused-assign-eliminator`
``p`` :ref:`unused-function-parameter-pruner`
``S`` :ref:`unused-store-eliminator`
``u`` :ref:`unused-pruner`
@@ -330,10 +349,7 @@ Abbreviation Full name
Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``.
For this reason the Yul optimizer always applies them before applying any steps supplied by the user.
-The ReasoningBasedSimplifier is an optimizer step that is currently not enabled
-in the default set of steps. It uses an SMT solver to simplify arithmetic expressions
-and boolean conditions. It has not received thorough testing or validation yet and can produce
-non-reproducible results, so please use with care!
+.. _selecting-optimizations:
Selecting Optimizations
-----------------------
@@ -343,7 +359,7 @@ You can override this sequence and supply your own using the ``--yul-optimizatio
.. code-block:: bash
- solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOc'
+ solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOcmu'
The order of steps is significant and affects the quality of the output.
Moreover, applying a step may uncover new optimization opportunities for others that were already applied,
@@ -400,7 +416,7 @@ and functions can be optimized in isolation without having to traverse the AST c
FunctionGrouper
^^^^^^^^^^^^^^^
-The function grouper has to be applied after the disambiguator and the function hoister.
+The function grouper has to be applied after the Disambiguator and the FunctionHoister.
Its effect is that all topmost elements that are not function definitions are moved
into a single block which is the first statement of the root block.
@@ -413,14 +429,14 @@ After this step, a program has the following normal form:
Where ``I`` is a (potentially empty) block that does not contain any function definitions (not even recursively)
and ``F`` is a list of function definitions such that no function contains a function definition.
-The benefit of this stage is that we always know where the list of function begins.
+The benefit of this stage is that we always know where the list of functions begins.
.. _for-loop-condition-into-body:
ForLoopConditionIntoBody
^^^^^^^^^^^^^^^^^^^^^^^^
-This transformation moves the loop-iteration condition of a for-loop into loop body.
+This transformation moves the loop-iteration condition of a ``for`` loop into loop body.
We need this transformation because :ref:`expression-splitter` will not
apply to iteration condition expressions (the ``C`` in the following example).
@@ -439,7 +455,7 @@ is transformed to
Body...
}
-This transformation can also be useful when paired with ``LoopInvariantCodeMotion``, since
+This transformation can also be useful when paired with LoopInvariantCodeMotion, since
invariants in the loop-invariant conditions can then be taken outside the loop.
.. _for-loop-init-rewriter:
@@ -447,7 +463,7 @@ invariants in the loop-invariant conditions can then be taken outside the loop.
ForLoopInitRewriter
^^^^^^^^^^^^^^^^^^^
-This transformation moves the initialization part of a for-loop to before
+This transformation moves the initialization part of a ``for`` loop to before
the loop:
.. code-block:: text
@@ -466,7 +482,7 @@ is transformed to
}
This eases the rest of the optimization process because we can ignore
-the complicated scoping rules of the for loop initialisation block.
+the complicated scoping rules of the ``for`` loop initialization block.
.. _var-decl-initializer:
@@ -575,7 +591,7 @@ It is not applied to loop iteration-condition, because the loop control flow doe
this "outlining" of the inner expressions in all cases. We can sidestep this limitation by applying
:ref:`for-loop-condition-into-body` to move the iteration condition into loop body.
-The final program should be in a form such that (with the exception of loop conditions)
+The final program should be in an *expression-split form*, where (with the exception of loop conditions)
function calls cannot appear nested inside expressions
and all function call arguments have to be variables.
@@ -584,7 +600,7 @@ and it is also easier to perform function call inlining. Furthermore, it is simp
to replace individual parts of expressions or re-organize the "expression tree".
The drawback is that such code is much harder to read for humans.
-.. _SSA-transform:
+.. _ssa-transform:
SSATransform
^^^^^^^^^^^^
@@ -629,25 +645,25 @@ are not modified) perform the following transforms:
Furthermore, always record the current value of ``i`` used for ``a`` and replace each
reference to ``a`` by ``a_i``.
The current value mapping is cleared for a variable ``a`` at the end of each block
-in which it was assigned to and at the end of the for loop init block if it is assigned
-inside the for loop body or post block.
+in which it was assigned to and at the end of the ``for`` loop init block if it is assigned
+inside the ``for`` loop body or post block.
If a variable's value is cleared according to the rule above and the variable is declared outside
the block, a new SSA variable will be created at the location where control flow joins,
this includes the beginning of loop post/body block and the location right after
-If/Switch/ForLoop/Block statement.
+``if``/``switch``/``for``/block statement.
-After this stage, the Redundant Assign Eliminator is recommended to remove the unnecessary
+After this stage, the UnusedAssignEliminator is recommended to remove the unnecessary
intermediate assignments.
-This stage provides best results if the Expression Splitter and the Common Subexpression Eliminator
+This stage provides best results if the ExpressionSplitter and the CommonSubexpressionEliminator
are run right before it, because then it does not generate excessive amounts of variables.
-On the other hand, the Common Subexpression Eliminator could be more efficient if run after the
+On the other hand, the CommonSubexpressionEliminator could be more efficient if run after the
SSA transform.
-.. _redundant-assign-eliminator:
+.. _unused-assign-eliminator:
-RedundantAssignEliminator
-^^^^^^^^^^^^^^^^^^^^^^^^^
+UnusedAssignEliminator
+^^^^^^^^^^^^^^^^^^^^^^
The SSA transform always generates an assignment of the form ``a := a_i``, even though
these might be unnecessary in many cases, like the following example:
@@ -675,7 +691,7 @@ The SSA transform converts this snippet to the following:
sstore(a_3, 1)
}
-The Redundant Assign Eliminator removes all the three assignments to ``a``, because
+The UnusedAssignEliminator removes all the three assignments to ``a``, because
the value of ``a`` is not used and thus turn this
snippet into strict SSA form:
@@ -688,7 +704,7 @@ snippet into strict SSA form:
sstore(a_3, 1)
}
-Of course the intricate parts of determining whether an assignment is redundant or not
+Of course the intricate parts of determining whether an assignment is unused or not
are connected to joining control flow.
The component works as follows in detail:
@@ -700,7 +716,7 @@ mapping from assignment statements to the three states
value will be used later by a reference to the variable.
When an assignment is visited, it is added to the mapping in the "undecided" state
-(see remark about for loops below) and every other assignment to the same variable
+(see remark about ``for`` loops below) and every other assignment to the same variable
that is still in the "undecided" state is changed to "unused".
When a variable is referenced, the state of any assignment to that variable still
in the "undecided" state is changed to "used".
@@ -715,7 +731,7 @@ Conflicting values are resolved in the following way:
- "unused", "used" -> "used"
- "undecided", "used" -> "used"
-For for-loops, the condition, body and post-part are visited twice, taking
+For ``for`` loops, the condition, body and post-part are visited twice, taking
the joining control-flow at the condition into account.
In other words, we create three control flow paths: Zero runs of the loop,
one run and two runs and then combine them at the end.
@@ -741,13 +757,13 @@ and thus
.. code-block:: none
- max(s, f(s), f(f(s))) = max(s, f(s), f(f(s)), f(f(f(s))), ...).
+ max(s, f(s), f(f(s))) = max(s, f(s), f(f(s)), f(f(f(s))), ...)
In summary, running the loop at most twice is enough because there are only three
different states.
-For switch statements that have a "default"-case, there is no control-flow
-part that skips the switch.
+For ``switch`` statements that have a default case, there is no control-flow
+part that skips the ``switch``.
When a variable goes out of scope, all statements still in the "undecided"
state are changed to "unused", unless the variable is the return
@@ -777,7 +793,7 @@ The following parts make an expression non-movable:
DataflowAnalyzer
^^^^^^^^^^^^^^^^
-The Dataflow Analyzer is not an optimizer step itself but is used as a tool
+The DataflowAnalyzer is not an optimizer step itself but is used as a tool
by other components. While traversing the AST, it tracks the current value of
each variable, as long as that value is a movable expression.
It records the variables that are part of the expression
@@ -788,7 +804,7 @@ of the currently stored expression for ``b``.
At control-flow joins, knowledge about variables is cleared if they have or would be assigned
in any of the control-flow paths. For instance, upon entering a
-for loop, all variables are cleared that will be assigned during the
+``for`` loop, all variables are cleared that will be assigned during the
body or the post block.
Expression-Scale Simplifications
@@ -802,7 +818,7 @@ and hopefully simpler expressions.
CommonSubexpressionEliminator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-This step uses the Dataflow Analyzer and replaces subexpressions that
+This step uses the DataflowAnalyzer and replaces subexpressions that
syntactically match the current value of a variable by a reference to
that variable. This is an equivalence transform because such subexpressions have
to be movable.
@@ -812,24 +828,24 @@ current value if the value is an identifier.
The combination of the two rules above allow to compute a local value
numbering, which means that if two variables have the same
-value, one of them will always be unused. The Unused Pruner or the
-Redundant Assign Eliminator will then be able to fully eliminate such
+value, one of them will always be unused. The UnusedPruner or the
+UnusedAssignEliminator will then be able to fully eliminate such
variables.
-This step is especially efficient if the expression splitter is run
+This step is especially efficient if the ExpressionSplitter is run
before. If the code is in pseudo-SSA form,
the values of variables are available for a longer time and thus we
have a higher chance of expressions to be replaceable.
-The expression simplifier will be able to perform better replacements
-if the common subexpression eliminator was run right before it.
+The ExpressionSimplifier will be able to perform better replacements
+if the CommonSubexpressionEliminator was run right before it.
.. _expression-simplifier:
-Expression Simplifier
-^^^^^^^^^^^^^^^^^^^^^
+ExpressionSimplifier
+^^^^^^^^^^^^^^^^^^^^
-The Expression Simplifier uses the Dataflow Analyzer and makes use
+The ExpressionSimplifier uses the DataflowAnalyzer and makes use
of a list of equivalence transforms on expressions like ``X + 0 -> X``
to simplify the code.
@@ -841,7 +857,7 @@ even when the code is in pseudo-SSA form.
Some of the patterns like ``X - X -> 0`` can only be applied as long
as the expression ``X`` is movable, because otherwise it would remove its potential side-effects.
Since variable references are always movable, even if their current
-value might not be, the Expression Simplifier is again more powerful
+value might not be, the ExpressionSimplifier is again more powerful
in split or pseudo-SSA form.
.. _literal-rematerialiser:
@@ -861,28 +877,12 @@ currently stored in storage resp. memory, if known.
Works best if the code is in SSA form.
-Prerequisite: Disambiguator, ForLoopInitRewriter.
-
-.. _reasoning-based-simplifier:
-
-ReasoningBasedSimplifier
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-This optimizer uses SMT solvers to check whether ``if`` conditions are constant.
-
-- If ``constraints AND condition`` is UNSAT, the condition is never true and the whole body can be removed.
-- If ``constraints AND NOT condition`` is UNSAT, the condition is always true and can be replaced by ``1``.
-
-The simplifications above can only be applied if the condition is movable.
-
-It is only effective on the EVM dialect, but safe to use on other dialects.
-
-Prerequisite: Disambiguator, SSATransform.
+Prerequisites: Disambiguator, ForLoopInitRewriter.
Statement-Scale Simplifications
-------------------------------
-.. _circular-reference-pruner:
+.. _circular-references-pruner:
CircularReferencesPruner
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -895,7 +895,7 @@ neither externally referenced nor referenced from the outermost context.
ConditionalSimplifier
^^^^^^^^^^^^^^^^^^^^^
-The Conditional Simplifier inserts assignments to condition variables if the value can be determined
+The ConditionalSimplifier inserts assignments to condition variables if the value can be determined
from the control-flow.
Destroys SSA form.
@@ -906,12 +906,12 @@ we cannot assign a specific value.
Current features:
-- switch cases: insert " := "
-- after if statement with terminating control-flow, insert " := 0"
+- ``switch`` cases: insert `` := ``
+- after ``if`` statement with terminating control-flow, insert `` := 0``
Future features:
-- allow replacements by "1"
+- allow replacements by ``1``
- take termination of user-defined functions into account
Works best with SSA form and if dead code removal has run before.
@@ -923,7 +923,7 @@ Prerequisite: Disambiguator.
ConditionalUnsimplifier
^^^^^^^^^^^^^^^^^^^^^^^
-Reverse of Conditional Simplifier.
+Reverse of ConditionalSimplifier.
.. _control-flow-simplifier:
@@ -932,14 +932,14 @@ ControlFlowSimplifier
Simplifies several control-flow structures:
-- replace if with empty body with pop(condition)
-- remove empty default switch case
-- remove empty switch case if no default case exists
-- replace switch with no cases with pop(expression)
-- turn switch with single case into if
-- replace switch with only default case with pop(expression) and body
-- replace switch with const expr with matching case body
-- replace ``for`` with terminating control flow and without other break/continue by ``if``
+- replace ``if`` with empty body with ``pop(condition)``
+- remove empty default ``switch`` case
+- remove empty ``switch`` case if no default case exists
+- replace ``switch`` with no cases with ``pop(expression)``
+- turn ``switch`` with single case into ``if``
+- replace ``switch`` with only default case with ``pop(expression)`` and body
+- replace ``switch`` with const expr with matching case body
+- replace ``for`` with terminating control flow and without other ``break``/``continue`` by ``if``
- remove ``leave`` at the end of a function.
None of these operations depend on the data flow. The StructuralSimplifier
@@ -949,6 +949,7 @@ The ControlFlowSimplifier does record the presence or absence of ``break``
and ``continue`` statements during its traversal.
Prerequisite: Disambiguator, FunctionHoister, ForLoopInitRewriter.
+
Important: Introduces EVM opcodes and thus can only be used on EVM code for now.
.. _dead-code-eliminator:
@@ -959,15 +960,16 @@ DeadCodeEliminator
This optimization stage removes unreachable code.
Unreachable code is any code within a block which is preceded by a
-leave, return, invalid, break, continue, selfdestruct, revert or by a call to a user-defined function that recurses infinitely.
+``leave``, ``return``, ``invalid``, ``break``, ``continue``, ``selfdestruct``, ``revert`` or by
+a call to a user-defined function that recurses infinitely.
Function definitions are retained as they might be called by earlier
code and thus are considered reachable.
-Because variables declared in a for loop's init block have their scope extended to the loop body,
+Because variables declared in a ``for`` loop's init block have their scope extended to the loop body,
we require ForLoopInitRewriter to run before this step.
-Prerequisite: ForLoopInitRewriter, Function Hoister, Function Grouper
+Prerequisites: ForLoopInitRewriter, FunctionHoister, FunctionGrouper.
.. _equal-store-eliminator:
@@ -978,12 +980,12 @@ This steps removes ``mstore(k, v)`` and ``sstore(k, v)`` calls if
there was a previous call to ``mstore(k, v)`` / ``sstore(k, v)``,
no other store in between and the values of ``k`` and ``v`` did not change.
-This simple step is effective if run after the SSA transform and the
-Common Subexpression Eliminator, because SSA will make sure that the variables
-will not change and the Common Subexpression Eliminator re-uses exactly the same
+This simple step is effective if run after the SSATransform and the
+CommonSubexpressionEliminator, because SSA will make sure that the variables
+will not change and the CommonSubexpressionEliminator re-uses exactly the same
variable if the value is known to be the same.
-Prerequisites: Disambiguator, ForLoopInitRewriter
+Prerequisites: Disambiguator, ForLoopInitRewriter.
.. _unused-pruner:
@@ -992,8 +994,8 @@ UnusedPruner
This step removes the definitions of all functions that are never referenced.
-It also removes the declaration of variables that are never referenced.
-If the declaration assigns a value that is not movable, the expression is retained,
+It also removes declarations of variables that are never referenced.
+If a declaration assigns a value that is not movable, the expression is retained,
but its value is discarded.
All movable expression statements (expressions that are not assigned) are removed.
@@ -1006,22 +1008,22 @@ StructuralSimplifier
This is a general step that performs various kinds of simplifications on
a structural level:
-- replace if statement with empty body by ``pop(condition)``
-- replace if statement with true condition by its body
-- remove if statement with false condition
-- turn switch with single case into if
-- replace switch with only default case by ``pop(expression)`` and body
-- replace switch with literal expression by matching case body
-- replace for loop with false condition by its initialization part
+- replace ``if`` statement with empty body by ``pop(condition)``
+- replace ``if`` statement with true condition by its body
+- remove ``if`` statement with false condition
+- turn ``switch`` with single case into ``if``
+- replace ``switch`` with only default case by ``pop(expression)`` and body
+- replace ``switch`` with literal expression by matching case body
+- replace ``for`` loop with false condition by its initialization part
-This component uses the Dataflow Analyzer.
+This component uses the DataflowAnalyzer.
.. _block-flattener:
BlockFlattener
^^^^^^^^^^^^^^
-This stage eliminates nested blocks by inserting the statement in the
+This stage eliminates nested blocks by inserting the statements in the
inner block at the appropriate place in the outer block. It depends on the
FunctionGrouper and does not flatten the outermost block to keep the form
produced by the FunctionGrouper.
@@ -1062,10 +1064,9 @@ This optimization moves movable SSA variable declarations outside the loop.
Only statements at the top level in a loop's body or post block are considered, i.e variable
declarations inside conditional branches will not be moved out of the loop.
-Requirements:
+ExpressionSplitter and SSATransform should be run upfront to obtain better results.
-- The Disambiguator, ForLoopInitRewriter and FunctionHoister must be run upfront.
-- Expression splitter and SSA transform should be run upfront to obtain better result.
+Prerequisites: Disambiguator, ForLoopInitRewriter, FunctionHoister.
Function-Level Optimizations
@@ -1092,7 +1093,7 @@ function ``f_1`` that takes only one argument, i.e.,
Other optimization steps will be able to make more simplifications to the function. The
optimization step is mainly useful for functions that would not be inlined.
-Prerequisites: Disambiguator, FunctionHoister
+Prerequisites: Disambiguator, FunctionHoister.
LiteralRematerialiser is recommended as a prerequisite, even though it's not required for
correctness.
@@ -1122,7 +1123,7 @@ The step LiteralRematerialiser is not required for correctness. It helps deal wi
``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``,
allowing us to rewrite the function.
-.. index:: ! unused store eliminator
+.. index:: ! UnusedStoreEliminator
.. _unused-store-eliminator:
UnusedStoreEliminator
@@ -1149,7 +1150,7 @@ For example, the following code
sstore(c, 3)
}
-will be transformed into the code below after the Unused Store Eliminator step is run
+will be transformed into the code below after the UnusedStoreEliminator step is run
.. code-block:: yul
@@ -1159,10 +1160,10 @@ will be transformed into the code below after the Unused Store Eliminator step i
sstore(c, 3)
}
-For memory store operations, things are generally simpler, at least in the outermost yul block as all such
+For memory store operations, things are generally simpler, at least in the outermost Yul block as all such
statements will be removed if they are never read from in any code path.
At function analysis level, however, the approach is similar to ``sstore``, as we do not know whether the memory location will
-be read once we leave the function's scope, so the statement will be removed only if all code code paths lead to a memory overwrite.
+be read once we leave the function's scope, so the statement will be removed only if all code paths lead to a memory overwrite.
Best run in SSA form.
@@ -1177,8 +1178,8 @@ If two functions are syntactically equivalent, while allowing variable
renaming but not any re-ordering, then any reference to one of the
functions is replaced by the other.
-The actual removal of the function is performed by the Unused Pruner.
+The actual removal of the function is performed by the UnusedPruner.
Function Inlining
-----------------
@@ -1199,7 +1200,7 @@ Furthermore, for all parameters, all of the following need to be true:
- The argument is movable.
- The parameter is either referenced less than twice in the function body, or the argument is rather cheap
- ("cost" of at most 1, like a constant up to 0xff).
+ ("cost" of at most 1, like a constant up to ``0xff``).
Example: The function to be inlined has the form of ``function f(...) -> r { r := E }`` where
``E`` is an expression that does not reference ``r`` and all arguments in the function call are movable expressions.
@@ -1213,11 +1214,11 @@ This component can only be used on sources with unique names.
FullInliner
^^^^^^^^^^^
-The Full Inliner replaces certain calls of certain functions
+The FullInliner replaces certain calls of certain functions
by the function's body. This is not very helpful in most cases, because
it just increases the code size but does not have a benefit. Furthermore,
code is usually very expensive and we would often rather have shorter
-code than more efficient code. In same cases, though, inlining a function
+code than more efficient code. In some cases, though, inlining a function
can have positive effects on subsequent optimizer steps. This is the case
if one of the function arguments is a constant, for example.
@@ -1237,6 +1238,11 @@ we can run the optimizer on this specialized function. If it
results in heavy gains, the specialized function is kept,
otherwise the original function is used instead.
+FunctionHoister and ExpressionSplitter are recommended as prerequisites since they make the step
+more efficient, but are not required for correctness.
+In particular, function calls with other function calls as arguments are not inlined, but running
+ExpressionSplitter beforehand ensures that there are no such calls in the input.
+
Cleanup
-------
@@ -1250,7 +1256,7 @@ variables as much as possible.
ExpressionJoiner
^^^^^^^^^^^^^^^^
-This is the opposite operation of the expression splitter. It turns a sequence of
+This is the opposite operation of the ExpressionSplitter. It turns a sequence of
variable declarations that have exactly one reference into a complex expression.
This stage fully preserves the order of function calls and opcode executions.
It does not make use of any information concerning the commutativity of the opcodes;
@@ -1270,21 +1276,21 @@ Because of that, the snippet ``let x := add(0, 2) let y := mul(x, 3)`` is
transformed to ``let y := mul(add(0, 2), 3)``, even though the ``add`` opcode
would be executed after the evaluation of the literal ``3``.
-.. _SSA-reverser:
+.. _ssa-reverser:
SSAReverser
^^^^^^^^^^^
-This is a tiny step that helps in reversing the effects of the SSA transform
-if it is combined with the Common Subexpression Eliminator and the
-Unused Pruner.
+This is a tiny step that helps in reversing the effects of the SSATransform
+if it is combined with the CommonSubexpressionEliminator and the
+UnusedPruner.
-The SSA form we generate is detrimental to code generation on the EVM and
-WebAssembly alike because it generates many local variables. It would
+The SSA form we generate is detrimental to code generation
+because it produces many local variables. It would
be better to just re-use existing variables with assignments instead of
fresh variable declarations.
-The SSA transform rewrites
+The SSATransform rewrites
.. code-block:: yul
@@ -1302,7 +1308,7 @@ to
a := a_2
The problem is that instead of ``a``, the variable ``a_1`` is used
-whenever ``a`` was referenced. The SSA transform changes statements
+whenever ``a`` was referenced. The SSATransform changes statements
of this form by just swapping out the declaration and the assignment. The above
snippet is turned into
@@ -1315,10 +1321,10 @@ snippet is turned into
let a_2 := a
This is a very simple equivalence transform, but when we now run the
-Common Subexpression Eliminator, it will replace all occurrences of ``a_1``
-by ``a`` (until ``a`` is re-assigned). The Unused Pruner will then
+CommonSubexpressionEliminator, it will replace all occurrences of ``a_1``
+by ``a`` (until ``a`` is re-assigned). The UnusedPruner will then
eliminate the variable ``a_1`` altogether and thus fully reverse the
-SSA transform.
+SSATransform.
.. _stack-compressor:
@@ -1349,9 +1355,9 @@ is comparatively cheap to evaluate. Furthermore, it is only semantically equival
the value of the expression did not change between the point of assignment and the
point of use. The main benefit of this stage is that it can save stack slots if it
leads to a variable being eliminated completely (see below), but it can also
-save a DUP opcode on the EVM if the expression is very cheap.
+save a ``DUP`` opcode on the EVM if the expression is very cheap.
-The Rematerialiser uses the Dataflow Analyzer to track the current values of variables,
+The Rematerialiser uses the DataflowAnalyzer to track the current values of variables,
which are always movable.
If the value is very cheap or the variable was explicitly requested to be eliminated,
the variable reference is replaced by its current value.
@@ -1399,14 +1405,62 @@ into
The LiteralRematerialiser should be run before this step.
+Codegen-Based Optimizer Module
+==============================
-WebAssembly specific
---------------------
+Currently, the codegen-based optimizer module provides two optimizations.
-MainFunction
-^^^^^^^^^^^^
+The first one, available in the legacy code generator, moves literals to the right side of
+commutative binary operators, which helps exploit their associativity.
+
+The other one, available in the IR-based code generator, enables the use of unchecked arithmetic
+when generating code for incrementing the counter variable of certain idiomatic ``for`` loops.
+This avoids wasting gas by identifying some conditions that guarantee that the counter variable
+cannot overflow.
+This eliminates the need to use a verbose unchecked arithmetic block inside the loop body to
+increment the counter variable.
+
+.. _unchecked-loop-optimizer:
+
+Unchecked Loop Increment
+------------------------
+
+Introduced in Solidity ``0.8.22``, the overflow check optimization step is concerned with identifying
+the conditions under which the ``for`` loop counter can be safely incremented
+without overflow checks.
+
+This optimization is **only** applied to ``for`` loops of the general form:
+
+.. code-block:: solidity
+
+ for (uint i = X; i < Y; ++i) {
+ // variable i is not modified in the loop body
+ }
+
+The condition and the fact that the counter variable is only ever incremented
+guarantee that it never overflows.
+The precise requirements for the loop to be eligible for the optimization are as follows:
+
+- The loop condition is a comparison of the form ``i < Y``, for a local counter variable ``i``
+ (called the "loop counter" hereon) and an expression ``Y``.
+- The built-in operator ``<`` is necessarily used in the loop condition and is the only operator
+ that triggers the optimization. ``<=`` and the like are intentionally excluded. Additionally,
+ user-defined operators are **not** eligible.
+- The loop expression is a prefix or postfix increment of the counter variable, i.e, ``i++`` or ``++i``.
+- The loop counter is a local variable of a built-in integer type.
+- The loop counter is **not** modified by the loop body or by the expression used as the loop condition.
+- The comparison is performed on the same type as the loop counter, meaning that the type of the
+ right-hand-side expression is implicitly convertible to the type of the counter, such that the latter
+ is not implicitly widened before the comparison.
-Changes the topmost block to be a function with a specific name ("main") which has no
-inputs nor outputs.
+To clarify the last condition, consider the following example:
+
+.. code-block:: solidity
+
+ for (uint8 i = 0; i < uint16(1000); i++) {
+ // ...
+ }
-Depends on the Function Grouper.
+In this case, the counter ``i`` has its type implicitly converted from ``uint8``
+to ``uint16`` before the comparison and the condition is in fact never false, so
+the overflow check for the increment cannot be removed.
diff --git a/docs/internals/source_mappings.rst b/docs/internals/source_mappings.rst
index 11027b8aca..68c29d955e 100644
--- a/docs/internals/source_mappings.rst
+++ b/docs/internals/source_mappings.rst
@@ -26,7 +26,7 @@ that are not part of the original input but are referenced from the source
mappings. These source files together with their identifiers can be
obtained via ``output['contracts'][sourceName][contractName]['evm']['bytecode']['generatedSources']``.
-.. note ::
+.. note::
In the case of instructions that are not associated with any particular source file,
the source mapping assigns an integer identifier of ``-1``. This may happen for
bytecode sections stemming from compiler-generated inline assembly statements.
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index 875e5ebc86..45857c3f89 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -85,13 +85,14 @@ registering with a username and password, all you need is an Ethereum keypair.
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
- pragma solidity ^0.8.4;
+ pragma solidity ^0.8.26;
+ // This will only compile via IR
contract Coin {
// The keyword "public" makes variables
// accessible from other contracts
address public minter;
- mapping (address => uint) public balances;
+ mapping(address => uint) public balances;
// Events allow clients to react to specific
// contract changes you declare
@@ -118,12 +119,7 @@ registering with a username and password, all you need is an Ethereum keypair.
// Sends an amount of existing coins
// from any caller to an address
function send(address receiver, uint amount) public {
- if (amount > balances[msg.sender])
- revert InsufficientBalance({
- requested: amount,
- available: balances[msg.sender]
- });
-
+ require(amount <= balances[msg.sender], InsufficientBalance(amount, balances[msg.sender]));
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
@@ -151,12 +147,12 @@ You do not need to do this, the compiler figures it out for you.
.. index:: mapping
-The next line, ``mapping (address => uint) public balances;`` also
+The next line, ``mapping(address => uint) public balances;`` also
creates a public state variable, but it is a more complex datatype.
The :ref:`mapping ` type maps addresses to :ref:`unsigned integers `.
Mappings can be seen as `hash tables `_ which are
-virtually initialised such that every possible key exists from the start and is mapped to a
+virtually initialized such that every possible key exists from the start and is mapped to a
value whose byte-representation is all zeros. However, it is neither possible to obtain a list of all keys of
a mapping, nor a list of all values. Record what you
added to the mapping, or use it in a context where this is not needed. Or
@@ -185,7 +181,7 @@ arguments ``from``, ``to`` and ``amount``, which makes it possible to track
transactions.
To listen for this event, you could use the following
-JavaScript code, which uses `web3.js `_ to create the ``Coin`` contract object,
+JavaScript code, which uses `web3.js `_ to create the ``Coin`` contract object,
and any user interface calls the automatically generated ``balances`` function from above:
.. code-block:: javascript
@@ -225,8 +221,8 @@ than the maximum value of ``uint`` (``2**256 - 1``). This is also true for the s
:ref:`Errors ` allow you to provide more information to the caller about
why a condition or operation failed. Errors are used together with the
:ref:`revert statement `. The ``revert`` statement unconditionally
-aborts and reverts all changes similar to the ``require`` function, but it also
-allows you to provide the name of an error and additional data which will be supplied to the caller
+aborts and reverts all changes, much like the :ref:`require function `.
+Both approaches allow you to provide the name of an error and additional data which will be supplied to the caller
(and eventually to the front-end application or block explorer) so that
a failure can more easily be debugged or reacted upon.
@@ -282,7 +278,7 @@ the source account is also not modified.
Furthermore, a transaction is always cryptographically signed by the sender (creator).
This makes it straightforward to guard access to specific modifications of the
database. In the example of the electronic currency, a simple check ensures that
-only the person holding the keys to the account can transfer money from it.
+only the person holding the keys to the account can transfer some compensation, e.g. Ether, from it.
.. index:: ! block
@@ -300,11 +296,11 @@ and then they will be executed and distributed among all participating nodes.
If two transactions contradict each other, the one that ends up being second will
be rejected and not become part of the block.
-These blocks form a linear sequence in time and that is where the word "blockchain"
-derives from. Blocks are added to the chain in rather regular intervals - for
-Ethereum this is roughly every 17 seconds.
+These blocks form a linear sequence in time, and that is where the word "blockchain" derives from.
+Blocks are added to the chain at regular intervals, although these intervals may be subject to change in the future.
+For the most up-to-date information, it is recommended to monitor the network, for example, on `Etherscan `_.
-As part of the "order selection mechanism" (which is called "mining") it may happen that
+As part of the "order selection mechanism", which is called `attestation `_, it may happen that
blocks are reverted from time to time, but only at the "tip" of the chain. The more
blocks are added on top of a particular block, the less likely this block will be reverted. So it might be that your transactions
are reverted and even removed from the blockchain, but the longer you wait, the less
@@ -419,13 +415,15 @@ In case of an exception that reverts changes, already used up gas is not refunde
Since EVM executors can choose to include a transaction or not,
transaction senders cannot abuse the system by setting a low gas price.
-.. index:: ! storage, ! memory, ! stack
+.. index:: ! storage, ! memory, ! stack, ! transient storage
-Storage, Memory and the Stack
-=============================
+.. _locations:
+
+Storage, Transient Storage, Memory and the Stack
+================================================
-The Ethereum Virtual Machine has three areas where it can store data:
-storage, memory and the stack.
+The Ethereum Virtual Machine has different areas where it can store data with the most
+prominent being storage, transient storage, memory and the stack.
Each account has a data area called **storage**, which is persistent between function calls
and transactions.
@@ -436,7 +434,15 @@ you should minimize what you store in persistent storage to what the contract ne
Store data like derived calculations, caching, and aggregates outside of the contract.
A contract can neither read nor write to any storage apart from its own.
-The second data area is called **memory**, of which a contract obtains
+Similar to storage, there is another data area called **transient storage**,
+where the main difference is that it is reset at the end of each transaction.
+The values stored in this data location persist only across function calls originating
+from the first call of the transaction.
+When the transaction ends, the transient storage is reset and the values stored there
+become unavailable to calls in subsequent transactions.
+Despite this, the cost of reading and writing to transient storage is significantly lower than for storage.
+
+The third data area is called **memory**, of which a contract obtains
a freshly cleared instance for each message call. Memory is linear and can be
addressed at byte level, but reads are limited to a width of 256 bits, while writes
can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when
@@ -458,6 +464,31 @@ in order to get deeper access to the stack,
but it is not possible to just access arbitrary elements deeper in the stack
without first removing the top of the stack.
+Calldata, Returndata and Code
+=============================
+
+There are also other data areas which are not as apparent as those discussed previously.
+However, they are routinely used during the execution of smart contract transactions.
+
+The calldata region is the data sent to a transaction as part of a smart contract transaction.
+For example, when creating a contract, calldata would be the constructor code of the new contract.
+The parameters of external functions are always initially stored in calldata in an ABI-encoded form
+and only then decoded into the location specified in their declaration.
+If declared as ``memory``, the compiler will eagerly decode them into memory at the beginning of the function,
+while marking them as ``calldata`` means that this will be done lazily, only when accessed.
+Value types and ``storage`` pointers are decoded directly onto the stack.
+
+The returndata is the way a smart contract can return a value after a call.
+In general, external Solidity functions use the ``return`` keyword to ABI-encode values into the returndata area.
+
+The code is the region where the EVM instructions of a smart contract are stored.
+Code is the bytes read, interpreted, and executed by the EVM during smart contract execution.
+Instruction data stored in the code is persistent as part of a contract account state field.
+Immutable and constant variables are stored in the code region.
+All references to immutables are replaced with the values assigned to them.
+A similar process is performed for constants which have their expressions inlined
+in the places where they are referenced in the smart contract code.
+
.. index:: ! instruction
Instruction Set
@@ -562,6 +593,25 @@ is removed from the state. Removing the contract in theory sounds like a good
idea, but it is potentially dangerous, as if someone sends Ether to removed
contracts, the Ether is forever lost.
+.. warning::
+ From ``EVM >= Cancun`` onwards, ``selfdestruct`` will **only** send all Ether in the account to the given recipient and not destroy the contract.
+ However, when ``selfdestruct`` is called in the same transaction that creates the contract calling it,
+ the behaviour of ``selfdestruct`` before Cancun hardfork (i.e., ``EVM <= Shanghai``) is preserved and will destroy the current contract,
+ deleting any data, including storage keys, code and the account itself.
+ See `EIP-6780 `_ for more details.
+
+ The new behaviour is the result of a network-wide change that affects all contracts present on
+ the Ethereum mainnet and testnets.
+ It is important to note that this change is dependent on the EVM version of the chain on which
+ the contract is deployed.
+ The ``--evm-version`` setting used when compiling the contract has no bearing on it.
+
+ Also, note that the ``selfdestruct`` opcode has been deprecated in Solidity version 0.8.18,
+ as recommended by `EIP-6049 `_.
+ The deprecation is still in effect and the compiler will still emit warnings on its use.
+ Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account.
+ Future changes to the EVM might further reduce the functionality of the opcode.
+
.. warning::
Even if a contract is removed by ``selfdestruct``, it is still part of the
history of the blockchain and probably retained by most Ethereum nodes.
@@ -584,9 +634,9 @@ Precompiled Contracts
=====================
There is a small set of contract addresses that are special:
-The address range between ``1`` and (including) ``8`` contains
+The address range between ``1`` and (including) ``0x0a`` contains
"precompiled contracts" that can be called as any other contract
-but their behaviour (and their gas consumption) is not defined
+but their behavior (and their gas consumption) is not defined
by EVM code stored at that address (they do not contain code)
but instead is implemented in the EVM execution environment itself.
diff --git a/docs/ir-breaking-changes.rst b/docs/ir-breaking-changes.rst
index 7e4efce688..4917cfc715 100644
--- a/docs/ir-breaking-changes.rst
+++ b/docs/ir-breaking-changes.rst
@@ -15,13 +15,13 @@ The IR-based code generator was introduced with an aim to not only allow
code generation to be more transparent and auditable but also
to enable more powerful optimization passes that span across functions.
-You can enable it on the command line using ``--via-ir``
+You can enable it on the command-line using ``--via-ir``
or with the option ``{"viaIR": true}`` in standard-json and we
encourage everyone to try it out!
For several reasons, there are tiny semantic differences between the old
and the IR-based code generator, mostly in areas where we would not
-expect people to rely on this behaviour anyway.
+expect people to rely on this behavior anyway.
This section highlights the main differences between the old and the IR-based codegen.
Semantic Only Changes
@@ -30,6 +30,8 @@ Semantic Only Changes
This section lists the changes that are semantic-only, thus potentially
hiding new and different behavior in existing code.
+.. _state-variable-initialization-order:
+
- The order of state variable initialization has changed in case of inheritance.
The order used to be:
@@ -122,8 +124,8 @@ hiding new and different behavior in existing code.
modifier mod() { _; _; }
}
- If you execute ``f(0)`` in the old code generator, it will return ``2``, while
- it will return ``1`` when using the new code generator.
+ If you execute ``f(0)`` in the old code generator, it will return ``1``, while
+ it will return ``0`` when using the new code generator.
.. code-block:: solidity
@@ -174,8 +176,8 @@ hiding new and different behavior in existing code.
The function ``preincr_u8(1)`` returns the following values:
- - Old code generator: 3 (``1 + 2``) but the return value is unspecified in general
- - New code generator: 4 (``2 + 2``) but the return value is not guaranteed
+ - Old code generator: ``3`` (``1 + 2``) but the return value is unspecified in general
+ - New code generator: ``4`` (``2 + 2``) but the return value is not guaranteed
.. index:: ! evaluation order; function arguments
@@ -247,7 +249,7 @@ hiding new and different behavior in existing code.
}
}
- The function `f()` behaves as follows:
+ The function ``f()`` behaves as follows:
- Old code generator: runs out of gas while zeroing the array contents after the large memory allocation
- New code generator: reverts due to free memory pointer overflow (does not run out of gas)
diff --git a/docs/language-influences.rst b/docs/language-influences.rst
index e4f0ab6902..a3ab1562e9 100644
--- a/docs/language-influences.rst
+++ b/docs/language-influences.rst
@@ -2,7 +2,7 @@
Language Influences
###################
-Solidity is a `curly-bracket language `_
+Solidity is a `curly-bracket language `_
that has been influenced and inspired by several well-known programming languages.
Solidity is most profoundly influenced by C++, but also borrowed concepts from languages like
diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst
index 9a58478586..600f2ed0f4 100644
--- a/docs/layout-of-source-files.rst
+++ b/docs/layout-of-source-files.rst
@@ -40,7 +40,7 @@ The comment is recognized by the compiler anywhere in the file at the
file level, but it is recommended to put it at the top of the file.
More information about how to use SPDX license identifiers
-can be found at the `SPDX website `_.
+can be found at the `SPDX website `_.
.. index:: ! pragma
@@ -182,7 +182,7 @@ Syntax and Semantics
Solidity supports import statements to help modularise your code that
are similar to those available in JavaScript
(from ES6 on). However, Solidity does not support the concept of
-a `default export `_.
+a `default export `_.
At a global level, you can use import statements of the following form:
diff --git a/docs/logo.svg b/docs/logo.svg
index 86b9f4995b..19391843b4 100644
--- a/docs/logo.svg
+++ b/docs/logo.svg
@@ -1,27 +1,8 @@
-
-
-
-