Skip to content

Commit c87324a

Browse files
feat: add Quasar variants for hello-solana, counter, and transfer-sol
Add Quasar framework implementations alongside existing Anchor, native, and Pinocchio variants for three basic examples: - hello-solana: logs a greeting and the program ID - counter: initialize + increment with PDA-derived state - transfer-sol: CPI transfer via system program + direct lamport manipulation Each is a standalone Cargo project (not in root workspace) with: - Program source using quasar-lang macros - Auto-generated client crate via quasar build - Tests using quasar-svm All examples build with 'quasar build' and pass 'quasar test'.
1 parent 6063401 commit c87324a

24 files changed

Lines changed: 650 additions & 0 deletions

File tree

basics/counter/quasar/.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Build artifacts
2+
/target
3+
4+
# Dependencies
5+
node_modules
6+
7+
# Environment
8+
.env
9+
.env.*
10+
11+
# OS
12+
.DS_Store

basics/counter/quasar/Cargo.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[package]
2+
name = "quasar-counter"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# Standalone workspace — not part of the root program-examples workspace.
7+
# Quasar uses a different resolver and dependency tree.
8+
[workspace]
9+
10+
[lints.rust.unexpected_cfgs]
11+
level = "warn"
12+
check-cfg = [
13+
'cfg(target_os, values("solana"))',
14+
]
15+
16+
[lib]
17+
crate-type = ["cdylib"]
18+
19+
[features]
20+
alloc = []
21+
client = []
22+
debug = []
23+
24+
[dependencies]
25+
quasar-lang = "0.0"
26+
solana-instruction = { version = "3.2.0" }
27+
28+
[dev-dependencies]
29+
quasar-counter-client = { path = "target/client/rust/quasar-counter-client" }
30+
quasar-svm = { version = "0.1" }
31+
solana-account = { version = "3.4.0" }
32+
solana-address = { version = "2.2.0", features = ["decode"] }
33+
solana-instruction = { version = "3.2.0", features = ["bincode"] }
34+
solana-pubkey = { version = "4.1.0" }

