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

Review ZeroHero Tutorial #231

Merged
merged 2 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
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

This file was deleted.

This file was deleted.

This file was deleted.

48 changes: 0 additions & 48 deletions docs/builder-guides/from- zero-to-ink-hero/nft/nft.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ sidebar_position: 3
in factory contract prior entering **setFeeTo** and **setFeeToSetter** there is a [check](https://github.com/Uniswap/v2-core/blob/ee547b17853e71ed4e0101ccfd52e70d5acded58/contracts/UniswapV2Factory.sol#L41) that caller is `feeToSetter`.
Let's create a custom modifier for it.

## only_fee_setter
## `only_fee_setter`

In *.logics/impls/factory/factory.rs* import `modifier_definition` and `modifiers`:
```rust
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Build Uniswap V2 core DEX",
"position": 3
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ sidebar_position: 1
# Prerequisites
This tutorial targets developers with an **advanced** level in ink! and an **intermediate** level in Rust.

| Tutorial | Difficulty |
|----------------------------------------------------------------------------|--------------------------------|
| [Your First Flipper Contract](../flipper-contract/flipper-contract.md) | Basic ink! - Basic Rust |
| [NFT contract with PSP34](../nft/nft.md) | Intermediate ink! - Basic Rust |

# To follow this tutorial you will need:
- To [set up your ink! environment](../../XVM%20and%20WASM/setup_your_ink_environment.md).
- To have knowledge about AMM & [Uniswap V2 implementation](https://docs.uniswap.org/contracts/v2/overview) (as this tutorial will focus on implementation).

## What will we do?
In this tutorial we will implement in ink! the follow contracts from the Solidity implementation of Uniswap V2 Core
In this tutorial we will implement in ink! the follow contracts from the Solidity implementation of Uniswap V2 Core:
- [Pair](https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol)
- [Factory](https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Your First Flipper Contract",
"position": 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ sidebar_position: 1

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

| Available Tutorials | Difficulty |
| Tutorial | Difficulty |
|----------------------------------------------------------------------------|--------------------------------|
| [NFT contract with PSP34](../nft/nft.md) | Intermediate ink! - Basic Rust |
| [Implement Uniswap V2 core DEX](../dex/uniswap-v2-dex-in-ink.md) | Advanced ink! - Basic Rust |
| [Implement Uniswap V2 core DEX](../dex/dex.md) | Advanced ink! - Basic Rust |

### To follow this tutorial you will need:
- To [set up your ink! environment](../../XVM%20and%20WASM/setup_your_ink_environment.md).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
sidebar_position: 2
---

# Flipper
# Flipper Contract
This is step-by-step explanation of ink! smart contract by using the most simple app, which is flipper. You will understand the basic structure of ink! smart-contract.

## What is Flipper
## What is Flipper?
Flipper is a very basic smart contract. It has only one boolean in the storage (`true` or `false`), and when you flip, the value will be changed in to the other.

## Preparation
Please refer to [Prerequisites](./prerequisites.md)
Please refer to [Prerequisites](./flipper-contract.md)

## Flipper Smart Contract
In a folder run:
Expand Down Expand Up @@ -42,7 +42,7 @@ Let’s dive into the structure.
- `Cargo.toml`: Package Config
- `lib.rs`: Your contract logic

### Flipper Contract (lib.rs)
### Flipper Contract `lib.rs`

```rust
#![cfg_attr(not(feature = "std"), no_std)]
Expand Down Expand Up @@ -121,7 +121,7 @@ mod flipper {
}
```

### Contract Structure (lib.rs)
### Contract Structure `lib.rs`

```rust
#![cfg_attr(not(feature = "std"), no_std)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Custom Trait

As a next step we want to expand contract with more utility methods to have more control over the nft creation, minting, payments and all that most of the nft projects will need.
To start with we will move mint() from contract lib.rs to a custom trait `PayableMint`.
As a next step we want to expand contract with more utility methods to have more control over the NFT creation, minting, payments and all that most of the NFT projects will need.
To start with we will move `mint()` from contract `lib.rs` to a custom trait `PayableMint`.

## Folder Structure for Custom Trait
Before starting to add code we need to prepare the scene for the external trait. Create new `logics` folder with following empty files:
Expand All @@ -25,8 +25,8 @@ Before starting to add code we need to prepare the scene for the external trait.
└── payable_mint.rs
```

## Module linking
With the extended structure we need to link all new modules. Let's start from `logics` folder:
## Module Linking
With the extended structure we need to link all new modules. Let's start from `logics` folder.
The crate's `lib.rs` needs to point to impls and trait folders and since it is top module for this crate it needs a few macros:
```rust
#![cfg_attr(not(feature = "std"), no_std)]
Expand All @@ -36,7 +36,7 @@ pub mod impls;
pub mod traits;
```

The crate's `Cargo.toml` will import all ink! and Openbrush crates and it will be used by the contract's Cargo.toml to import all methods. We will name this package `payable_mint`
The crate's `Cargo.toml` will import all ink! and Openbrush crates and it will be used by the contract's `Cargo.toml` to import all methods. We will name this package `payable_mint`.
```toml
[package]
name = "payable_mint_pkg"
Expand Down Expand Up @@ -76,11 +76,11 @@ std = [
"openbrush/std",
]
```
Add same `mod.rs` file in folders: traits, impls, impls/payable_mint
Add same `mod.rs` file in folders: traits, impls, and impls/payable_mint.
```rust
pub mod payable_mint;
```
As a last step add link to `payable_mint` in Contract's Cargo.toml
As a last step add link to `payable_mint` in contract's `Cargo.toml`.
```toml
payable_mint_pkg = { path = "../../logics", default-features = false }

Expand All @@ -92,7 +92,7 @@ std = [
]
```

## Define custom trait
## Define Custom Trait
In `logics/traits/payable_mint.rs` add trait definition for PayableMint.
```rust
use openbrush::{
Expand All @@ -117,8 +117,8 @@ pub trait PayableMint {

You may notice a couple of new macro commands used. More details on these and other macros can be found throughout the advanced tutorial for DEX.

## Move mint() to Custom trait implementation
Now let's move `mint()` method from the contract's lib.rs to the newly created `logics/impls/payable_mint.rs` file. We do not want to have duplicated calls in the contract.
## Move `mint()` to Custom Trait Implementation
Now let's move `mint()` method from the contract's `lib.rs` to the newly created `logics/impls/payable_mint.rs` file. We do not want to have duplicated calls in the contract.

```rust
pub use crate::traits::payable_mint::PayableMint;
Expand Down Expand Up @@ -149,7 +149,7 @@ where
}
}
```
Last remaining step is to import and implement `PayableMint` for our `Contract`:
Last remaining step is to import and implement `PayableMint` for our contract:
```rust
use payable_mint::{
traits::payable_mint::*,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Events
Last missing piece for our contract is event handling.

## What is an event for smart contract
## What is an event for smart contract?
Events are important for smart contracts because they facilitate communication between smart contracts and their user interfaces. In traditional web development, a server response is provided in a callback to the frontend. In blockchain, when a transaction is executed, smart contracts can emit events to the blockchain that the frontend can then process.

## Minting event
## Minting Event
In our contract there is one occasion where an event should be emitted and that is when token is minted.
One could expect that by calling Openbrush `_mint_to()`, and event will be emitted but upon closer examination we can see that `_emit_transfer_event()` has empty default [implementation](https://github1s.com/Supercolony-net/openbrush-contracts/blob/main/contracts/src/token/psp34/psp34.rs#L151-L152). This gives flexibility to create events for our needs.

```rust
default fn _emit_transfer_event(&self, _from: Option<AccountId>, _to: Option<AccountId>, _id: Id) {}
```
Let's define two events that are needed for token handling, *Transfer* and *Approve*. This needs to be done in the contracts's `lib.rs`. Please note that there is no Mint event. Mint is covered by *Transfer* event where `from` will be the contract address.
Let's define two events that are needed for token handling, *Transfer* and *Approve*. This needs to be done in the contracts's `lib.rs`. Please note that there is no `Mint` event. `Mint` is covered by *Transfer* event where `from` will be the contract address.
```rust
use ink_lang::codegen::{
EmitEvent,
Expand Down Expand Up @@ -65,7 +65,7 @@ impl psp34::Internal for Shiden34Contract {
}
```

## Update unit test
## Update Unit Test
As a last check let's add event check at the end of our unit test. Since our test minted 5 tokens we expect 5 events to be emitted.
```rust
assert_eq!(5, ink_env::test::recorded_events().count());
Expand All @@ -75,7 +75,7 @@ After this step your code should look like [this](https://github.com/swanky-dapp
## Next step
Congratulations on the successful completion of this tutorial!
As a next step check the code from [main](https://github.com/swanky-dapps/nft/) branch for the repository used for this tutorial. There you can enhance your knowledge on:
- better unit test coverage
- several new methods
- end-to-end test
- better error handling
- Better unit test coverage.
- Several new methods.
- End-to-end test.
- Better error handling.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Override mint() method
# Override `mint()` Method

## Mint allowed only for owner

Expand Down Expand Up @@ -27,9 +27,9 @@ _instance._init_with_owner(_instance.env().caller());
```

At this step of tutorial we will make couple of changes:
* We do not want tokens to be mintable only by owner. We want everyone who paid to be able to mint
* Charge 1 SDN token for each minted token (or any other native token depending on the used network)
* Constructor will not call mint method
* We do not want tokens to be mintable only by owner. We want everyone who paid to be able to mint.
* Charge 1 SDN token for each minted token (or any other native token depending on the used network).
* Constructor will not call mint method.


## Add payable mint() method
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# PayableMint Trait Implementation
In this section we will
* define new data type,
* implement methods defined in the PayableMint trait from previous section
* update contract's constructor to accept new parameters
* write unit test for `mint()`
In this section we will:
* Define new data type.
* Implement methods defined in the PayableMint trait from previous section.
* Update contract's constructor to accept new parameters.
* Write unit test for `mint()`.

## Data type definition
Since our contract will now accept new parameters we need storage to keep them. Let's create new file `logics/impls/types.rs` and add:
Expand All @@ -21,11 +21,11 @@ pub struct Data {
pub price_per_mint: Balance,
}
```
Do not forget to update mod.rs file with:
Do not forget to update `mod.rs` file with:
```rust
pub mod types;
```
Since we introduced Data storage we need to add a trait bond.
Since we introduced data storage we need to add a trait bond.
```rust
impl<T> PayableMint for T
where
Expand All @@ -46,9 +46,9 @@ pub trait Internal {
}
```

## Mint implementation
There are several checks we need to do before proceeding with the token mint. We have implemented these methods in the Internal trait.
### Check transferred funds and check the overflow
## Mint Implementation
There are several checks we need to do before proceeding with the token mint. We have implemented these methods in the `internal` trait.
### Check Transferred Funds and Overflow
```rust
default fn check_value(
&self,
Expand All @@ -66,7 +66,7 @@ default fn check_value(
}
```

### Check amount of tokens to be minted
### Check Amount of Tokens to be Minted
```rust
/// Check amount of tokens to be minted
default fn check_amount(&self, mint_amount: u64) -> Result<(), PSP34Error> {
Expand Down Expand Up @@ -105,7 +105,7 @@ default fn mint(&mut self, to: AccountId, mint_amount: u64) -> Result<(), PSP34E
Ok(())
}
```
## Withdraw implementation
## Withdraw Implementation
Enable contract owner to be able to withdraw funds from contract by implementing withdraw method:
```rust
/// Withdraws funds to contract owner
Expand All @@ -123,7 +123,7 @@ default fn withdraw(&mut self) -> Result<(), PSP34Error> {
Ok(())
}
```
## Set base_uri and get token uri
## Set `base_uri` and get `token_uri`
Let's first create `token_exist` check and place it in the Internal trait:
```rust
/// Check if token is minted
Expand Down Expand Up @@ -163,12 +163,12 @@ default fn token_uri(&self, token_id: u64) -> Result<PreludeString, PSP34Error>
}
```

## Update contract
## Update Contract
Since we have added new type `Data` let's import it:
```rust
use payable_mint::impls::payable_mint::*;
```
And add new element in the `struct Contract`:
Add a new element in the `struct Contract`:
```rust
#[storage_field]
payable_mint: types::Data,
Expand Down Expand Up @@ -197,7 +197,7 @@ pub fn new(
```

## Write unit test
Let's write a simple unit test to check mint() method. In ink! contract the unit test is placed inside the contract module. By default Alice creates the contract.
Let's write a simple unit test to check `mint()` method. In ink! contract the unit test is placed inside the contract module. By default Alice creates the contract.
After all imports let's write helper method to initiate contract:
```rust
#[cfg(test)]
Expand Down
Loading