diff --git a/docs/tutorial/platform/05-first-contract.md b/docs/tutorial/platform/05-first-contract.md
index 5eb1465..cf7a9f2 100644
--- a/docs/tutorial/platform/05-first-contract.md
+++ b/docs/tutorial/platform/05-first-contract.md
@@ -3,15 +3,18 @@ title: First contract
description: Write your first smart contract
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
# First contract
In the hello world, you used an already-made smart contract that implements a name service. It is a [rudimentary one](https://github.com/deus-labs/cw-contracts/blob/v0.11.0/contracts/nameservice/src/contract.rs). This somewhat longer-running exercise intends to build progressively a better nameservice, which could be [this one](https://github.com/public-awesome/names/blob/v1.2.8/contracts/name-minter/src/contract.rs), from the ground up.
-
+:::info Exercise progression
In practice, you will progressively build [this name service](https://github.com/b9lab/cw-my-nameservice). The exercise is built such that you can skip ahead by switching to the appropriate [branch](https://github.com/b9lab/cw-my-nameservice/branches) as mentioned at the top of the page of each exercise section.
-
+:::
It offers two tracks, one local and the other with Docker, so that you can postpone installing the prerequisites.
@@ -21,88 +24,87 @@ It was built with Rust 1.80.1 for CosmWasm 2.1.3. It may work with other version
Most likely, you will start your CosmWasm project as a Rust project. Use `cargo` to initialize a new one.
-
-
- ```sh
+
+
+ ```shell
cargo new my-nameservice --lib --edition 2021
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm --interactive --tty \
--volume $(pwd):/root/ --workdir /root \
rust:1.80.1 \
cargo new my-nameservice --lib --edition 2021
```
-
-
+
+
Move into the project directory.
-```sh
+```shell
cd my-nameservice
```
-
+:::info Exercise progression
At this stage, you should have something similar to the [`initial-cargo`](https://github.com/b9lab/cw-my-nameservice/tree/initial-cargo) branch.
-
+:::
-If you are using VisualStudio Code, feel free to copy the `.vscode` content you see [here]((https://github.com/b9lab/cw-my-nameservice/tree/initial-cargo).
+If you are using Visual Studio Code, feel free to copy the `.vscode` content you see [here]((https://github.com/b9lab/cw-my-nameservice/tree/initial-cargo).
## The instantiation message
With the base project ready, you can move to your first message. Your smart contract will be instantiated, and the `instantiate` function needs a message. Create it in a new `src/msg.rs` file:
-
-```rust
+```rust title="src/msg.rs"
use cosmwasm_schema::cw_serde;
#[cw_serde]
pub struct InstantiateMsg {}
```
-
You use the attribute macro [`cw_serde`](https://docs.cosmwasm.com/core/entrypoints#defining-your-own-messages) in order to make your for-now-empty _instantiate_ message serializable. Make its content available to the Rust project by replacing the sample code in `src/lib.rs` with:
-
- ```diff-rs
- + pub mod msg;
- - pub fn add(left: u64, right: u64) -> u64 {
- - left + right
- - }
- -
- - #[cfg(test)]
- - mod tests {
- - ...
- - }
- ```
-
+```rust title="src/lib.rs"
+//with-coverage
++ pub mod msg;
+//no-coverage-start
+- pub fn add(left: u64, right: u64) -> u64 {
+- left + right
+- }
+-
+- #[cfg(test)]
+- mod tests {
+- ...
+- }
+//no-coverage-end
+```
Note that it says `pub` as the message needs to be known outside of the project, including tests.
Back in `src/msg.rs` you will notice that `cosmwasm_schema` now appears as an `unresolved import`. You see the same message if you try to build:
-
-
- ```sh
+
+
+ ```shell
cargo build
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root/ -w /root \
rust:1.80.1 \
cargo build
```
-
-
+
+
Returns:
-```txt
+```text
error[E0432]: unresolved import `cosmwasm_schema`
--> src/msg.rs:1:5
|
@@ -112,27 +114,28 @@ error[E0432]: unresolved import `cosmwasm_schema`
Indeed, you need to add the relevant dependency:
-
-
- ```sh
+
+
+ ```shell
cargo add cosmwasm-schema@2.1.3
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root/ -w /root \
rust:1.80.1 \
cargo add cosmwasm-schema@2.1.3
```
-
-
+
+
-
+:::info Exercise progression
-At this stage, you should have something similar to the [`instantiation-message`](https://github.com/b9lab/cw-my-nameservice/tree/instantiation-message) branch, with [this](https://github.com/b9lab/cw-my-nameservice/compare/initial-cargo..instantiation-message) as the diff.
+At this stage, you should have something similar to the [`instantiation-message`](https://github.com/b9lab/cw-my-nameservice/tree/instantiation-message) branch,
+with [this](https://github.com/b9lab/cw-my-nameservice/compare/initial-cargo..instantiation-message) as the diff.
-
+:::
## The instantiation function
@@ -140,22 +143,20 @@ With the message declared, you can move on to the function that will instantiate
Create a new file `src/contract.rs` with:
-
- ```rust
- use crate::msg::InstantiateMsg;
- use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, StdError};
-
- #[cfg_attr(not(feature = "library"), entry_point)]
- pub fn instantiate(
- _: DepsMut,
- _: Env,
- _: MessageInfo,
- _: InstantiateMsg,
- ) -> Result {
- Ok(Response::default())
- }
- ```
-
+```rust title="src/contract.rs"
+use crate::msg::InstantiateMsg;
+use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, StdError};
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn instantiate(
+ _: DepsMut,
+ _: Env,
+ _: MessageInfo,
+ _: InstantiateMsg,
+) -> Result {
+ Ok(Response::default())
+}
+```
Note how:
@@ -169,242 +170,241 @@ Note how:
Also make it available to the Rust project by adding the following line to `src/lib.rs`:
-
- ```diff-rs
- + pub mod contract;
- pub mod msg;
- ```
-
+```rust title="src/lib.rs"
+//with-coverage
++ pub mod contract;
+pub mod msg;
+```
The module is also marked as public because the CosmWasm system needs to be able to call its function(s).
Once again, there is a missing dependency: `cosmwasm_std`. Add it:
-
-
- ```sh
+
+
+ ```shell
cargo add cosmwasm-std@2.1.3
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root/ -w /root \
rust:1.80.1 \
cargo add cosmwasm-std@2.1.3
```
-
-
+
+
-
+:::info Exercise progression
At this stage, you should have something similar to the [`instantiation-function`](https://github.com/b9lab/cw-my-nameservice/tree/instantiation-function) branch, with [this](https://github.com/b9lab/cw-my-nameservice/compare/instantiation-message..instantiation-function) as the diff.
-
+:::
## Improve error reporting
With a view to improving error reporting as you progress, you introduce your own error type. In a new `src/error.rs`, add:
-
- ```rust
- use cosmwasm_std::StdError;
- use thiserror::Error;
+```rust title="src/error.rs"
+use cosmwasm_std::StdError;
+use thiserror::Error;
- #[derive(Error, Debug)]
- pub enum ContractError {
- #[error("{0}")]
- Std(#[from] StdError),
- }
- ```
-
+#[derive(Error, Debug)]
+pub enum ContractError {
+ #[error("{0}")]
+ Std(#[from] StdError),
+}
+```
-Note that it uses the popular [thiserror package](https://docs.rs/thiserror/latest/thiserror). Again, add the following line to `src/lib.rs`.
+Note that it uses the popular [thiserror package](https://docs.rs/thiserror/latest/thiserror).
+Again, add the following line to `src/lib.rs`.
-
- ```diff-rs
- pub mod contract;
- + mod error;
- pub mod msg;
- ```
-
+```rust title="src/lib.rs"
+pub mod contract;
+//with-coverage
++ mod error;
+pub mod msg;
+```
Note that it is not `pub` as it only needs to be available within the Rust library project.
And don't forget to add the corresponding dependency:
-
-
- ```sh
+
+
+ ```shell
cargo add thiserror@1.0.63
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root/ -w /root \
rust:1.80.1 \
cargo add thiserror@1.0.63
```
-
-
+
+
Now that the new error type has been declared, you can use it in `src/contract.rs`:
-
- ```diff-rs
- - use crate::msg::InstantiateMsg;
- - use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, StdError};
- + use crate::{error::ContractError, msg::InstantiateMsg};
- + use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response};
- +
- + type ContractResult = Result;
-
- #[cfg_attr(not(feature = "library"), entry_point)]
- pub fn instantiate(
- ...
- - ) -> Result {
- + ) -> ContractResult {
- ...
- }
- ```
-
+```diff-rs title="src/contract.rs"
+//no-coverage-start
+- use crate::msg::InstantiateMsg;
+- use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, StdError};
+//no-coverage-end
+//with-coverage-start
++ use crate::{error::ContractError, msg::InstantiateMsg};
++ use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response};
++
++ type ContractResult = Result;
+//with-coverage-end
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn instantiate(
+ ...
+//no-coverage
+- ) -> Result {
+//with-coverage
++ ) -> ContractResult {
+ ...
+}
+```
Note how:
-* It uses the new error type in a new alias type for the oft-used `Result` type.
-* It uses the new type as the return of the `instantiate` function.
+- It uses the new error type in a new alias type for the oft-used `Result` type.
+- It uses the new type as the return of the `instantiate` function.
-
+:::info Exercise progression
At this stage, you should have something similar to the [`improve-error-reporting`](https://github.com/b9lab/cw-my-nameservice/tree/improve-error-reporting) branch, with [this](https://github.com/b9lab/cw-my-nameservice/compare/instantiation-function..improve-error-reporting) as the diff.
-
+:::
## Compilation to WebAssembly
You can already build with the `cargo build` command. How about building to WebAssembly? You need to add the WebAssembly compiling target for that, if it was not yet installed.
-
-
- ```sh
+
+
+ ```shell
rustup target add wasm32-unknown-unknown
```
-
-
+
+
To avoid downloading the `wasm32` target every time, it is good to create a new Docker image that includes it. Create a new file `builder.dockerfile`:
-
- ```Dockerfile
+
+ ```Dockerfile title="builder.dockerfile"
FROM rust:1.80.1
RUN rustup target add wasm32-unknown-unknown
```
-
+
And build the image to be named `rust-cosmwasm:1.80.1`:
- ```sh
+ ```shell
docker build . --file builder.dockerfile --tag rust-cosmwasm:1.80.1
```
-
-
+
+
With the target installed, you can compile to WebAssembly with:
-
-
- ```sh
+
+
+ ```shell
cargo build --release --target wasm32-unknown-unknown
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root -w /root \
rust-cosmwasm:1.80.1 \
cargo build --release --target wasm32-unknown-unknown
```
-
-
+
+
This `cargo build` command is a bit verbose so it pays to create an alias. The right place for that is in `.cargo/config.toml`. Create the folder and the file:
-```sh
+```shell
mkdir .cargo
touch .cargo/config.toml
```
And in it, put:
-
-```toml
+```toml title=".cargo/config.toml"
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
```
-
With this alias defined, you can now use `cargo wasm` instead of writing `cargo build --release --target wasm32-unknown-unknown`. Change your command to:
-
-
- ```sh
+
+
+ ```shell
cargo wasm
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root -w /root \
rust-cosmwasm:1.80.1 \
cargo wasm
```
-
-
+
+
## Compilation to CosmWasm
While you are working on the configuration, you might as well add some elements necessary to compile to a type amenable to the CosmWasm module, along with flags curated by the CosmWasm team. Add the following lines in `Cargo.toml` below the `[package]` section:
-
- ```diff
- [package]
- name = "my-nameservice"
- version = "0.1.0"
- edition = "2021"
-
- + # Linkage options. More information: https://doc.rust-lang.org/reference/linkage.html
- + [lib]
- + crate-type = ["cdylib", "rlib"]
-
- + [features]
- + # Use library feature to disable all instantiate/execute/query exports
- + library = []
-
- + # Optimizations in release builds. More information: https://doc.rust-lang.org/cargo/reference/profiles.html
- + [profile.release]
- + opt-level = "z"
- + debug = false
- + rpath = false
- + lto = true
- + debug-assertions = false
- + codegen-units = 1
- + panic = 'abort'
- + incremental = false
- + overflow-checks = true
-
- [dependencies]
- ...
- ```
-
+```toml title="Cargo.toml"
+[package]
+name = "my-nameservice"
+version = "0.1.0"
+edition = "2021"
+
+//with-coverage-start
++ # Linkage options. More information: https://doc.rust-lang.org/reference/linkage.html
++ [lib]
++ crate-type = ["cdylib", "rlib"]
+
++ [features]
++ # Use library feature to disable all instantiate/execute/query exports
++ library = []
+
++ # Optimizations in release builds. More information: https://doc.rust-lang.org/cargo/reference/profiles.html
++ [profile.release]
++ opt-level = "z"
++ debug = false
++ rpath = false
++ lto = true
++ debug-assertions = false
++ codegen-units = 1
++ panic = 'abort'
++ incremental = false
++ overflow-checks = true
+//with-coverage-end
+
+[dependencies]
+...
+```
You can now build your smart contract, then store and deploy on-chain the generated wasm found in `target/wasm32-unknown-unknown/release/my_nameservice.wasm`. Refer to the hello world for how to do it.
-
+:::info Exercise progression
At this stage, you should have something similar to the [`compilation-elements`](https://github.com/b9lab/cw-my-nameservice/tree/compilation-elements) branch, with [this](https://github.com/b9lab/cw-my-nameservice/compare/improve-error-reporting..compilation-elements) as the diff.
-
+:::
## Unit testing
@@ -412,38 +412,37 @@ You have not written much of a smart contract. However it is still useful to pre
In `src/contract.rs`, add this at the end of the file:
-
- ```rust
- #[cfg(test)]
- mod tests {
- use crate::msg::InstantiateMsg;
- use cosmwasm_std::{testing, Addr, Response};
-
- #[test]
- fn test_instantiate() {
- // Arrange
- let mut mocked_deps_mut = testing::mock_dependencies();
- let mocked_env = testing::mock_env();
- let mocked_addr = Addr::unchecked("addr");
- let mocked_msg_info = testing::message_info(&mocked_addr, &[]);
-
- let instantiate_msg = InstantiateMsg {};
-
- // Act
- let contract_result = super::instantiate(
- mocked_deps_mut.as_mut(),
- mocked_env,
- mocked_msg_info,
- instantiate_msg,
- );
-
- // Assert
- assert!(contract_result.is_ok(), "Failed to instantiate");
- assert_eq!(contract_result.unwrap(), Response::default())
- }
+
+```rust title="src/contract.rs"
+#[cfg(test)]
+mod tests {
+ use crate::msg::InstantiateMsg;
+ use cosmwasm_std::{testing, Addr, Response};
+
+ #[test]
+ fn test_instantiate() {
+ // Arrange
+ let mut mocked_deps_mut = testing::mock_dependencies();
+ let mocked_env = testing::mock_env();
+ let mocked_addr = Addr::unchecked("addr");
+ let mocked_msg_info = testing::message_info(&mocked_addr, &[]);
+
+ let instantiate_msg = InstantiateMsg {};
+
+ // Act
+ let contract_result = super::instantiate(
+ mocked_deps_mut.as_mut(),
+ mocked_env,
+ mocked_msg_info,
+ instantiate_msg,
+ );
+
+ // Assert
+ assert!(contract_result.is_ok(), "Failed to instantiate");
+ assert_eq!(contract_result.unwrap(), Response::default())
}
- ```
-
+}
+```
Note how:
@@ -453,25 +452,25 @@ Note how:
With the test ready, you can run it with the following command:
-
-
- ```sh
+
+
+ ```shell
cargo test
```
-
-
- ```sh
+
+
+ ```shell
docker run --rm -it \
-v $(pwd):/root/ -w /root \
rust:1.80.1 \
cargo test
```
-
-
+
+
Which should print its success in the output:
-```txt
+```text
...
running 1 test
test contract::tests::test_instantiate ... ok
@@ -480,8 +479,9 @@ test contract::tests::test_instantiate ... ok
## Conclusion
-
+:::info Exercise progression
-At this stage, you should have something similar to the [`first-unit-test`](https://github.com/b9lab/cw-my-nameservice/tree/first-unit-test) branch, with [this](https://github.com/b9lab/cw-my-nameservice/compare/compilation-elements..first-unit-test) as the diff.
+At this stage, you should have something similar to the [`first-unit-test`](https://github.com/b9lab/cw-my-nameservice/tree/first-unit-test) branch,
+with [this](https://github.com/b9lab/cw-my-nameservice/compare/compilation-elements..first-unit-test) as the diff.
-
+:::