Building the staking smart contract with Solana blockchain
DingTian
Posted on March 26, 2022
Summary
Solana is a decentralized blockchain platform created by Anatoly Yakavenko.Solana has a block time of 400 ms which is freakingly fast because of POH mechanism. I am not going to write the detailed information of POH in solana blockchain. If you want to get more information, I recommend you to go through a whitepaper of solana.In this article , I am going to deal the basic Xtoken staking smart contract programme in solana blockchain.
Prerequisite
Rust programming
Solana Tool Suit (Solana CLI)
Anchor framework
You need to install above prerequisites on your pc before we build the staking smart contract programming.Those needs to program for the task.
Rust is a very powerful general-purpose programming language.
Solana Tool Suit — This includes the Solana CLI.
Anchor is a framework for developing Solana smart contract that contains several developer tools. So basically, the Anchor is a lifesaver and makes it really easy to develop smart contracts.
Getting Started
To get started, create a new anchor project in your console:
anchor init basicStaking
In the project structure, you will see the following files and folders.
program — This is the directory of Solana programs (Smart contracts)
test — This is where javascript test code lives
migrations — This is the deploy script
app — This is where frontend is going to be built
Let’s look at our lib.rs file in the program directory.
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod basicStaking {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> ProgramResult { Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
This is the most basic program written by CLI. There is a function initialize when invoked do nothing just execute successfully, the initialize struct defines the context of the initialize function.
The stakeholders who owns xToken stakes some amounts into the staking smart contract. Instead of staking some amounts by the holders, staking contract will provide the reward tokens as the xToken after some periods.
We assume we created xToken by Solana cli with 100,000,000 totalSupply.If you don’t understand well for this part, you can reference the solana document how to create a custom token on the solana blockchain.
As well, staking smart contract includes 10,000,000 xTokens to return the rewards to stakeholders.
Those are allowed by tokenomics before TGE step. TGE — Token Generation Event.
So let’s build simple staking smart contract now.
// pub mod utils;
use {
// crate::utils::*,
anchor_lang::{prelude::*, solana_program::program::{invoke,invoke_signed}},
spl_token::state,
};
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod basic_staking {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
Ok(())
}
pub fn stake(ctx:Context<Stake>,amount: u64) -> ProgramResult{
let account = &mut ctx.accounts.holder;
//invoke to transfer token into staking contract
let token_program = ctx.accounts.token_program.clone();
let source = ctx.accounts.stake_token.clone();
let destination = ctx.accounts.stake_pot.clone();
let authority = ctx.accounts.authority.clone();
invoke(&spl_token::instruction::transfer(
token_program.key,
source.key,
destination.key,
authority.key,
&[],
amount,
)?,
&[source, destination, authority, token_program],
);
account.stake_amount += amount;
let now_ts = Clock::get().unwrap().unix_timestamp;
account.stake_time = now_ts;
Ok(())
}
pub fn unstake(ctx:Context<Stake>,amount:u64) -> ProgramResult{
let account = &mut ctx.accounts.holder;
//invoke to transfer token into holder address
account.stake_amount -= amount;
let now_ts = Clock::get().unwrap().unix_timestamp;
account.stake_time = now_ts;
Ok(())
}
pub fn claim(ctx:Context<Stake>) -> ProgramResult{
let account = &mut ctx.accounts.holder;
//invoke to transfer reward token into holder
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
#[derive(Accounts)]
pub struct SetAuthority<'info>{
#[account(mut, signer)]
authority: AccountInfo<'info>,
#[account(mut)]
new_authority: AccountInfo<'info>,
#[account(mut, owner = spl_token::id())]
stake_pot:AccountInfo<'info>,
#[account(address=spl_token::id())]
token_program:AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct Stake<'info>{
#[account(mut, signer)]
authority: AccountInfo<'info>,
#[account(mut,signer)]
pub holder:Account<'info,StakeAccount>,
#[account(mut, owner=spl_token::id())]
stake_token: AccountInfo<'info>,
#[account(mut, owner=spl_token::id())]
stake_pot: AccountInfo<'info>,
#[account(address=spl_token::id())]
token_program:AccountInfo<'info>,
}
#[account]
pub struct StakeAccount{
pub stake_amount:u64,
pub stake_time:i64,
}
the StakeAccount struct is our Account contains a count variable that is going to store our stake data.
The Stake struct is our instruction struct that defines our context for creating an account.
We declares three functions for stake,unstake,claim to implement the staking logic . Those are instructions to invoke.
Cool. We are done with this amazing program.
Now, run the test.
anchor test
After the test passes, we can now deploy the program. Be sure that solana-test-validator is running.
anchor deploy
Conclusion
Please note that you might not use this codebase because of some codebases based on logic of staking. There are bunch of codebases to run the staking contract. I only explained how to configure out the staking contract building in this article. So I recommend you to understand those steps here. Thanks for considering my article today!
Posted on March 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.