This is a guide for building a liquid staking contract in CosmWasm for Archway protocol

Introduction

_liquid staking_ is a contract for you to delegate and bond your native tokens to earn staking rewards without losing access to your funds.

We need a cw20token contract to represent our staked native token. Staking contract will be the minter of this token.

https://miro.medium.com/max/770/1*urb7hz0uqULNuNdiKxj1QA.png

In this guide, we will learn more about how to write, deploy and interact with liquid staking contract.

Initiating your project

We create a new project without using stater template to initiate our contract.

$ archway new staking

Creating new Archway project…
✔ Do you want to use a starter template? … no
✔ Select the project environment › Testnet
? Select a testnet to use › — Use arrow-keys. Return to submit.
❯ Constantine
Stable — recommended for dApp development
Titus
Augusta
Torii

Go inside the project directory, we edit the Cargo.tomlfile as below to add dependencies for our contract:

[dependencies]
cosmwasm-std = { version = “1.0.0-beta8”, features = [“staking”] }
cosmwasm-storage = “1.0.0-beta5”
cw-storage-plus = “0.12”
cw20 = “0.13.2”
…

The staking feature is added to cosmwasm-stdto include staking module to our contract. We also use cw20 here to get a lot of helpers for interacting with cw20contract.

Storage

Linked-list storage

We need a linked-list in our contract to crease an unstaking queue. Each node of the linked-list will contain an unstaking request.The reason we use linked-list in our code is for unstaker to not wait full 21 days to undelegate his token. The native tokens of those who want to stake will be sent to unstakers in unstaking queue, thus making unstaking process much more faster.

To create linked-list storage, we use 2 available storages:

To save basic information of the link-list, we will use Singleton. For this storage to work, we create LinkedListstruct that contains all the vars we want to put inside the storage. To load and save data inside the storage in a transaction, we create the linked_list function. We also create a linked_list_read function to read data in a query:

// file src/linked_list.rs
use cosmwasm_std::{Storage,};
use cosmwasm_storage::{
    singleton, singleton_read, ReadonlySingleton,
    Singleton,
};
use  schemars::JsonSchema;
use  serde::{Deserialize, Serialize};

static LINKED_LIST_KEY: &[u8] = b"linked_list";

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct LinkedList {
	pub head_id: u64,
	pub tail_id: u64,
	pub length: u64,
}

pub fn linked_list(storage: &mut dyn Storage) -> Singleton<LinkedList> {
    singleton(storage, LINKED_LIST_KEY)
}

pub fn linked_list_read(storage: &dyn Storage) -> ReadonlySingleton<LinkedList> {
    singleton_read(storage, LINKED_LIST_KEY)
}