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

Add example smart contracts with comprehensive README. #1

Merged
merged 29 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
44dfe4c
Add toolchain and fmt.
deuszx Oct 28, 2022
74e6ea5
Add BulletinBoard contract.
deuszx Oct 27, 2022
40a8d41
Add HighlightedPosts contract.
deuszx Oct 27, 2022
e99edad
Call HighlightedPosts contract from BulletinBoard.
deuszx Oct 28, 2022
979c0d4
Add README to the `/contracts`.
deuszx Oct 27, 2022
cae3fb3
Housekeepin.
deuszx Oct 28, 2022
2196784
Showcase alternative way to call a contract.
deuszx Oct 28, 2022
fa5e4e2
Add setup and example deployment to the README.
deuszx Oct 28, 2022
0bedbbc
Showcase contract instatiation in constructor.
deuszx Oct 31, 2022
0c6b5f4
Update README.
deuszx Oct 31, 2022
7a561a8
Add deployment scripts.
deuszx Nov 1, 2022
22c0a19
Update README to reflect new deployment processes.
deuszx Nov 1, 2022
557b443
Fix typos.
deuszx Nov 2, 2022
3ace884
Remove incomplete sections from README.
deuszx Nov 2, 2022
9fe3b59
Update Rust edition in rustmft files and reformat.
deuszx Nov 2, 2022
747a91d
Fix ink* versions to ~3.3.0
deuszx Nov 2, 2022
ee93d22
Let only caller to modify the contract state.
deuszx Nov 2, 2022
db773ec
Update ink versions to 3.4.0
deuszx Nov 2, 2022
a608cf5
Remove code and README section about cross-contract testing.
deuszx Nov 2, 2022
5cf9d73
Capitalize headers
deuszx Nov 2, 2022
b4901c3
Set the method's selector via ink macro .
deuszx Nov 2, 2022
8117fd0
Apply suggestions from code review
deuszx Nov 3, 2022
bc42083
Rename as per review suggestions.
deuszx Nov 2, 2022
9ac5ec2
Updates as per review.
deuszx Nov 5, 2022
aacd3e1
Add newlines at the end of files.
deuszx Nov 5, 2022
f85785b
Apply suggestions from code review
deuszx Nov 7, 2022
c91cbc8
Post-review changes.
deuszx Nov 7, 2022
cabe217
Update .gitignore.
deuszx Nov 7, 2022
be3820a
Update README
deuszx Nov 7, 2022
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
2 changes: 2 additions & 0 deletions contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bulletin_board/target
highlighted_posts/target
deuszx marked this conversation as resolved.
Show resolved Hide resolved
33 changes: 15 additions & 18 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
* [When to use `panic!`/`assert!` and when return a `Result`.](#panic-and-when-to-return-a-result)
* [What are selectors and how to use them.](#call-another-contract-and-handle-the-response)
* [How to call another contract and handle the response.](#call-another-contract-and-handle-the-response)
* [How to test cross-contract calls.](#test-a-cross-contract-call)
* [How to build a contract and optimize it.](#build-your-local-contract-with-optimizations)
* [How to deploy a contract using Contracts UI. And interact with it.](#deploy-a-contract-using-contracts-ui)
* [How to deploy a contract to custom environment.](#deploying-example-contracts-using-scripts)
Expand All @@ -23,13 +22,7 @@ Let's start..

## Setting up the environment
h4nsu marked this conversation as resolved.
Show resolved Hide resolved

### Install Rust & Cargo

A prerequisite is to have Rust and Cargo installed. Please follow [the official guide](https://doc.rust-lang.org/cargo/getting-started/installation.html).

### ink!

We will need to install ink! dependencies: binaryen, and ink! contract linters. Finally a `cargo contract`. All these steps are described in the [ink! documentation](https://doc.rust-lang.org/cargo/getting-started/installation.html).
To set up the environment before, please follow the guide from [our documentation](https://docs.alephzero.org/smart-contracts-tutorial/installing-required-tools).
deuszx marked this conversation as resolved.
Show resolved Hide resolved

## Example contracts

Expand All @@ -48,8 +41,12 @@ in respective root folders (`/bulletin_board` and `highlighted_posts`). Verify t
* `*.wasm` -- the actual logic of the contract compiled into WASM code.
* `*.contract` -- the two above bundled up.

Note the lack of `+nightly`, in the above command, which is suggested in most guides - that's b/c we've specified the version of toolchain being used in the `rust-toolchain` files.

### Deploying

h4nsu marked this conversation as resolved.
Show resolved Hide resolved
Tutorial below will explain how to develop and test smart contracts using either the local Aleph Zero network or already-existing one, here we will be using our [Testnet](https://test.azero.dev/).

#### Prerequisities for interacting with Aleph Zero Testnet

1. Install PolkadotJS browser extension.
Expand Down Expand Up @@ -108,17 +105,17 @@ For Testnet (or any other network for that matter), you will have to fill in the
### Emit events and verify in tests you did

#### Creating and emitting events
See `lib.rs` for `#[ink(event)]` on how to define it and [`fn emit_event`](./bulletin_board/lib.rs#L462) to see how to emit it.
See `lib.rs` for `#[ink(event)]` on how to define it and [`fn emit_event`](./bulletin_board/lib.rs#L465) to see how to emit it.

> Thing to note here is the custom `emit_event` function - you may have seen in official ink! documentation that events are emitted via `self::env().emit_event(my_event)` calls. The "official" version works when there is only one contract emitting events on our _execution path_. If our contract emits events and, during execution, calls another contract that emits events AND we have that contract as a dependency, we will have two unreleated event families (from two different contracts) and the compiler will fail to resolve type boundaries correctly. For more details, see comments on [`fn emit_event`](./bulletin_board/lib.rs#L462).
> Thing to note here is the custom `emit_event` function - you may have seen in official ink! documentation that events are emitted via `self::env().emit_event(my_event)` calls. The "official" version works when there is only one contract emitting events on our _execution path_. If our contract emits events and, during execution, calls another contract that emits events AND we have that contract as a dependency, we will have two unreleated event families (from two different contracts) and the compiler will fail to resolve type boundaries correctly. For more details, see comments on [`fn emit_event`](./bulletin_board/lib.rs#L465).

#### Testing the events were emitted

In `lib.rs` look for calls to [`recorded_events()`](./bulletin_board/lib.rs#L579), to collect the emitted events, and [`assert_expected_*_event`](./bulletin_board/lib.rs#L580) to test whether we got the expected ones.
In `lib.rs` look for calls to [`recorded_events()`](./bulletin_board/lib.rs#L582), to collect the emitted events, and [`assert_expected_*_event`](./bulletin_board/lib.rs#L583) to test whether we got the expected ones.

### Do logging in your contract

In `lib.rs` see [invocation](./bulletin_board/lib.rs#L233) of `ink_env::debug_println!` - this will produce a log message when ran in test. To verify, run [`event_on_post`](./bulletin_board/lib.rs#L574) test and observe the following log:
In `lib.rs` see [invocation](./bulletin_board/lib.rs#L236) of `ink_env::debug_println!` - this will produce a log message when ran in test. To verify, run [`event_on_post`](./bulletin_board/lib.rs#L577) test and observe the following log:
```shell
running 1 test
`AccountId([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])` wants to create a post that expires after `100` blocks with the text `"Text"`
Expand All @@ -137,19 +134,19 @@ All you need is a code hash of the other contract you want to instantiate. See a

### Transfer tokens as part of a contract call

If you want your method to accept token transfer, you need to tag it with `payable` keyword: `#[ink(payable)]`. See [`BulletinBoard::post`](./bulletin_board/lib.rs#L222) for an example.
If you want your method to accept token transfer, you need to tag it with `payable` keyword: `#[ink(payable)]`. See [`BulletinBoard::post`](./bulletin_board/lib.rs#L225) for an example.

For an example on how to do a cross-contract call _and_ transfer tokens, see [`highlight_post`](./bulletin_board/lib.rs#L406).
For an example on how to do a cross-contract call _and_ transfer tokens, see [`highlight_post`](./bulletin_board/lib.rs#L409).

### Unit test a contract

See [`bulletin_board::tests`](./bulletin_board/lib.rs#L493) for various tests, including mocking the blockchain environment - setting caller, token balance, etc.
See [`bulletin_board::tests`](./bulletin_board/lib.rs#L496) for various tests, including mocking the blockchain environment - setting caller, token balance, etc.

### Terminate a contract (and why)

If you want to delete an instance of the contract because it's incorrect, no longer needed (and we want to free the storage) or for any other reason we can do it by _terminating_ a contract.

To delete an instance of the contract, call `self.env().terminate_contract(<beneficiary>)`. You can choose the _beneficiary_ that will receive tokens that the contract owns. For the example, see [`terminate_contract`](./bulletin_board/lib.rs#L314).
To delete an instance of the contract, call `self.env().terminate_contract(<beneficiary>)`. You can choose the _beneficiary_ that will receive tokens that the contract owns. For the example, see [`terminate_contract`](./bulletin_board/lib.rs#L317).

### `panic!` and when to return a `Result`

Expand All @@ -167,8 +164,8 @@ Every contract _instance_ is stored under an address of type `AccountId`. To cal

Calling another contract can be currently made in two ways:

1) Building the call manually. An example of that is [`highlight_post`](./bulletin_board/lib.rs#L412). Here, we set every piece of the call by hand and we have no help from the compiler (to tell us whether we use correct arguments or if the return type is valid). This manual approach gives contract author access to ink!-level [errors](https://docs.rs/ink_env/3.4.0/ink_env/enum.Error.html) which gives an option to recover from the low-level failures.
2) Using the macro-generated `*Ref` pattern. An example of that is [`delete_highlight`](./bulletin_board/lib.rs#L450). This approach is type-safe but doesn't allow for transferring tokens with the call. At least not currently.
1) Building the call manually. An example of that is [`highlight_post`](./bulletin_board/lib.rs#L409). Here, we set every piece of the call by hand and we have no help from the compiler (to tell us whether we use correct arguments or if the return type is valid). This manual approach gives contract author access to ink!-level [errors](https://docs.rs/ink_env/3.4.0/ink_env/enum.Error.html) which gives an option to recover from the low-level failures.
2) Using the macro-generated `*Ref` pattern. An example of that is [`delete_highlight`](./bulletin_board/lib.rs#L446). This approach is type-safe but doesn't allow for transferring tokens with the call. At least not currently.

Both approaches, if done correctly, provide a typed access to another contract.

Expand Down
1 change: 0 additions & 1 deletion contracts/bulletin_board/.gitignore

This file was deleted.

7 changes: 5 additions & 2 deletions contracts/bulletin_board/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

// An entrypoint to all ink! smart contracts.
// When expanded, this macro will:
// * Add local type aliases to the `mod notice_pillar`, like `Environment`,
// * Add local type aliases to the `mod bulletin_board`, like `Environment`,
// `AccountId`, `Balance`, `Hash`, `Timestamp` and `BlockNumber`. All will
// resolve to defaults `ink_env::DefaultEnvironment::<type>`
// * Adds useful #[doc] macros
Expand Down Expand Up @@ -191,7 +191,10 @@ mod bulletin_board {
})
}

// Constructors can delegate to other constructors.
// Contracts can have multiple constructors. You can choose which to use
// when instantiating a contract.
/// Creates an instance of `BulletinBoard` contract where posting is
/// "free".
#[ink(constructor)]
pub fn free() -> Self {
initialize_contract(|instance: &mut BulletinBoard| {
Expand Down
1 change: 0 additions & 1 deletion contracts/highlighted_posts/.gitignore

This file was deleted.

3 changes: 2 additions & 1 deletion scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ BULLETIN_BOARD=$(cargo contract instantiate --url "$NODE_URL" --suri "$AUTHORITY
# We're initializing `highlighted_posts` contract in the constructor of `bulletin board` so there will be multiple new contract addresses.
# `cargo contract` prints the first one, rather than the last one, so we have to extract it from the events.
BULLETIN_BOARD=$(echo "$BULLETIN_BOARD" | grep -A3 "Event Contracts ➜ Instantiated" | grep contract | tail -1 | cut -d ' ' -f11)
echo "Bulletin board instance address: $BULLETIN_BOARD"
echo "Bulletin board instance address: $BULLETIN_BOARD"

3 changes: 2 additions & 1 deletion scripts/deploy_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ set -euo pipefail

source $(pwd)/scripts/env/local

$(pwd)/scripts/deploy.sh
$(pwd)/scripts/deploy.sh

3 changes: 2 additions & 1 deletion scripts/deploy_testnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ set -euo pipefail

source $(pwd)/scripts/env/testnet

$(pwd)/scripts/deploy.sh
$(pwd)/scripts/deploy.sh

3 changes: 2 additions & 1 deletion scripts/env/local
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export NODE_URL=ws://localhost:9944

export AUTHORITY_SEED=//Alice
export AUTHORITY_SEED=//Alice

3 changes: 2 additions & 1 deletion scripts/env/testnet
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export NODE_URL=wss://ws.test.azero.dev

export AUTHORITY_SEED=
export AUTHORITY_SEED=