Smart Contract on Aura Network
Aura uses CosmWasm, a WebAssembly smart contract platform (or module) that integrate natively with Cosmos SDK. Smart contracts are written in RUST, compiled into Wasm then uplodaed to the Aura chain.
You can learn more about CosmWasm in the official Cosmwasm document.
1. Prerequisitesโ
Rustโ
Make sure you have all required binaries for programming with Rust and Wasm. The standard approach is to use rustup to maintain dependencies and handle updating multiple versions of cargo(v1.55.0+) and rustc, which you will be using.
After install rustup tool, make sure you have the wasm32 target:
rustup target list --installed
rustup target add wasm32-unknown-unknown
Cargoโ
Install cargo-generate and cargo-run-script. If not installed, please run the command below:
cargo install cargo-generate --features vendored-openssl
cargo install cargo-run-script
2. Creating a new contract from templateโ
Now, create your new contract. Go to the folder in which you want to place it and run:
Latest
cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME
Older Version
Pass version as branch flag:
cargo generate --git https://github.com/aura-nw/cw-template.git --branch <version> --name PROJECT_NAME
You will now have a new folder called PROJECT_NAME
(I hope you changed that to something else)
containing a simple working contract and build system that you can customize.
Add a git Remoteโ
After generating, you have a initialized local git repo, but no commits, and no remote.
Go to a server (eg. github) and create a new upstream repo (called YOUR-GIT-URL
below).
Then run the following:
# this is needed to create a valid Cargo.lock file
cargo check
git branch -M main
git add .
git commit -m 'Initial Commit'
git remote add origin YOUR-GIT-URL
git push -u origin main
3. Developing the contractโ
We will start with a very simple tutorial of a Flower Store where you can add new flowers,selling and retrieving information from the chain.
3.1 Defining the Stateโ
This is basically a key-value storage that contains the state of the flower store. At src/state.rs, we will create a state with the name Flower. We will also interact with the state through 2 functions store and store_query.
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::Storage;
use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
static STORE_KEY: &[u8] = b"store";
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Flower {
pub id: String,
pub name: String,
pub amount: i32,
pub price: i32,
}
pub fn store(storage: &mut dyn Storage) -> Bucket<Flower> {
bucket(storage, STORE_KEY)
}
pub fn store_query(storage: &dyn Storage) -> ReadonlyBucket<Flower> {
bucket_read(storage, STORE_KEY)
}
3.2 Constructing messagesโ
Next we want to update the file src/msg.rs where the contract's input/out messages are defined.
There are 3 basic types of messages:
- InstantiateMsg
- ExecuteMsg
- QueryMsg
A. InstantiateMsgโ
InstantiateMsg are the data and functions that need to be initialized for the contract. In this particular case we are trying to create an initial flower for the store with amount and price and default id will be "0".
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub name: String,
pub amount: i32,
pub price: i32,
}
ExecuteMsgโ
How ExecuteMsg is defined will depend on the functions to be developed, so it will be presented as an enum. We will define 2 message AddNew and Sell for store management functions.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
AddNew {
id: String,
name: String,
amount: i32,
price: i32,
},
Sell {
id: String,
amount: i32,
},
}
QueryMsgโ
We will define the simplest message with the only required information being the id of the flower, and the output to describe what the returned message should look like we have a FlowerInfoResponse.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
// GetFlower returns the flower's information
GetFlower { id: String },
}
// We define a custom struct for each query response
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct FlowerInfoResponse {
pub flower: Option<Flower>,
}