How to Build a Counter Program with Anchor
https://beta.solpg.io/66624e49cffcf4b13384d14b
Starter Code
- open solana playground
- starter code
lib.ts
use anchor_lang::prelude::*;
declare_id!("");
#[program]
pub mod counter {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
pub fn increment(_ctx: Context<Increment>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
#[derive(Accounts)]
pub struct Increment {}
#[account]
pub struct Counter {}
Terminal
build
Output
$ build
Building...
Build successful. Completed in 3.82s.
Define Counter Account Type
lib.ts
#[account]
pub struct Counter {
pub count: u64,
}
Diff
+ #[account]
+ pub struct Counter {
+ pub count: u64,
+ }
- #[account]
- pub struct Counter {}
Terminal
build
Implement Initialize Instruction
- define required accounts
lib.ts
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
payer = user,
space = 8 + 8
)]
pub counter: Account<'info, Counter>,
pub system_program: Program<'info, System>,
}
Diff
- #[derive(Accounts)]
- pub struct Initialize {}
+ #[derive(Accounts)]
+ pub struct Initialize<'info> {
+ #[account(mut)]
+ pub user: Signer<'info>,
+
+ #[account(
+ init,
+ payer = user,
+ space = 8 + 8
+ )]
+ pub counter: Account<'info, Counter>,
+ pub system_program: Program<'info, System>,
+ }
- implement instruction
lib.ts
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let counter = &ctx.accounts.counter;
msg!("Counter account created! Current count: {}", counter.count);
Ok(())
}
Diff
- pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
- Ok(())
- }
+ pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
+ let counter = &ctx.accounts.counter;
+ msg!("Counter account created! Current count: {}", counter.count);
+ Ok(())
+ }
Terminal
build
Implement Increment Instruction
- define required accounts
lib.ts
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut)]
pub counter: Account<'info, Counter>,
}
Diff
- #[derive(Accounts)]
- pub struct Increment {}
+ #[derive(Accounts)]
+ pub struct Increment<'info> {
+ #[account(mut)]
+ pub counter: Account<'info, Counter>,
+ }
- implement instruction
lib.ts
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
msg!("Previous counter: {}", counter.count);
// Increment the count value stored on the counter account by 1
counter.count = counter.count + 1;
msg!("Counter incremented! Current count: {}", counter.count);
Ok(())
}
Diff
- pub fn increment(_ctx: Context<Increment>) -> Result<()> {
- Ok(())
- }
+ pub fn increment(ctx: Context<Increment>) -> Result<()> {
+ // Mutable reference to the counter account from the Increment struct
+ let counter = &mut ctx.accounts.counter;
+ msg!("Previous counter: {}", counter.count);
+
+ // Increment the count value stored on the counter account by 1
+ counter.count = counter.count + 1;
+ msg!("Counter incremented! Current count: {}", counter.count);
+ Ok(())
+ }
Terminal
build
Deploy Program
- deploy program, airdrop if needed
Terminal
deploy
Output
$ deploy
Deploying... This could take a while depending on the program size and network conditions.
Deployment successful. Completed in 17s.
Test File Setup
anchor.test.ts
import { Keypair } from "@solana/web3.js";
describe("counter", () => {
const program = pg.program;
// Generate a new keypair to use as the address the counter account
const counterAccount = new Keypair();
it("Is initialized!", async () => {});
it("Increment", async () => {});
});
Invoke Initialize Instruction
anchor.test.ts
it("Is initialized!", async () => {
// Invoke the initialize instruction
const transactionSignature = await program.methods
.initialize()
.accounts({
counter: counterAccount.publicKey,
})
.signers([counterAccount]) // include counter keypair as additional signer
.rpc({ skipPreflight: true });
// Fetch the counter account data
const accountData = await program.account.counter.fetch(
counterAccount.publicKey,
);
console.log(`Transaction Signature: ${transactionSignature}`);
console.log(`Count: ${accountData.count}`);
});
Diff
- it("Is initialized!", async () => {});
+ it("Is initialized!", async () => {
+ // Invoke the initialize instruction
+ const transactionSignature = await program.methods
+ .initialize()
+ .accounts({
+ counter: counterAccount.publicKey,
+ })
+ .signers([counterAccount]) // include counter keypair as additional signer
+ .rpc({ skipPreflight: true });
+
+ // Fetch the counter account data
+ const accountData = await program.account.counter.fetch(
+ counterAccount.publicKey,
+ );
+
+ console.log(`Transaction Signature: ${transactionSignature}`);
+ console.log(`Count: ${accountData.count}`);
+ });
Invoke Increment Instruction
anchor.test.ts
it("Increment", async () => {
// Invoke the increment instruction
const transactionSignature = await program.methods
.increment()
.accounts({
counter: counterAccount.publicKey,
})
.rpc();
// Fetch the counter account data
const accountData = await program.account.counter.fetch(
counterAccount.publicKey,
);
console.log(`Transaction Signature: ${transactionSignature}`);
console.log(`Count: ${accountData.count}`);
});
Diff
- it("Increment", async () => {});
+ it("Increment", async () => {
+ // Invoke the increment instruction
+ const transactionSignature = await program.methods
+ .increment()
+ .accounts({
+ counter: counterAccount.publicKey,
+ })
+ .rpc();
+
+ // Fetch the counter account data
+ const accountData = await program.account.counter.fetch(
+ counterAccount.publicKey,
+ );
+
+ console.log(`Transaction Signature: ${transactionSignature}`);
+ console.log(`Count: ${accountData.count}`);
+ });
Run Test
- run test
Terminal
test
Output
Running tests...
anchor.test.ts:
counter
Transaction Signature: 3pVEPm3SEzr64eLqkauMQBLWHQQ5aiZUoNDnwUWfSe1TGeTEP7njy7sGFgnG6mcEWE7BfAnLhSbZRhdCxyHvGDF9
Count: 0
✔ Is initialized! (2406ms)
Transaction Signature: 56aQPsuWjyDV2vhuvhtfZ5NkbnGmTuiQVQakUEM8mEE3HWGir9rufxKYaN8m6byX2urEwSDdNF8SHDkdzyEVtxc9
Count: 1
✔ Increment (897ms)
2 passing (3s)
Close Program
- run test
Terminal
solana program close <program_id>
Terminal
solana program close J2WA6mGXrutGo1ZSRijNWh7tDPmLbZm8UmQfffwVEHhq
Output
$ solana program close J2WA6mGXrutGo1ZSRijNWh7tDPmLbZm8UmQfffwVEHhq
Loading Solana CLI...
Success.
Closed Program Id J2WA6mGXrutGo1ZSRijNWh7tDPmLbZm8UmQfffwVEHhq, 2.85580632 SOL reclaimed