Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 3 additions & 2 deletions basics/cross-program-invocation/native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
"type": "module",
"scripts": {
"test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts",
"build-and-test": "cargo build-sbf --sbf-out-dir=./tests/fixtures && pnpm test",
"build-and-test": "cargo build-sbf --sbf-out-dir=./tests/fixtures --manifest-path=programs/lever/Cargo.toml && cargo build-sbf --sbf-out-dir=./tests/fixtures --manifest-path=programs/hand/Cargo.toml && pnpm test",
"build": "cargo build-sbf --sbf-out-dir=./program/target/so",
"deploy": "solana program deploy ./program/target/so/program.so"
},
"dependencies": {
"@solana/web3.js": "^1.98.4",
"borsh": "^2.0.0",
"buffer": "^6.0.3",
"fs": "^0.0.1-security"
"fs": "^0.0.1-security",
"litesvm": "0.8.0"
},
"devDependencies": {
"@types/bn.js": "^5.1.0",
Expand Down
83 changes: 83 additions & 0 deletions basics/cross-program-invocation/native/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 84 additions & 27 deletions basics/cross-program-invocation/native/tests/test.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,127 @@
import { Buffer } from "node:buffer";
import { LiteSVM, TransactionMetadata } from "litesvm";
import {
Connection,
Keypair,
SystemProgram,
sendAndConfirmTransaction,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import * as borsh from "borsh";
import * as path from "path";
import * as fs from "node:fs";
import * as os from "node:os";
import { describe, it, before } from "node:test";

function createKeypairFromFile(path: string): Keypair {
return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(require("node:fs").readFileSync(path, "utf-8"))));
const PowerStatusSchema = { struct: { is_on: "u8" } };
const SetPowerStatusSchema = { struct: { name: "string" } };

function borshSerialize(schema: borsh.Schema, data: object): Buffer {
return Buffer.from(borsh.serialize(schema, data));
}

describe("CPI Example", () => {
const connection = new Connection("http://localhost:8899", "confirmed");
const payer = createKeypairFromFile(`${require("node:os").homedir()}/.config/solana/id.json`);
const hand = createKeypairFromFile("./target/so/hand-keypair.json");
const lever = createKeypairFromFile("./target/so/lever-keypair.json");
describe("Native CPI Example", () => {
let svm: LiteSVM;
let payer: Keypair;
let handProgramId: Keypair;
let leverProgramId: Keypair;
let powerAccount: Keypair;

before(() => {
svm = new LiteSVM();
payer = Keypair.generate();

handProgramId = Keypair.fromSecretKey(
Uint8Array.from(
JSON.parse(fs.readFileSync("./tests/fixtures/cross_program_invocatio_native_hand-keypair.json", "utf-8"))
)
);
leverProgramId = Keypair.fromSecretKey(
Uint8Array.from(
JSON.parse(fs.readFileSync("./tests/fixtures/cross_program_invocatio_native_lever-keypair.json", "utf-8"))
)
);

svm.airdrop(payer.publicKey, BigInt(10 * 1_000_000_000));

const PowerStatusSchema = { struct: { is_on: "u8" } };
const SetPowerStatusSchema = { struct: { name: "string" } };
const native_hand = path.join("./tests/fixtures", "cross_program_invocatio_native_hand.so");
const native_lever = path.join("./tests/fixtures", "cross_program_invocatio_native_lever.so");

function borshSerialize(schema: borsh.Schema, data: object): Buffer {
return Buffer.from(borsh.serialize(schema, data));
}
svm.addProgramFromFile(
handProgramId.publicKey,
native_hand
);
svm.addProgramFromFile(
leverProgramId.publicKey,
native_lever
);

const powerAccount = Keypair.generate();
powerAccount = Keypair.generate();
});

it("Initialize the lever!", async () => {
it("Initialize the lever!", () => {
const ix = new TransactionInstruction({
keys: [
{ pubkey: powerAccount.publicKey, isSigner: true, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
programId: lever.publicKey,
data: borshSerialize(PowerStatusSchema, { is_on: true }),
programId: leverProgramId.publicKey,
data: borshSerialize(PowerStatusSchema, { is_on: 1 }),
});

await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer, powerAccount]);
const tx = new Transaction();
tx.recentBlockhash = svm.latestBlockhash();
tx.feePayer = payer.publicKey;
tx.add(ix);
tx.sign(payer, powerAccount);

const res = svm.sendTransaction(tx);
if (!(res instanceof TransactionMetadata)) {
throw new Error(`Transaction failed: ${res.meta().toString()}`);
}
});

it("Pull the lever!", async () => {
it("Pull the lever!", () => {
const ix = new TransactionInstruction({
keys: [
{ pubkey: powerAccount.publicKey, isSigner: false, isWritable: true },
{ pubkey: lever.publicKey, isSigner: false, isWritable: false },
{ pubkey: leverProgramId.publicKey, isSigner: false, isWritable: false },
],
programId: hand.publicKey,
programId: handProgramId.publicKey,
data: borshSerialize(SetPowerStatusSchema, { name: "Chris" }),
});

await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
const tx = new Transaction();
tx.recentBlockhash = svm.latestBlockhash();
tx.feePayer = payer.publicKey;
tx.add(ix);
tx.sign(payer);

const res = svm.sendTransaction(tx);
if (!(res instanceof TransactionMetadata)) {
throw new Error(`Transaction failed: ${res.meta().toString()}`);
}
});

it("Pull it again!", async () => {
it("Pull it again!", () => {
const ix = new TransactionInstruction({
keys: [
{ pubkey: powerAccount.publicKey, isSigner: false, isWritable: true },
{ pubkey: lever.publicKey, isSigner: false, isWritable: false },
{ pubkey: leverProgramId.publicKey, isSigner: false, isWritable: false },
],
programId: hand.publicKey,
programId: handProgramId.publicKey,
data: borshSerialize(SetPowerStatusSchema, { name: "Ashley" }),
});

await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
const tx = new Transaction();
tx.recentBlockhash = svm.latestBlockhash();
tx.feePayer = payer.publicKey;
tx.add(ix);
tx.sign(payer);

const res = svm.sendTransaction(tx);
if (!(res instanceof TransactionMetadata)) {
throw new Error(`Transaction failed: ${res.meta().toString()}`);
}
});
});