From 1a2a900d4e92eb2ccbaee8137a0eb90c58d03c08 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Fri, 2 Oct 2026 12:07:29 +0200 Subject: [PATCH 01/14] Modify documentation for wasm32v1-none target --- .../smart-contracts/develop-contracts.rst | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/source/mainnet/learn/smart-contracts/develop-contracts.rst b/source/mainnet/learn/smart-contracts/develop-contracts.rst index 7ea0d2f514..bfd39c01cf 100644 --- a/source/mainnet/learn/smart-contracts/develop-contracts.rst +++ b/source/mainnet/learn/smart-contracts/develop-contracts.rst @@ -28,7 +28,8 @@ Smart contracts do not have to be written in Rust. This is simply the first SDK provided. Manually written Wasm, or Wasm compiled from C, C++, AssemblyScript_, and others, is equally valid on the chain, as long as it adheres to the :ref:`Wasm -limitations Concordium imposes `. +limitations Concordium imposes `. Technically, the Wasm must +adhere to `WebAssembly Core Specification 1.0`_. .. seealso:: @@ -54,9 +55,10 @@ To obtain correct exports, the `crate-type` attribute must be set to Write a smart contract using ``concordium_std`` =============================================== -It is recommended to use the ``concordium_std`` crate, which provides a -more Rust-like experience for developing smart contract modules and calling -host functions. +It is highly recommended to use the ``concordium_std`` Rust crate, which provides a +more standard Rust-like experience for developing smart contract modules and calling +host functions. When using ``concordium_std``, you smart contract should be compiled +to the ``no_std`` target wasm32v-none_. The crate enables writing init and receive functions as simple Rust functions annotated with ``#[init(...)]`` and ``#[receive(...)]``, respectively. @@ -65,6 +67,8 @@ Here is an example of a smart contract that implements a counter: .. code-block:: rust + #![no_std] + use concordium_std::*; type State = u32; @@ -121,32 +125,11 @@ There are a number of things to notice: necessary. Otherwise, the state will appear as having mutated and you will also pay for the cost of saving and serializing the state. -.. note:: - - Note that deserialization is not without cost, and in some cases the - user might want more fine-grained control over the use of host functions. - For such use cases the annotations support a ``low_level`` option, which has - less overhead, but requires more from the user. - .. todo:: - Describe low-level - Introduce the concept of host functions before using them in the note above -.. [#serialize] If the state contains one or more of the types |StateBox|_, - |StateMap|_, or |StateSet|_, it should implement ``Serial`` - and ``DeserialWithState`` instead. The difference is the - deserialization, where ``Serialize`` is a combination of the - traits ``Serial`` and ``Deserial``. - ``State*`` types are essentially pointers to data stored in - state, and when serialized, only the pointer is written, while - the values are stored in the state. To load - the values again, the state context is needed, hence the ``DeserialWithState``. - -.. note:: - - There is also the option of building a contract using ``no_std``. For more information, read :ref:`no-std` - .. _serialize-state-and-parameters: Serializable state and parameters @@ -184,7 +167,7 @@ state into multiple nodes in the state tree. Which provide an interface similar to that of a map and set. These types cannot implement ``Serialize``, but they *do* implement ``Serial`` and ``DeserialWithState`` [#serialize]_. -``concordium_std`` also has a macros for deriving these two types for +``concordium_std`` also has macros for deriving these two types for user-defined structs and enums. .. code-block:: rust @@ -207,6 +190,16 @@ the state must implement ``Serialize`` *or* ``Serial + DeserialWithState``. Strictly speaking you only need to deserialize bytes to your parameter type, but it is convenient to be able to serialize types when writing tests. +.. [#serialize] If the state contains one or more of the types |StateBox|_, + |StateMap|_, or |StateSet|_, it should implement ``Serial`` + and ``DeserialWithState`` instead. The difference is the + deserialization, where ``Serialize`` is a combination of the + traits ``Serial`` and ``Deserial``. + ``State*`` types are essentially pointers to data stored in + state, and when serialized, only the pointer is written, while + the values are stored in the state. To load + the values again, the state context is needed, hence the ``DeserialWithState``. + .. _working-with-parameters: Work with parameters @@ -223,7 +216,9 @@ As an example, see the following contract in which the parameter ``ReceiveParameter`` is deserialized on the highlighted line: .. code-block:: rust - :emphasize-lines: 25 + :emphasize-lines: 27 + + #![no_std] use concordium_std::*; @@ -363,13 +358,13 @@ Build a smart contract module with ``cargo-concordium`` ======================================================= The Rust compiler has good support for compiling to Wasm using the -``wasm32-unknown-unknown`` target. +wasm32v1-none_ target. However, even when compiling with ``--release`` the resulting build includes large sections of debug information in custom sections, which are not useful for smart contracts on-chain. -To optimize the build and allow for new features such as embedding schemas, Concordium -recommends using ``cargo-concordium`` to build smart contracts. +To optimize the build and allow for features such as embedding schemas, Concordium +highly recommends using ``cargo-concordium`` to build smart contracts. .. seealso:: @@ -422,3 +417,5 @@ macro, e.g.: ``#[init(..., payable)]`` and ``#[receive(..., payable)]``. .. |StateSet| replace:: ``StateSet`` .. _payable: https://docs.rs/concordium-std/latest/concordium_std/attr.receive.html#payable-make-function-accept-an-amount-of-ccd .. |payable| replace:: ``payable`` +.. _WebAssembly Core Specification 1.0: https://www.w3.org/TR/wasm-core-1/ +.. _wasm32v1-none: https://doc.rust-lang.org/rustc/platform-support/wasm32v1-none.html From ba6a7301705b2a0e18feac7f02f1a58690f2dd74 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Fri, 2 Oct 2026 15:16:17 +0200 Subject: [PATCH 02/14] Modify documentation for wasm32v1-none target --- .../how-to/smart-contracts/build-contract.rst | 45 +----- .../how-to/smart-contracts/setup-contract.rst | 137 ++++++------------ .../smart-contracts/develop-contracts.rst | 2 +- 3 files changed, 49 insertions(+), 135 deletions(-) diff --git a/source/mainnet/how-to/smart-contracts/build-contract.rst b/source/mainnet/how-to/smart-contracts/build-contract.rst index 6857e5cc2a..e823ceccca 100644 --- a/source/mainnet/how-to/smart-contracts/build-contract.rst +++ b/source/mainnet/how-to/smart-contracts/build-contract.rst @@ -12,45 +12,21 @@ Set up smart contract development tools This guide covers how to install the tools needed to develop, build, and deploy smart contracts on Concordium. -.. Note:: - - You can also watch a video about installing the smart contract tools. - - .. raw:: html - - - Once you are familiar with smart contracts, it is a good idea to read the :ref:`Smart contracts best practices`. -.. Note:: - - To request CCDs for testing, use the buttons in the Concordium Wallets when running Testnet. - Rust and Cargo ============== First, `install rustup`_, which installs both Rust_ and Cargo_ on your machine. -.. Note:: - - Currently, Rust toolchain versions up to ``1.81`` are and newer are not supported by older ``cargo-concordium`` versions ( <= ``4.0.0``). Update ``cargo-concordium`` if you see the error ``Unexpected byte 0x80. Expected 0x00`` as follows: - - .. code-block:: console - - $ cargo install cargo-concordium - $ cargo concordium --version - $ cargo-concordium 4.1.1 - - The minimum supported rust version is currently version ``1.73`` - Then use ``rustup`` to install the Wasm target, which is used for compilation: .. code-block:: console - $rustup target add wasm32-unknown-unknown + $ rustup target add wasm32v1-none -``cargo-concordium`` +cargo-concordium ==================== ``cargo-concordium`` is the tool for developing smart contracts for the Concordium @@ -63,29 +39,18 @@ To install ``cargo-concordium`` run: .. code-block:: console - $cargo install --locked cargo-concordium + $ cargo install --locked cargo-concordium For a description of how to use the ``cargo-concordium`` run: .. code-block:: console - $cargo concordium --help + $ cargo concordium --help To use verifiable builds with cargo-concordium a container runtime such as `Docker `_ is required. -VSCode extension ----------------- - -The `VSCode extension `__ can help you develop Concordium smart contracts. The extension sets up the editor for development, installs the ``cargo-concordium`` smart contract development tool for all supported platforms, and provides commands in the editor for the essential workflows, such as building and testing smart contracts. - -You can watch a video about how to use the VSCode extension. - -.. raw:: html - - - Typescript smart contract client generator ------------------------------------------- +========================================== The `Typescript smart contract client generator `_ helps you generate JavaScript/TypeScript clients for smart contracts on the Concordium blockchain, providing a lower development time and better type-safety. diff --git a/source/mainnet/how-to/smart-contracts/setup-contract.rst b/source/mainnet/how-to/smart-contracts/setup-contract.rst index 8608f26d78..2b8046f5dc 100644 --- a/source/mainnet/how-to/smart-contracts/setup-contract.rst +++ b/source/mainnet/how-to/smart-contracts/setup-contract.rst @@ -11,124 +11,73 @@ Set up a project This guide shows you how to create a new Concordium smart contract project, either from a template or from scratch. You will need cargo-concordium installed. After following this guide, you will have a new Rust project set up with the correct structure and dependencies for Concordium smart contract development. This guide documents two different options (*from a template* or *from scratch*) to create a new Concordium smart contract project. -The *from a template* option is available for ``cargo-concordium`` version 2.2.0 or greater. It provides you with some -smart contract templates. Choose the template that best fits your project scope. +It provides you with some smart contract templates. Choose the template that best fits your project scope. The *from scratch* option guides you through the process when you want to start a new project without any boilerplate code. -.. tab-set:: +From a template (recommended) +============================= - .. tab-item:: From a template (recommended) +Concordium maintains several smart contract +`templates `_. +For generating the smart contracts from the above templates, the ``cargo-generate`` crate is required. +``cargo-generate`` can be installed by running the following command: - Concordium maintains several smart contract - `templates `_ (currently a ``default`` template and a ``cis2-nft`` template). - For generating the smart contracts from the above templates, the ``cargo-generate`` crate is required. - ``cargo-generate`` can be installed by running the following command: +.. code-block:: console - .. code-block:: console + $ cargo install --locked cargo-generate - $cargo install --locked cargo-generate +To start a new Concordium smart contract project from a template, run the command: - To start a new Concordium smart contract project from a template, run the command: +.. code-block:: console - .. code-block:: console + $ cargo concordium init - $cargo concordium init +Select the `default` template unless you have other preferences. - The path where the project should be created can be provided with the ``--path`` option. - You can find additional information on the available templates in the - `README file `_. +You can find additional information on the available templates in the +`README file `_. - .. tab-item:: From scratch +From scratch +============ - A smart contract in Rust is written as an ordinary Rust library crate. - The library is then compiled to Wasm using the Rust target - ``wasm32-unknown-unknown`` and, since it is just a Rust library, you can use - Cargo_ for dependency management. +A smart contract in Rust is written as an ordinary Rust library crate. +The library is then compiled to Wasm using the Rust target +``wasm32v1-none`` and, since it is just a Rust library, you can use +Cargo_ for dependency management. - To set up a new smart contract project, first create a project directory. Inside - the project directory run the following in a terminal: +To set up a new smart contract project, first create a project directory. Inside +the project directory run the following in a terminal: - .. code-block:: console +.. code-block:: console - $cargo init --lib + $ cargo init --lib - This will set up a default Rust library project by creating a few files and - directories. - Your directory should now contain a ``Cargo.toml`` file and a ``src`` - directory and some hidden files. +This will set up a default Rust library project by creating a few files and +directories. +Your directory should now contain a ``Cargo.toml`` file and a ``src`` +directory and some hidden files. - To be able to build Wasm you need to tell cargo the right ``crate-type``. - This is done by adding the following in the ``Cargo.toml`` file :: +To be able to build Wasm you need to tell cargo the right ``crate-type``. +This is done by adding the following in the ``Cargo.toml`` file :: - [lib] - crate-type = ["cdylib", "rlib"] + [lib] + crate-type = ["cdylib", "rlib"] - **Add the smart contract standard library** +**Add the smart contract standard library** - The next step is to add ``concordium-std`` as a dependency. - It is a library for Rust containing procedural macros and functions for - writing small and efficient smart contracts. +The next step is to add ``concordium-std`` as a dependency. +It is a library for Rust containing procedural macros and functions for +writing small and efficient smart contracts. - To add the library, open ``Cargo.toml`` and add the line - ``concordium-std = "*"`` (preferably, replace the `*` with the latest version of `concordium-std`_) in - the ``[dependencies]`` section:: +To add the library, open ``Cargo.toml`` and add the line +``concordium-std = "*"`` (preferably, replace the `*` with the latest version of `concordium-std`_) in +the ``[dependencies]`` section:: - [dependencies] - concordium-std = "6.0" + [dependencies] + concordium-std = "6.0" - The crate documentation is on docs.rs_. - - .. note:: - - If you wish to use a modified version of this crate, you will have to clone - the repository with ``concordium-std`` and have the dependency point at the - directory instead, by adding the following to ``Cargo.toml``:: - - [dependencies] - concordium-std = { path = "./path/to/concordium-std" } - -.. _setup-wee-alloc-feature: - -.. note:: - - To compile your smart contracts, a memory `allocator `_ is used. - ``concordium-std`` version ``<6.0.0`` hard-coded the use of the `wee_alloc `_ allocator. - In ``concordium-std`` version ``>=6.0.0``, ``wee_alloc`` is a feature and needs to be explicitly enabled. - When ``std`` feature is enabled the allocator provided by the Rust standard library is used - by default but when the ``wee_alloc`` feature is enabled in addition, ``wee_alloc`` is used instead. - - You can enable the ``wee_alloc`` feature in ``concordium-std`` version ``>=6.0.0`` by using: - - .. code-block:: rust - - [dependencies] - concordium-std = {version = "6.0", features = ["wee_alloc"]} - - Alternatively, if you want to test with and without ``wee_alloc`` enabled add a ``wee_alloc`` feature to the smart contract crate as follows: - - .. code-block:: rust - - [features] - default = ["std", "wee_alloc"] - std = ["concordium-std/std"] - wee_alloc = ["concordium-std/wee_alloc"] - - The main reason for using ``wee_alloc`` instead of the default allocator - is that ``wee_alloc`` has a smaller code footprint, i.e, the resulting smart contracts modules are going to - be smaller. Smaller modules will be cheaper to deploy and run. Concordium nodes will load the smart contract module - code into memory when executing a smart contract function on-chain. Hence, the smart contract module size - has an impact on the execution cost. - -.. note:: - - ``Wee_alloc`` is unmaintained currently and hence an optional feature for backward compatibility. - There are other allocators available, read :ref:`sc-costs-custom-allocator` for a guide on how to use one. - -.. seealso:: - - It is possible to build smart contracts without using Rust's ``std``. - For more information, see :ref:`no-std`. +The crate documentation is on docs.rs_. .. _Rust: https://www.rust-lang.org/ .. _Cargo: https://doc.rust-lang.org/cargo/ diff --git a/source/mainnet/learn/smart-contracts/develop-contracts.rst b/source/mainnet/learn/smart-contracts/develop-contracts.rst index bfd39c01cf..d045a89bfc 100644 --- a/source/mainnet/learn/smart-contracts/develop-contracts.rst +++ b/source/mainnet/learn/smart-contracts/develop-contracts.rst @@ -58,7 +58,7 @@ Write a smart contract using ``concordium_std`` It is highly recommended to use the ``concordium_std`` Rust crate, which provides a more standard Rust-like experience for developing smart contract modules and calling host functions. When using ``concordium_std``, you smart contract should be compiled -to the ``no_std`` target wasm32v-none_. +to the ``no_std`` target wasm32v1-none_. The crate enables writing init and receive functions as simple Rust functions annotated with ``#[init(...)]`` and ``#[receive(...)]``, respectively. From a4e2351a80a3656907ec04a22e96ed871e87fcf6 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Fri, 2 Oct 2026 15:31:13 +0200 Subject: [PATCH 03/14] Modify documentation for wasm32v1-none target --- .../how-to/smart-contracts/build-contract.rst | 5 ----- .../how-to/smart-contracts/setup-contract.rst | 18 +++++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/source/mainnet/how-to/smart-contracts/build-contract.rst b/source/mainnet/how-to/smart-contracts/build-contract.rst index e823ceccca..1bb4bae3dd 100644 --- a/source/mainnet/how-to/smart-contracts/build-contract.rst +++ b/source/mainnet/how-to/smart-contracts/build-contract.rst @@ -63,11 +63,6 @@ The tool to deploy and interact with smart contracts is To ease deployment and initialization, you can use the `Smart contract deploy and initialize tool `__. It works with the |bw| to deploy and initialize smart contracts to Mainnet and Testnet. -.. note:: - - To deploy smart contract modules and interact with the chain, make sure - that you are :ref:`running a node`. - .. _Rust: https://www.rust-lang.org/ .. _Cargo: https://doc.rust-lang.org/cargo/ .. _install rustup: https://rustup.rs/ diff --git a/source/mainnet/how-to/smart-contracts/setup-contract.rst b/source/mainnet/how-to/smart-contracts/setup-contract.rst index 2b8046f5dc..11c8528adb 100644 --- a/source/mainnet/how-to/smart-contracts/setup-contract.rst +++ b/source/mainnet/how-to/smart-contracts/setup-contract.rst @@ -64,26 +64,30 @@ This is done by adding the following in the ``Cargo.toml`` file :: [lib] crate-type = ["cdylib", "rlib"] +And you need to declare you library as ``no_std`` in ``lib.rs``: + +.. code-block:: rust + + #![no_std] + **Add the smart contract standard library** -The next step is to add ``concordium-std`` as a dependency. +The next step is to add ``concordium-std`` as a dependency. The crate documentation is on docs.rs_. It is a library for Rust containing procedural macros and functions for writing small and efficient smart contracts. -To add the library, open ``Cargo.toml`` and add the line -``concordium-std = "*"`` (preferably, replace the `*` with the latest version of `concordium-std`_) in +To add the library, open ``Cargo.toml`` and add ``concordium-std`` in the ``[dependencies]`` section:: [dependencies] - concordium-std = "6.0" + concordium-std = "11.0" + -The crate documentation is on docs.rs_. .. _Rust: https://www.rust-lang.org/ .. _Cargo: https://doc.rust-lang.org/cargo/ .. _rustup: https://rustup.rs/ .. _repository: https://gitlab.com/Concordium/concordium-std -.. _docs.rs: https://docs.rs/crate/concordium-std/ -.. _`concordium-std`: https://docs.rs/crate/concordium-std/ +.. _docs.rs: https://docs.rs/concordium-std/latest/concordium_std/ That is it! You are now ready to develop your own smart contract. From 167d5fcfcfeaffc28fb67d5c6adb5b024da7b165 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 12:07:45 +0200 Subject: [PATCH 04/14] Modify documentation for wasm32v1-none target --- .../how-to/smart-contracts/build-contract.rst | 4 +- .../how-to/smart-contracts/build-schema.rst | 13 +-- .../how-to/smart-contracts/compile-module.rst | 102 +++++++----------- 3 files changed, 42 insertions(+), 77 deletions(-) diff --git a/source/mainnet/how-to/smart-contracts/build-contract.rst b/source/mainnet/how-to/smart-contracts/build-contract.rst index 1bb4bae3dd..a50f425dff 100644 --- a/source/mainnet/how-to/smart-contracts/build-contract.rst +++ b/source/mainnet/how-to/smart-contracts/build-contract.rst @@ -54,8 +54,8 @@ Typescript smart contract client generator The `Typescript smart contract client generator `_ helps you generate JavaScript/TypeScript clients for smart contracts on the Concordium blockchain, providing a lower development time and better type-safety. -Concordium software -=================== +Concordium client +================= The tool to deploy and interact with smart contracts is :ref:`concordium-client`. It is distributed as part of the diff --git a/source/mainnet/how-to/smart-contracts/build-schema.rst b/source/mainnet/how-to/smart-contracts/build-schema.rst index ef22707fb1..0583c69a32 100644 --- a/source/mainnet/how-to/smart-contracts/build-schema.rst +++ b/source/mainnet/how-to/smart-contracts/build-schema.rst @@ -158,11 +158,6 @@ Building the schema Now, you are ready to build the actual schema using ``cargo-concordium``, and you have the options to embed the schema and/or write the schema to a file and/or print the schema to the console. -.. seealso:: - - For more on which to choose see - :ref:`here`. - Embedding the schema -------------------- @@ -191,7 +186,7 @@ must exist and the file will be created in following command $cargo concordium build --schema-out "/some/path/schema.bin" -If using ``cargo concordium`` version 2.6.0 or newer then the schema can be +The schema can be output in JSON format that can be more suitable for use in dApps. When building the contract use ``--schema-json-out DIR`` to output the schema for each contract in the module to a JSON file inside the directory ``DIR``. The @@ -202,7 +197,7 @@ names that exist in the module or a counter in case of special characters in the $cargo concordium build --schema-json-out "/some/path/" -If using ``cargo concordium`` version 2.7.0 or newer then the schema can be +The schema can be output in base64 format that is currently supported in the |bw|. When building the contract use ``--schema-base64-out FILE``, where ``FILE`` is a path and filename. The path must exist and the file will be created in following command @@ -237,8 +232,6 @@ schemas in all the formats will be output Converting a binary schema to JSON ---------------------------------- -These commands are available in ``cargo concordium`` version 2.6.0 or newer. - To convert an existing binary schema (obtained via ``--schema-out``) use the ``cargo concordium schema-json`` subcommand, e.g., @@ -256,8 +249,6 @@ module (obtained via ``cargo concordium build``) by using Converting a binary schema to base64 ------------------------------------ -These commands are available in ``cargo concordium`` version 2.7.0 or newer. - To convert an existing binary schema (obtained via ``--schema-out``) use the ``cargo concordium schema-base64`` subcommand, e.g., diff --git a/source/mainnet/how-to/smart-contracts/compile-module.rst b/source/mainnet/how-to/smart-contracts/compile-module.rst index d52139ed5b..c7fe9b5ed7 100644 --- a/source/mainnet/how-to/smart-contracts/compile-module.rst +++ b/source/mainnet/how-to/smart-contracts/compile-module.rst @@ -18,7 +18,7 @@ a Wasm module. Preparation =========== -Make sure to have Rust and Cargo installed and the ``wasm32-unknown-unknown`` +Make sure to have Rust and Cargo installed and the ``wasm32v1-none`` target, together with |cargo-concordium|_ and the Rust source code for a smart contract module, you wish to compile. @@ -27,100 +27,74 @@ contract module, you wish to compile. For instructions on how to install the developer tools see :ref:`build-contract`. + Compiling to Wasm ================= -To help building smart contract modules and to take advantage of features -such as :ref:`contract schemas `, Concordium recommends using the -``cargo-concordium`` tool for building Rust_ smart contracts. - -In order to build a smart contract for deployment, run: +Running the ``cargo concordium build`` command will produce a smart contract module placed at the location +given by the ``--out`` option (otherwise the default location is in the directory ``concordium-out``). +For example, running the following command will output your smart contract module into the root folder of your project in a file called ``my_module.wasm.v1``. .. code-block:: console - $cargo concordium build --verifiable docker.io/concordium/verifiable-sc:1.70.0 --out contract.wasm.v1 + $ cargo concordium build --out ./my_module.wasm.v1 -This uses Cargo_ for building, but runs further optimizations on the result. +.. note:: -The ``--verifiable`` option is available on ``cargo-concordium`` version 3.1 or newer. It will cause ``cargo-concordium`` to build the sources -in a fixed container to make the build reproducible. It will additionally produce -a ``tar`` file with packaged sources that were used for the build. The list of -available docker images can be found on `DockerHub. `_ + It is possible to compile using Cargo_ directly without doing a full build of the smart contract. If you just want to "check" our sources, you can run: -The ``tar`` archive should be uploaded and made publicly available, and its -link should be embedded into the deployed module using the ``cargo concordium edit-build-info`` -command. For example + .. code-block:: console -.. code-block:: console + $ cargo check --target=wasm32v1-none - $cargo concordium edit-build-info --module module.wasm.v1 --source-link https://link.to/module.wasm.v1.tar --verify + Notice that building with + .. code-block:: console -The ``--out`` option is required for verifiable builds, and instructs ``cargo-concordium`` to output the build artifact at the specified location. + $ cargo check --target=wasm32v1-none --release -Verifiable builds require a container runtime such as `Docker `_ to be installed. + produces a pure Wasm module as output. But Cargo concordium will embed schema and version information that is needed in addition. -Additional information about verifiable builds can be found on `Github `_. +.. _cargo-concordium: https://crates.io/crates/cargo-concordium +.. |cargo-concordium| replace:: ``cargo-concordium`` -.. Note:: - If you receive an error similiar to the one below, you need to update your ``cargo-concordium`` to version 3.0 or later. +.. note:: - .. code-block:: console + The suffix ``v1`` refers to smart contract version 1. Version 0 smart contracts are no longer supported by the tooling. - Error: Could not build smart contract. - Caused by: - 0: Could not build module schema. - 1: Could not generate module schema from Wasm module. - 2: Unsupported instruction 0xc0 +Verifiable builds +================= -If you want a smaller code footprint, enable the :ref:`wee_alloc feature ` by using: +Compiling the smart contract above is fine for development. But once you want to deploy a contract on chain, it is +recommended to do a verifiable build. A verifiable build links the smart contract module with the source code it is build +from in a verifiable way. +In order to build a verifiable smart contract, run: .. code-block:: console - $cargo concordium build --verifiable docker.io/concordium/verifiable-sc:1.70.0 --out contract.wasm.v1 -- --features wee_alloc - -.. seealso:: - - For building the schema for a smart contract module, some :ref:`further - preparation is required `. - Building and embedding the schema can and should be combined with a verifiable build using the ``--verifiable`` option. - -.. note:: - - It is also possible to compile using Cargo_ directly by running: + $ cargo concordium build --verifiable --out contract.wasm.v1 - .. code-block:: console - - $cargo build --target=wasm32-unknown-unknown [--release] +This uses Cargo_ for building, but runs further optimizations on the result. - Note that even with ``--release`` set, the produced Wasm module includes - debug information. +A verifiable build will cause ``cargo-concordium`` to build the sources +in a container to make the build reproducible. It will additionally produce +a ``tar`` file with packaged sources that were used for the build. -Non-verifiable builds ---------------------- +The ``tar`` archive should be uploaded and made publicly available, and its +link should be embedded into the deployed module using the ``cargo concordium edit-build-info`` +command. For example -Omitting the ``--verifiable`` option from the build command will make a build on the host machine. -This is typically not verifiable since the Rust toolchain is affected by the build environment. -However, for local development, non-verifiable builds can be useful. +.. code-block:: console -By default, running the ``cargo concordium build`` command will produce a smart contract module which can be found -relative to your project root folder in ``./target/concordium/wasm32-unknown-unknown/release/my_module.wasm.v1``. -The ``--out`` option can be supplied also for non-verifiable builds. -For example, running the following command will output your smart contract module into the root folder of your project in a file called ``my_module.wasm.v1``. + $ cargo concordium edit-build-info --module module.wasm.v1 --source-link https://link.to/module.wasm.v1.tar --verify -.. code-block:: console - $cargo concordium build --out ./my_module.wasm.v1 +Verifiable builds require a container runtime such as `Docker `_ to be installed. -.. note:: +Additional information about verifiable builds can be found in Cargo concordium `README.md `_. - ``cargo-concordium`` produces several smart contract modules with different suffixes. The suffix corresponds - to the smart contract version, i.e. ``my_module.wasm/my_module.wasm.v0`` for V0 contracts and ``my_module.wasm.v1`` - for V1 contracts. Concordium recommends using the wasm module with the ``.v1`` extension - (the most-up-to date smart contract version). - The file ``my_module.wasm.v1`` will be used when :ref:`deploying ` a smart contract on-chain. +To further optmize the build, you may consider using the ``bump_alloc`` allocator for your smart contract. See `concordium_std features`_. -.. _cargo-concordium: https://crates.io/crates/cargo-concordium -.. |cargo-concordium| replace:: ``cargo-concordium`` +.. _concordium_std features: https://docs.rs/concordium-std/latest/concordium_std/#features \ No newline at end of file From 459622c91b8a79a7bfd5514743efa239d59bd3b7 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 12:47:03 +0200 Subject: [PATCH 05/14] Modify documentation for wasm32v1-none target --- source/mainnet/how-to/index.rst | 4 +- .../smart-contracts/fallback-entrypoints.rst | 2 +- .../integration-test-contract.rst | 17 +-- .../mainnet/how-to/smart-contracts/no-std.rst | 137 ------------------ .../smart-contracts/upgradeable-contract.rst | 4 - 5 files changed, 9 insertions(+), 155 deletions(-) delete mode 100644 source/mainnet/how-to/smart-contracts/no-std.rst diff --git a/source/mainnet/how-to/index.rst b/source/mainnet/how-to/index.rst index cc28059c2c..2a1eb265cb 100644 --- a/source/mainnet/how-to/index.rst +++ b/source/mainnet/how-to/index.rst @@ -90,7 +90,6 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid - :doc:`Build a contract schema ` - :doc:`Use custom errors ` - :doc:`Pass JSON parameters ` - - :doc:`Use no_std ` - :doc:`Use fallback entrypoints ` - :doc:`Write an upgradeable contract ` - :doc:`Implement the factory pattern ` @@ -169,8 +168,7 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid Build a contract schema Use custom errors Pass JSON parameters - Use no_std - Use fallback entrypoints + Use fallback entrypoints Write an upgradeable contract Implement the factory pattern Unit test a contract diff --git a/source/mainnet/how-to/smart-contracts/fallback-entrypoints.rst b/source/mainnet/how-to/smart-contracts/fallback-entrypoints.rst index 17439b706f..a18bc393d2 100644 --- a/source/mainnet/how-to/smart-contracts/fallback-entrypoints.rst +++ b/source/mainnet/how-to/smart-contracts/fallback-entrypoints.rst @@ -20,7 +20,7 @@ You also need to have the following installed: - Rust - Cargo -- The ``wasm32-unknown-unknown`` compiling target +- The ``wasm32v1-none`` compiling target - ``cargo-concordium`` .. seealso:: diff --git a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst index 3a295d16f6..a4fcf88cfc 100644 --- a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst +++ b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst @@ -12,9 +12,8 @@ This guide describes how to write *integration tests* in Rust for your smart con .. note:: - Unit testing your contracts with the |test_infrastructure|_ has been deprecated in favor of |concordium-smart-contract-testing|_. + Unit testing your contracts with the ``test_infrastructure`` has been deprecated in favor of what is described on the present page. To migrate your contracts and tests see :ref:`migrate-contracts-for-std-8.1`. - You can read the :ref:`old documentation for unit testing here ` if you are not ready to migrate your contracts. The library allows you to test individual contracts in isolation, but, notably, also interactions between multiple contracts. When running the tests, they are executed locally on the exact contract code that is deployed on the chain, and using the same execution engine that the nodes use. @@ -23,19 +22,17 @@ This allows you to refactor and optimize your contracts for speed and efficiency The high-level process of adding integration tests to your existing smart contract project is as follows: -1. Add the testing library to your ``Cargo.toml`` file and use Rust edition ``2021``: +1. Add the testing library to your ``Cargo.toml`` file: .. code-block:: yaml [package] # ... - edition = "2021" [dev-dependencies] - concordium-smart-contract-testing = "1.0" + concordium-smart-contract-testing = "4.4.0" By putting it under ``dev-dependencies``, it is only included for tests. - You must use edition ``2021`` or greater as that is a requirement for the testing library. 2. Write tests in files residing in ``my-project/tests/``. Example content: @@ -169,10 +166,10 @@ Deploying smart contract modules is a two-step process. First, you load the module with the function |module_load_v1|_, then you deploy it to the chain with the method |Chain_module_deploy_v1|_. Loading as a separate step allows you to reuse the loaded module across multiple tests for efficiency. -The module to load must be a ``wasm`` module compiled with ``cargo concordium build`` or, if using cargo concordium version 2.9.0+, ``cargo concordium test --out path/to/wasm/module``. -Using the test command is ideal, as that will both compile the module *and* run the tests. +The module to load must be a ``wasm`` module compiled with ``cargo concordium build``. The easiest is to run ``cargo concordium test``, +which will both compile the module *and* run the tests. By compiling the module every time, you ensure that the tests run on the newest version of your code. -For example, for ``cargo concordium test --embed-schema --out my_module.wasm.v1``, you write: +For example, for ``cargo concordium test --out my_module.wasm.v1``, you write: .. code-block:: rust @@ -516,7 +513,7 @@ Example: to: AccountAddress([0u8;32]), }]); -.. _concordium-smart-contract-testing: https://docs.rs/concordium-std-derive/latest/concordium_smart-contract-testing +.. _concordium-smart-contract-testing: https://docs.rs/concordium-smart-contract-testing/latest/concordium_smart_contract_testing .. |concordium-smart-contract-testing| replace:: ``concordium-smart-contract-testing`` .. _Account: https://docs.rs/concordium-smart-contract-testing/latest/concordium_smart_contract_testing/struct.Account.html .. |Account| replace:: ``Account`` diff --git a/source/mainnet/how-to/smart-contracts/no-std.rst b/source/mainnet/how-to/smart-contracts/no-std.rst deleted file mode 100644 index e051f6afb6..0000000000 --- a/source/mainnet/how-to/smart-contracts/no-std.rst +++ /dev/null @@ -1,137 +0,0 @@ -.. _no-std: - -================ -Using ``no_std`` -================ - -.. admonition:: At a glance - - This guide shows how to enable ``no_std`` in your Concordium smart contract to reduce the size of the compiled Wasm module. You will need an existing Rust smart contract and the nightly Rust toolchain. After following this guide, your contract will compile without the Rust standard library, resulting in a smaller binary. - -This guide shows how to enable ``no_std`` for your rust smart contract, -potentially reducing the size of the resulting Wasm module by several kilobytes. - -Preparation -=========== - -Compiling ``concordium-std`` without the ``std`` feature requires using the rust -nightly toolchain, which can be installed using ``rustup``: - -.. code-block:: console - - $rustup toolchain install nightly - -Then add the wasm32 target by using - -.. code-block:: console - - $rustup +nightly target add wasm32-unknown-unknown - -Setting up the module for ``no_std`` -==================================== - -The ``concordium-std`` library exposes a ``std`` feature, which enables the use -of the rust standard library. -This feature is enabled by default. - -To disable it, one must simply disable default features for the -``concordium-std`` in the dependencies of your module. -You can update your `Cargo.toml` file by using: - -.. code-block:: rust - - [dependencies] - concordium-std = { version = "10.0", default-features = false } - -.. note:: - - To compile your smart contracts, a memory `allocator `_ is used. - ``concordium-std`` version ``<6.0.0`` hard-coded the use of the `wee_alloc `_ allocator. - In ``concordium-std`` version in the range of ``>=6.0.0`` and ``<10.0.0``, ``wee_alloc`` is a feature and needs to be explicitly enabled. - In ``concordium-std`` version ``>=10.0.0``, `bump_alloc `_ is a feature and needs to be explicitly enabled. - When ``std`` feature is enabled, the allocator provided by the Rust standard library is used - by default but when the ``wee_alloc``/``bump_alloc`` feature is enabled in addition, `bump_alloc `_ ( or `wee_alloc `_) is used instead. - Read :ref:`sc-costs-custom-allocator` for more information on custom allocators. - - You can enable the ``std`` feature and the ``wee_alloc`` feature in ``concordium-std`` version in the range of ``>=6.0.0`` and ``<10.0.0`` by using: - - .. code-block:: rust - - [dependencies] - concordium-std = {version = "6.0", features = ["wee_alloc"]} - - You can enable the ``std`` feature and the ``bump_alloc`` feature in ``concordium-std`` version ``>=10.0.0`` by using: - - .. code-block:: rust - - [dependencies] - concordium-std = {version = "10.0", features = ["bump_alloc"]} - - Alternatively, if you want to test with and without ``wee_alloc``/``bump_alloc`` enabled add a ``wee_alloc``/``bump_alloc`` feature to the smart contract crate as follows: - - .. code-block:: rust - - [features] - default = ["std", "bump_alloc"] - std = ["concordium-std/std"] - bump_alloc = ["concordium-std/bump_alloc"] - - The above code blocks will use the `bump_alloc `_ allocator and not the allocator - provided by the Rust standard library when compiled with the default features as follows: - - .. code-block:: console - - $cargo concordium build - -When ``no_std`` is used either ``wee_alloc``/``bump_alloc`` must be enabled, or another global allocator -must be set in the smart contract. You can add the ``wee_alloc``/``bump_alloc`` feature by using e.g.: - -.. code-block:: rust - - [features] - bump_alloc = ["concordium-std/bump_alloc"] - -To be able to toggle between with and without std, also add a ``std`` to your -own module, which enables the ``std`` feature of ``concordium-std``: - -.. code-block:: rust - - [features] - std = ["concordium-std/std"] - -This is the setup of the smart contract examples, where ``std`` for each -smart contract module is enabled by default. - -Building the module -=================== - -In order to use the nightly toolchain, add ``+nightly`` right after -``cargo``: - -.. code-block:: console - - $cargo +nightly concordium build - -If you want to disable the default features of your own smart contract module, -you can pass extra arguments for ``cargo``: - -.. code-block:: console - - $cargo +nightly concordium build -- --no-default-features --features bump_alloc - -.. note:: - - The above command works with ``concordium-std`` version ``>=10.0.0``, because the - ``bump_alloc`` feature needs to be explicitly enabled. - - If you use ``concordium-std`` version in the range of ``>=6.0.0`` and ``<10.0.0`` use the following instead: - - .. code-block:: console - - $cargo +nightly concordium build -- --no-default-features --features wee_alloc - - If you use ``concordium-std`` version ``<6.0.0`` use the following instead: - - .. code-block:: console - - $cargo +nightly concordium build -- --no-default-features diff --git a/source/mainnet/how-to/smart-contracts/upgradeable-contract.rst b/source/mainnet/how-to/smart-contracts/upgradeable-contract.rst index 994b1d79ce..d3ac9b4714 100644 --- a/source/mainnet/how-to/smart-contracts/upgradeable-contract.rst +++ b/source/mainnet/how-to/smart-contracts/upgradeable-contract.rst @@ -81,10 +81,6 @@ This has the benefit of being in the same transaction as the upgrade itself, mak by the default (*high_level*) ``upgrade`` function, it would overwrite the state stored by the ``migration`` function. The :ref:`upgrade tutorial` provides an example where ``low_level`` is *necessary* since the shape of the state is changed in the ``migration`` function. -.. note:: - - The code snippet above is using Rust and ``concordium-std`` version 5 or newer. - The JSON parameter for triggering an upgrade is of the form: .. code-block:: json From 67f9a69c99f4f5cd7aa41540b81469216a741303 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 12:56:02 +0200 Subject: [PATCH 06/14] Modify documentation for wasm32v1-none target --- source/mainnet/how-to/governance/voting.rst | 2 +- .../infrastructure/import-validator-keys.rst | 4 +-- .../best-practices/development.rst | 4 +-- .../how-to/smart-contracts/deploy-module.rst | 16 ++-------- .../smart-contracts/initialize-contract.rst | 10 +++--- .../smart-contracts/inspect-instance.rst | 2 +- .../smart-contracts/interact-instance.rst | 6 ++-- .../smart-contracts/invoke-instance.rst | 14 ++++---- .../technical-reference/auxiliary-tools.rst | 2 +- .../concordium-client/concordium-client.rst | 16 +++++----- .../concordium-client/multi-sig.rst | 26 +++++++-------- .../concordium-client/query-node.rst | 32 +++++++++---------- .../concordium-client/transactions.rst | 28 ++++++++-------- .../tutorials/counter/counter-contract.rst | 18 +++++------ source/mainnet/tutorials/quick-start.rst | 6 ++-- .../smartContractUpgrade.rst | 18 +++++------ 16 files changed, 97 insertions(+), 107 deletions(-) diff --git a/source/mainnet/how-to/governance/voting.rst b/source/mainnet/how-to/governance/voting.rst index 587fb16f2c..1d90221d6b 100644 --- a/source/mainnet/how-to/governance/voting.rst +++ b/source/mainnet/how-to/governance/voting.rst @@ -101,7 +101,7 @@ These wallets do not have the capability to connect to dApps. But you do have an .. code-block:: console - $concordium-client --secure --grpc-ip grpc.mainnet.concordium.software transaction send --amount AMOUNT --receiver A --sender B --memo delegatevote + $ concordium-client --secure --grpc-ip grpc.mainnet.concordium.software transaction send --amount AMOUNT --receiver A --sender B --memo delegatevote #. Enter the command above in the Concordium Client, where AMOUNT is the number of CCD to be sent (1 micro-CCD is enough), A is the name/address of the account to which the vote is delegated, and B is the sender name/address. Note the memo ``delegatevote`` for the delegation to be valid. Furthermore, there is no service license agreement for the grpc endpoint. diff --git a/source/mainnet/how-to/infrastructure/import-validator-keys.rst b/source/mainnet/how-to/infrastructure/import-validator-keys.rst index 2ac4e3a963..4b47111bec 100644 --- a/source/mainnet/how-to/infrastructure/import-validator-keys.rst +++ b/source/mainnet/how-to/infrastructure/import-validator-keys.rst @@ -263,7 +263,7 @@ Select your platform below to configure your node with validator keys. .. code-block:: console - $concordium-client validator add .json --sender validatorAccount --stake --validator-credentials-out /validator-credentials.json + $ concordium-client validator add .json --sender validatorAccount --stake --validator-credentials-out /validator-credentials.json where you replace @@ -311,7 +311,7 @@ You can use ``concordium-client`` to see the status of the node. For more inform .. code-block:: console - $concordium-client raw GetNodeInfo + $ concordium-client raw GetNodeInfo ... diff --git a/source/mainnet/how-to/smart-contracts/best-practices/development.rst b/source/mainnet/how-to/smart-contracts/best-practices/development.rst index 0cdadcdc10..9c95cc4cb2 100644 --- a/source/mainnet/how-to/smart-contracts/best-practices/development.rst +++ b/source/mainnet/how-to/smart-contracts/best-practices/development.rst @@ -194,8 +194,8 @@ Consider the following map for storing all user bids in an auction contract: .. code-block:: rust - pub struct State { - bids: StateMap + pub struct State { + bids: StateMap } Computing the maximum for each new bid requires iterating over the map. diff --git a/source/mainnet/how-to/smart-contracts/deploy-module.rst b/source/mainnet/how-to/smart-contracts/deploy-module.rst index 31682e053f..6e199eea23 100644 --- a/source/mainnet/how-to/smart-contracts/deploy-module.rst +++ b/source/mainnet/how-to/smart-contracts/deploy-module.rst @@ -38,22 +38,12 @@ with name account-name, run the following command: .. code-block:: console - $concordium-client module deploy my_module.wasm.v1 --sender account_name + $ concordium-client module deploy my_module.wasm.v1 --sender account_name .. note:: The ``--sender`` option can be omitted if the account "default" is to be used. For brevity, you will do so in the following. - Modules built with ``cargo-concordium`` (version 2+) get a suffix corresponding to - the smart contract version, i.e. ``my_module.wasm.v0`` for V0 contracts and - ``my_module.wasm.v1`` for V1 contracts. - - When deploying a smart contract module built using ``cargo-concordium`` - version < 2, or built directly with ``cargo``, it is necessary to - specify the smart contract version with the ``--contract-version [v0, v1]`` - option. These module files will not have the version suffix, e.g. - ``.v0``, or ``.v1``, but just be called ``.wasm``. - If successful, the output should be similar to the following: .. code-block:: console @@ -90,7 +80,7 @@ Here, you are naming the module ``my_deployed_module``: .. code-block:: console - $concordium-client module deploy my_module.wasm.v1 --name my_deployed_module + $ concordium-client module deploy my_module.wasm.v1 --name my_deployed_module If successful, the output should be similar to the following: @@ -105,7 +95,7 @@ To name a deployed module with reference .. code-block:: console - $concordium-client module name \ + $ concordium-client module name \ 9eb82a01d96453dbf793acebca0ce25c617f6176bf7a564846240c9a68b15fd2 \ --name some_deployed_module diff --git a/source/mainnet/how-to/smart-contracts/initialize-contract.rst b/source/mainnet/how-to/smart-contracts/initialize-contract.rst index f9d37f37b2..f3ac0b1256 100644 --- a/source/mainnet/how-to/smart-contracts/initialize-contract.rst +++ b/source/mainnet/how-to/smart-contracts/initialize-contract.rst @@ -51,7 +51,7 @@ following command: .. code-block:: console - $concordium-client contract init \ + $ concordium-client contract init \ 9eb82a01d96453dbf793acebca0ce25c617f6176bf7a564846240c9a68b15fd2 \ --sender my_account \ --contract my_contract \ @@ -99,7 +99,7 @@ parameter file ``my_parameter.json`` in JSON format, run the following command: .. code-block:: console - $concordium-client contract init \ + $ concordium-client contract init \ 9eb82a01d96453dbf793acebca0ce25c617f6176bf7a564846240c9a68b15fd2 \ --contract my_parameter_contract \ --energy 10000 \ @@ -154,7 +154,7 @@ parameter file ``my_parameter.bin`` in binary format, run the following command: .. code-block:: console - $concordium-client contract init \ + $ concordium-client contract init \ 9eb82a01d96453dbf793acebca0ce25c617f6176bf7a564846240c9a68b15fd2 \ --contract my_parameter_contract \ --energy 10000 \ @@ -195,7 +195,7 @@ it ``my_named_contract``: .. code-block:: console - $concordium-client contract init \ + $ concordium-client contract init \ 9eb82a01d96453dbf793acebca0ce25c617f6176bf7a564846240c9a68b15fd2 \ --contract my_contract \ --energy 10000 \ @@ -214,7 +214,7 @@ the following command: .. code-block:: console - $concordium-client contract name 0 --name my_named_contract + $ concordium-client contract name 0 --name my_named_contract If successful, the output should be similar to the following: diff --git a/source/mainnet/how-to/smart-contracts/inspect-instance.rst b/source/mainnet/how-to/smart-contracts/inspect-instance.rst index b4e6158d0a..b08ddf566c 100644 --- a/source/mainnet/how-to/smart-contracts/inspect-instance.rst +++ b/source/mainnet/how-to/smart-contracts/inspect-instance.rst @@ -30,7 +30,7 @@ address index ``0``, run the following command: .. code-block:: console - $concordium-client contract show 0 + $ concordium-client contract show 0 The output should be similar to the following: diff --git a/source/mainnet/how-to/smart-contracts/interact-instance.rst b/source/mainnet/how-to/smart-contracts/interact-instance.rst index 91a87faf25..f863da9d11 100644 --- a/source/mainnet/how-to/smart-contracts/interact-instance.rst +++ b/source/mainnet/how-to/smart-contracts/interact-instance.rst @@ -46,7 +46,7 @@ run the following command: .. code-block:: console - $concordium-client contract update 0 --entrypoint my_receive --energy 10000 --sender MyAccount + $ concordium-client contract update 0 --entrypoint my_receive --energy 10000 --sender MyAccount If successful, the output should be similar to the following: @@ -76,7 +76,7 @@ format, run the following command: .. code-block:: console - $concordium-client contract update 0 --sender MyAccount --entrypoint my_parameter_receive \ + $ concordium-client contract update 0 --sender MyAccount --entrypoint my_parameter_receive \ --energy 10000 \ --parameter-json my_parameter.json @@ -130,7 +130,7 @@ format, run the following command: .. code-block:: console - $concordium-client contract update 0 --sender MyAccount --entrypoint my_parameter_receive \ + $ concordium-client contract update 0 --sender MyAccount --entrypoint my_parameter_receive \ --energy 10000 \ --parameter-binary my_parameter.bin diff --git a/source/mainnet/how-to/smart-contracts/invoke-instance.rst b/source/mainnet/how-to/smart-contracts/invoke-instance.rst index e703d25512..4c1babaa1e 100644 --- a/source/mainnet/how-to/smart-contracts/invoke-instance.rst +++ b/source/mainnet/how-to/smart-contracts/invoke-instance.rst @@ -37,7 +37,7 @@ entrypoint ``my_receive``, run the following command: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_receive + $ concordium-client contract invoke 0 --entrypoint my_receive If successful, the output should be similar to the following: @@ -71,20 +71,20 @@ sender account: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_receive --invoker-account + $ concordium-client contract invoke 0 --entrypoint my_receive --invoker-account Use the ``invoker-contract`` parameter to invoke an entrypoint with a sender contract: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_receive --invoker-contract + $ concordium-client contract invoke 0 --entrypoint my_receive --invoker-contract Use the ``amount`` parameter to invoke an entrypoint with the specified amount of CCD. .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_receive --amount + $ concordium-client contract invoke 0 --entrypoint my_receive --amount .. note:: @@ -96,7 +96,7 @@ in: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_receive --block + $ concordium-client contract invoke 0 --entrypoint my_receive --block Passing parameters in JSON format --------------------------------- @@ -116,7 +116,7 @@ format, run the following command: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_parameter_receive \ + $ concordium-client contract invoke 0 --entrypoint my_parameter_receive \ --parameter-json my_parameter.json If successful, the output should be similar to the following: @@ -167,7 +167,7 @@ format, run the following command: .. code-block:: console - $concordium-client contract invoke 0 --entrypoint my_parameter_receive \ + $ concordium-client contract invoke 0 --entrypoint my_parameter_receive \ --parameter-bin my_parameter.bin If successful, the output should be similar to the following: diff --git a/source/mainnet/technical-reference/auxiliary-tools.rst b/source/mainnet/technical-reference/auxiliary-tools.rst index 23584f239e..2b59ad1571 100644 --- a/source/mainnet/technical-reference/auxiliary-tools.rst +++ b/source/mainnet/technical-reference/auxiliary-tools.rst @@ -43,7 +43,7 @@ Display your keys with the following command: .. code-block:: console - $concordium-client config show + $ concordium-client config show Save the ``encryptedSignKey`` blob to a file named ``output.json``. The content of that file should look similar to the below content. diff --git a/source/mainnet/technical-reference/concordium-client/concordium-client.rst b/source/mainnet/technical-reference/concordium-client/concordium-client.rst index 82424e4ad6..6e25e2c390 100644 --- a/source/mainnet/technical-reference/concordium-client/concordium-client.rst +++ b/source/mainnet/technical-reference/concordium-client/concordium-client.rst @@ -125,7 +125,7 @@ topic to see the available commands within that topic: .. code-block:: console - $concordium-client config --help + $ concordium-client config --help Usage: concordium-client config COMMAND Commands for inspecting and changing local configuration. @@ -141,7 +141,7 @@ Give the full command to see available options related to that command: .. code-block:: console - $concordium-client config account import --help + $ concordium-client config account import --help Usage: concordium-client config account import FILE [--name NAME] Import an account to persistent config. @@ -202,7 +202,7 @@ Display contents .. code-block:: console - $concordium-client config show + $ concordium-client config show Display the full contents of the persistent configuration. This will display the stored keys that are used for signing transactions (under the ``Account Keys`` @@ -214,7 +214,7 @@ Example: .. code-block:: console - $concordium-client config show + $ concordium-client config show Base configuration: - Verbose: no - Account config dir: /var/lib/concordium/config/accounts @@ -282,7 +282,7 @@ Add named account .. code-block:: console - $concordium-client config account name ADDRESS [--name NAME] + $ concordium-client config account name ADDRESS [--name NAME] Add an account address to persistent configuration, naming it. This name may now be used to refer to the account throughout the client. @@ -295,7 +295,7 @@ Add key to an account .. code-block:: console - $concordium-client config account add-keys --account ACCOUNT --keys KEYS + $ concordium-client config account add-keys --account ACCOUNT --keys KEYS Add a sign/verify key-pair to a specific account. The ``KEYS`` parameter must be a JSON file that contains the keys that will be added in the same format as they @@ -331,7 +331,7 @@ Update keys of an account .. code-block:: console - $concordium-client config account update-keys --account ACCOUNT --keys KEYS + $ concordium-client config account update-keys --account ACCOUNT --keys KEYS Update a sign/verify key-pair on a specific account. The ``KEYS`` parameter must be a JSON file that contains the keys that will be added in the same format as for adding keys. @@ -342,7 +342,7 @@ Remove keys of an account .. code-block:: console - $concordium-client config account remove-keys --account ACCOUNT --credential-index CREDENTIALINDEX KEYINDICES + $ concordium-client config account remove-keys --account ACCOUNT --credential-index CREDENTIALINDEX KEYINDICES Remove sign/verify key-pairs from a specific credential of an account. The ``CREDENTIALINDEX`` specifies the credential that the key pairs should be removed from, and the space-seperated list of key indices specify which of the key pairs that should be removed. diff --git a/source/mainnet/technical-reference/concordium-client/multi-sig.rst b/source/mainnet/technical-reference/concordium-client/multi-sig.rst index eb27391319..ac87103386 100644 --- a/source/mainnet/technical-reference/concordium-client/multi-sig.rst +++ b/source/mainnet/technical-reference/concordium-client/multi-sig.rst @@ -91,7 +91,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account show \ + $ concordium-client account show \ --grpc-port \ --grpc-ip @@ -99,7 +99,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account show \ + $ concordium-client account show \ --grpc-port 20000 \ --grpc-ip grpc.testnet.concordium.com \ --secure @@ -128,7 +128,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account update-keys ./update-keys.json \ + $ concordium-client account update-keys ./update-keys.json \ --credId \ --sender \ --grpc-port \ @@ -138,7 +138,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account update-keys ./update-keys.json \ + $ concordium-client account update-keys ./update-keys.json \ --credId \ --sender \ --grpc-port 20000 \ @@ -183,7 +183,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account update-credentials \ + $ concordium-client account update-credentials \ --new-credentials new-credential.json \ --new-threshold \ --sender \ @@ -194,7 +194,7 @@ To add additional keys to an existing account on Concordium using the ``concordi .. code-block:: console - $concordium-client account update-credentials \ + $ concordium-client account update-credentials \ --new-credentials new-credential.json \ --new-threshold \ --sender \ @@ -222,7 +222,7 @@ To view the key directory path that the ``concordium-client`` tool is using, run .. code-block:: console - $concordium-client config show + $ concordium-client config show The goal is to add additional keys for your account to the local key directory of the ``concordium-client`` tool in this section (Option 2). The guide for the first option is in the @@ -286,7 +286,7 @@ tool in this section (Option 2). The guide for the first option is in the .. code-block:: console - $concordium-client config account import browser_wallet.export \ + $ concordium-client config account import browser_wallet.export \ --name A summary of the achievements from this section: @@ -319,7 +319,7 @@ tool in this section (Option 2). The guide for the first option is in the .. code-block:: console - $concordium-client config account update-keys \ + $ concordium-client config account update-keys \ --keys new-keys.json \ --account @@ -411,7 +411,7 @@ run the following command: .. code-block:: console - $concordium-client transaction send \ + $ concordium-client transaction send \ --receiver 4bbdAUCDK2D6cUvUeprGr4FaSaHXKuYmYVjyCa4bXSCu3NUXzA \ --amount 1 \ --out ./transaction.json \ @@ -463,7 +463,7 @@ from a file, run the following command: .. code-block:: console - $concordium-client transaction send \ + $ concordium-client transaction send \ --keys ./keypair.json \ --receiver 4bbdAUCDK2D6cUvUeprGr4FaSaHXKuYmYVjyCa4bXSCu3NUXzA \ --amount 1 \ @@ -523,7 +523,7 @@ previous section) on a potentially different device by a different entity, run t .. code-block:: console - $concordium-client transaction add-signature ./transaction.json \ + $ concordium-client transaction add-signature ./transaction.json \ --grpc-port 20000 \ --grpc-ip grpc.testnet.concordium.com \ --secure @@ -578,7 +578,7 @@ previous section) on-chain, run the following command: .. code-block:: console - $concordium-client transaction submit ./transaction.json \ + $ concordium-client transaction submit ./transaction.json \ --grpc-port 20000 \ --grpc-ip grpc.testnet.concordium.com \ --secure diff --git a/source/mainnet/technical-reference/concordium-client/query-node.rst b/source/mainnet/technical-reference/concordium-client/query-node.rst index 82fd9bb6b6..fecd3f6b5f 100644 --- a/source/mainnet/technical-reference/concordium-client/query-node.rst +++ b/source/mainnet/technical-reference/concordium-client/query-node.rst @@ -30,7 +30,7 @@ List accounts .. code-block:: console - $concordium-client account list [--block BLOCK-HASH] + $ concordium-client account list [--block BLOCK-HASH] List the addresses of all accounts on the chain as of a specific block: @@ -41,7 +41,7 @@ Example .. code-block:: console - $concordium-client account list + $ concordium-client account list 2zgcMk7heVZKaaBfPtxVqmvE3GnrrP7N2nFGHoiC6X9nZT9TaG 33MT5V7LAzbjfRS537nqq9AqHb4ALymQWwYhriE3kcYr8qsDoS 3GqF3FQPxyxUChnBcwsC5jmY4kqWyi6R8dNXHk88GYqCPKaLGP @@ -52,7 +52,7 @@ Inspect specific account .. code-block:: console - $concordium-client account show [ACCOUNT] [--block BLOCK] [--encrypted] [--decrypt-encrypted] + $ concordium-client account show [ACCOUNT] [--block BLOCK] [--encrypted] [--decrypt-encrypted] Display all publicly available information of a specific account as of a specific block. For accounts for which secret keys are available this command @@ -70,7 +70,7 @@ Example .. code-block:: console - $concordium-client account show my-account --shielded + $ concordium-client account show my-account --shielded Local name: my-account Address: 2zgcMk7heVZKaaBfPtxVqmvE3GnrrP7N2nFGHoiC6X9nZT9TaG Amount: 1026.000000 CCD @@ -119,7 +119,7 @@ Transaction status .. code-block:: console - $concordium-client transaction status TX-HASH + $ concordium-client transaction status TX-HASH Display the lifecycle state of a :term:`transaction` (pending, committed, finalized, or absent). @@ -132,7 +132,7 @@ Example .. code-block:: console - $concordium-client transaction status 0fda6e284f9cd4429c6f76fd1bf6179aad4fa1bb218fe5ec8ad33916bf84a833 + $ concordium-client transaction status 0fda6e284f9cd4429c6f76fd1bf6179aad4fa1bb218fe5ec8ad33916bf84a833 Transaction is finalized into block e2a12d06273f5641ea8157e04367eae49a72706aa831aa58b60ee5c062cdd6e2 with status "success" and cost 0.011200 CCD (112 NRG). Block state @@ -143,7 +143,7 @@ Inspect specific block .. code-block:: console - $concordium-client block show [BLOCK-HASH] + $ concordium-client block show [BLOCK-HASH] Display information about a specific block. Note that some fields (e.g. slot time) are objective (i.e. all nodes participating in the Concordium network will @@ -156,7 +156,7 @@ Example .. code-block:: console - $concordium-client block show e2a12d06273f5641ea8157e04367eae49a72706aa831aa58b60ee5c062cdd6e2 + $ concordium-client block show e2a12d06273f5641ea8157e04367eae49a72706aa831aa58b60ee5c062cdd6e2 Hash: e2a12d06273f5641ea8157e04367eae49a72706aa831aa58b60ee5c062cdd6e2 Parent block: 01aea0ec91fe37cb956aafcd6d0ab7f86cfd0207e5fffc2a87d40657e2c4fa40 Last finalized block: dbf61032a23e020dc6793cbf242c8eadcd91586d84873dee4ae92856b29e2b3f @@ -185,7 +185,7 @@ Inspect consensus parameters .. code-block:: console - $concordium-client consensus show-parameters [--include-bakers] [--block BLOCK-HASH] + $ concordium-client consensus show-parameters [--include-bakers] [--block BLOCK-HASH] Show :term:`election parameters` for a specific block, optionally including bakers and their :term:`lottery power`: @@ -200,7 +200,7 @@ Example .. code-block:: console - $concordium-client consensus show-parameters --include-bakers + $ concordium-client consensus show-parameters --include-bakers Election nonce: 17afce44c8eb1a7e0c48ec28bff50df3f43b36e68155f311f5574108564a2b66 Bakers: Account Lottery power Account Name @@ -220,7 +220,7 @@ Inspect consensus status .. code-block:: console - $concordium-client consensus status + $ concordium-client consensus status Display key blocks along with various statistics related to block production. @@ -234,7 +234,7 @@ Example .. code-block:: console - $concordium-client consensus status + $ concordium-client consensus status Best block: 9cd0a5f1dc488b919847e4b3e98aeea567fe80fafd077bacc2901f145f973c6d Genesis block: f97d975f0e92297c51e24c3b0d8fd39dfe8e1b148d993eba6e9389d4083f7a64 Genesis time: 2022-11-11 12:00:00 UTC @@ -271,7 +271,7 @@ ID layer .. code-block:: console - $concordium-client identity show (identity-providers|anonymity-revokers) [--block BLOCK] + $ concordium-client identity show (identity-providers|anonymity-revokers) [--block BLOCK] Display the list of identity providers or :term:`Privacy Guardians` at a given block, defaulting to the best block. @@ -286,7 +286,7 @@ exchange rates, query the chain parameters of the best block: .. code-block:: console - $concordium-client raw GetBlockChainParameters + $ concordium-client raw GetBlockChainParameters You can also add a block hash at the end of the command to query a specific block. @@ -321,7 +321,7 @@ following command: .. code-block:: console - $concordium-client raw GetBlockPendingUpdates + $ concordium-client raw GetBlockPendingUpdates This prints a JSON list containing any such pending updates. As before you can also pass a block hash to the command to query a specific block. @@ -334,7 +334,7 @@ Earliest time a validator may be expected to produce a block .. code-block:: console - $concordium-client validator win-time 1 + $ concordium-client validator win-time 1 Validator 1 is expected to produce a block no sooner than: Thu, 26 Oct 2023 07:01:26 UTC (in 34s 699ms) diff --git a/source/mainnet/technical-reference/concordium-client/transactions.rst b/source/mainnet/technical-reference/concordium-client/transactions.rst index de09cf716c..e09e322136 100644 --- a/source/mainnet/technical-reference/concordium-client/transactions.rst +++ b/source/mainnet/technical-reference/concordium-client/transactions.rst @@ -14,7 +14,7 @@ You can perform all types of transactions with the :ref:`concordium-client at ``. For example, to send a transaction from A to B that: @@ -349,13 +349,13 @@ Use the following command: .. code-block:: console - $concordium-client transaction send-scheduled --schedule "100 at 2021-01-01T12:00:00Z, 150 at 2021-02-15T12:00:00Z, 200 at 2021-12-31T12:00:00Z" --receiver B --sender A + $ concordium-client transaction send-scheduled --schedule "100 at 2021-01-01T12:00:00Z, 150 at 2021-02-15T12:00:00Z, 200 at 2021-12-31T12:00:00Z" --receiver B --sender A If you query the account information of the recipient account afterwards, it will show the list of releases that are still pending to be released: .. code-block:: console - $concordium-client account show B + $ concordium-client account show B Local name: B Address: 3WbgGP2iE21HyrBg5kL429ZXWu2dNDXzzjZ7qwu9neop2bSCRJ Balance: 550.000000 CCD @@ -385,7 +385,7 @@ The command is: .. code-block:: console - $concordium-client delegator add --sender EXAMPLEACCT --stake 5000 --target 12345 + $ concordium-client delegator add --sender EXAMPLEACCT --stake 5000 --target 12345 The command has the following required arguments: @@ -421,7 +421,7 @@ Use the consensus command ``show-chain-parameters`` to show a number of paramete .. code-block:: console - $concordium-client consensus show-chain-parameters + $ concordium-client consensus show-chain-parameters To see the chain parameters for a specific block use the ``--block`` flag to specify the block hash. diff --git a/source/mainnet/tutorials/counter/counter-contract.rst b/source/mainnet/tutorials/counter/counter-contract.rst index 78627cd5e1..7861f807f2 100644 --- a/source/mainnet/tutorials/counter/counter-contract.rst +++ b/source/mainnet/tutorials/counter/counter-contract.rst @@ -127,7 +127,7 @@ Now we can deploy the smart contract using the Concordium client CLI. If you are .. code-block:: console - $concordium-client module deploy dist/module.wasm.v1 \ + $ concordium-client module deploy dist/module.wasm.v1 \ --sender \ --grpc-port 20001 @@ -135,7 +135,7 @@ Or, if you just want to try things out on testnet, you can use the testing nodes .. code-block:: console - $concordium-client module deploy dist/module.wasm.v1 \ + $ concordium-client module deploy dist/module.wasm.v1 \ --sender \ --grpc-ip grpc.testnet.concordium.com \ --grpc-port 20000 \ @@ -149,7 +149,7 @@ Finally, let's initialize a contract instance, so you are ready to invoke the co .. code-block:: console - $concordium-client contract init \ + $ concordium-client contract init \ --sender \ --energy 30000 \ --contract counter \ @@ -158,8 +158,8 @@ Finally, let's initialize a contract instance, so you are ready to invoke the co Or, use this command to use the Concordium testnet node: .. code-block:: console - - $concordium-client contract init \ + + $ concordium-client contract init \ --sender \ --energy 30000 \ --contract counter \ @@ -181,7 +181,7 @@ First, check the initial state of the contract. Use this command if you're hosti .. code-block:: console - $concordium-client contract invoke \ + $ concordium-client contract invoke \ --entrypoint view \ --grpc-port 20001 @@ -189,7 +189,7 @@ Or, use this command to use the Concordium testnet node: .. code-block:: console - $concordium-client contract invoke \ + $ concordium-client contract invoke \ --entrypoint view \ --grpc-ip grpc.testnet.concordium.com \ --grpc-port 20000 \ @@ -210,7 +210,7 @@ Now we can invoke the update function with that input by using a contract update .. code-block:: console - $concordium-client contract update \ + $ concordium-client contract update \ --entrypoint update \ --parameter-json input.json \ --sender \ @@ -221,7 +221,7 @@ Or, to use Concordium's testnet node, use this command: .. code-block:: console - $concordium-client contract update \ + $ concordium-client contract update \ --entrypoint update \ --parameter-json input.json \ --sender \ diff --git a/source/mainnet/tutorials/quick-start.rst b/source/mainnet/tutorials/quick-start.rst index e4d3d76731..25c06dcd7a 100644 --- a/source/mainnet/tutorials/quick-start.rst +++ b/source/mainnet/tutorials/quick-start.rst @@ -115,7 +115,7 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $concordium-client module deploy my_module.wasm.v1 --sender account_name + $ concordium-client module deploy my_module.wasm.v1 --sender account_name The ``--sender`` option can be omitted if the account "default" is to be used. @@ -140,7 +140,7 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $concordium-client module deploy my_module.wasm.v1 --name my_deployed_module + $ concordium-client module deploy my_module.wasm.v1 --name my_deployed_module If successful, the output will be similar to the following: @@ -158,7 +158,7 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $concordium-client contract update 0 --entrypoint my_receive --energy 10000 --sender MyAccount + $ concordium-client contract update 0 --entrypoint my_receive --energy 10000 --sender MyAccount If successful, the output will be similar to the following: diff --git a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst index 366acb680a..ae154bd022 100644 --- a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst +++ b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst @@ -178,7 +178,7 @@ This command will create the ``smart_contract_upgrade.wasm.v1`` file in your cur .. code-block:: console - $concordium-client module deploy ./smart_contract_upgrade.wasm.v1 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client module deploy ./smart_contract_upgrade.wasm.v1 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure .. image:: ./images/deploy_contract_version1.png :alt: Deploy contract version 1 @@ -197,13 +197,13 @@ Initialize a ``contract-version1`` smart contract instance with the command: .. code-block:: console - $concordium-client contract init --contract smart_contract_upgrade --energy 30000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract init --contract smart_contract_upgrade --energy 30000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure For example, when using the module reference from the image above, the command will look as follows: .. code-block:: console - $concordium-client contract init 8fc09d2519f516cfbb3d139b1e567753780fbb52854ecbf9a12c447756d18eb0 --contract smart_contract_upgrade --energy 30000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract init 8fc09d2519f516cfbb3d139b1e567753780fbb52854ecbf9a12c447756d18eb0 --contract smart_contract_upgrade --energy 30000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure .. image:: ./images/initialize_contract.png :alt: Initialize contract version 1 @@ -215,13 +215,13 @@ Before upgrading the ``contract-version1``, you can check its state with the vie .. code-block:: console - $concordium-client contract invoke --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract invoke --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure For example, when using the smart contract index from the image above, the command will look as follows: .. code-block:: console - $concordium-client contract invoke 4462 --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract invoke 4462 --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure You should see the following output. @@ -251,7 +251,7 @@ This command will create the ``smart_contract_upgrade.wasm.v1`` file in your cur .. code-block:: console - $concordium-client module deploy ./smart_contract_upgrade.wasm.v1 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client module deploy ./smart_contract_upgrade.wasm.v1 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure .. image:: ./images/deploy_contract_version2.png :alt: Deploy contract version 2 @@ -303,13 +303,13 @@ Upgrade the smart contract as follows: .. code-block:: console - $concordium-client contract update --entrypoint upgrade --parameter-json upgrade.json --energy 5000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract update --entrypoint upgrade --parameter-json upgrade.json --energy 5000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure For example, when using the smart contract index from the image above, the command will look as follows: .. code-block:: console - $concordium-client contract update 4462 --entrypoint upgrade --parameter-json upgrade.json --energy 5000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract update 4462 --entrypoint upgrade --parameter-json upgrade.json --energy 5000 --sender --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure You should see the following output. @@ -321,7 +321,7 @@ You can check that the state migration was successful by inspecting the state wi .. code-block:: console - $concordium-client contract invoke --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure + $ concordium-client contract invoke --entrypoint view --grpc-port 20000 --grpc-ip grpc.testnet.concordium.com --secure .. image:: ./images/view_contract_version2.png :alt: View contract version 2 From f42c79d3950a7bbca3ac466f7ea3a1b39f253205 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 13:28:46 +0200 Subject: [PATCH 07/14] Modify documentation for wasm32v1-none target --- .../how-to/smart-contracts/build-schema.rst | 30 +++++++++---------- .../smart-contracts/unit-test-contract.rst | 10 +++---- .../tutorials/counter/counter-contract.rst | 4 +-- .../tutorials/piggy-bank/deploying.rst | 2 +- .../mainnet/tutorials/piggy-bank/testing.rst | 6 ++-- .../mainnet/tutorials/piggy-bank/writing.rst | 2 +- source/mainnet/tutorials/quick-start.rst | 10 +++---- .../smartContractUpgrade.rst | 4 +-- source/shared/setup-env.rst | 4 +-- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/source/mainnet/how-to/smart-contracts/build-schema.rst b/source/mainnet/how-to/smart-contracts/build-schema.rst index 0583c69a32..35a3fd99ff 100644 --- a/source/mainnet/how-to/smart-contracts/build-schema.rst +++ b/source/mainnet/how-to/smart-contracts/build-schema.rst @@ -165,7 +165,7 @@ The schema is embedded by default when building the smart contract module: .. code-block:: console - $cargo concordium build + $ cargo concordium build If successful the output of the command will tell you the total sie of the schema in bytes. @@ -173,7 +173,7 @@ You can disable the default behavior (not recommended) with: .. code-block:: console - $cargo concordium build --no-schema-embed + $ cargo concordium build --no-schema-embed Outputting a schema file ------------------------ @@ -184,7 +184,7 @@ must exist and the file will be created in following command .. code-block:: console - $cargo concordium build --schema-out "/some/path/schema.bin" + $ cargo concordium build --schema-out "/some/path/schema.bin" The schema can be output in JSON format that can be more suitable for use in dApps. When building @@ -195,7 +195,7 @@ names that exist in the module or a counter in case of special characters in the .. code-block:: console - $cargo concordium build --schema-json-out "/some/path/" + $ cargo concordium build --schema-json-out "/some/path/" The schema can be output in base64 format that is currently supported in the |bw|. When building @@ -204,20 +204,20 @@ must exist and the file will be created in following command .. code-block:: console - $cargo concordium build --schema-base64-out "/some/path/base64_schema.b64" + $ cargo concordium build --schema-base64-out "/some/path/base64_schema.b64" Instead of writing the base64 representation of the schema to the file provided with the ``--schema-base64-out`` flag, you can print it to the console by using a dash character (-) in following command .. code-block:: console - $cargo concordium build --schema-base64-out - + $ cargo concordium build --schema-base64-out - The ``--schema-out``, ``--schema-json-out`` and ``--schema-base64-out`` can be used at the same time and schemas in all the formats will be output .. code-block:: console - $cargo concordium build --schema-out "/some/path/schema.bin" --schema-json-out "/some/path/" --schema-base64-out "/some/path/base64_schema.b64" + $ cargo concordium build --schema-out "/some/path/schema.bin" --schema-json-out "/some/path/" --schema-base64-out "/some/path/base64_schema.b64" .. note :: @@ -237,14 +237,14 @@ To convert an existing binary schema (obtained via ``--schema-out``) use the .. code-block:: console - $cargo concordium schema-json --schema "/some/path/schema.bin" --out "/some/path/" + $ cargo concordium schema-json --schema "/some/path/schema.bin" --out "/some/path/" Alternatively, a schema in JSON can be extracted from an embedded schema in a module (obtained via ``cargo concordium build``) by using .. code-block:: console - $cargo concordium schema-json --module "module.wasm.v1" --out "/some/path/" + $ cargo concordium schema-json --module "module.wasm.v1" --out "/some/path/" Converting a binary schema to base64 ------------------------------------ @@ -254,14 +254,14 @@ To convert an existing binary schema (obtained via ``--schema-out``) use the .. code-block:: console - $cargo concordium schema-base64 --schema "/some/path/schema.bin" --out "/some/path/base64_schema.b64" + $ cargo concordium schema-base64 --schema "/some/path/schema.bin" --out "/some/path/base64_schema.b64" Alternatively, a schema in base64 format can be extracted from an embedded schema in a module (obtained via ``cargo concordium build``) by using .. code-block:: console - $cargo concordium schema-base64 --module "module.wasm.v1" --out "/some/path/base64_schema.b64" + $ cargo concordium schema-base64 --module "module.wasm.v1" --out "/some/path/base64_schema.b64" Instead of writing the base64 representation of the schema to the file provided with the ``--out`` flag, you can print it to the console by using a dash character (-) or by omitting the ``--out`` flag. The following four @@ -269,13 +269,13 @@ commands print the base64 representation of the schema to the console: .. code-block:: console - $cargo concordium schema-base64 --schema "schema.bin" + $ cargo concordium schema-base64 --schema "schema.bin" - $cargo concordium schema-base64 --schema "schema.bin" --out - + $ cargo concordium schema-base64 --schema "schema.bin" --out - - $cargo concordium schema-base64 --module "/some/path/module.wasm.v1" + $ cargo concordium schema-base64 --module "/some/path/module.wasm.v1" - $cargo concordium schema-base64 --module "/some/path/module.wasm.v1" --out - + $ cargo concordium schema-base64 --module "/some/path/module.wasm.v1" --out - .. _cargo-concordium: https://crates.io/crates/cargo-concordium .. |cargo-concordium| replace:: ``cargo-concordium`` diff --git a/source/mainnet/how-to/smart-contracts/unit-test-contract.rst b/source/mainnet/how-to/smart-contracts/unit-test-contract.rst index bef248dd0c..9a6e08fd9a 100644 --- a/source/mainnet/how-to/smart-contracts/unit-test-contract.rst +++ b/source/mainnet/how-to/smart-contracts/unit-test-contract.rst @@ -50,7 +50,7 @@ Use ``cargo`` to run the test: .. code-block:: console - $cargo test + $ cargo test By default, this command compiles the contract and tests to machine code for your local target (most likely ``x86_64``), and runs them. @@ -111,7 +111,7 @@ Tests can now be built and run using: .. code-block:: console - $cargo concordium test + $ cargo concordium test This command compiles the tests for Wasm with the ``wasm-test`` feature enabled for ``concordium-std`` and uses the test runner from ``cargo-concordium``. @@ -695,7 +695,7 @@ The same command is used for running Wasm QuickCheck tests as in :ref:`tests_in_ .. code-block:: console - $cargo concordium test + $ cargo concordium test When a test fails, it reports the random seed used to produce the input values. The random numbers are generated using a deterministic pseudo-random number generator from this seed. @@ -704,13 +704,13 @@ The seed is a ``u64`` number, which can be provided along with the test command: .. code-block:: console - $cargo concordium test --seed 1234567890 + $ cargo concordium test --seed 1234567890 Concordium QuickCheck tests can also be run with: .. code-block:: console - $cargo test + $ cargo test By default, this command compiles the contract, unit tests, and QuickCheck tests to machine code for your local target (most likely x86_64) and runs them. diff --git a/source/mainnet/tutorials/counter/counter-contract.rst b/source/mainnet/tutorials/counter/counter-contract.rst index 7861f807f2..51eb53f2c4 100644 --- a/source/mainnet/tutorials/counter/counter-contract.rst +++ b/source/mainnet/tutorials/counter/counter-contract.rst @@ -27,7 +27,7 @@ Once you have setup your development environment, you are ready to create your s .. code-block:: console - $cargo concordium init + $ cargo concordium init When prompted for which template to expand, select the ``default`` option. You will then be asked for a name for your project. In this example we'll use "counter", but you can choose whatever name you want. @@ -119,7 +119,7 @@ Create a ``dist`` folder for the compiled WASM contract. Then, run the build com .. code-block:: console - $cargo concordium build --out dist/module.wasm.v1 + $ cargo concordium build --out dist/module.wasm.v1 You may get a warning about the build not being verifiable, which you may ignore. diff --git a/source/mainnet/tutorials/piggy-bank/deploying.rst b/source/mainnet/tutorials/piggy-bank/deploying.rst index 62622f3109..efc3b3fe50 100644 --- a/source/mainnet/tutorials/piggy-bank/deploying.rst +++ b/source/mainnet/tutorials/piggy-bank/deploying.rst @@ -30,7 +30,7 @@ Repeat this step since you might have done some changes to the smart contract co .. code-block:: console - $cargo concordium build --out piggy_bank_part2.wasm.v1 + $ cargo concordium build --out piggy_bank_part2.wasm.v1 .. note:: diff --git a/source/mainnet/tutorials/piggy-bank/testing.rst b/source/mainnet/tutorials/piggy-bank/testing.rst index 829d459c54..a63632bf8a 100644 --- a/source/mainnet/tutorials/piggy-bank/testing.rst +++ b/source/mainnet/tutorials/piggy-bank/testing.rst @@ -231,7 +231,7 @@ Then compile your contract with: .. code-block:: console - $cargo concordium build --out piggy_bank_part2.wasm.v1 + $ cargo concordium build --out piggy_bank_part2.wasm.v1 This produces the Wasm module ``piggy_bank_part2.wasm.v1`` in the root of your project, unless you have any typos or bugs in your code. If that is the case, try to fix them using the helpful error messages from the compiler or go back to the end of part 1 and copy the full contract code again. @@ -245,7 +245,7 @@ If that is the case, try to fix them using the helpful error messages from the c .. code-block:: console - $cargo concordium test --out piggy_bank_part2.wasm.v1 + $ cargo concordium test --out piggy_bank_part2.wasm.v1 Please note that the test command only builds your module in cargo concordium version 2.9.0+. Also note that for the highest assurance of correctness, you should *deploy the exact module* that you also tested. @@ -412,7 +412,7 @@ Run the test to check that it compiles and succeeds. .. code-block:: console - $cargo concordium test --out piggy_bank_part2.wasm.v1 + $ cargo concordium test --out piggy_bank_part2.wasm.v1 Note that the command recompiles the Wasm module and replaces the old module in the same location due to the ``--out`` parameter. diff --git a/source/mainnet/tutorials/piggy-bank/writing.rst b/source/mainnet/tutorials/piggy-bank/writing.rst index 54036911c5..dab8364e7b 100644 --- a/source/mainnet/tutorials/piggy-bank/writing.rst +++ b/source/mainnet/tutorials/piggy-bank/writing.rst @@ -548,7 +548,7 @@ You now have all the parts for your piggy bank smart contract. Before you start .. code-block:: console - $cargo concordium build + $ cargo concordium build This should succeed if everything is set up correctly. Otherwise, compare your code with the one found here_. diff --git a/source/mainnet/tutorials/quick-start.rst b/source/mainnet/tutorials/quick-start.rst index 25c06dcd7a..70ee75f89f 100644 --- a/source/mainnet/tutorials/quick-start.rst +++ b/source/mainnet/tutorials/quick-start.rst @@ -38,13 +38,13 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $cargo install --locked cargo-generate + $ cargo install --locked cargo-generate To start a new Concordium smart contract project from a template, run the command: .. code-block:: console - $cargo concordium init + $ cargo concordium init The path where the project should be created can be provided with the ``--path`` option. @@ -84,13 +84,13 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $cargo concordium build + $ cargo concordium build This uses Cargo_ for building, but runs further optimizations on the result. Running the ``cargo concordium build`` command will produce a smart contract module which can be found relative to your project root folder in ``./target/concordium/wasm32-unknown-unknown/release/my_module.wasm.v1``. Alternatively, you can supply the location where to store the smart contract module using the ``--out`` option. For example running the following command will output your smart contract module into the root folder of your project in a file name ``my_module.wasm.v1``. .. code-block:: console - $cargo concordium build --out ./my_module.wasm.v1 + $ cargo concordium build --out ./my_module.wasm.v1 .. Note:: @@ -100,7 +100,7 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: console - $cargo build --target=wasm32-unknown-unknown [--release] + $ cargo build --target=wasm32-unknown-unknown [--release] Note that even with ``--release`` set, the produced Wasm module includes debug information. diff --git a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst index ae154bd022..ed407508ee 100644 --- a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst +++ b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst @@ -164,7 +164,7 @@ Compile the smart contract to a Wasm module which you will deploy to testnet in .. code-block:: console - $cargo concordium build --out smart_contract_upgrade.wasm.v1 + $ cargo concordium build --out smart_contract_upgrade.wasm.v1 .. image:: ./images/compile_contract_version1.png :alt: Compile contract version 1 @@ -241,7 +241,7 @@ Compile the smart contract to a Wasm module which you will deploy to testnet in .. code-block:: console - $cargo concordium build --out smart_contract_upgrade.wasm.v1 + $ cargo concordium build --out smart_contract_upgrade.wasm.v1 .. image:: ./images/compile_contract_version2.png :alt: Compile contract version 2 diff --git a/source/shared/setup-env.rst b/source/shared/setup-env.rst index 216180c89a..e92f92dc79 100644 --- a/source/shared/setup-env.rst +++ b/source/shared/setup-env.rst @@ -60,13 +60,13 @@ To install ``cargo-concordium`` run: .. code-block:: console - $cargo install --locked cargo-concordium + $ cargo install --locked cargo-concordium For a description of how to use the ``cargo-concordium`` run: .. code-block:: console - $cargo concordium --help + $ cargo concordium --help To use verifiable builds with cargo-concordium a container runtime such as `Docker `_ is required. From e3ec5ff7d64a74ab60bd2b185bceee750f53ebd2 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 13:32:15 +0200 Subject: [PATCH 08/14] Modify documentation for wasm32v1-none target --- source/shared/setup-env.rst | 40 ++----------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/source/shared/setup-env.rst b/source/shared/setup-env.rst index e92f92dc79..e571b86c19 100644 --- a/source/shared/setup-env.rst +++ b/source/shared/setup-env.rst @@ -6,14 +6,6 @@ Set up the development environment Before starting the tutorials, you must prepare your development environment by installing a number of tools. This topic covers the setup required for the tutorials. -.. Note:: - - You can also watch a video about installing the smart contract tools. - - .. raw:: html - - - First, you need to install ``rustup`` which installs Rust and Cargo to your computer. Go to `Rustup `_ to install ``rustup`` for your platform. Type **1** to continue the installation. @@ -26,36 +18,14 @@ Finally, when Rust and Cargo are successfully installed in your system, you shou .. image:: images/mint-rust-install-done.png :width: 100% -.. Note:: - - Currently, Rust toolchain versions up to ``1.81`` are and newer are not supported by older ``cargo-concordium`` versions ( <= ``4.0.0``). Update ``cargo-concordium`` if you see the error ``Unexpected byte 0x80. Expected 0x00`` as follows: - - .. code-block:: console - - $ cargo install cargo-concordium - $ cargo concordium --version - $ cargo-concordium 4.1.1 - - The minimum supported rust version is currently version ``1.73`` - Copy and paste the commands in a terminal to install Wasm which will be used for building contracts. .. code-block:: console - rustup target add wasm32-unknown-unknown + rustup target add wasm32v1-none -During Wasm installation in your system you should see something similar to below. - -.. image:: images/mint-wasm-install.png - :width: 100% - -Now you need to install the Concordium software package. ``cargo-concordium`` is the tool for developing smart contracts for the Concordium blockchain. It can be used for :ref:`compiling` and :ref:`testing` smart contracts, and enables features such as :ref:`building contract schemas`. :ref:`Click here` and download the version 2.2.0 or greater of ``cargo-concordium`` for your operating system. The tool is the same for both testnet and mainnet. - -.. note:: - - If you are not using Ubuntu/Linux as your operating system, the following screenshots and commands will be different. - Remember to adjust the following commands based on your operating system. +Now you need to install the Concordium software package. ``cargo-concordium`` is the tool for developing smart contracts for the Concordium blockchain. It can be used for :ref:`compiling` and :ref:`testing` smart contracts, and enables features such as :ref:`building contract schemas`. To install ``cargo-concordium`` run: .. code-block:: console @@ -73,12 +43,6 @@ To use verifiable builds with cargo-concordium a container runtime such as `Dock .. image:: images/cargo-help.png :width: 100% -.. Note:: - - If you have a warning on a Mac device that says “cargo-concordium cannot be opened because the developer cannot be verified” that means it requires permission to run and you should go to **System Preferences → Security** and unlock it with your password and click **Allow Anyway**. - - .. image:: images/mac-warning.png - :width: 100% .. _interact-with-your-contract: From a9184c3eccf9db1331922f35148a0cbaceacdad7 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 14:21:50 +0200 Subject: [PATCH 09/14] Modify documentation for wasm32v1-none target --- .../how-to/governance/install-ledger-app.rst | 14 ++-- .../how-to/smart-contracts/compile-module.rst | 5 +- .../integration-test-contract.rst | 2 +- .../tutorials/piggy-bank/deploying.rst | 2 +- .../mainnet/tutorials/piggy-bank/testing.rst | 7 +- source/mainnet/tutorials/quick-start.rst | 26 ++----- .../smartContractUpgrade.rst | 6 +- .../mainnet/tutorials/voting/voting-dapp.rst | 12 ++-- source/shared/setup-env.rst | 71 +------------------ 9 files changed, 31 insertions(+), 114 deletions(-) diff --git a/source/mainnet/how-to/governance/install-ledger-app.rst b/source/mainnet/how-to/governance/install-ledger-app.rst index 0f10c25acc..3db6b91219 100644 --- a/source/mainnet/how-to/governance/install-ledger-app.rst +++ b/source/mainnet/how-to/governance/install-ledger-app.rst @@ -279,7 +279,7 @@ You need to install a custom certificate to ensure that the LEDGER device trusts .. code-block:: console :substitutions: - $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| + $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| .. For now, setting up custom CAs on Nano S+ does not make any difference, as sideloading signed apps is not working. .. @@ -290,14 +290,14 @@ You need to install a custom certificate to ensure that the LEDGER device trusts .. .. code-block:: console .. :substitutions: .. - .. $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| + .. $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| .. .. .. group-tab:: Nano S+ .. .. .. code-block:: console .. :substitutions: .. - .. $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus + .. $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus #. Load the certificate onto the LEDGER device by running the following script from the extracted folder: @@ -375,14 +375,14 @@ After installing the certificate, you can proceed to install the Concordium LEDG .. code-block:: console :substitutions: - $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| + $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| .. group-tab:: Nano S+ .. code-block:: console :substitutions: - $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus + $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus #. Install the Concordium application on the LEDGER device by running the following script from the folder you extracted the files to: @@ -458,14 +458,14 @@ For the app to work properly with the current version of the Desktop Wallet, mak .. code-block:: console :substitutions: - $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| + $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanos-|nano-s-firmware| .. group-tab:: Nano S+ .. code-block:: console :substitutions: - $cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus + $ cd ~/Downloads/concordium-governance-ledger-app-|ccd-governance-version|-nanosplus #. Install the Concordium application on the LEDGER device by running the following script from the folder you extracted the files to: diff --git a/source/mainnet/how-to/smart-contracts/compile-module.rst b/source/mainnet/how-to/smart-contracts/compile-module.rst index c7fe9b5ed7..a9b4b3f71a 100644 --- a/source/mainnet/how-to/smart-contracts/compile-module.rst +++ b/source/mainnet/how-to/smart-contracts/compile-module.rst @@ -51,9 +51,10 @@ For example, running the following command will output your smart contract modul .. code-block:: console - $ cargo check --target=wasm32v1-none --release + $ cargo build --target=wasm32v1-none --release - produces a pure Wasm module as output. But Cargo concordium will embed schema and version information that is needed in addition. + produces a pure Wasm module as output. But Cargo concordium will embed schema and version information that is needed in addition, + and also optimize the Wasm by stripping unused code. .. _cargo-concordium: https://crates.io/crates/cargo-concordium .. |cargo-concordium| replace:: ``cargo-concordium`` diff --git a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst index a4fcf88cfc..f3d15aa071 100644 --- a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst +++ b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst @@ -30,7 +30,7 @@ The high-level process of adding integration tests to your existing smart contra # ... [dev-dependencies] - concordium-smart-contract-testing = "4.4.0" + concordium-smart-contract-testing = "5.0.0" By putting it under ``dev-dependencies``, it is only included for tests. diff --git a/source/mainnet/tutorials/piggy-bank/deploying.rst b/source/mainnet/tutorials/piggy-bank/deploying.rst index efc3b3fe50..43d780041e 100644 --- a/source/mainnet/tutorials/piggy-bank/deploying.rst +++ b/source/mainnet/tutorials/piggy-bank/deploying.rst @@ -38,7 +38,7 @@ Repeat this step since you might have done some changes to the smart contract co .. note:: - When you use the above command *without* the ``--out`` flag, you can find the module in the folder ``./target/concordium/wasm32-unknown-unknown/release/``. + When you use the above command *without* the ``--out`` flag, you can find the module in the folder ``./concordium_out/``. Use the Wasm module file suffixed with ``v1`` when deploying to the chain. The ``piggy_bank_part2.wasm`` file (without the ``v1`` suffix) is not the ``v0`` module, but rather the raw Wasm module produced by cargo. The ``v1`` suffixed module has been stripped for debugging information, which makes it significantly smaller. diff --git a/source/mainnet/tutorials/piggy-bank/testing.rst b/source/mainnet/tutorials/piggy-bank/testing.rst index a63632bf8a..5d82065aea 100644 --- a/source/mainnet/tutorials/piggy-bank/testing.rst +++ b/source/mainnet/tutorials/piggy-bank/testing.rst @@ -119,14 +119,12 @@ Adding the testing library Start by adding the |concordium-smart-contract-testing|_ library to the ``Cargo.toml`` located in the project root. Then, add the |concordium-std-derive|_ library as well, which contains useful macros for testing. -You should add them under the section ``[dev-dependencies]``, which are dependencies only needed during development, as it is only needed during testing. -The libraries require the Rust edition ``2021`` or greater, which you must also set: +You should add them under the section ``[dev-dependencies]``, which are dependencies only needed during development, as it is only needed during testing: .. code-block:: toml [package] # ... - edition = "2021" [dev-dependencies] concordium-smart-contract-testing = "3.0" @@ -247,8 +245,7 @@ If that is the case, try to fix them using the helpful error messages from the c $ cargo concordium test --out piggy_bank_part2.wasm.v1 - Please note that the test command only builds your module in cargo concordium version 2.9.0+. - Also note that for the highest assurance of correctness, you should *deploy the exact module* that you also tested. + Note that for the highest assurance of correctness, you should *deploy the exact module* that you also tested. Going back to your test case, use the function |module_load_v1|_ to load the module. diff --git a/source/mainnet/tutorials/quick-start.rst b/source/mainnet/tutorials/quick-start.rst index 70ee75f89f..7391ea483a 100644 --- a/source/mainnet/tutorials/quick-start.rst +++ b/source/mainnet/tutorials/quick-start.rst @@ -48,11 +48,10 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi The path where the project should be created can be provided with the ``--path`` option. - You can use the `concordium-std`_ library to help you build smart contracts or build without Rust's ``std``. To add the library, open ``Cargo.toml`` and add the line - ``concordium-std = "*"`` (preferably, replace the `*` with the latest version of `concordium-std`_) in the ``[dependencies]`` section: + You can use the `concordium-std`_ library to help you build smart contracts or build without Rust's ``std``. To add the library, open ``Cargo.toml`` and add the library in the ``[dependencies]`` section: [dependencies] - concordium-std = "5.1" + concordium-std = "11.0" The library documentation is on `docs.rs`_. @@ -62,6 +61,8 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi .. code-block:: rust + #![no_std] + use concordium_std::*; For information about developing and editing your smart contracts, see :ref:`Developing smart contracts`. @@ -86,24 +87,12 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi $ cargo concordium build - This uses Cargo_ for building, but runs further optimizations on the result. Running the ``cargo concordium build`` command will produce a smart contract module which can be found relative to your project root folder in ``./target/concordium/wasm32-unknown-unknown/release/my_module.wasm.v1``. Alternatively, you can supply the location where to store the smart contract module using the ``--out`` option. For example running the following command will output your smart contract module into the root folder of your project in a file name ``my_module.wasm.v1``. + This uses Cargo_ for building, but runs further optimizations on the result. Running the ``cargo concordium build`` command will produce a smart contract module which can be found relative to your project root folder in ``./concordium-out/my_module.wasm.v1``. Alternatively, you can supply the location where to store the smart contract module using the ``--out`` option. For example running the following command will output your smart contract module into the root folder of your project in a file name ``my_module.wasm.v1``. .. code-block:: console $ cargo concordium build --out ./my_module.wasm.v1 - .. Note:: - - For building the schema for a smart contract module, some :ref:`further preparation is required `. - - It is also possible to compile using Cargo_ directly by running: - - .. code-block:: console - - $ cargo build --target=wasm32-unknown-unknown [--release] - - Note that even with ``--release`` set, the produced Wasm module includes - debug information. .. dropdown:: Step 5 - Deploy your smart contract @@ -123,11 +112,6 @@ Before starting, it is a good idea to read the :ref:`Smart contracts best practi the smart contract version, i.e. ``my_module.wasm.v0`` for V0 contracts and ``my_module.wasm.v1`` for V1 contracts. - When deploying a smart contract module built directly with ``cargo``, it is necessary to - specify the smart contract version with the ``--contract-version [v0, v1]`` - option. These module files will not have the version suffix, e.g. - ``.v0``, or ``.v1``, but just be called ``.wasm``. - If successful, the output should be similar to the following: .. code-block:: console diff --git a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst index ed407508ee..8af9af0c9d 100644 --- a/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst +++ b/source/mainnet/tutorials/smartContractUpgrade/smartContractUpgrade.rst @@ -152,13 +152,13 @@ Clone the `smart contract upgrade example .. code-block:: console - $git clone https://github.com/Concordium/concordium-browser-wallet + $ git clone https://github.com/Concordium/concordium-browser-wallet Navigate to the ``examples/voting`` subdirectory, then build and run the frontend as described below: @@ -95,31 +95,31 @@ Navigate to the ``examples/voting`` subdirectory, then build and run the fronten .. code-block:: console - $yarn + $ yarn - Run ``yarn build`` to build the package. .. code-block:: console - $yarn build + $ yarn build - Navigate to the voting example folder. .. code-block:: console - $cd ./examples/voting/ + $ cd ./examples/voting/ - Run ``yarn watch`` to enable hot-reload (useful for development) of the web frontend whenever you do any changes to the code. .. code-block:: console - $yarn watch + $ yarn watch - Run ``yarn start`` in another terminal to start the web frontend. .. code-block:: console - $yarn start + $ yarn start The command will log a URL in the console. Open this URL in the Chrome browser. diff --git a/source/shared/setup-env.rst b/source/shared/setup-env.rst index e571b86c19..e965888fb1 100644 --- a/source/shared/setup-env.rst +++ b/source/shared/setup-env.rst @@ -55,7 +55,7 @@ Rename the package to ``concordium-client`` in case it has some version annotati .. code-block:: console - $ls | grep 'concordium-client' + $ ls | grep 'concordium-client' .. image:: images/pb_tutorial_10.png :width: 70 % @@ -76,7 +76,7 @@ Before you can use the downloaded Concordium Client on Linux you have to make th .. code-block:: console - $chmod +x concordium-client + $ chmod +x concordium-client .. image:: images/pb_tutorial_8.png :width: 50 % @@ -85,78 +85,13 @@ Check whether you can execute the ``concordium-client`` tool. .. code-block:: console - $./concordium-client --help + $ ./concordium-client --help You should see some output that will help you in getting familiar with the ``concordium-client`` tool. .. image:: images/pb_tutorial_9.png :width: 100 % -Your next task enables the ``concordium-client`` tool to talk to a testnet node. There are two options to achieve this: - -.. dropdown:: **Option 1 (beginners)** - - This option explains how to transfer the ``concordium-client`` tool to your instance and execute commands from within the instance. - - **Advantage**: You can execute the commands within your instance. - - **Disadvantage**: You have to transfer files between your local machine and your instance. - - Transfer the ``concordium-client`` package from your machine via a file-sharing tool (such as `FileZilla `_ or the ``sftp`` command) to your instance. - - Connect to your instance and make your package executable again as you have done previously already: - - .. code-block:: console - - $chmod +x concordium-client - - Check if everything is connected correctly by displaying the best/latest block. - - .. code-block:: console - - $./concordium-client block show --grpc-port 20001 - - You should see some block data output. - - .. image:: images/pb_tutorial_18.png - :width: 100 % - - .. note:: - - Port 20001 is open by default on your testnet node to interact with it. - -.. dropdown:: **Option 2 (advanced users)** - - This option explains how you can use the ``concordium-client`` tool locally on your machine and connect remotely to your node running on the server. - - **Advantage**: You don't have to transfer files between your local machine and your instance later in the tutorial. - - **Disadvantage**: You have to use ssh with port forwarding when you run a command locally. - - Since you have a remote server your cloud provider usually gives you an option to ssh into it. Add the following port forwarding rule to your method to ssh into your instance in terminal A. The port 20001 on your localhost is forwarded to the port 20001 on your instance. - - .. code-block:: console - - $ssh -NL localhost:20001::20001 @ - - .. image:: images/pb_tutorial_26.png - :width: 100 % - - .. note:: - - Port 20001 is open by default on your testnet node to interact with it. Cloud providers often use ``ubuntu`` as the default and the as the default . - - Go in another terminal B to the folder where you downloaded the ``concordium-client``. Check if everything is connected correctly by displaying the best/latest block. - - .. code-block:: console - - $./concordium-client block show --grpc-port 20001 - - You should see some block data output. - - .. image:: images/pb_tutorial_17.png - :width: 100 % - Concordium node on Testnet ========================== From aa882397a558d8382415833086ccc0001d1f2986 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 16:13:36 +0200 Subject: [PATCH 10/14] Modify documentation for wasm32v1-none target --- source/mainnet/how-to/index.rst | 2 - .../best-practices/development.rst | 15 +- .../smart-contracts/unit-test-contract.rst | 849 ------------------ 3 files changed, 10 insertions(+), 856 deletions(-) delete mode 100644 source/mainnet/how-to/smart-contracts/unit-test-contract.rst diff --git a/source/mainnet/how-to/index.rst b/source/mainnet/how-to/index.rst index 2a1eb265cb..5be222c8ed 100644 --- a/source/mainnet/how-to/index.rst +++ b/source/mainnet/how-to/index.rst @@ -93,7 +93,6 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid - :doc:`Use fallback entrypoints ` - :doc:`Write an upgradeable contract ` - :doc:`Implement the factory pattern ` - - :doc:`Unit test a contract ` - :doc:`Integration test a contract ` - :doc:`Deploy a smart contract module ` @@ -171,7 +170,6 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid Use fallback entrypoints Write an upgradeable contract Implement the factory pattern - Unit test a contract Integration test a contract Deploy a smart contract module Migrate contracts diff --git a/source/mainnet/how-to/smart-contracts/best-practices/development.rst b/source/mainnet/how-to/smart-contracts/best-practices/development.rst index 9c95cc4cb2..0eda351706 100644 --- a/source/mainnet/how-to/smart-contracts/best-practices/development.rst +++ b/source/mainnet/how-to/smart-contracts/best-practices/development.rst @@ -316,11 +316,16 @@ Code documentation Automated testing ----------------- -The Concordium standard library `concordium-std`_ offers several possibilities for testing the smart contract code. - -- Use :ref:`Integration testing ` to test particular cases where you define what is the valid output. -- (**Deprecated**) Use :ref:`Unit testing ` to test particular cases where you define what is the valid output. -- (**Deprecated**) :ref:`Property-based testing ` is a variant of randomized testing that repeatedly checks a *property* with randomly generated input. +Integration tests of smart contracts can be implemented as described on :ref:`Integration testing `. +Integration tests allows you to test the contract in an environment where: + +- The smart contract runs in the real Wasm interpreter +- The smart contract interacts with the real host functions and real chain integration +- The chain itself is stubbed, as the only component that is not "real" + +Besides from those tests, you can also implement plain Rust unit tests for functions that does not interact with host functions. +A third, and more advanced, possibility is using the `concordium_test macro `_. +Examples may be found in `concordium-std tests `_. Use the :ref:`smart contract specification ` guidelines from this document to come up with cases and properties to test. diff --git a/source/mainnet/how-to/smart-contracts/unit-test-contract.rst b/source/mainnet/how-to/smart-contracts/unit-test-contract.rst deleted file mode 100644 index 9a6e08fd9a..0000000000 --- a/source/mainnet/how-to/smart-contracts/unit-test-contract.rst +++ /dev/null @@ -1,849 +0,0 @@ -.. _unit-test-contract: - -============ -Unit testing -============ - -.. admonition:: At a glance - - This guide covers the legacy unit testing approach for Concordium smart contracts using the ``test_infrastructure`` module. Note that this approach is deprecated — new projects should use :ref:`integration tests ` instead. You will need an existing Rust smart contract. After following this guide, you will have unit tests running against your contract logic. - -.. warning:: - - Unit testing your contracts with the |test_infrastructure|_ has been deprecated in favor of |concordium-smart-contract-testing|_. - To migrate your contracts and tests see :ref:`migrate-contracts-for-std-8.1` and :ref:`integration-test-contract`. - - If you are not ready to migrate your contracts, you can still use the guide below. - Just make sure to add an ``#[allow(deprecated)]`` attribute above your test module to avoid warnings: - - .. code-block:: rust - - #[allow(deprecated)] - #[cfg(test)] - mod tests{ - use concordium_std::test_infrastructure::*; - // ... - } - -This guide describes how to write unit tests for a smart contract written in -Rust. - -A smart contract in Rust is written as a library and you can unit test it like a -library by annotating functions with a ``#[test]`` attribute. - -.. code-block:: rust - - // contract code - ... - - #[cfg(test)] - mod test { - - #[test] - fn some_test() { ... } - - #[test] - fn another_test() { ... } - } - -Use ``cargo`` to run the test: - -.. code-block:: console - - $ cargo test - -By default, this command compiles the contract and tests to machine code for -your local target (most likely ``x86_64``), and runs them. -This kind of testing can be useful in initial development and for testing -functional correctness. -For comprehensive testing, it is important to involve the target platform, i.e., -`Wasm32`. - -.. _tests_in_wasm: - -Running tests in Wasm -===================== - -Compiling the tests to native machine code is sufficient for most cases, but it -is also possible to compile the tests to Wasm and run them using the exact -interpreter that is used by the nodes. -This makes the test environment closer to the run environment on-chain and could, -in some cases, catch more bugs. -One notable difference between different environments is regarding the size of -pointers, where `Wasm32` uses four bytes as opposed to eight, which is common -for most platforms. - -The development tool ``cargo-concordium`` includes a test runner for Wasm, which -uses the same Wasm-interpreter as the one shipped in the Concordium nodes. - -.. seealso:: - - For instructions about how to install ``cargo-concordium``, see :ref:`build-contract`. - -The unit test has to be annotated with ``#[concordium_test]`` instead of -``#[test]``, and ``#[concordium_cfg_test]`` is used instead of ``#[cfg(test)]``: - -.. code-block:: rust - - // contract code - ... - - #[concordium_cfg_test] - mod test { - - #[concordium_test] - fn some_test() { ... } - - #[concordium_test] - fn another_test() { ... } - } - -The ``#[concordium_test]`` macro sets up your tests to be run in Wasm when -``concordium-std`` is compiled with the ``wasm-test`` feature. Otherwise, it -falls back to behave just like ``#[test]``, meaning it is still possible to run -unit tests targeting native code using ``cargo test``. - -Similarly, the macro ``#[concordium_cfg_test]`` includes your module when build -``concordium-std`` with ``wasm-test`` otherwise behaves like ``#[test]``, -allowing you to control when to include tests in the build. - -Tests can now be built and run using: - -.. code-block:: console - - $ cargo concordium test - -This command compiles the tests for Wasm with the ``wasm-test`` feature enabled -for ``concordium-std`` and uses the test runner from ``cargo-concordium``. - -.. warning:: - - Error messages from ``panic!``, and therefore also the different variations - of ``assert!``, are *not* shown when compiling to Wasm. - - Instead, use ``fail!`` and the ``claim!`` variants to do assertions when - testing, as these reports back the error messages to the test runner *before* - failing the test. - Both are part of ``concordium-std``. - - The remainder of this guide will use the ``claim!`` variants for assertions. - -Writing unit tests -================== - -Unit tests typically follow a three-part structure in which you: set up some -state, run some unit of code, and make assertions about the state and output of -the code. - -If the contract functions are written using ``#[init(..)]`` or -``#[receive(..)]``, you can test these functions directly in the unit test. - -.. code-block:: rust - - use concordium_std::*; - - #[init(contract = "my_contract")] - fn contract_init( - ctx: &impl HasInitContext, - state_builder: &mut StateBuilder, - ) -> InitResult { ... } - - #[receive(contract = "my_contract", name = "my_receive")] - fn contract_receive( - ctx: &impl HasReceiveContext, - host: &impl HasHost, - ) -> ReceiveResult { ... } - - #[cfg(test)] - mod test { - use super::*; - use concordium_std::test_infrastructure::*; - - #[test] - fn some_init_test() { - // Create a test context. - let mut ctx = TestInitContext::empty(); - // Set the fields that your init method accesses. - ctx.set_init_origin(AccountAddress([0; 32])); - // Create a test state builder. - let mut state_builder = TestStateBuilder::new(); - - // Call the init method. - let result = contract_init(&ctx, &mut state_builder); - - // Assert properties. - claim_eq!(result, Ok(State::new())); - } - - #[test] - fn some_receive_test() { - // Create a test context. - let mut ctx = TestReceiveContext::empty(); - // Set the fields that your receive method accesses. - ctx.set_self_address(ContractAddress{ index: 0, subindex: 0 }); - // Create a test host with state. - let host = TestHost::new(State::new(), TestStateBuilder::new()); - - // Call the receive method. - let result = contract_receive(&ctx, &host); - - // Make assertions. - claim_eq!(result, Ok(MyReturnValue::new())); - claim_eq!(host.get_transfers(), []); // No transfers occured. - } - } - - -The submodule |test_infrastructure|_ of |concordium_std|_ contains a number of -test stubs, including the ones shown in the example, e.g., ``TestHost`` and ``TestInitContext``. - -.. seealso:: - - For more information and examples, see the crate documentation of - |concordium_std|_. - - -.. _testing_contract_invocations: - -Testing contract invocations with mocks -======================================= - -To test receive methods that invoke contracts with -``host.invoke_contract(...)``, you should set up mocking functions that act as -the invoked contract. The |test_infrastructure|_ has a number of helpers for -mocking contracts. - -To set up a mock entrypoint, use the |setup_mock_entrypoint|_ method from |TestHost|_. -It expects a ``ContractAddress`` and an ``OwnedEntrypointName`` to specify which -entrypoint on which contract you are mocking. -It also expects a ``MockFn``, which you can create in several different ways. - -The simplest way to create a ``MockFn`` is with ``returning_ok``, which creates -a mock function that returns the same ``Ok(..)`` value every time: - -.. code-block:: rust - :emphasize-lines: 14 - - // Contract code + general test setup - - #[test] - fn mock_test_return_ok() { - ... - let mut host = TestHost::new(State::new(), TestStateBuilder::new()); - - host.setup_mock_entrypoint( - ContractAddress { - index: 1, - subindex: 0, - }, - OwnedEntrypointName::new_unchecked("some_receive_method".to_string()), - MockFn::returning_ok(42u8), - ); - ... - } - -For returning the same error every time, use the ``returning_err``. -Use this to test missing contracts or entrypoints, as invoking -entrypoints for which no mock has been set up results in a runtime error: - -.. code-block:: rust - :emphasize-lines: 8 - - ... - host.setup_mock_entrypoint( - ContractAddress { - index: 1, - subindex: 0, - }, - OwnedEntrypointName::new_unchecked("some_receive_method".to_string()), - MockFn::returning_err::<()>(CallContractError::MissingContract), - ); - ... - -.. note:: - - The ``returning_err`` method is generic because - ``CallContractError`` is generic and can return a value - with its logic error: - - .. code-block:: rust - :emphasize-lines: 8-9 - - ... - host.setup_mock_entrypoint( - ContractAddress { - index: 1, - subindex: 0, - }, - OwnedEntrypointName::new_unchecked("some_receive_method".to_string()), - MockFn::returning_err::(CallContractError::LogicReject{ - reason: -1, return_value: "Something went wrong!".to_string()}), - ); - ... - -For more advanced types of mocks, use the functions ``MockFn::new_v1``, ``MockFn::new_v0``, or -``MockFn::new``. -Each of these functions takes a closure that has access to the parameter and amount -used in ``invoke_contract(parameter, amount, ..)``, but also the balance and -state of the contract you are testing. -The methods differ in what the closure should return. -V0 contracts do not have a return value, whereas V1 contracts always do. - -Here is an example of a mocked entrypoint that only uses the parameter -and amount. For simplicity, it just traps if the input is not as expected: - -.. code-block:: rust - :emphasize-lines: 10-23 - - ... - let mut host = TestHost::new(State::new(), TestStateBuilder::new()); - - host.setup_mock_entrypoint( - ContractAddress { - index: 1, - subindex: 0, - }, - OwnedEntrypointName::new_unchecked("some_receive_method".to_string()), - MockFn::new_v1(|parameter, amount, _balance, _state: &mut State| { - let n: u64 = match from_bytes(parameter.0) { - Ok(n) => n, - Err(_) => return Err(CallContractError::Trap), - }; - - if amount.micro_ccd < 100 { - return Err(CallContractError::Trap), - } - - let state_modified = false; // Mock did not modify the state. - - Ok((state_modified, n + 1)) - }), - ); - ... - -To test a contract that invokes itself, either directly or indirectly (e.g., ``A`` calls -``B`` which then calls ``A``, or with even more indirections), use the -state and balance fields: - -.. code-block:: rust - :emphasize-lines: 2-7, 11-24 - - ... - let mut ctx = TestReceiveContext::empty(); - let self_address = ContractAddress { - index: 0, - subindex: 0, - }; - ctx.set_self_address(self_address); - - let mut host = TestHost::new(State::new(), TestStateBuilder::new()); - - // Meant to mock calls to the contract itself, where amounts sent - // don't leave the contract and each call increments a counter. - host.setup_mock_entrypoint( - self_address, - OwnedEntrypointName::new_unchecked("self_receive".to_string()), - MockFn::new_v1(|_parameter, amount, balance, state: &mut State| { - - *balance += amount; - state.counter += 1; - - let state_modified = true; // Mock _did_ modify the state. - - Ok((state_modified, ())) - }), - ); - ... - -.. _reentracny-unit-testing: - -Reentrancy ----------- - -When invoking another smart contract, you give away control to that contract in the middle of execution. -The external contract can, for example, call back entrypoints of your contract. -This behavior is called *reentrancy* and is well-known from concurrency: a procedure can be interrupted in the middle of its execution, called again, and then resume execution. -See the details about handling external calls and ways of protecting against reentrancy-related issues in the :ref:`development best practices `. - -The state of your contract might not be the same before and after ``invoke_contract``, since the contract you call can invoke any entrypoint of your own contract. - -.. code-block:: rust - - let state_copy = *host.state(); - host.invoke_contract(...); - - // *host.state() and state_copy might not be equal any more due to reentrancy. - do_something_with(state_copy); - -Consider a concrete example of reentrancy when the state is *not* updated properly before making an external call. -This can lead to reentrant calls that pass some validation that is based on the current state, even though these calls should fail. -The classic example of such a security issue is `the DAO `_ Ethereum smart contract that was drained of funds due to the reentrancy vulnerability. -Below is a code snippet that implements a small part similar to the DAO contract that stores balances for arbitrary addresses in a map ``StateMap``. -The users can request their funds back; if a user is a smart contract, the funds are sent to a specified entrypoint. - -.. code-block:: rust - :emphasize-lines: 40-42 - - #[receive( - contract = "reentrancy", - name = "withdraw_reentrancy", - parameter = "OwnedEntrypointName", - error = "Error", - mutable - )] - fn withdraw_reentrancy( - ctx: &impl HasReceiveContext, - host: &mut impl HasHost, StateApiType = S>, - ) -> Result<(), Error> { - let sender = ctx.sender(); - - // Get balance for the sender, or reject if the sender is not found or the - // balance is zero. - let sender_balance = match host.state().balances.get(&sender) { - Some(bal) if *bal > Amount::zero() => *bal, - _ => return Err(Error::WithdrawWithoutFunds), - }; - - match sender { - Address::Account(acc) => host.invoke_transfer(&acc, sender_balance)?, - Address::Contract(addr) => { - let entrypoint: OwnedEntrypointName = ctx.parameter_cursor().get()?; - // At this point we are handing out the control out to an unknown - // smart contract. This contract can call this entry point - // again multiple times before the rest of the code is reached. - host.invoke_contract( - &addr, - &Parameter(&[]), - entrypoint.as_entrypoint_name(), - sender_balance, - )?; - } - }; - - // Reset the sender's balance to zero. - // This code is reached only after transfering CCD back/calling an - // external contract. - if let Some(mut v) = host.state().balances.get_mut(&sender) { - *v = Amount::zero(); - } - - Ok(()) - } - -The problem in the code above is that resetting the sender's balance to zero happens *after* the call to an external contract is completed. -The sender's balance in the *contract state* is used to determine how much funds should be transferred to the sender. -Since it is not updated, the external contract can make a call back to ``withdraw_reentrancy`` and pass the balance validation. -Testing this behavior with mocks require some insights. -In particular, the example below mimics the original ``withdraw_reentrancy`` code in the mock entrypoint. - -.. code-block:: rust - - #[concordium_test] - fn test_withdraw_reentrancy() { - ... - - // Assume that `CONTRACT_ADDRESS` has 1 micro CCD - // Set the contract balance to 2 micro CCD - host.set_self_balance(Amount::from_micro_ccd(2)); - - // Set up a mock entrypoint that calls back to our contract. - // The mock emulates the `withdraw_reentrancy` logic to model - // a reentrancy attack that will withdraw the sender's balance twice. - host.setup_mock_entrypoint( - CONTRACT_ADDRESS, - OwnedEntrypointName::new_unchecked("withdraw_reentrancy".to_string()), - MockFn::new_v1(|_parameter, _amount, balance, state: &mut State<_>| { - // `invoke_contract` cannot be called inside this mock, but - // `balance` gives access to the balance of the contract making - // this invocation. The `withdraw_reentrancy` invocation can be - // simulated by subtracting the sender's amount stored in the - // contract state from `balance`. - - let b = state.balances.get_mut(&Address::Contract(CONTRACT_ADDRESS)); - - let mut sender_balance = match b { - Some(bal) if *bal > Amount::zero() => bal, - _ => fail!("Insufficent funds"), - }; - - // Emulate withdraw by subtracting the sender's balance. - *balance -= *sender_balance; - - // Reset the sender's balance to zero. - *sender_balance = Amount::zero(); - - let state_modified = true; - Ok((state_modified, ())) - }), - ); - // Withdraw 1 micro CCD - withdraw_reentrancy(&ctx, &mut host).expect_report("Withdraw call failed"); - - let resulting_balance = host.self_balance(); - let expected_balance = 1; - - claim_eq!( - resulting_balance, - expected_balance, - "Balance is not updated correctly: expected {:?}, found: {:?}", - expected_balance, - resulting_balance - ); - } - -The test fails with the following message: - -.. code-block:: text - - Incorrect balance: expected Amount { micro_ccd: 1 }, found: Amount { micro_ccd: 0 } - -That means that the contract called has stolen funds through a reentrant call. -A simple fix to this behavior is to place the highlighted line in ``withdraw_reentrancy`` *before* making a call to an external contract. -In this case, the ``withdraw_reentrancy`` call will fail because the non-zero balance condition is no longer satisfied in the mock entrypoint. - -Testing with state rollbacks -============================ - -Invocations of smart contracts on the chain are transactional. This means that -if a contract changes its state and then fails, the state is rolled back to how -it was before the invocation. - -If you want the same behavior when testing, it is necessary to use a helper -method on the |TestHost|_, namely |with_rollback|_. -To illustrate, here is an example in which the receive function increments the -state and then immediately fails: - -.. code-block:: rust - :emphasize-lines: 23, 25, 35, 37 - - type State = u8; - - #[receive(contract = "my_contract", name = "increment", mutable)] - fn receive( - _ctx: &impl HasReceiveContext, - host: &mut impl HasHost, - ) -> ReceiveResult<()> { - *host.state_mut() += 1; // Mutate state. - Err(Reject::default()) // Then fail. - } - - #[concordium_cfg_test] - mod tests { - use super::*; - use concordium_std::test_infrastructure::*; - - #[test] - fn test_without_rollback() { - let state = 0; - let ctx = TestReceiveContext::empty(); - let mut host = TestHost::new(state, StateBuilder::new()); - - let _ = receive(&ctx, &mut host); - - claim_eq!(*host.state(), 0); // FAILS! State wasn't rolled back. - } - - #[test] - fn test_with_rollback() { - let state = 0; - let ctx = TestReceiveContext::empty(); - let mut host = TestHost::new(state, StateBuilder::new()); - - // Use the `with_rollback` method. - let _ = host.with_rollback(|host| receive(&ctx, host)); - - claim_eq!(*host.state(), 0); // Success! - } - } - -|with_rollback|_ works by creating a clone of the ``State``, invoking the -receive function and, if it failed, rolling back the state. -This means that ``State`` must implement the trait |StateClone|_, which -fortunately is implemented for all |Clone|_ types. -However, it is not possible to implement |Clone|_ correctly for your state if it -includes one of the special state types. - -This is how to handle the two scenarios: - -- Derive |StateClone|_ for your state (see example below) if it has one or more fields comprised - of |StateBox|_, |StateSet|_, or |StateMap|_. -- Otherwise, derive |Clone|_ for your ``State``. - -Here is an example of how to derive |StateClone|_: - -.. code-block:: rust - - #[derive(StateClone)] - #[concordium(state_parameter = "S")] - struct State { - my_state_map: StateMap, - } - -You can read more about deriving |StateClone|_ on `docs.rs `_. - -.. note:: - - The state also needs to be rolled back on errors occuring in mock - entrypoints as described in - :ref:`testing_contract_invocations`, but that is handled by the test - framework itself. This means that mock entrypoints are handled - transactionally, even without the use of |with_rollback|_. - -Testing transfers -================= - -|TestHost|_ has three helper methods that are useful when testing that the correct ``invoke_transfer`` s have occurred. - -Use ``transfer_occurred`` to check for specific transfers: - -.. code-block:: rust - :emphasize-lines: 8 - - // Contract code + general test setup - - #[test] - fn test_transfer() { - ... - let receiver = AccountAddress([0;32]); - let amount = Amount::from_ccd(10); - claim!(host.transfer_occurred(&receiver, amount)); - } - -Use ``get_transfers`` to get a sorted list of all transfers that occurred: - -.. code-block:: rust - :emphasize-lines: 4 - - let receiver0 = AccountAddress([0;32]); - let receiver1 = AccountAddress([1;32]); - let amount = Amount::from_ccd(10); - claim_eq!(host.get_transfers(), [(receiver0, amount), (receiver1, amount)]); - -Use ``get_transfers_to`` to get a sorted list of all transfers to a specific -account: - -.. code-block:: rust - :emphasize-lines: 4 - - let receiver0 = AccountAddress([0;32]); - let amount0 = Amount::from_ccd(10); - let amount1 = Amount::from_ccd(20); - claim_eq!(host.get_transfers_to(receiver0), [amount0, amount1]); - -.. _writing_property_based_tests: - -Writing property-based tests -============================ - -The property-based testing technique allows for testing statements about your code that are expected to be true for any input parameters, possibly satisfying some precondition. -You can think of a precondition and a property as functions returning a boolean. -That is, for a function ``fun``, a property looks as the following: "for any input ``x``, ``y``, ``z``, such that ``precondition(x, y, z) = true``, ``property(x, y, z, fun(x,y,z)) = true``". -The input to such tests is generated randomly. -An example of a property is "for any integers ``n`` and ``m``, such that ``even(n) = true`` and ``even(m) = true``, ``even(n + m) = true``". - -Property-based testing is supported using the |QuickCheck|_ crate. -The tests should be placed in the same module as regular unit tests and annotated with the ``#[concordium_quickcheck]`` macro. -The return value of the function should be a boolean corresponding to whether the property holds. - -To get started, add the ``concordium-quickcheck`` feature to ``concordium-std`` as a ``dev``-dependency in ``Cargo.toml``: - -.. code-block:: - - ... - - [dev-dependencies] - concordium-std = { version = "5.1", features = ["concordium-quickcheck"] } - - ... - -The ``concordium_quickcheck`` macro takes the ``num_tests`` attribute for specifying the number of random tests to run. -In the code snippet below, the parameters ``address`` and ``amount`` are generated randomly. -The process of generating random input and running the test is repeated 500 times because you set ``num_tests = 500``. -If you omit the ``num_tests`` attribute, it defaults to a 100 tests. - -.. code-block:: rust - - #[concordium_cfg_test] - mod test { - - #[concordium_quickcheck(num_tests = 500)] - fn some_property_test(address: Address, amount: Amount) -> bool { - ... - // Instantiate custom struct with random parameters, if necessary. - let input = MyParameters { sender: address, payment: amount } - ... - } - } - -The types ``Address`` and ``Amount`` in the example have ``Arbitrary`` trait implementations, which are used to obtain random values. -Read more about available ``Arbitrary`` instances for Concordium-specific types in |concordium_contracts_common|_ documentation. -|QuickCheck|_ defines ``Arbitrary`` instances for standard data types, like numbers and collections (``Vec``, ``BTreeMap``, etc.). -These instances are available by default when writing tests. -Custom user data type instances, like ``MyParameters`` above, can be created directly in tests using the random input parameters or by defining ``Arbitrary`` instances. -See more details on QuickCheck's ``Arbitrary`` `here `_. - -.. warning:: - - The fact that many random tests passed successfully does not automatically mean that the property holds for **all** inputs. - Often the input space is quite large to be covered fully. - In this case, it is important to think carefully about what an implementation of the ``Arbitrary`` trait is doing to generate random input for your specific data. - In order to cover corner cases, you can bias the generated data to produce values that are deemed as potentially problematic. - - - -The same command is used for running Wasm QuickCheck tests as in :ref:`tests_in_wasm`: - -.. code-block:: console - - $ cargo concordium test - -When a test fails, it reports the random seed used to produce the input values. -The random numbers are generated using a deterministic pseudo-random number generator from this seed. -After making the required fixes to the code, you can use the same seed to see whether the previously failed tests work on the same generated values. -The seed is a ``u64`` number, which can be provided along with the test command: - -.. code-block:: console - - $ cargo concordium test --seed 1234567890 - -Concordium QuickCheck tests can also be run with: - -.. code-block:: console - - $ cargo test - -By default, this command compiles the contract, unit tests, and QuickCheck tests to machine code for your local target (most likely x86_64) and runs them. - -.. note:: - - Printing and supplying a seed is only possible using ``cargo concordium test``. - -.. warning:: - - Avoid using ``fail!`` and ``claim!`` variants in ``#[concordium_quickcheck]`` tests. - In Wasm unit tests (see :ref:`tests_in_wasm`) these commands report an error. - However, using them in QuickCheck tests makes the tests fail without providing a counterexample when running with ``cargo concordium test``. - Also avoid using ``assert_eq!``, ``panic!``, or any other command that panics. - Return a boolean value instead. - -Example -------- - -Consider a counter with a threshold: if the count is less than the threshold, it gets incremented; otherwise, it stays unchanged. - -.. code-block:: rust - :emphasize-lines: 19-22 - - use concordium_std::*; - - #[derive(Serialize)] - struct State { - threshold: u16, - count: u16, - } - - impl State { - fn new(threshold: u16) -> Self { - State { - count: 0, - threshold, - } - } - - // Increment only if the current count is below the threshold. - fn increment(&mut self) { - // Can you see a problem here? - if self.count <= self.threshold { - self.count += 1; - } - } - } - - #[init(contract = "my_contract")] - fn contract_init( - ctx: &impl HasInitContext, - state_builder: &mut StateBuilder, - ) -> InitResult { ... } - - #[receive(contract = "my_contract", name = "my_receive", mutable)] - fn contract_update_counter( - _ctx: &impl HasReceiveContext, - host: &mut impl HasHost, - ) -> ReceiveResult<()> { ... } - - #[concordium_cfg_test] - mod test { - use super::*; - - // Property: counter stays below the threshold for any number of calls `n`. - // Run 500 tests with random `n` and `threshold` values. - #[concordium_quickcheck(num_tests = 500)] - fn prop_counter_always_below_threshold(threshold: u16, n: u16) -> bool { - let mut state = State::new(threshold); - for _ in 0..n { - state.increment() - } - state.count <= threshold - } - } - -The test fails with a counterexample, i.e., an input that breaks the property: - -.. code-block:: - - TestResult { - status: Fail, - arguments: [ - "0", - "1", - ], - err: None, - } - -The ``arguments`` part shows the values that caused the test to fail. -In this case, if the threshold is ``0`` and the number of calls is ``1``, then the counter becomes ``1`` after calling ``state.increment()``, breaking the property. - -.. note:: - - |QuickCheck|_ implements a special mechanism called "shrinking" to find the simplest counterexample. - For the example above, ``0`` and ``1`` is the simplest input on which the test failed. - -The issue is the comparison operator. -It should be ``<`` instead of ``<=``. -If you change the highlighted lines in the code above to: - -.. code-block:: rust - - if self.count < self.threshold { - self.count += 1; - } - -then all ``500`` tests pass successfully. - - -.. |test_infrastructure| replace:: ``test_infrastructure`` -.. _test_infrastructure: https://docs.rs/concordium-std/latest/concordium_std/test_infrastructure -.. |concordium_std| replace:: ``concordium_std`` -.. _concordium_std: https://docs.rs/concordium-std/latest/concordium_std -.. |concordium_contracts_common| replace:: ``concordium_contracts_common`` -.. _concordium_contracts_common: https://docs.rs/concordium-contracts-common/latest/concordium_contracts_common -.. _TestHost: https://docs.rs/concordium-std/latest/concordium_std/test_infrastructure/struct.TestHost.html -.. |TestHost| replace:: ``TestHost`` -.. _setup_mock_entrypoint: https://docs.rs/concordium-std/latest/concordium_std/test_infrastructure/struct.TestHost.html#method.setup_mock_entrypoint -.. |setup_mock_entrypoint| replace:: ``setup_mock_entrypoint`` -.. _with_rollback: https://docs.rs/concordium-std/latest/concordium_std/test_infrastructure/struct.TestHost.html#method.with_rollback -.. |with_rollback| replace:: ``with_rollback`` -.. _Clone: https://doc.rust-lang.org/std/clone/trait.Clone.html -.. |Clone| replace:: ``Clone`` -.. _StateClone: https://docs.rs/concordium-std/latest/concordium_std/trait.StateClone.html -.. |StateClone| replace:: ``StateClone`` -.. _StateBox: https://docs.rs/concordium-std/latest/concordium_std/struct.StateBox.html -.. |StateBox| replace:: ``StateBox`` -.. _StateMap: https://docs.rs/concordium-std/latest/concordium_std/struct.StateMap.html -.. |StateMap| replace:: ``StateMap`` -.. _StateSet: https://docs.rs/concordium-std/latest/concordium_std/struct.StateSet.html -.. |StateSet| replace:: ``StateSet`` -.. |QuickCheck| replace:: ``QuickCheck`` -.. _QuickCheck: https://docs.rs/quickcheck/latest/quickcheck -.. _concordium-smart-contract-testing: https://docs.rs/concordium-std-derive/latest/concordium_smart-contract-testing -.. |concordium-smart-contract-testing| replace:: ``concordium-smart-contract-testing`` From f0132fb990996e04692192fa05fc441d1e8066f4 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 16:28:52 +0200 Subject: [PATCH 11/14] Modify documentation for wasm32v1-none target --- source/mainnet/how-to/index.rst | 2 - .../integration-test-contract.rst | 7 +- .../smart-contracts/migrate-contracts.rst | 168 ------------------ 3 files changed, 1 insertion(+), 176 deletions(-) delete mode 100644 source/mainnet/how-to/smart-contracts/migrate-contracts.rst diff --git a/source/mainnet/how-to/index.rst b/source/mainnet/how-to/index.rst index 5be222c8ed..8b2738d71a 100644 --- a/source/mainnet/how-to/index.rst +++ b/source/mainnet/how-to/index.rst @@ -101,7 +101,6 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid - :doc:`Inspect ` - :doc:`Invoke ` - - :doc:`Migrate contracts ` - :doc:`Best practices ` - :doc:`Development ` @@ -172,7 +171,6 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid Implement the factory pattern Integration test a contract Deploy a smart contract module - Migrate contracts Best practices .. toctree:: diff --git a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst index f3d15aa071..795e5c6d37 100644 --- a/source/mainnet/how-to/smart-contracts/integration-test-contract.rst +++ b/source/mainnet/how-to/smart-contracts/integration-test-contract.rst @@ -10,13 +10,8 @@ Integration tests This guide describes how to write *integration tests* in Rust for your smart contracts using the `Concordium smart contract testing library `_. -.. note:: - - Unit testing your contracts with the ``test_infrastructure`` has been deprecated in favor of what is described on the present page. - To migrate your contracts and tests see :ref:`migrate-contracts-for-std-8.1`. - The library allows you to test individual contracts in isolation, but, notably, also interactions between multiple contracts. -When running the tests, they are executed locally on the exact contract code that is deployed on the chain, and using the same execution engine that the nodes use. +When running the tests, they are executed locally on the exact contract code that is deployed on the chain, and using the same execution engine that the nodes use. Only the chain itself is stubbed. V0 smart contracts are not supported, but all V1 smart contract features are, including upgrades, and it is also possible to see the energy usage of your contracts. This allows you to refactor and optimize your contracts for speed and efficiency with greater ease and confidence. diff --git a/source/mainnet/how-to/smart-contracts/migrate-contracts.rst b/source/mainnet/how-to/smart-contracts/migrate-contracts.rst deleted file mode 100644 index dd6ab78e73..0000000000 --- a/source/mainnet/how-to/smart-contracts/migrate-contracts.rst +++ /dev/null @@ -1,168 +0,0 @@ -.. _migrate-contracts-for-std-8.1: - -============================================== -Migrate contracts for ``concordium-std`` 8.1 -============================================== - -.. admonition:: At a glance - - This guide shows you how to migrate your existing smart contracts to use the simplified concrete types introduced in ``concordium-std`` 8.1. You will need an existing smart contract that uses the deprecated ``test_infrastructure`` approach. After following this guide, your contract will use fewer generics and be compatible with the ``concordium-smart-contract-testing`` integration test library. - -With the |concordium_std|_ version ``8.1`` release, writing and reading smart contracts is easier than ever before. -The new version of the standard library reduces the need for generics and traits in your init and receive methods. -These generics and traits were there to support testing with the |test_infrastructure|_, which has been deprecated in favor of the |concordium-smart-contract-testing|_ library. - -This guide shows you how to migrate your contract code to use the simpler concrete types and use fewer generics. - -.. note:: - - You should only migrate your contract code if you are also ready to migrate all your tests, that invoke init or receive methods directly, to use the |concordium-smart-contract-testing|_ library. - -Migrating ``init`` methods -========================== - -To migrate a typical ``init`` method you must change the following: - -- Remove the generic parameter ```` on the init method -- Replace the trait ``&impl HasInitContext`` with the concrete type ``&InitContext`` -- Remove the generic parameter ```` on the ``StateBuilder`` - -Here is an example: - -.. code-block:: rust - :emphasize-lines: 10-12 - - /// Before - #[init(contract = "contract_before")] - fn init_before( - ctx: &impl HasInitContext, - state_builder: &mut StateBuilder, - ) -> InitResult { todo!() } - - /// After - #[init(contract = "contract_after")] - fn init_after( // `` removed - ctx: &InitContext, // `impl` and `Has` removed - state_builder: &mut StateBuilder, // `` removed - ) -> InitResult { todo!() } - - -Migrating ``receive`` methods -============================= - -To migrate a typical ``receive`` method you must change the following: - -- Remove the generic parameter ```` on the receive method -- Replace the trait ``&impl HasReceiveContext`` with the concrete type ``&ReceiveContext`` -- Replace the trait ``&impl HasHost<..>`` with the concrete type ``&Host`` -- Remove the generic parameter ``StateApiType = S`` on the ``Host`` - -Here is an example: - -.. code-block:: rust - :emphasize-lines: 10-12 - - /// Before - #[receive(contract = "my_contract", name = "my_receive")] - fn receive_before( - ctx: &impl HasReceiveContext, - host: &impl HasHost, - ) -> ReceiveResult { todo!() } - - /// After - #[receive(contract = "my_contract", name = "my_receive")] - fn receive_after( // `` removed - ctx: &ReceiveContext, // `impl` and `Has` removed - host: &Host, // `impl Has` and `, StateApiType = S removed - ) -> ReceiveResult { todo!() } - -Migrating advanced state types -============================== - -If your contract state directly, or indirectly, contains one or more advanced state types, i.e., |StateMap|_, |StateSet|_, or |StateBox|_, then you also need to make a small adjustment. -The advanced state types are generic over not only the types stored, such as the keys and values in a map but also over a type that implements the |HasStateApi|_ trait. -This is because the deprecated |test_infrastructure|_ used a different implementation of the underlying contract state, i.e., a different implementation of |HasStateApi|_, than the Concordium nodes do. -But |concordium-smart-contract-testing|_ uses the exact same state implementation as the nodes do and it is therefore possible to specify the concrete type, |StateApi|_, as the default. - -Until the |test_infrastructure|_ module is completely removed, the libraries will still support it, and thus the generic parameter ``S`` must still be present. - -To migrate an advanced state type you must change the following: - -- Set ``StateApi`` as the default type for the generic parameters that must implement |HasStateApi|_ (typically named ``S``) -- Remove the generic type parameter for the |HasStateApi|_ type where you use your state type, e.g., ``MyState`` instead of ``MyState`` - -Here is an example of the change you must make: - -.. code-block:: rust - :emphasize-lines: 15, 23 - - /// Before - struct MyState { - my_map: StateMap, - } - - #[init(contract = "contract_before")] - fn init_before( - ctx: &impl HasInitContext, - state_builder: &mut StateBuilder, - ) -> InitResult> { - Ok(MyState{ my_map: state_builder.new_map() }) - } - - /// After - struct MyState { - my_map: StateMap, - } - - #[init(contract = "contract_before")] - fn init_before( - ctx: &InitContext, - state_builder: &mut StateBuilder, - ) -> InitResult { - Ok(MyState{ my_map: state_builder.new_map() }) - } - -Reference material for migrating types and tests -================================================ - -The examples above show how to migrate most contracts, but for advanced contracts, there may be more types to migrate. -The list below shows how to achieve that. -It also includes types already described above: - -- ``&impl HasInitContext`` becomes ``&InitContext`` -- ``&impl HasReceiveContext`` becomes ``&ReceiveContext`` -- ``&mut StateBuilder`` becomes ``&mut StateBuilder`` -- ``&impl HasHost`` becomes ``&Host`` -- ``&mut impl HasHost`` becomes ``&mut Host`` -- When using the ``low_level`` attribute: - - - On inits: ``&mut impl HasStateApi`` becomes ``&mut StateApi`` - - On receives: ``&mut impl Host`` becomes ``&mut LowLevelHost`` - -- ``struct MyState { my_map: StateMap<_,_, S> }`` becomes ``struct MyState { my_map: StateMap<_, _, S> }`` -- ``&impl HasCryptoPrimitives`` becomes ``&CryptoPrimitives`` -- ``&impl HasChainMetadata`` becomes ``&ChainMetadata`` -- ``&mut impl HasLogger`` becomes ``&mut Logger`` - -To migrate your tests, read the how-to guide :ref:`integration-test-contract`. -You can also refer to the `pull request `_, where our example contracts were rewritten. -This shows both the removal of generics and how to migrate tests from using |test_infrastructure|_ to |concordium-smart-contract-testing|_. - -.. |concordium_std| replace:: ``concordium_std`` -.. _concordium_std: https://docs.rs/concordium-std/latest/concordium_std -.. |test_infrastructure| replace:: ``test_infrastructure`` -.. _test_infrastructure: https://docs.rs/concordium-std/8.1/concordium_std/test_infrastructure -.. _concordium-smart-contract-testing: https://docs.rs/concordium-std-derive/latest/concordium_smart-contract-testing -.. |concordium-smart-contract-testing| replace:: ``concordium-smart-contract-testing`` -.. _StateBox: https://docs.rs/concordium-std/latest/concordium_std/struct.StateBox.html -.. |StateBox| replace:: ``StateBox`` -.. _StateMap: https://docs.rs/concordium-std/latest/concordium_std/struct.StateMap.html -.. |StateMap| replace:: ``StateMap`` -.. _StateSet: https://docs.rs/concordium-std/latest/concordium_std/struct.StateSet.html -.. |StateSet| replace:: ``StateSet`` -.. _HasStateApi: https://docs.rs/concordium-std/8.0.0/concordium_std/trait.HasStateApi.html -.. |HasStateApi| replace:: ``HasStateApi`` -.. _StateApi: https://docs.rs/concordium-std/latest/concordium_std/type.StateApi.html -.. |StateApi| replace:: ``StateApi`` -.. _HasLogger: https://docs.rs/concordium-std/8.0.0/concordium_std/trait.HasLogger.html -.. |HasLogger| replace:: ``HasLogger`` From f9abf40e8d8b8db27c8a292bce04501f909f71a9 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Wed, 7 Oct 2026 16:32:55 +0200 Subject: [PATCH 12/14] Modify documentation for wasm32v1-none target --- .../how-to/smart-contracts/best-practices/development.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/mainnet/how-to/smart-contracts/best-practices/development.rst b/source/mainnet/how-to/smart-contracts/best-practices/development.rst index 0eda351706..ef7d42c0fb 100644 --- a/source/mainnet/how-to/smart-contracts/best-practices/development.rst +++ b/source/mainnet/how-to/smart-contracts/best-practices/development.rst @@ -321,11 +321,11 @@ Integration tests allows you to test the contract in an environment where: - The smart contract runs in the real Wasm interpreter - The smart contract interacts with the real host functions and real chain integration -- The chain itself is stubbed, as the only component that is not "real" +- Only the chain itself is stubbed, as the only component that is not "real" -Besides from those tests, you can also implement plain Rust unit tests for functions that does not interact with host functions. +Besides from integration tests, you can also implement plain Rust unit tests for functions that does not interact with the host. A third, and more advanced, possibility is using the `concordium_test macro `_. -Examples may be found in `concordium-std tests `_. +Examples of this may be found in `concordium-std tests `_. Use the :ref:`smart contract specification ` guidelines from this document to come up with cases and properties to test. From 7716574009ac7c1302f166f3c5c4f73e062db9c2 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Fri, 9 Oct 2026 14:17:45 +0200 Subject: [PATCH 13/14] Wasm32v1 release --- source/mainnet/downloads.rst | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/mainnet/downloads.rst b/source/mainnet/downloads.rst index 45b5020649..cb8a6cd651 100644 --- a/source/mainnet/downloads.rst +++ b/source/mainnet/downloads.rst @@ -190,17 +190,6 @@ cargo-concordium For information about installing ``cargo-concordium``, see :ref:`Install tools for development `. -.. Note:: - - From version 2.8.0 the distribution for ``cargo-concordium`` has been simplified. Now, once you have installed rustup, you can quickly and easily install ``cargo-concordium`` without downloading a separate package or going through many steps. If you already have ``cargo-concordium`` installed, you may need to remove the existing ``cargo-concordium`` from your PATH to be able to update versions in the future. - -VSCode extension ----------------- - -You can `install the VSCode extension `__ for smart contract development from the VSCode marketplace. - -For information about using the VSCode extension, `watch the video `_. - Smart contract deploy and initialize tool ========================================= From 9cfad637ee6162c75f4251f4f13003e58ca3e0b8 Mon Sep 17 00:00:00 2001 From: Allan Rasmussen Date: Fri, 16 Oct 2026 14:12:37 +0200 Subject: [PATCH 14/14] Modify documentation for wasm32v1-none target --- source/mainnet/how-to/index.rst | 2 +- .../how-to/smart-contracts/compile-module.rst | 2 +- .../learn/smart-contracts/develop-contracts.rst | 2 +- .../tutorials/counter/counter-contract.rst | 2 +- .../tutorials/images/mint-wasm-install.png | Bin 27341 -> 0 bytes source/mainnet/tutorials/quick-start.rst | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 source/mainnet/tutorials/images/mint-wasm-install.png diff --git a/source/mainnet/how-to/index.rst b/source/mainnet/how-to/index.rst index 8b2738d71a..215c509cc5 100644 --- a/source/mainnet/how-to/index.rst +++ b/source/mainnet/how-to/index.rst @@ -166,7 +166,7 @@ Step-by-step guides for completing specific tasks on Concordium. Browse all guid Build a contract schema Use custom errors Pass JSON parameters - Use fallback entrypoints + Use fallback entrypoints Write an upgradeable contract Implement the factory pattern Integration test a contract diff --git a/source/mainnet/how-to/smart-contracts/compile-module.rst b/source/mainnet/how-to/smart-contracts/compile-module.rst index a9b4b3f71a..7d063fa8c1 100644 --- a/source/mainnet/how-to/smart-contracts/compile-module.rst +++ b/source/mainnet/how-to/smart-contracts/compile-module.rst @@ -96,6 +96,6 @@ Verifiable builds require a container runtime such as `Docker `_. -To further optmize the build, you may consider using the ``bump_alloc`` allocator for your smart contract. See `concordium_std features`_. +To further optimize the build, you may consider using the ``bump_alloc`` allocator for your smart contract. See `concordium_std features`_. .. _concordium_std features: https://docs.rs/concordium-std/latest/concordium_std/#features \ No newline at end of file diff --git a/source/mainnet/learn/smart-contracts/develop-contracts.rst b/source/mainnet/learn/smart-contracts/develop-contracts.rst index d045a89bfc..232a32318e 100644 --- a/source/mainnet/learn/smart-contracts/develop-contracts.rst +++ b/source/mainnet/learn/smart-contracts/develop-contracts.rst @@ -57,7 +57,7 @@ Write a smart contract using ``concordium_std`` It is highly recommended to use the ``concordium_std`` Rust crate, which provides a more standard Rust-like experience for developing smart contract modules and calling -host functions. When using ``concordium_std``, you smart contract should be compiled +host functions. When using ``concordium_std``, your smart contract should be compiled to the ``no_std`` target wasm32v1-none_. The crate enables writing init and receive functions as simple Rust diff --git a/source/mainnet/tutorials/counter/counter-contract.rst b/source/mainnet/tutorials/counter/counter-contract.rst index 51eb53f2c4..a37cc00775 100644 --- a/source/mainnet/tutorials/counter/counter-contract.rst +++ b/source/mainnet/tutorials/counter/counter-contract.rst @@ -158,7 +158,7 @@ Finally, let's initialize a contract instance, so you are ready to invoke the co Or, use this command to use the Concordium testnet node: .. code-block:: console - + $ concordium-client contract init \ --sender \ --energy 30000 \ diff --git a/source/mainnet/tutorials/images/mint-wasm-install.png b/source/mainnet/tutorials/images/mint-wasm-install.png deleted file mode 100644 index dcef9243fa8e027fde1e8b1fa4ffed429c4455bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27341 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