Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explain the cargo contract new template #131

Merged
merged 1 commit into from
Jan 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 181 additions & 2 deletions versioned_docs/version-4.0.0-alpha.1/basics/contract-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,185 @@ cargo contract build

If everything looks good, then we are ready to start programming!

## What the template contains
## Template Content

TODO
The template contains scaffolded code that provides a starting point
for writing an ink! contract. In the following we'll take a look
at what the files contain.
The files you get locally will look similar, just that we added
explanatory comments here.

### `Cargo.toml`

```toml
[package]
name = "foobar"
version = "0.1.0"
authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
# The `ink` crate contains the ink! eDSL and re-exports
# a number of other ink! specific crates. For example,
# `ink::env` is the `ink_env` crate that contains functions
# to interact with a contract's environment (querying information
# about a caller, the current block number, etc.).
ink = { version = "4.0.0-beta", default-features = false }

# Substrate blockchains use the SCALE codec for anything to
# do with data encoding/decoding. If an ink! contract is called
# the passed values have to be SCALE-encoded and return values
# have to be SCALE-decoded. All values that are put into a
# contract's storage are SCALE-encoded as well.
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }

# This crate is used to write information about a contract's
# types into the contract's metadata (i.e. its ABI). This is
# needed so that a client knows that a contract message requires
# e.g. an Array and that it has to SCALE-encode the value as an Array.
scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
# This developer dependency is for the End-to-End testing framework.
ink_e2e = { path = "../../crates/e2e" }

[lib]
name = "foobar"
path = "lib.rs"

# This setting typically specifices that you'd like the compiler to
# create a dynamic system library. For WebAssembly though it specifies
# that the compiler should create a `*.wasm` without a start function.
crate-type = [
"cdylib",
]

[features]
default = ["std"]
std = [
"ink/std",
"scale/std",
"scale-info/std",
]
ink-as-dependency = []

# This feature is just a convention, so that the end-to-end tests
# are only executed if `cargo test` is explicitly invoked with
# `--features e2e-tests`.
e2e-tests = []
```

### `lib.rs`

Every ink! contract is required to contain:

* Exactly one `#[ink(storage)]` struct.
* At least one `#[ink(constructor)]` function.
* At least one `#[ink(message)]` function.

The scaffolded code will look similar to the following, we've
changed the comments though to explain what is going on there
on a high level.

```rust
// If the `std` feature from the `Cargo.toml` is not enabled
// we switch on `no_std`, this has the effect of Rusts standard
// library not being included in our contract.
//
// The Rust standard library is OS-dependent and Wasm is
// architecture independent.
#![cfg_attr(not(feature = "std"), no_std)]

// This is the ink! macro, the starting point for your contract.
// Everything below it might look like Rust code, but it is actually
// run through a parser in ink!.
#[ink::contract]
pub mod flipper {
/// This is the contract's storage.
#[ink(storage)]
pub struct Flipper {
value: bool,
}

impl Flipper {
/// A constructor that the contract can be initialized with.
#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
/* --snip-- */
}

/// An alternative constructor that the contract can be
/// initialized with.
#[ink(constructor)]
pub fn new_default() -> Self {
/* --snip-- */
}

/// A state-mutating function that the contract exposes to the
/// outside world.
///
/// By default functions are private, they have to be annotated
/// with `#[ink(message)]` and `pub` to be available from the
/// outside.
#[ink(message)]
pub fn flip(&mut self) {
/* --snip-- */
}

/// A public contract function that has no side-effects.
///
/// Note that while purely reading functions can be invoked
/// by submitting a transaction on-chain, this is usually
/// not done as they have no side-effects and the transaction
/// costs would be wasted.
/// Instead those functions are typically invoked via RPC to
/// return a contract's state.
#[ink(message)]
pub fn get(&self) -> bool {
/* --snip-- */
}
}

#[cfg(test)]
mod tests {
use super::*;

/// This attribute denotes that the test is executed in
/// a simulated, mocked blockchain environment. There are
/// functions available to influence how the test environment
/// is configured (e.g. setting an account to a specified balance).
#[ink::test]
fn default_works() {
/* --snip-- */
}

/* --snip-- */
}

#[cfg(all(test, feature = "e2e-tests"))]
mod e2e_tests {
use super::*;
use ink_e2e::build_message;

type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

/// With this attribute the contract will be compiled and deployed
/// to a Substrate node that is required to be running in the
/// background.
///
/// We offer API functions that enable developers to then interact
/// with the contract. ink! will take care of putting contract calls
/// into transactions that will be submitted to the Substrate chain.
///
/// Developers can define assertions on the outcome of their transactions,
/// such as checking for state mutations, transaction failures or
/// incurred gas costs.
#[ink_e2e::test]
async fn it_works(mut client: ink_e2e::Client<C, E>) -> E2EResult<()> {
/* --snip-- */
}

/* --snip-- */
}
}
```