Skip to content

Commit

Permalink
Merge pull request #7 from inkdevhub/vsofiya-inkdevhub-docs-1
Browse files Browse the repository at this point in the history
Update multiple files
  • Loading branch information
vsofiya authored Jan 9, 2024
2 parents ee491be + 2f59042 commit a9ae2bb
Show file tree
Hide file tree
Showing 28 changed files with 1,410 additions and 13 deletions.
19 changes: 16 additions & 3 deletions docs/build/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
---
title: Introduction
title: Build
position: 1
---

# Overview

This section contains all the information you need to start building with ink!
Welcome to the Build section of the ink! Dev Hub documentation, your comprehensive guide to developing WASM (ink!) smart contracts within the Polkadot and Kusama ecosystems. Here, you'll find all the tools and resources you need to bring your innovative smart contract ideas to life.

## Prerequisites
From scaffolding your project with Swanky to leveraging DRink!'s minimal runtime for effective contract interactions, this section covers it all. Our goal is to empower you, whether you're a seasoned web3 developer or new to the ecosystem, to seamlessly navigate the complexities of WASM smart contract development.

# Swanky Suite

Swanky is designed to be the go-to developer tool for every aspect of developing WASM (ink!) smart contracts for Polkadot, from scaffolding to live-net deployment. While some tools currently exist, Swanky's intent is to integrate and extend these tools as necessary, offering a more streamlined, dev-friendly experience.

The development of a smart contract project follows a clear, necessary sequence: scaffolding a new project, building and testing locally, deploying and testing on a test network, and finally deploying on a live network. Swanky is designed to provide support at every stage of this process, making it an indispensable asset for any WASM (ink!) smart contract developer.

# DRink!

DRink! library provides a minimal viable functionality for arbitrary runtime interaction and standard contract-related operations (like code upload, instantiation or calling). DRink! was designed with a particular trade-off in mind: giving up the whole node layer with simultaneously gaining direct access to the runtime. For that, we make use of the existing machinery exposed by the Substrate framework, that before was primarily used for pallet unit testing. We build (in-memory) minimal runtime supporting ink! smart contracts (although the library supports arbitrary ink!-compatible runtime) and expose a convenient, synchronous interface for interacting with the chain.

Since there is no node running in the background, we can benefit from omitting node/network configuration issues, blocktime/finalization delays or overhead coming from asynchronous communication between e2e client and RPC chain service.

DRink! originally came with drink-cli: a command-line tool with terminal graphic interface for local playing with contracts.

1 change: 1 addition & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
title: About ink! Dev Hub
sidebar_position: 1
---

Expand Down
4 changes: 4 additions & 0 deletions docs/learn/examples/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Tutorials",
"position": 1
}
11 changes: 10 additions & 1 deletion docs/learn/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
---
sidebar_position: 2
title: Learn
position: 1
---

# Overview

Welcome to the Learn section of the ink! Dev Hub documentation, where your journey into the world of WASM (ink!) smart contracts begins. This section is tailored to equip you with the knowledge and skills necessary to navigate the Polkadot and Kusama ecosystems confidently. Whether you're new to blockchain development or an experienced web3 developer looking to expand your expertise, our comprehensive learning resources are designed to cater to your needs.

As you progress through the Learn section, you'll gain valuable insights and hands-on experience with smart contract development, enabling you to harness the full potential of ink!.

Let's embark on this educational journey together and unlock the endless possibilities that ink! smart contracts offer!
4 changes: 4 additions & 0 deletions docs/learn/tutorials/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Tutorials",
"position": 1
}
4 changes: 4 additions & 0 deletions docs/learn/tutorials/flipper-contract/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Your First Flipper Contract",
"position": 1
}
28 changes: 28 additions & 0 deletions docs/learn/tutorials/flipper-contract/flipper-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
sidebar_position: 1
---

# Prerequisites

This tutorial targets developers with no experience in ink! and a **basic** level in Rust.

| Tutorial | Difficulty |
|----------------------------------------------------------------------------|--------------------------------|
| NFT contract with PSP34 | Intermediate ink! - Basic Rust |
| Implement Uniswap V2 core DEX | Advanced ink! - Basic Rust |

