9 min read
Overview
Programs are what Solana calls Smart Contracts--they are the engine that handles information and requests: everything from token transfers and Candy Machine mints to 'hello world' logs and DeFi escrow governance. Solana supports writing on-chain programs using Rust, C, and C++ programming languages. Anchor is a framework that accelerates building secure Rust programs on Solana. Let's build your first Solana Program with Anchor!
What You Will Do
This is the 2nd guide in a 2 part series. In Part 1 we covered creating your first Solana Program on Anchor. The program allows a client-side request to be made to Solana's devnet and get a 'Hello World' log. In this guide, we will build on that Program and implement an increment function to track how many times your program has been used:
- Create a program instruction to initialize a new data account
- Update the hello_world function to update increment a data account on each call
- Create a client-side request to call our updated function
What You Will Need
- Complete Part 1 of this Series. We will build off of the program you build there.
- Basic knowledge of Solana Fundamentals
- Basic knowledge of the JavaScript/TypeScript and Rust programming languages
- A modern web browser (e.g., Google Chrome)
Initiate Your Project
We will be building off of the project from Part 1 of this Series. If you have that project open, go ahead and proceed to the next section.
If you do not already have the 'Hello World' project, you can create catch up by creating a new Anchor project on Solana Playground. Open lib.rs. Delete the existing contents, and paste this code:
use anchor_lang::prelude::*;
declare_id!("11111111111111111111111111111111");
#[program]
mod hello_world {
use super::*;
pub fn say_hello(_ctx: Context<SayHello>) -> Result<()> {
msg!("Hello World!");
Ok(())
}
}
#[derive(Accounts)]
pub struct SayHello {}
Logs for Simplified Debugging
You can now access Logs for your RPC endpoints, helping you troubleshoot issues more effectively. If you encounter an issue with your RPC calls, simply check the logs in your QuickNode dashboard to identify and resolve problems quickly. Learn more about log history limits on our pricing page.
Create and Connect a Wallet
Since this project is just for demonstration purposes, we can use a "throw-away" wallet. Solana Playground makes it easy to create one. You should see a red dot "Not connected" in the bottom left corner of the browser window. Click it:
Solana Playground will generate a wallet for you (or you can import your own). Feel free to save it for later use if you like, and click continue when you're ready. A new wallet will be initiated and connected to Solana devnet. Solana Playground airdrops some SOL to your new wallet automatically, but we will request a little extra to ensure we have enough for deploying our program. In the browser terminal, you can use Solana CLI commands. Enter solana airdrop 2 to drop 2 SOL into your wallet. Your wallet should now be connected to devnet with a balance of 6 SOL:
You are ready to go! Let's build!
Create a Counter Account
Create Initialize Structs
To count how many times our "hello_world" function has been called, we will need to create a new data account owned by our program. That data account will need two new structs:
1. an Account struct, Counter that will be used to keep track of our count (this will be an unsigned 64-bit integer, u64). #[account] pulls in some of the muscle of Anchor that does a lot of heavy lifting for us regarding serializing and deserializing our data.
#[account]
pub struct Counter {
count: u64
}
2. a new Context will be used to create a new counter account. The context, Initialize, will tell our program which Public Keys we will need to provide when sending our transaction instructions from the client. #[derive(Accounts)] is abstracting a lot of content for us--we will cover that in a future guide. For now, know that Anchor is simplifying our code quite a bit!
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = signer, space = 8 + 8)]
pub counter: Account<'info, Counter>,
#[account(mut)]
pub signer: Signer<'info>,
pub system_program: Program<'info, System>,
}
Our Initialize struct will require three Public Keys:
- counter, the public key of the new data account we are creating (of type, Counter created above). Note here that we must pass a few arguments to initiate our new account:
- init to tell Anchor that we are initializing a new account.
- defining a public key responsible for paying the rent associated with the new account (payer), which we have set to our signer
- space is used to calculate how many bytes our account will need (more bytes require more rent, so we want to be accurate with our requirements). We will need 8 bytes for our account discriminator (required for every account) and 8 bytes for our u64. See Anchor's Space Reference Guide for space requirements for all types.
- signer, the wallet responsible for signing the initialize transaction (and for paying the fees outlined above).
- system_program, which will own our new account and handle the SOL transfer between accounts
Create Initialize Counter Function
Great! Now that our structs are defined, we need to create an initialize function. Inside of hello_world after the say_hello function, create a new function, initialize_counter:
pub fn initialize_counter(ctx: Context<Initialize>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.count = 0;
msg!("Initialized new count. Current value: {}!", counter.count);
Ok(())
}
Our function will pass a context, ctx, of type Initialize (from our previous step). Because we have included all of the necessary account information in our Initialize struct, Anchor can do most of the heavy lifting for us to create our new account. However, we need to call our counter account and set its initial value to 0. Because we are modifying counter, we must tag the variable as mutable using &mut. Finally, we will add a log show that our counter has been initiated with the correct initial balance. Anchor will make sure our data is serialized correctly!
Great job! Let's create our counter.
Initialize Counter from Client
First, we will need to Build and Update our program:
-
Click