A Guide to Counter DApp Development on Solana Blockchain

A Guide to Counter DApp Development on Solana Blockchain
8 min read

This blog gives a comprehensive guide to smart contract development using Anchor for counter dApp development on the Solana blockchain.

About Solana

Solana is a high-performance blockchain known for its remarkable speed and scalability. It uses proof-of-history (PoH) and proof-of-stake (PoS) to process thousands of transactions per second, offering low fees. Solana’s native cryptocurrency is SOL.

Its expanding environment fosters the growth of decentralised apps, or dApps. The network's primary goals are interoperability and decentralisation. Solana is a strong blockchain innovation platform in spite of a few challenges.

Check It Out: What Makes Solana Blockchain Development Stand Out

Writing Smart Contracts on Solana using Anchor

Set Up Environment

Install Rust, Solana CLI, and Anchor CLI for development, for more details refer to https://www.anchor-lang.com/docs/installation.

Initialize Project

Use Anchor CLI to create a project with smart contract templates.

Define Contract

Create your Rust smart contract code by establishing state structures and initialising accounts in the lib.rs file.

Compile and Deploy

Use Anchor CLI to compile your code into a Solana program and deploy it to the network.

Interact

By submitting transactions to its entry points, users can communicate with your contract.

Testing

Test your contract and use Anchor for upgrades.

Suggested Read: Exploring the Potential of Solana Smart Contract Development

Creating an Update Counter Smart Contract

About Smart Contract

This is a simple smart contract built using Anchor. This smart contract allows you to initialize a counter account and then increment and decrement it. The counter account can only be increased or decreased by the creator, who can also decide to delete it.

Concepts Covered:

  1. PDA — Program Derived Address
  2. Structs
  3. Modify the state of the smart contract
  4. Add Signers for signing the transaction
  5. Error Code
  6. InitSpace for default spacing of account struct
  7. Closing a created PDA and getting the Rent SOL back

Dependencies Version

Anchor 0.28.0

Solana CLI 1.16.9

Project Creation Command

anchor init solana-counter

Functions and Functionality

First of all, we’ll create an account struct that will store data.

#[account]

#[derive(Default, InitSpace)]
pub struct Counter {
pub owner: Pubkey,
pub counter: u64,
pub bump: u8,
}

Explanation

  1. Owner: To store the owner who created the counter account
  2. Counter: To store the count of a particular counter account
  3. Bump: To store the canonical bump of the account

Then we’ll manage this created account as follows:

1. Initialize: To initialize the counter account which can store the above details, below is the code to initialize a counter account.

Account

#[derive(Accounts)]

pub struct Initialize<'info> {
#[account(
init,
payer = initializer,
seeds = [
COUNTER_SEED.as_bytes(),
initializer.key.as_ref()
],
bump,
space = 8 + Counter::INIT_SPACE
)]
pub counter_account: Account<'info, Counter>,
    #[account(mut)]

pub initializer: Signer<'info>,
pub system_program: Program<'info, System>,
}

Function

pub fn initialize(ctx: Context) -> Result<()> {

let counter_account = &mut ctx.accounts.counter_account;
        counter_account.owner = ctx.accounts.initializer.key();

counter_account.counter = 0;
counter_account.bump = *ctx.bumps.get("counter_account").unwrap();
Ok(())
}

Explanation

  • Counter account: a PDA type account that will be initialized first with the seeds (COUNTER_SEED and initializer account) so that for every initializer there can be a different counter account, we’ll store the owner, set the counter to 0 and the canonical bump.
  • Initializer: a Signer-type account that will pay for the account creation.
  • System Program: an account with the System Programme that will be used to register for the System Programme.

2. Increment Counter: To increment the counter account, below is the code to increment a counter account.

Account

#[derive(Accounts)]

pub struct Update<'info> {
#[account(
mut,
seeds = [
COUNTER_SEED.as_bytes(),
updater.key.as_ref()
],
bump = counter_account.bump,
)]
pub counter_account: Account<'info, Counter>,
    #[account(

mut,
constraint = updater.key() == counter_account.owner @ ErrorCode::AccessDenied
)]
pub updater: Signer<'info>,
}

Function

pub fn increment_counter(ctx: Context) -> Result<()> {

let counter_account = &mut ctx.accounts.counter_account;
        counter_account.counter += 1;        Ok(())

}

Explanation

  • Counter account: We will pass through the same PDA account that we previously created in order to access the account's data.
  • Updater: a Signer-type account that will pay for the account updation.

3. Decrement Counter: To decrement the counter account, below is the code to decrement a counter account.

Function

pub fn decrement_counter(ctx: Context) -> Result<()> {

let counter_account = &mut ctx.accounts.counter_account;
        require!(counter_account.counter > 0, ErrorCode::InvalidCount);        counter_account.counter -= 1;        Ok(())

}

Explanation

  • Counter account: the same PDA account that we created before will be passed so that we can access the data from that account.
  • Updater: a Signer-type account that will pay for the account updation.

Note: We can use the same Update Account in Increment for decrement as well.

4. Remove Counter: To remove the counter account, below is the code to remove a counter account.

Account

#[derive(Accounts)]

pub struct Remove<'info> {
#[account(
mut,
seeds = [
COUNTER_SEED.as_bytes(),
remover.key.as_ref()
],
bump = counter_account.bump,
close = remover
)]
pub counter_account: Account<'info, Counter>,
    #[account(

mut,
constraint = remover.key() == counter_account.owner @ ErrorCode::AccessDenied
)]
pub remover: Signer<'info>,
}

Function

pub fn remove_counter(_ctx: Context) -> Result<()> {

Ok(())
}

Explanation

  • Counter account: the same PDA account that we created before will be passed so that we can access the data from that account.
  • Remover: a Signer type account, who will get the SOL for the account removal.

Steps to Deploy on Localhost

“solana config get” — Make sure it shows localhost configuration, if not run the command below.

“solana config set –url localhost”

After the instance is set to localhost, run the command below.

After the instance is set to localhost, run the command below.

“anchor localnet” — This will start a local validator so that you can deploy and run the smart contract.

“anchor build” — This will build the smart contract.

“anchor keys list” — Copy the program ID that is returned and paste it in lib.rs and Anchor.toml also check if the cluster is set to “localnet”.

“anchor build” — This will build the smart contract again with the updated program ID.

“anchor deploy” — This will deploy the smart contract on the localhost.

“anchor run test” — This will run the smart contract test cases.

Complete code — https://github.com/siddharth-oodles/solana-counter

Explore More: Why Develop DApps on Solana

Solana DApp Development with Oodles

A comprehensive range of dApp development services for the Solana blockchain is provided by Oodles Blockchain. We enable you to develop robust Solana dApps for fintech, non-fungible token marketplaces, gaming, and beyond. Connect with our Solana developers to discuss your project needs.

In case you have found a mistake in the text, please send a message to the author by selecting the mistake and pressing Ctrl-Enter.
Oodles Blockchain 68
Full-Stack Blockchain Development Services and Solutions for Startups and Enterprises for Business Excellence Transform your business processes into highly sec...
Comments (0)

    No comments yet

You must be logged in to comment.

Sign In / Sign Up