basics/counter/quasar/Quasar.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[project]
2+
name = "quasar_counter"
3+
4+
[toolchain]
5+
type = "solana"
6+
7+
[testing]
8+
language = "rust"
9+
10+
[testing.rust]
11+
framework = "quasar-svm"
12+
13+
[testing.rust.test]
14+
program = "cargo"
15+
args = [
16+
"test",
17+
"tests::",
18+
]
19+
20+
[clients]
21+
languages = ["rust"]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use {
2+
crate::state::Counter,
3+
quasar_lang::prelude::*,
4+
};
5+
6+
/// Accounts for incrementing a counter.
7+
#[derive(Accounts)]
8+
pub struct Increment<'info> {
9+
#[account(mut)]
10+
pub counter: &'info mut Account<Counter>,
11+
}
12+
13+
impl<'info> Increment<'info> {
14+
#[inline(always)]
15+
pub fn increment(&mut self) -> Result<(), ProgramError> {
16+
let current: u64 = self.counter.count.into();
17+
self.counter.count = PodU64::from(current.checked_add(1).unwrap());
18+
Ok(())
19+
}
20+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use {
2+
crate::state::Counter,
3+
quasar_lang::prelude::*,
4+
};
5+
6+
/// Accounts for creating a new counter.
7+
/// The counter is derived as a PDA from ["counter", payer] seeds.
8+
#[derive(Accounts)]
9+
pub struct InitializeCounter<'info> {
10+
#[account(mut)]
11+
pub payer: &'info mut Signer,
12+
#[account(mut, init, payer = payer, seeds = [b"counter", payer], bump)]
13+
pub counter: &'info mut Account<Counter>,
14+
pub system_program: &'info Program<System>,
15+
}
16+
17+
impl<'info> InitializeCounter<'info> {
18+
#[inline(always)]
19+
pub fn initialize_counter(&mut self) -> Result<(), ProgramError> {
20+
self.counter.set_inner(0u64);
21+
Ok(())
22+
}
23+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod initialize_counter;
2+
pub mod increment;
3+
4+
pub use initialize_counter::*;
5+
pub use increment::*;

basics/counter/quasar/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![cfg_attr(not(test), no_std)]
2+
3+
use quasar_lang::prelude::*;
4+
5+
mod instructions;
6+
use instructions::*;
7+
mod state;
8+
#[cfg(test)]
9+
mod tests;
10+
11+
declare_id!("HYSDBQLVUSMRQKQZxfKJwDy5PPrZb7bvuBLaWfbcYhEP");
12+
13+
#[program]
14+
mod quasar_counter {
15+
use super::*;
16+
17+
#[instruction(discriminator = 0)]
18+
pub fn initialize_counter(ctx: Ctx<InitializeCounter>) -> Result<(), ProgramError> {
19+
ctx.accounts.initialize_counter()
20+
}
21+
22+
#[instruction(discriminator = 1)]
23+
pub fn increment(ctx: Ctx<Increment>) -> Result<(), ProgramError> {
24+
ctx.accounts.increment()
25+
}
26+
}

basics/counter/quasar/src/state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use quasar_lang::prelude::*;
2+
3+
/// On-chain counter account.
4+
#[account(discriminator = 1)]
5+
pub struct Counter {
6+
pub count: u64,
7+
}

basics/counter/quasar/src/tests.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use quasar_svm::{Account, Instruction, Pubkey, QuasarSvm};
2+
use solana_address::Address;
3+
4+
use quasar_counter_client::{InitializeCounterInstruction, IncrementInstruction};
5+
6+
fn setup() -> QuasarSvm {
7+
let elf = include_bytes!("../target/deploy/quasar_counter.so");
8+
QuasarSvm::new().with_program(&Pubkey::from(crate::ID), elf)
9+
}
10+
11+
fn signer(address: Pubkey) -> Account {
12+
quasar_svm::token::create_keyed_system_account(&address, 10_000_000_000)
13+
}
14+
15+
fn empty(address: Pubkey) -> Account {
16+
Account {
17+
address,
18+
lamports: 0,
19+
data: vec![],
20+
owner: quasar_svm::system_program::ID,
21+
executable: false,
22+
}
23+
}
24+
25+
#[test]
26+
fn test_initialize_counter() {
27+
let mut svm = setup();
28+
29+
let payer = Pubkey::new_unique();
30+
let system_program = quasar_svm::system_program::ID;
31+
32+
// Derive the counter PDA from ["counter", payer].
33+
let (counter, _) = Pubkey::find_program_address(
34+
&[b"counter", payer.as_ref()],
35+
&Pubkey::from(crate::ID),
36+
);
37+
38+
let instruction: Instruction = InitializeCounterInstruction {
39+
payer: Address::from(payer.to_bytes()),
40+
counter: Address::from(counter.to_bytes()),
41+
system_program: Address::from(system_program.to_bytes()),
42+
}
43+
.into();
44+
45+
let result = svm.process_instruction(
46+
&instruction,
47+
&[signer(payer), empty(counter)],
48+
);
49+
50+
result.assert_success();
51+
52+
// Verify the counter account was created with count = 0.
53+
let counter_account = result.account(&counter).unwrap();
54+
// Data: 1 byte discriminator (1) + 8 bytes u64 (0)
55+
assert_eq!(counter_account.data.len(), 9);
56+
assert_eq!(counter_account.data[0], 1); // discriminator
57+
assert_eq!(&counter_account.data[1..], &[0u8; 8]); // count = 0
58+
}
59+
60+
#[test]
61+
fn test_increment() {
62+
let mut svm = setup();
63+
64+
let payer = Pubkey::new_unique();
65+
let system_program = quasar_svm::system_program::ID;
66+
67+
// Derive the counter PDA.
68+
let (counter, _) = Pubkey::find_program_address(
69+
&[b"counter", payer.as_ref()],
70+
&Pubkey::from(crate::ID),
71+
);
72+
73+
// First, initialise the counter.
74+
let init_instruction: Instruction = InitializeCounterInstruction {
75+
payer: Address::from(payer.to_bytes()),
76+
counter: Address::from(counter.to_bytes()),
77+
system_program: Address::from(system_program.to_bytes()),
78+
}
79+
.into();
80+
81+
let result = svm.process_instruction(
82+
&init_instruction,
83+
&[signer(payer), empty(counter)],
84+
);
85+
result.assert_success();
86+
87+
// Grab updated accounts after init.
88+
let counter_after_init = result.account(&counter).unwrap().clone();
89+
90+
// Increment the counter.
91+
let increment_instruction: Instruction = IncrementInstruction {
92+
counter: Address::from(counter.to_bytes()),
93+
}
94+
.into();
95+
96+
let result = svm.process_instruction(
97+
&increment_instruction,
98+
&[counter_after_init],
99+
);
100+
result.assert_success();
101+
102+
// Verify count = 1.
103+
let counter_account = result.account(&counter).unwrap();
104+
let count_bytes: [u8; 8] = counter_account.data[1..9].try_into().unwrap();
105+
let count = u64::from_le_bytes(count_bytes);
106+
assert_eq!(count, 1, "counter should be 1 after one increment");
107+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Build artifacts
2+
/target
3+
4+
# Dependencies
5+
node_modules
6+
7+
# Environment
8+
.env
9+
.env.*
10+
11+
# OS
12+
.DS_Store

0 commit comments

Comments
 (0)