### To follow this tutorial you will need:
- To [set up your ink! environment](https://docs.astar.network/docs/build/environment/ink_environment).
- Basic Rust knowledge. [Learn Rust](https://www.rust-lang.org/learn).

### What will we do?
In this tutorial we will implement the most basic contract: [Flipper](https://github.com/paritytech/ink/blob/v4.0.0/examples/flipper/lib.rs) in ink!.

### What will we use?
- [ink! 4.0.0](https://github.com/paritytech/ink/tree/v4.0.0)

### What will you learn?
- Anatomy of an ink! contract
- Define contract storage
- Callable functions
- Unit test your contract
300 changes: 300 additions & 0 deletions docs/learn/tutorials/flipper-contract/flipper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
---
sidebar_position: 2
---

# Flipper Contract
This is step-by-step explanation of the process behind building an ink! smart contract, using a simple app called Flipper. The examples provided within this guide will help you develop an understanding of the basic elements and structure of ink! smart contracts.

## What is Flipper?
Flipper is a basic smart contract that allows the user to toggle a boolean value located in storage to either `true` or `false`. When the flip function is called, the value will change from one to the other.

## Prerequisites
Please refer to the previous section for the list of prerequisites.

## Flipper Smart Contract
In a new project folder, execute the following:

```bash
$ cargo contract new flipper # flipper is introduced from the beginning.
```

```bash
$ cd flipper/
$ cargo contract build #build flipper app
```

💡 If you receive an error such as:
```bash
ERROR: cargo-contract cannot build using the "stable" channel. Switch to nightly.
```
Execute:
```bash
$ rustup default nightly
```
to reconfigure the default Rust toolchain to use the nightly build, or
```
$ cargo +nightly contract build
```
to use the nightly build explicitly, which may be appropriate for developers working exclusively with ink!

Once the operation has finished, and the Flipper project environment has been initialized, we can perform an examination of the file and folder structure.
Let’s dive a bit deeper into the project structure:

### The File Structure of Flipper

- `target`: Contains build / binary information.
- `Cargo.lock`: The lock file for dependency package.
- `Cargo.toml`: The package configuration.
- `lib.rs`: The contract logic.

### Flipper Contract `lib.rs`

```rust
#![cfg_attr(not(feature = "std"), no_std)]

#[ink::contract]
mod flipper {

/// Defines the storage of your contract.
/// Add new fields to the below struct in order
/// to add new static storage fields to your contract.
#[ink(storage)]
pub struct Flipper {
/// Stores a single `bool` value on the storage.
value: bool,
}

impl Flipper {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
Self { value: init_value }
}

/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}

/// A message that can be called on instantiated contracts.
/// This one flips the value of the stored `bool` from `true`
/// to `false` and vice versa.
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
}

/// Simply returns the current value of our `bool`.
#[ink(message)]
pub fn get(&self) -> bool {
self.value
}
}

/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
/// module and test functions are marked with a `#[test]` attribute.
/// The below code is technically just normal Rust code.
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;

/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let flipper = Flipper::default();
assert_eq!(flipper.get(), false);
}

/// We test a simple use case of our contract.
#[ink::test]
fn it_works() {
let mut flipper = Flipper::new(false);
assert_eq!(flipper.get(), false);
flipper.flip();
assert_eq!(flipper.get(), true);
}
}
}
```

### Contract Structure `lib.rs`

```rust
#![cfg_attr(not(feature = "std"), no_std)]

use ink_lang as ink;

#[ink::contract]
mod flipper {

// This section defines storage for the contract.
#[ink(storage)]
pub struct Flipper {
}

// This section defines the functional logic of the contract.
impl Flipper {
}

// This section is used for testing, in order to verify contract validity.
#[cfg(test)]
mod tests {
}
}
```

### Storage

```rust
#[ink(storage)]
pub struct Flipper {

}
```

This annotates a struct that represents the **contract's internal state.** ([details](https://use.ink/macros-attributes/storage)):

```rust
#[ink(storage)]
```

Storage types:

- Rust primitives types
- `bool`
- `u{8,16,32,64,128}`
- `i{8,16,32,64,128}`
- `String`
- Substrate specific types
- `AccountId`
- `Balance`
- `Hash`
- ink! storage type
- `Mapping`
- Custom data structure [details](https://use.ink/datastructures/custom-datastructure)

This means the contract (Flipper) stores a single `bool` value in storage.

```rust
#[ink(storage)]
pub struct Flipper {
value: bool,
}
```

### Callable Functions
At the time the contract is deployed, a constructor is responsible for **bootstrapping the initial state** into storage. [For more information](https://use.ink/macros-attributes/constructor).

```rust
#[ink(constructor)]
```

The addition of the following function will initialize `bool` to the specified `init_value`.

```rust
#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
Self { value: init_value }
}
```

Contracts can also contain multiple constructors. Here is a constructor that assigns a default value to `bool`. As other language, default value of `bool` is `false`.

```rust
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
```

The following will permit a function to be **publicly dispatchable**, meaning that the function can be called through a message, which is a way for contracts and external accounts to interact with the contract. Find more information [here](https://use.ink/macros-attributes/message)). Note that all public functions **must** use the `#[ink(message)]` attribute.

```rust
#[ink(message)]
```

The `flip` function modifies storage items, and `get` function retrieves a storage item.

```rust
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
}

#[ink(message)]
pub fn get(&self) -> bool {
self.value
}
```

💡 If you are simply *reading* from contract storage, you will only need to pass `&self`, but if you wish to *modify* storage items, you will need to explicitly mark it as mutable `&mut self`.

```rust
impl Flipper {

#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
Self { value: init_value }
}

/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}

/// A message that can be called on instantiated contracts.
/// This one flips the value of the stored `bool` from `true`
/// to `false` and vice versa.
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
}

/// Simply returns the current value of our `bool`.
#[ink(message)]
pub fn get(&self) -> bool {
self.value
}
}
```

### Test

```rust
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;

/// Imports `ink_lang` so we can use `#[ink::test]`.
use ink_lang as ink;

/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let flipper = Flipper::default();
assert_eq!(flipper.get(), false);
}

/// We test a simple use case of our contract.
#[ink::test]
fn it_works() {
let mut flipper = Flipper::new(false);
assert_eq!(flipper.get(), false);
flipper.flip();
assert_eq!(flipper.get(), true);
}
}
```

### Compile, Deploy and Interact with Contracts


Follow this guide to deploy your contract [using Polkadot UI](https://docs.astar.network/docs/build/wasm/tooling/polkadotjs/). Once deployed, you will be able to interact with it.
Loading

0 comments on commit a9ae2bb

Please sign in to comment.