Skip to content

Commit

Permalink
examples: Add an example with instruction method (coral-xyz#2501)
Browse files Browse the repository at this point in the history
Co-authored-by: acheron <acheroncrypto@gmail.com>
  • Loading branch information
2 people authored and vadorovsky committed Jun 20, 2023
1 parent 5b61de6 commit 5334ad9
Show file tree
Hide file tree
Showing 11 changed files with 433 additions and 7 deletions.
9 changes: 9 additions & 0 deletions examples/tutorial/basic-5/Anchor.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[provider]
cluster = "localnet"
wallet = "~/.config/solana/id.json"

[programs.localnet]
basic_5 = "DuT6R8tQGYa8ACYXyudFJtxDppSALLcmK39b7918jeSC"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
4 changes: 4 additions & 0 deletions examples/tutorial/basic-5/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[workspace]
members = [
"programs/*"
]
13 changes: 13 additions & 0 deletions examples/tutorial/basic-5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# basic-5

This is a robot program developed as a Rust Smart Contract(running on Solana Blockchain).
It simplifies actions of a robot on-chain.
This program acts as an example for developers who are new to Solana ecosystem to learn on how the typescript client interacts with the program on-chain.

Instructions of the program:

1. Create
2. Walk
3. Run
4. Jump
5. Reset
19 changes: 19 additions & 0 deletions examples/tutorial/basic-5/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "basic-5",
"version": "0.27.0",
"license": "(MIT OR Apache-2.0)",
"homepage": "https://github.com/coral-xyz/anchor#readme",
"bugs": {
"url": "https://github.com/coral-xyz/anchor/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/coral-xyz/anchor.git"
},
"engines": {
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
}
}
17 changes: 17 additions & 0 deletions examples/tutorial/basic-5/programs/basic-5/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "basic-5"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.60"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "basic_5"

[features]
no-entrypoint = []
cpi = ["no-entrypoint"]

[dependencies]
anchor-lang = { path = "../../../../../lang" }
2 changes: 2 additions & 0 deletions examples/tutorial/basic-5/programs/basic-5/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
115 changes: 115 additions & 0 deletions examples/tutorial/basic-5/programs/basic-5/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use anchor_lang::prelude::*;

declare_id!("DuT6R8tQGYa8ACYXyudFJtxDppSALLcmK39b7918jeSC");

#[program]
pub mod basic_5 {
use super::*;

pub fn create(ctx: Context<Create>) -> Result<()> {
let action_state = &mut ctx.accounts.action_state;
// * - means dereferencing
action_state.user = *ctx.accounts.user.key;
// Lets initialize the state
action_state.action = 0;

Ok(())
}

pub fn walk(ctx: Context<Walk>) -> Result<()> {
let action_state = &mut ctx.accounts.action_state;
// Lets change the robot action state to "walk"
action_state.action = 1;

Ok(())
}

pub fn run(ctx: Context<Run>) -> Result<()> {
let action_state = &mut ctx.accounts.action_state;
// Lets change the robot action state to "run"
action_state.action = 2;

Ok(())
}

pub fn jump(ctx: Context<Jump>) -> Result<()> {
let action_state = &mut ctx.accounts.action_state;
// Lets change the robot action state to "jump"
action_state.action = 3;

Ok(())
}

pub fn reset(ctx: Context<Reset>) -> Result<()> {
let action_state = &mut ctx.accounts.action_state;
// Lets reset the robot action states
action_state.action = 0;

Ok(())
}
}

#[derive(Accounts)]
pub struct Create<'info> {
// init means to create action_state account
// bump to use unique address for action_state account
#[account(
init,
payer = user,
space = 8 + ActionState::INIT_SPACE,
seeds = [b"action-state", user.key().as_ref()],
bump
)]
pub action_state: Account<'info, ActionState>,
// mut makes it changeble (mutable)
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Walk<'info> {
// Only the user on account action_state, should be able to change state
#[account(mut, has_one = user)]
pub action_state: Account<'info, ActionState>,
// mut makes it changeble (mutable)
#[account(mut)]
pub user: Signer<'info>,
}

#[derive(Accounts)]
pub struct Run<'info> {
// Only the user on account action_state, should be able to change state
#[account(mut, has_one = user)]
pub action_state: Account<'info, ActionState>,
// mut makes it changeble (mutable)
#[account(mut)]
pub user: Signer<'info>,
}

