Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example using the instructions array for a state RPC #84 #2501

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/tutorial/basic-5/.gitignore
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

.anchor
.DS_Store
target
**/*.rs.bk
node_modules
test-ledger
8 changes: 8 additions & 0 deletions examples/tutorial/basic-5/.prettierignore
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

.anchor
.DS_Store
target
node_modules
dist
build
test-ledger
15 changes: 15 additions & 0 deletions examples/tutorial/basic-5/Anchor.toml
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[features]
seeds = false
skip-lint = false
lastemp marked this conversation as resolved.
Show resolved Hide resolved
[programs.localnet]
basic_5 = "DuT6R8tQGYa8ACYXyudFJtxDppSALLcmK39b7918jeSC"

[registry]
url = "https://api.apr.dev"
lastemp marked this conversation as resolved.
Show resolved Hide resolved

[provider]
cluster = "Localnet"
lastemp marked this conversation as resolved.
Show resolved Hide resolved
wallet = "/home/xxxx/.config/solana/id.json"
lastemp marked this conversation as resolved.
Show resolved Hide resolved

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

[profile.release]
overflow-checks = true
lto = "fat"
codegen-units = 1
[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
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.

Below are some basic features contained in the program;

i. Create <br />
ii. Walk <br />
iii. Run <br />
iv. Jump <br />
v. Reset <br />
lastemp marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions examples/tutorial/basic-5/migrations/deploy.ts
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Migrations are an early feature. Currently, they're nothing more than this
// single deploy script that's invoked from the CLI, injecting a provider
// configured from the workspace's Anchor.toml.

const anchor = require("@project-serum/anchor");

module.exports = async function (provider) {
// Configure client to use the provider.
anchor.setProvider(provider);

// Add your deploy script here.
};
19 changes: 19 additions & 0 deletions examples/tutorial/basic-5/package.json
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"scripts": {
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
},
"dependencies": {
"@project-serum/anchor": "^0.26.0"
},
"devDependencies": {
"chai": "^4.3.4",
"mocha": "^9.0.3",
"ts-mocha": "^10.0.0",
"@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0",
"typescript": "^4.3.5",
"prettier": "^2.6.2"
}
}
19 changes: 19 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,19 @@
[package]
name = "basic-5"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

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

[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = []

[dependencies]
anchor-lang = "0.26.0"
lastemp marked this conversation as resolved.
Show resolved Hide resolved
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 = []
118 changes: 118 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,118 @@
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=ActionState::LEN, seeds=[b"action-state".as_ref(), 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]
pub struct ActionState {
pub user: Pubkey,
pub action: u8,
}

const DISCRIMINATOR_LENGTH: usize = 8;
const PUBLIC_KEY_LENGTH: usize = 32;
const U8_LENGTH: usize = 1;

impl ActionState {
const LEN: usize = DISCRIMINATOR_LENGTH +
lastemp marked this conversation as resolved.
Show resolved Hide resolved
PUBLIC_KEY_LENGTH +
U8_LENGTH;
}
116 changes: 116 additions & 0 deletions examples/tutorial/basic-5/tests/basic-5.ts
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import * as anchor from "@project-serum/anchor";
lastemp marked this conversation as resolved.
Show resolved Hide resolved
import { Program } from "@project-serum/anchor";
import { Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
import { Basic5 } from "../target/types/basic_5";

describe("basic-5", () => {
// Configure the client to use the local cluster.
//anchor.setProvider(anchor.AnchorProvider.env());
let provider = anchor.AnchorProvider.local("http://127.0.0.1:8899")
lastemp marked this conversation as resolved.
Show resolved Hide resolved

const program = anchor.workspace.Basic5 as Program<Basic5>;
const user = anchor.web3.Keypair.generate();

let [action_state] = anchor.web3.PublicKey.findProgramAddressSync(
lastemp marked this conversation as resolved.
Show resolved Hide resolved
[anchor.utils.bytes.utf8.encode("action-state"),
user.publicKey.toBuffer()
],
program.programId);

before(async () => {

let res = await provider.connection.requestAirdrop(user.publicKey, 10 * anchor.web3.LAMPORTS_PER_SOL);

let latestBlockHash = await provider.connection.getLatestBlockhash()

await provider.connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: res,
});

});

it("basic-5: Robot actions!", async () => {

// Array of instructions
const instructions: TransactionInstruction[] = [
// First instruction: set up the Solana accounts to be used
program.instruction.create({
lastemp marked this conversation as resolved.
Show resolved Hide resolved
accounts: {
actionState: action_state,
user: user.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
}),
// Second instruction: Invoke the Robot to walk
program.instruction.walk({
accounts: {
actionState: action_state,
user: user.publicKey,
},
}),
// Third instruction: Invoke the Robot to run
program.instruction.run({
accounts: {
actionState: action_state,
user: user.publicKey,
},
}),
// Fourth instruction: Invoke the Robot to jump
program.instruction.jump({
accounts: {
actionState: action_state,
user: user.publicKey,
},
}),
// Fifth instruction: Reset actions of the Robot
program.instruction.reset({
accounts: {
actionState: action_state,
user: user.publicKey,
},
}),

];

createAndSendV0Tx(instructions);

});

async function createAndSendV0Tx(txInstructions: TransactionInstruction[]) {
// Step 1 - Fetch 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.publicKey,
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`
transaction.sign([user]);
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.") }
//console.log('🎉 Transaction Succesfully Confirmed!', '\n', `https://explorer.solana.com/tx/${txid}?cluster=devnet`);
console.log('🎉 Transaction Succesfully Confirmed!');
let result = await program.account.actionState.fetch(action_state);
console.log("robot action state details: ", result);
}

});
11 changes: 11 additions & 0 deletions examples/tutorial/basic-5/tsconfig.json
lastemp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"types": ["mocha", "chai"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}

Loading