#[derive(Accounts)]
pub struct Jump<'info> {
// Only the user on account action_state, should be able to change state
#[account(mut, has_one = user)]
pub action_state: Account<'info, ActionState>,
// mut makes it changeble (mutable)
#[account(mut)]
pub user: Signer<'info>,
}

#[derive(Accounts)]
pub struct Reset<'info> {
// Only the user on account action_state, should be able to change state
#[account(mut, has_one = user)]
pub action_state: Account<'info, ActionState>,
// mut makes it changeble (mutable)
#[account(mut)]
pub user: Signer<'info>,
}

#[account]
#[derive(InitSpace)]
pub struct ActionState {
pub user: Pubkey,
pub action: u8,
}
123 changes: 123 additions & 0 deletions examples/tutorial/basic-5/tests/basic-5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as anchor from "@coral-xyz/anchor";
import {
TransactionInstruction,
TransactionMessage,
VersionedTransaction,
} from "@solana/web3.js";
import { Basic5 } from "../target/types/basic_5";

describe("basic-5", () => {
const provider = anchor.AnchorProvider.local();

// Configure the client to use the local cluster.
anchor.setProvider(provider);

const program = anchor.workspace.Basic5 as anchor.Program<Basic5>;
const user = provider.wallet.publicKey;

let [actionState] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("action-state"), user.toBuffer()],
program.programId
);

it("basic-5: Robot actions!", async () => {
// Create instruction: set up the Solana accounts to be used
const createInstruction = await program.methods
.create()
.accounts({
actionState,
user,
systemProgram: anchor.web3.SystemProgram.programId,
})
.instruction();
// Walk instruction: Invoke the Robot to walk
const walkInstruction = await program.methods
.walk()
.accounts({
actionState,
user,
})
.instruction();
// Run instruction: Invoke the Robot to run
const runInstruction = await program.methods
.run()
.accounts({
actionState,
user,
})
.instruction();
// Jump instruction: Invoke the Robot to jump
const jumpInstruction = await program.methods
.jump()
.accounts({
actionState,
user,
})
.instruction();
// Reset instruction: Reset actions of the Robot
const resetInstruction = await program.methods
.reset()
.accounts({
actionState,
user,
})
.instruction();

// Array of instructions
const instructions: TransactionInstruction[] = [
createInstruction,
walkInstruction,
runInstruction,
jumpInstruction,
resetInstruction,
];

await createAndSendV0Tx(instructions);
});

async function createAndSendV0Tx(txInstructions: TransactionInstruction[]) {
// Step 1 - Fetch the latest blockhash
let latestBlockhash = await provider.connection.getLatestBlockhash(
"confirmed"
);
console.log(
" ✅ - Fetched latest blockhash. Last Valid Height:",
latestBlockhash.lastValidBlockHeight
);

// Step 2 - Generate Transaction Message
const messageV0 = new TransactionMessage({
payerKey: user,
recentBlockhash: latestBlockhash.blockhash,
instructions: txInstructions,
}).compileToV0Message();
console.log(" ✅ - Compiled Transaction Message");
const transaction = new VersionedTransaction(messageV0);

// Step 3 - Sign your transaction with the required `Signers`
provider.wallet.signTransaction(transaction);
console.log(" ✅ - Transaction Signed");

// Step 4 - Send our v0 transaction to the cluster
const txid = await provider.connection.sendTransaction(transaction, {
maxRetries: 5,
});
console.log(" ✅ - Transaction sent to network");

// Step 5 - Confirm Transaction
const confirmation = await provider.connection.confirmTransaction({
signature: txid,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
});
if (confirmation.value.err) {
throw new Error(
` ❌ - Transaction not confirmed.\nReason: ${confirmation.value.err}`
);
}

console.log("🎉 Transaction Succesfully Confirmed!");
let result = await program.account.actionState.fetch(actionState);
console.log("Robot action state details: ", result);
}
});
10 changes: 10 additions & 0 deletions examples/tutorial/basic-5/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"types": ["mocha"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}
10 changes: 7 additions & 3 deletions examples/tutorial/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@
"basic-1",
"basic-2",
"basic-3",
"basic-4"
"basic-4",
"basic-5"
],
"dependencies": {
"@coral-xyz/anchor": "file:../../ts/packages/anchor"
},
"devDependencies": {
"mocha": "9.2.2",
"prettier": "^2.5.1"
"mocha": "^9.2.2",
"prettier": "^2.5.1",
"@types/mocha": "^9.1.1",
"ts-mocha": "^10.0.0",
"typescript": "^4.9.5"
}
}
Loading

0 comments on commit 5334ad9

Please sign in to comment.