diff --git a/.gitignore b/.gitignore index 406e30870..d137957db 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ node_modules/ /target deploy +.claude diff --git a/basics/account-data/quasar/Cargo.toml b/basics/account-data/quasar/Cargo.toml index a5999e69d..993ca2b42 100644 --- a/basics/account-data/quasar/Cargo.toml +++ b/basics/account-data/quasar/Cargo.toml @@ -22,13 +22,13 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] # Not using the generated client: it depends on quasar_lang::client::DynBytes # which isn't in the published crate yet. Tests build instruction data manually. -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/account-data/quasar/src/instructions/create.rs b/basics/account-data/quasar/src/instructions/create.rs index 1cb4a5a12..1a3503e00 100644 --- a/basics/account-data/quasar/src/instructions/create.rs +++ b/basics/account-data/quasar/src/instructions/create.rs @@ -1,33 +1,31 @@ use { - crate::state::AddressInfo, - quasar_lang::prelude::*, + crate::state::{AddressInfo, AddressInfoInner}, + quasar_lang::{prelude::*, sysvars::Sysvar}, }; /// Accounts for creating a new address info account. -/// Dynamic accounts use owned `Account` rather than `&'info mut Account` because -/// dynamic types carry cached byte offsets that cannot be represented as a pointer cast. #[derive(Accounts)] -pub struct CreateAddressInfo<'info> { +pub struct CreateAddressInfo { #[account(mut)] - pub payer: &'info mut Signer, - #[account(mut, init, payer = payer, seeds = [b"address_info", payer], bump)] - pub address_info: Account>, - pub system_program: &'info Program, + pub payer: Signer, + #[account(mut, init, payer = payer, seeds = AddressInfo::seeds(payer), bump)] + pub address_info: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_create_address_info( - accounts: &mut CreateAddressInfo, name: &str, + accounts: &mut CreateAddressInfo, + name: &str, house_number: u8, street: &str, city: &str, ) -> Result<(), ProgramError> { + let rent = Rent::get()?; accounts.address_info.set_inner( - house_number, - name, - street, - city, + AddressInfoInner { house_number, name, street, city }, accounts.payer.to_account_view(), - None, + rent.lamports_per_byte(), + rent.exemption_threshold_raw(), ) } diff --git a/basics/account-data/quasar/src/lib.rs b/basics/account-data/quasar/src/lib.rs index 36253c9ae..cc6bb40c4 100644 --- a/basics/account-data/quasar/src/lib.rs +++ b/basics/account-data/quasar/src/lib.rs @@ -25,10 +25,10 @@ mod quasar_account_data { #[instruction(discriminator = 0)] pub fn create_address_info( ctx: Ctx, - name: String, house_number: u8, - street: String, - city: String, + name: String<50>, + street: String<50>, + city: String<50>, ) -> Result<(), ProgramError> { instructions::handle_create_address_info(&mut ctx.accounts, name, house_number, street, city) } diff --git a/basics/account-data/quasar/src/state.rs b/basics/account-data/quasar/src/state.rs index ba7a8e14f..e54e874cd 100644 --- a/basics/account-data/quasar/src/state.rs +++ b/basics/account-data/quasar/src/state.rs @@ -1,14 +1,12 @@ use quasar_lang::prelude::*; /// Onchain address info account with dynamic string fields. -/// Uses Quasar's `String` marker type for variable-length string data. -/// The lifetime `'a` is required because the generated code produces `&'a str` accessors. -/// /// Note: Quasar requires all fixed-size fields to precede dynamic (String/Vec) fields. -#[account(discriminator = 1)] -pub struct AddressInfo<'a> { +#[account(discriminator = 1, set_inner)] +#[seeds(b"address_info", payer: Address)] +pub struct AddressInfo { pub house_number: u8, - pub name: String, - pub street: String, - pub city: String, + pub name: String<50>, + pub street: String<50>, + pub city: String<50>, } diff --git a/basics/account-data/quasar/src/tests.rs b/basics/account-data/quasar/src/tests.rs index d95a14815..79eac1313 100644 --- a/basics/account-data/quasar/src/tests.rs +++ b/basics/account-data/quasar/src/tests.rs @@ -20,28 +20,28 @@ fn empty(address: Pubkey) -> Account { } } -/// Build create_address_info instruction data manually. +/// Build the create_address_info instruction data using Quasar's compact +/// wire format: a header containing all fixed fields and length prefixes, +/// followed by a tail with all dynamic byte payloads grouped together. /// -/// Wire format (from reading the #[instruction] codegen): -/// [disc: 1 byte] -/// [ZC struct: house_number u8] -/// [name: u32 LE length prefix + bytes] (String → DynKind::Str with U32 prefix) -/// [street: u32 LE length prefix + bytes] -/// [city: u32 LE length prefix + bytes] +/// Layout: +/// header: [disc: u8 = 0][house_number: u8][name_len: u8][street_len: u8][city_len: u8] +/// tail: [name bytes][street bytes][city bytes] +/// +/// `String<50>` defaults to a u8 length prefix because MAX (50) fits in a byte. fn build_create_instruction_data(name: &str, house_number: u8, street: &str, city: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 + let mut data = Vec::with_capacity(5 + name.len() + street.len() + city.len()); - // Fixed ZC struct: house_number + // Header + data.push(0u8); // instruction discriminator data.push(house_number); + data.push(name.len() as u8); + data.push(street.len() as u8); + data.push(city.len() as u8); - // Dynamic String args with u32 length prefix - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + // Tail data.extend_from_slice(name.as_bytes()); - - data.extend_from_slice(&(street.len() as u32).to_le_bytes()); data.extend_from_slice(street.as_bytes()); - - data.extend_from_slice(&(city.len() as u32).to_le_bytes()); data.extend_from_slice(city.as_bytes()); data @@ -81,34 +81,25 @@ fn test_create_address_info() { // Verify the account data. let account = result.account(&address_info).unwrap(); - // Onchain layout (from #[account] dynamic codegen): - // [disc: 1 byte = 1] - // [ZC header: house_number u8] - // [name: u8 prefix + bytes] (String uses u8 prefix) - // [street: u8 prefix + bytes] - // [city: u8 prefix + bytes] + // Onchain layout for a Quasar `#[account]` with dynamic fields uses the + // compact "header then tail" format. Length prefixes are grouped in the + // header, the actual bytes follow in the tail. + // header: [disc: 1][house_number: u8][name_len: u8][street_len: u8][city_len: u8] + // tail: [name bytes][street bytes][city bytes] + // String<50> defaults to a u8 length prefix because MAX (50) fits in a byte. assert_eq!(account.data[0], 1, "discriminator"); assert_eq!(account.data[1], 42, "house_number"); - - let mut offset = 2; - - // name: u8 prefix + "Alice" - let name_len = account.data[offset] as usize; - offset += 1; + let name_len = account.data[2] as usize; + let street_len = account.data[3] as usize; + let city_len = account.data[4] as usize; assert_eq!(name_len, 5); - assert_eq!(&account.data[offset..offset + name_len], b"Alice"); - offset += name_len; - - // street: u8 prefix + "Main Street" - let street_len = account.data[offset] as usize; - offset += 1; assert_eq!(street_len, 11); - assert_eq!(&account.data[offset..offset + street_len], b"Main Street"); - offset += street_len; - - // city: u8 prefix + "New York" - let city_len = account.data[offset] as usize; - offset += 1; assert_eq!(city_len, 8); - assert_eq!(&account.data[offset..offset + city_len], b"New York"); + + let header_end = 5; + assert_eq!(&account.data[header_end..header_end + name_len], b"Alice"); + let street_start = header_end + name_len; + assert_eq!(&account.data[street_start..street_start + street_len], b"Main Street"); + let city_start = street_start + street_len; + assert_eq!(&account.data[city_start..city_start + city_len], b"New York"); } diff --git a/basics/checking-accounts/quasar/Cargo.toml b/basics/checking-accounts/quasar/Cargo.toml index 5ce153113..eec54aa7d 100644 --- a/basics/checking-accounts/quasar/Cargo.toml +++ b/basics/checking-accounts/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-checking-accounts-client = { path = "target/client/rust/quasar-checking-accounts-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/checking-accounts/quasar/src/instructions/check_accounts.rs b/basics/checking-accounts/quasar/src/instructions/check_accounts.rs index f64b05137..f25b55aef 100644 --- a/basics/checking-accounts/quasar/src/instructions/check_accounts.rs +++ b/basics/checking-accounts/quasar/src/instructions/check_accounts.rs @@ -8,21 +8,21 @@ use quasar_lang::prelude::*; /// Note: Anchor's `#[account(owner = id())]` owner constraint is not directly available /// in Quasar. Owner checks can be done manually in the instruction body if needed. #[derive(Accounts)] -pub struct CheckAccounts<'info> { +pub struct CheckAccounts { /// Checks that this account signed the transaction. - pub payer: &'info Signer, + pub payer: Signer, /// No checks performed — the caller is responsible for validation. #[account(mut)] - pub account_to_create: &'info mut UncheckedAccount, + pub account_to_create: UncheckedAccount, /// No automatic owner check in Quasar; see note above. #[account(mut)] - pub account_to_change: &'info mut UncheckedAccount, + pub account_to_change: UncheckedAccount, /// Checks the account is executable and matches the system program address. - pub system_program: &'info Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_check_accounts(accounts: &CheckAccounts) -> Result<(), ProgramError> { +pub fn handle_check_accounts(_accounts: &mut CheckAccounts) -> Result<(), ProgramError> { // All validation happens declaratively via the account types above. // If any check fails, the runtime rejects the transaction before this runs. Ok(()) diff --git a/basics/close-account/quasar/Cargo.toml b/basics/close-account/quasar/Cargo.toml index 1f3c9b00d..9da62371f 100644 --- a/basics/close-account/quasar/Cargo.toml +++ b/basics/close-account/quasar/Cargo.toml @@ -20,11 +20,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/close-account/quasar/src/instructions/close_user.rs b/basics/close-account/quasar/src/instructions/close_user.rs index c8444f2cd..ff56535f3 100644 --- a/basics/close-account/quasar/src/instructions/close_user.rs +++ b/basics/close-account/quasar/src/instructions/close_user.rs @@ -1,18 +1,15 @@ -use { - crate::state::UserState, - quasar_lang::prelude::*, -}; +use {crate::state::UserState, quasar_lang::prelude::*}; /// Accounts for closing a user account. /// The `close = user` attribute in the Anchor version triggers an automatic epilogue. /// In Quasar, we call `close()` explicitly — it zeros the discriminator, drains lamports /// to the destination, reassigns the owner to the system program, and resizes to 0. #[derive(Accounts)] -pub struct CloseUser<'info> { +pub struct CloseUser { #[account(mut)] - pub user: &'info mut Signer, + pub user: Signer, #[account(mut)] - pub user_account: Account>, + pub user_account: Account, } #[inline(always)] diff --git a/basics/close-account/quasar/src/instructions/create_user.rs b/basics/close-account/quasar/src/instructions/create_user.rs index 1f50705f5..be2da0b88 100644 --- a/basics/close-account/quasar/src/instructions/create_user.rs +++ b/basics/close-account/quasar/src/instructions/create_user.rs @@ -1,26 +1,30 @@ use { - crate::state::UserState, - quasar_lang::prelude::*, + crate::state::{UserState, UserStateInner}, + quasar_lang::{prelude::*, sysvars::Sysvar}, }; /// Accounts for creating a new user. #[derive(Accounts)] -pub struct CreateUser<'info> { +pub struct CreateUser { #[account(mut)] - pub user: &'info mut Signer, - #[account(mut, init, payer = user, seeds = [b"USER", user], bump)] - pub user_account: Account>, - pub system_program: &'info Program, + pub user: Signer, + #[account(mut, init, payer = user, seeds = UserState::seeds(user), bump)] + pub user_account: Account, + pub system_program: Program, } #[inline(always)] -pub fn handle_create_user(accounts: &mut CreateUser, name: &str, bump: u8) -> Result<(), ProgramError> { +pub fn handle_create_user( + accounts: &mut CreateUser, + name: &str, + bump: u8, +) -> Result<(), ProgramError> { let user_address = *accounts.user.to_account_view().address(); + let rent = Rent::get()?; accounts.user_account.set_inner( - bump, - user_address, - name, + UserStateInner { bump, user: user_address, name }, accounts.user.to_account_view(), - None, + rent.lamports_per_byte(), + rent.exemption_threshold_raw(), ) } diff --git a/basics/close-account/quasar/src/lib.rs b/basics/close-account/quasar/src/lib.rs index d8838eb01..64af1b7f3 100644 --- a/basics/close-account/quasar/src/lib.rs +++ b/basics/close-account/quasar/src/lib.rs @@ -16,7 +16,7 @@ mod quasar_close_account { /// Create a user account with a name. #[instruction(discriminator = 0)] - pub fn create_user(ctx: Ctx, name: String) -> Result<(), ProgramError> { + pub fn create_user(ctx: Ctx, name: String<50>) -> Result<(), ProgramError> { let bump = ctx.bumps.user_account; instructions::handle_create_user(&mut ctx.accounts, name, bump) } diff --git a/basics/close-account/quasar/src/state.rs b/basics/close-account/quasar/src/state.rs index fa9a9c925..6e3c71590 100644 --- a/basics/close-account/quasar/src/state.rs +++ b/basics/close-account/quasar/src/state.rs @@ -2,9 +2,10 @@ use quasar_lang::prelude::*; /// User account with a dynamic name field. /// Fixed fields (bump, user) must precede dynamic fields (name). -#[account(discriminator = 1)] -pub struct UserState<'a> { +#[account(discriminator = 1, set_inner)] +#[seeds(b"USER", user: Address)] +pub struct UserState { pub bump: u8, pub user: Address, - pub name: String, + pub name: String<50>, } diff --git a/basics/close-account/quasar/src/tests.rs b/basics/close-account/quasar/src/tests.rs index 370496f46..a1fcc3d5c 100644 --- a/basics/close-account/quasar/src/tests.rs +++ b/basics/close-account/quasar/src/tests.rs @@ -20,11 +20,15 @@ fn empty(address: Pubkey) -> Account { } } -/// Build create_user instruction data. -/// Wire format: [disc=0] [name: u32 prefix + bytes] +/// Build create_user instruction data using Quasar's compact wire format +/// (header then tail). `String<50>` defaults to a u8 length prefix. +/// +/// header: [disc: u8 = 0][name_len: u8] +/// tail: [name bytes] fn build_create_instruction(name: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + let mut data = Vec::with_capacity(2 + name.len()); + data.push(0u8); // discriminator + data.push(name.len() as u8); data.extend_from_slice(name.as_bytes()); data } diff --git a/basics/counter/quasar/Cargo.toml b/basics/counter/quasar/Cargo.toml index 7963c22b5..2ac1aa296 100644 --- a/basics/counter/quasar/Cargo.toml +++ b/basics/counter/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-counter-client = { path = "target/client/rust/quasar-counter-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/counter/quasar/src/instructions/increment.rs b/basics/counter/quasar/src/instructions/increment.rs index 989101f9e..0a6fc9b95 100644 --- a/basics/counter/quasar/src/instructions/increment.rs +++ b/basics/counter/quasar/src/instructions/increment.rs @@ -1,13 +1,10 @@ -use { - crate::state::Counter, - quasar_lang::prelude::*, -}; +use {crate::state::Counter, quasar_lang::prelude::*}; /// Accounts for incrementing a counter. #[derive(Accounts)] -pub struct Increment<'info> { +pub struct Increment { #[account(mut)] - pub counter: &'info mut Account, + pub counter: Account, } #[inline(always)] diff --git a/basics/counter/quasar/src/instructions/initialize_counter.rs b/basics/counter/quasar/src/instructions/initialize_counter.rs index 8d02d6df5..c7335c0cf 100644 --- a/basics/counter/quasar/src/instructions/initialize_counter.rs +++ b/basics/counter/quasar/src/instructions/initialize_counter.rs @@ -1,21 +1,19 @@ -use { - crate::state::Counter, - quasar_lang::prelude::*, -}; +use crate::state::{Counter, CounterInner}; +use quasar_lang::prelude::*; /// Accounts for creating a new counter. /// The counter is derived as a PDA from ["counter", payer] seeds. #[derive(Accounts)] -pub struct InitializeCounter<'info> { +pub struct InitializeCounter { #[account(mut)] - pub payer: &'info mut Signer, - #[account(mut, init, payer = payer, seeds = [b"counter", payer], bump)] - pub counter: &'info mut Account, - pub system_program: &'info Program, + pub payer: Signer, + #[account(mut, init, payer = payer, seeds = Counter::seeds(payer), bump)] + pub counter: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_initialize_counter(accounts: &mut InitializeCounter) -> Result<(), ProgramError> { - accounts.counter.set_inner(0u64); + accounts.counter.set_inner(CounterInner { count: 0 }); Ok(()) } diff --git a/basics/counter/quasar/src/state.rs b/basics/counter/quasar/src/state.rs index d97b5558e..988faa3e6 100644 --- a/basics/counter/quasar/src/state.rs +++ b/basics/counter/quasar/src/state.rs @@ -1,7 +1,8 @@ use quasar_lang::prelude::*; /// Onchain counter account. -#[account(discriminator = 1)] +#[account(discriminator = 1, set_inner)] +#[seeds(b"counter", payer: Address)] pub struct Counter { pub count: u64, } diff --git a/basics/create-account/quasar/Cargo.toml b/basics/create-account/quasar/Cargo.toml index d1e584d97..2c3e2cae2 100644 --- a/basics/create-account/quasar/Cargo.toml +++ b/basics/create-account/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-create-account-client = { path = "target/client/rust/quasar-create-account-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/create-account/quasar/src/instructions/create_system_account.rs b/basics/create-account/quasar/src/instructions/create_system_account.rs index 876e9883b..18f984ca0 100644 --- a/basics/create-account/quasar/src/instructions/create_system_account.rs +++ b/basics/create-account/quasar/src/instructions/create_system_account.rs @@ -1,28 +1,25 @@ -use quasar_lang::prelude::*; +use quasar_lang::{prelude::*, sysvars::Sysvar}; /// Accounts for creating a new system-owned account. /// Both payer and new_account must sign the transaction. #[derive(Accounts)] -pub struct CreateSystemAccount<'info> { +pub struct CreateSystemAccount { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub new_account: &'info Signer, - pub system_program: &'info Program, + pub new_account: Signer, + pub system_program: Program, } #[inline(always)] -pub fn handle_create_system_account(accounts: &CreateSystemAccount) -> Result<(), ProgramError> { - // Create a zero-data account owned by the system program, - // funded with the minimum rent-exempt balance. +pub fn handle_create_system_account( + accounts: &mut CreateSystemAccount, +) -> Result<(), ProgramError> { let system_program_address = Address::default(); - accounts.system_program - .create_account_with_minimum_balance( - accounts.payer, - accounts.new_account, - 0, // space: zero bytes of data - &system_program_address, - None, // fetch Rent sysvar automatically - )? + let rent = Rent::get()?; + let lamports = rent.minimum_balance_unchecked(0); + accounts + .system_program + .create_account(&accounts.payer, &accounts.new_account, lamports, 0u64, &system_program_address) .invoke() } diff --git a/basics/cross-program-invocation/quasar/hand/Cargo.toml b/basics/cross-program-invocation/quasar/hand/Cargo.toml index 55ec9838e..f86dd8f0c 100644 --- a/basics/cross-program-invocation/quasar/hand/Cargo.toml +++ b/basics/cross-program-invocation/quasar/hand/Cargo.toml @@ -21,11 +21,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/cross-program-invocation/quasar/hand/Quasar.toml b/basics/cross-program-invocation/quasar/hand/Quasar.toml index 3a8dba276..1ecfdff83 100644 --- a/basics/cross-program-invocation/quasar/hand/Quasar.toml +++ b/basics/cross-program-invocation/quasar/hand/Quasar.toml @@ -18,4 +18,5 @@ args = [ ] [clients] +path = "target/client" languages = ["rust"] diff --git a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs index 5713a60aa..7b15184c7 100644 --- a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs +++ b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs @@ -1,17 +1,14 @@ -use quasar_lang::{ - cpi::{BufCpiCall, InstructionAccount}, - prelude::*, -}; +use quasar_lang::prelude::*; /// Accounts for the hand program's pull_lever instruction. /// The lever_program uses `Program` with a custom marker type /// that implements `Id` — this lets Quasar verify the program address and /// the executable flag during account parsing. #[derive(Accounts)] -pub struct PullLever<'info> { +pub struct PullLever { #[account(mut)] - pub power: &'info UncheckedAccount, - pub lever_program: &'info Program, + pub power: UncheckedAccount, + pub lever_program: Program, } #[inline(always)] @@ -25,34 +22,22 @@ pub fn handle_pull_lever(accounts: &PullLever, name: &str) -> Result<(), Program let name_bytes = name.as_bytes(); let data_len = 1 + 4 + name_bytes.len(); - // Discriminator = 1 (switch_power) data[0] = 1; - // Name string: u32 little-endian length prefix + bytes let len_bytes = (name_bytes.len() as u32).to_le_bytes(); data[1] = len_bytes[0]; data[2] = len_bytes[1]; data[3] = len_bytes[2]; data[4] = len_bytes[3]; - // Copy name bytes let mut i = 0; while i < name_bytes.len() { data[5 + i] = name_bytes[i]; i += 1; } - let power_view = accounts.power.to_account_view(); - let lever_view = accounts.lever_program.to_account_view(); - - // Build CPI call with 1 account (power, writable, not a signer). - let cpi = BufCpiCall::<1, 128>::new( - lever_view.address(), - [InstructionAccount::writable(power_view.address())], - [power_view], - data, - data_len, - ); - + let mut cpi = DynCpiCall::<1, 128>::new(accounts.lever_program.address()); + cpi.push_account(accounts.power.to_account_view(), false, true)?; + cpi.set_data(&data[..data_len])?; cpi.invoke() } diff --git a/basics/cross-program-invocation/quasar/hand/src/lib.rs b/basics/cross-program-invocation/quasar/hand/src/lib.rs index e272cf83c..e3e425d92 100644 --- a/basics/cross-program-invocation/quasar/hand/src/lib.rs +++ b/basics/cross-program-invocation/quasar/hand/src/lib.rs @@ -26,7 +26,7 @@ mod quasar_hand { /// Pull the lever by invoking the lever program's switch_power via CPI. #[instruction(discriminator = 0)] - pub fn pull_lever(ctx: Ctx, name: String) -> Result<(), ProgramError> { + pub fn pull_lever(ctx: Ctx, name: String<50>) -> Result<(), ProgramError> { instructions::handle_pull_lever(&mut ctx.accounts, name) } } diff --git a/basics/cross-program-invocation/quasar/lever/Cargo.toml b/basics/cross-program-invocation/quasar/lever/Cargo.toml index a50958f7d..fceab3f06 100644 --- a/basics/cross-program-invocation/quasar/lever/Cargo.toml +++ b/basics/cross-program-invocation/quasar/lever/Cargo.toml @@ -21,11 +21,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/cross-program-invocation/quasar/lever/Quasar.toml b/basics/cross-program-invocation/quasar/lever/Quasar.toml index b994e3950..a3aa238be 100644 --- a/basics/cross-program-invocation/quasar/lever/Quasar.toml +++ b/basics/cross-program-invocation/quasar/lever/Quasar.toml @@ -18,4 +18,5 @@ args = [ ] [clients] +path = "target/client" languages = ["rust"] diff --git a/basics/favorites/quasar/Cargo.toml b/basics/favorites/quasar/Cargo.toml index e2cf1940e..3fbf2f1b4 100644 --- a/basics/favorites/quasar/Cargo.toml +++ b/basics/favorites/quasar/Cargo.toml @@ -20,11 +20,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/favorites/quasar/src/instructions/set_favorites.rs b/basics/favorites/quasar/src/instructions/set_favorites.rs index d5bfe44a0..f1c4e1f0b 100644 --- a/basics/favorites/quasar/src/instructions/set_favorites.rs +++ b/basics/favorites/quasar/src/instructions/set_favorites.rs @@ -1,25 +1,26 @@ use { - crate::state::Favorites, - quasar_lang::prelude::*, + crate::state::{Favorites, FavoritesInner}, + quasar_lang::{prelude::*, sysvars::Sysvar}, }; /// Accounts for setting user favourites. Uses `init_if_needed` so the same /// instruction can create or update the favourites PDA. #[derive(Accounts)] -pub struct SetFavorites<'info> { +pub struct SetFavorites { #[account(mut)] - pub user: &'info mut Signer, - #[account(mut, init_if_needed, payer = user, seeds = [b"favorites", user], bump)] - pub favorites: Account>, - pub system_program: &'info Program, + pub user: Signer, + #[account(mut, init_if_needed, payer = user, seeds = Favorites::seeds(user), bump)] + pub favorites: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_set_favorites(accounts: &mut SetFavorites, number: u64, color: &str) -> Result<(), ProgramError> { + let rent = Rent::get()?; accounts.favorites.set_inner( - number, - color, + FavoritesInner { number, color }, accounts.user.to_account_view(), - None, + rent.lamports_per_byte(), + rent.exemption_threshold_raw(), ) } diff --git a/basics/favorites/quasar/src/lib.rs b/basics/favorites/quasar/src/lib.rs index d6af2e37d..e716772fc 100644 --- a/basics/favorites/quasar/src/lib.rs +++ b/basics/favorites/quasar/src/lib.rs @@ -22,7 +22,7 @@ mod quasar_favorites { pub fn set_favorites( ctx: Ctx, number: u64, - color: String, + color: String<50>, ) -> Result<(), ProgramError> { instructions::handle_set_favorites(&mut ctx.accounts, number, color) } diff --git a/basics/favorites/quasar/src/state.rs b/basics/favorites/quasar/src/state.rs index 5d9fa39a5..d30d895bb 100644 --- a/basics/favorites/quasar/src/state.rs +++ b/basics/favorites/quasar/src/state.rs @@ -5,8 +5,9 @@ use quasar_lang::prelude::*; /// The Anchor version also stores `hobbies: Vec`, but Quasar doesn't /// support nested dynamic types (Vec). We keep number + color, which /// demonstrates fixed + dynamic field mixing in Quasar. -#[account(discriminator = 1)] -pub struct Favorites<'a> { +#[account(discriminator = 1, set_inner)] +#[seeds(b"favorites", user: Address)] +pub struct Favorites { pub number: u64, - pub color: String, + pub color: String<50>, } diff --git a/basics/favorites/quasar/src/tests.rs b/basics/favorites/quasar/src/tests.rs index ef141e2dd..78d56563e 100644 --- a/basics/favorites/quasar/src/tests.rs +++ b/basics/favorites/quasar/src/tests.rs @@ -20,16 +20,20 @@ fn empty(address: Pubkey) -> Account { } } -/// Build set_favorites instruction data. -/// Wire format: [disc=0] [ZC: number(u64)] [color: u32 prefix + bytes] +/// Build set_favorites instruction data using Quasar's compact wire format +/// (header then tail). `String<50>` defaults to a u8 length prefix. +/// +/// header: [disc: u8 = 0][number: u64 LE][color_len: u8] +/// tail: [color bytes] fn build_set_favorites(number: u64, color: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 + let mut data = Vec::with_capacity(10 + color.len()); - // Fixed ZC args: number (u64, but as Pod it's le bytes) + // Header + data.push(0u8); // discriminator data.extend_from_slice(&number.to_le_bytes()); + data.push(color.len() as u8); - // Dynamic String arg: color with u32 prefix - data.extend_from_slice(&(color.len() as u32).to_le_bytes()); + // Tail data.extend_from_slice(color.as_bytes()); data diff --git a/basics/hello-solana/quasar/Cargo.toml b/basics/hello-solana/quasar/Cargo.toml index cf3cdcacb..fc1e68a99 100644 --- a/basics/hello-solana/quasar/Cargo.toml +++ b/basics/hello-solana/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-hello-solana-client = { path = "target/client/rust/quasar-hello-solana-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/hello-solana/quasar/src/instructions/hello.rs b/basics/hello-solana/quasar/src/instructions/hello.rs index aec626623..d36abb017 100644 --- a/basics/hello-solana/quasar/src/instructions/hello.rs +++ b/basics/hello-solana/quasar/src/instructions/hello.rs @@ -4,13 +4,13 @@ use quasar_lang::prelude::*; /// A payer (signer) is required to submit the transaction, but the program /// simply logs a greeting and the program ID. #[derive(Accounts)] -pub struct Hello<'info> { +pub struct Hello { #[allow(dead_code)] - pub payer: &'info Signer, + pub payer: Signer, } #[inline(always)] -pub fn handle_hello(accounts: &Hello) -> Result<(), ProgramError> { +pub fn handle_hello(_accounts: &mut Hello) -> Result<(), ProgramError> { log("Hello, Solana!"); log("Our program's Program ID: FLUH9c5oAfXb1eYbkZvdGK9r9SLQJBUi2DZQaBVj7Tzr"); Ok(()) diff --git a/basics/pda-rent-payer/quasar/Cargo.toml b/basics/pda-rent-payer/quasar/Cargo.toml index f4189e248..a0af6710b 100644 --- a/basics/pda-rent-payer/quasar/Cargo.toml +++ b/basics/pda-rent-payer/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-pda-rent-payer-client = { path = "target/client/rust/quasar-pda-rent-payer-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/pda-rent-payer/quasar/src/instructions/create_new_account.rs b/basics/pda-rent-payer/quasar/src/instructions/create_new_account.rs index aa9eac30a..3fdf30b91 100644 --- a/basics/pda-rent-payer/quasar/src/instructions/create_new_account.rs +++ b/basics/pda-rent-payer/quasar/src/instructions/create_new_account.rs @@ -1,18 +1,18 @@ -use quasar_lang::prelude::*; +use quasar_lang::{prelude::*, sysvars::Sysvar}; /// Accounts for creating a new account funded by the rent vault PDA. /// The rent vault signs the create_account CPI via PDA seeds. #[derive(Accounts)] -pub struct CreateNewAccount<'info> { +pub struct CreateNewAccount { #[account(mut)] - pub new_account: &'info Signer, + pub new_account: Signer, #[account(mut, seeds = [b"rent_vault"], bump)] - pub rent_vault: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub rent_vault: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_create_new_account(accounts: &CreateNewAccount, rent_vault_bump: u8) -> Result<(), ProgramError> { +pub fn handle_create_new_account(accounts: &mut CreateNewAccount, rent_vault_bump: u8) -> Result<(), ProgramError> { // Build PDA signer seeds: ["rent_vault", bump]. let bump_bytes = [rent_vault_bump]; let seeds: &[Seed] = &[ @@ -21,15 +21,10 @@ pub fn handle_create_new_account(accounts: &CreateNewAccount, rent_vault_bump: u ]; let system_program_address = Address::default(); + let rent = Rent::get()?; + let lamports = rent.minimum_balance_unchecked(0); - // Create a zero-data system-owned account, funded from the vault. accounts.system_program - .create_account_with_minimum_balance( - accounts.rent_vault, - accounts.new_account, - 0, // space: zero bytes of data - &system_program_address, - None, // fetch Rent sysvar automatically - )? + .create_account(&accounts.rent_vault, &accounts.new_account, lamports, 0u64, &system_program_address) .invoke_signed(seeds) } diff --git a/basics/pda-rent-payer/quasar/src/instructions/init_rent_vault.rs b/basics/pda-rent-payer/quasar/src/instructions/init_rent_vault.rs index 8765f2b61..191b46f45 100644 --- a/basics/pda-rent-payer/quasar/src/instructions/init_rent_vault.rs +++ b/basics/pda-rent-payer/quasar/src/instructions/init_rent_vault.rs @@ -5,17 +5,17 @@ use quasar_lang::prelude::*; /// When lamports are sent to a new address, the system program creates /// a system-owned account automatically. #[derive(Accounts)] -pub struct InitRentVault<'info> { +pub struct InitRentVault { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut, seeds = [b"rent_vault"], bump)] - pub rent_vault: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub rent_vault: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_init_rent_vault(accounts: &InitRentVault, fund_lamports: u64) -> Result<(), ProgramError> { +pub fn handle_init_rent_vault(accounts: &mut InitRentVault, fund_lamports: u64) -> Result<(), ProgramError> { accounts.system_program - .transfer(accounts.payer, accounts.rent_vault, fund_lamports) + .transfer(&accounts.payer, &accounts.rent_vault, fund_lamports) .invoke() } diff --git a/basics/processing-instructions/quasar/Cargo.toml b/basics/processing-instructions/quasar/Cargo.toml index 751b86ffe..26cf2e808 100644 --- a/basics/processing-instructions/quasar/Cargo.toml +++ b/basics/processing-instructions/quasar/Cargo.toml @@ -20,11 +20,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/processing-instructions/quasar/src/instructions/go_to_park.rs b/basics/processing-instructions/quasar/src/instructions/go_to_park.rs index af93b6c15..ce71aeef9 100644 --- a/basics/processing-instructions/quasar/src/instructions/go_to_park.rs +++ b/basics/processing-instructions/quasar/src/instructions/go_to_park.rs @@ -3,13 +3,13 @@ use quasar_lang::prelude::*; /// Minimal accounts context — a signer is needed to submit the transaction. /// The instruction just processes instruction data (name + height). #[derive(Accounts)] -pub struct Park<'info> { +pub struct Park { #[allow(dead_code)] - pub signer: &'info Signer, + pub signer: Signer, } #[inline(always)] -pub fn handle_go_to_park(accounts: &Park, _name: &str, height: u32) -> Result<(), ProgramError> { +pub fn handle_go_to_park(_accounts: &mut Park, _name: &str, height: u32) -> Result<(), ProgramError> { // Quasar's `log()` takes &str, no format! macro available in no_std. // We can't interpolate the name or height into the log message, so // we use static messages — same logic as the Anchor version, just diff --git a/basics/processing-instructions/quasar/src/lib.rs b/basics/processing-instructions/quasar/src/lib.rs index 909d1dcc3..653b403d3 100644 --- a/basics/processing-instructions/quasar/src/lib.rs +++ b/basics/processing-instructions/quasar/src/lib.rs @@ -17,7 +17,7 @@ mod quasar_processing_instructions { /// Quasar can parse String instruction args (u32-prefixed wire format) but /// can't interpolate them into log messages (no format! in no_std). #[instruction(discriminator = 0)] - pub fn go_to_park(ctx: Ctx, name: String, height: u32) -> Result<(), ProgramError> { + pub fn go_to_park(ctx: Ctx, height: u32, name: String<50>) -> Result<(), ProgramError> { instructions::handle_go_to_park(&mut ctx.accounts, name, height) } } diff --git a/basics/program-derived-addresses/quasar/Cargo.toml b/basics/program-derived-addresses/quasar/Cargo.toml index fbd8f73ef..1f4e9e287 100644 --- a/basics/program-derived-addresses/quasar/Cargo.toml +++ b/basics/program-derived-addresses/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-program-derived-addresses-client = { path = "target/client/rust/quasar-program-derived-addresses-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/program-derived-addresses/quasar/src/instructions/create.rs b/basics/program-derived-addresses/quasar/src/instructions/create.rs index 29c1fda11..2b4210d08 100644 --- a/basics/program-derived-addresses/quasar/src/instructions/create.rs +++ b/basics/program-derived-addresses/quasar/src/instructions/create.rs @@ -1,21 +1,21 @@ use { - crate::state::PageVisits, + crate::state::{PageVisits, PageVisitsInner}, quasar_lang::prelude::*, }; /// Accounts for creating a new page visits counter. /// The counter is derived as a PDA from ["page_visits", payer] seeds. #[derive(Accounts)] -pub struct CreatePageVisits<'info> { +pub struct CreatePageVisits { #[account(mut)] - pub payer: &'info mut Signer, - #[account(mut, init, payer = payer, seeds = [b"page_visits", payer], bump)] - pub page_visits: &'info mut Account, - pub system_program: &'info Program, + pub payer: Signer, + #[account(mut, init, payer = payer, seeds = PageVisits::seeds(payer), bump)] + pub page_visits: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_create_page_visits(accounts: &mut CreatePageVisits) -> Result<(), ProgramError> { - accounts.page_visits.set_inner(0u64); + accounts.page_visits.set_inner(PageVisitsInner { page_visits: 0 }); Ok(()) } diff --git a/basics/program-derived-addresses/quasar/src/instructions/increment.rs b/basics/program-derived-addresses/quasar/src/instructions/increment.rs index 8925e2694..042038386 100644 --- a/basics/program-derived-addresses/quasar/src/instructions/increment.rs +++ b/basics/program-derived-addresses/quasar/src/instructions/increment.rs @@ -6,10 +6,10 @@ use { /// Accounts for incrementing page visits. /// The user account is needed to derive the PDA seeds for validation. #[derive(Accounts)] -pub struct IncrementPageVisits<'info> { - pub user: &'info UncheckedAccount, +pub struct IncrementPageVisits { + pub user: UncheckedAccount, #[account(mut)] - pub page_visits: &'info mut Account, + pub page_visits: Account, } #[inline(always)] diff --git a/basics/program-derived-addresses/quasar/src/state/page_visits.rs b/basics/program-derived-addresses/quasar/src/state/page_visits.rs index 9b9898af6..d81790b49 100644 --- a/basics/program-derived-addresses/quasar/src/state/page_visits.rs +++ b/basics/program-derived-addresses/quasar/src/state/page_visits.rs @@ -2,7 +2,8 @@ use quasar_lang::prelude::*; /// PDA account that tracks page visits for a user. /// Derived from seeds: ["page_visits", user_pubkey]. -#[account(discriminator = 1)] +#[account(discriminator = 1, set_inner)] +#[seeds(b"page_visits", payer: Address)] pub struct PageVisits { pub page_visits: u64, } diff --git a/basics/realloc/quasar/Cargo.toml b/basics/realloc/quasar/Cargo.toml index 4ed2077eb..d61ef5b9d 100644 --- a/basics/realloc/quasar/Cargo.toml +++ b/basics/realloc/quasar/Cargo.toml @@ -20,11 +20,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/realloc/quasar/src/instructions/initialize.rs b/basics/realloc/quasar/src/instructions/initialize.rs index 6072e9e1e..ad652200d 100644 --- a/basics/realloc/quasar/src/instructions/initialize.rs +++ b/basics/realloc/quasar/src/instructions/initialize.rs @@ -1,24 +1,26 @@ use { - crate::state::MessageAccount, - quasar_lang::prelude::*, + crate::state::{MessageAccount, MessageAccountInner}, + quasar_lang::{prelude::*, sysvars::Sysvar}, }; /// Accounts for initialising a new message account. /// The message_account is a random keypair (not a PDA) — same as the Anchor version. #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info mut Signer, + pub payer: Signer, #[account(mut, init, payer = payer)] - pub message_account: Account>, - pub system_program: &'info Program, + pub message_account: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_initialize(accounts: &mut Initialize, message: &str) -> Result<(), ProgramError> { + let rent = Rent::get()?; accounts.message_account.set_inner( - message, + MessageAccountInner { message }, accounts.payer.to_account_view(), - None, + rent.lamports_per_byte(), + rent.exemption_threshold_raw(), ) } diff --git a/basics/realloc/quasar/src/instructions/update.rs b/basics/realloc/quasar/src/instructions/update.rs index 77ad2b665..c0aa1a022 100644 --- a/basics/realloc/quasar/src/instructions/update.rs +++ b/basics/realloc/quasar/src/instructions/update.rs @@ -1,25 +1,27 @@ use { - crate::state::MessageAccount, - quasar_lang::prelude::*, + crate::state::{MessageAccount, MessageAccountInner}, + quasar_lang::{prelude::*, sysvars::Sysvar}, }; /// Accounts for updating a message account. /// Quasar's `set_inner` automatically handles realloc when the new message /// is longer than the current account data. No explicit realloc needed. #[derive(Accounts)] -pub struct Update<'info> { +pub struct Update { #[account(mut)] - pub payer: &'info mut Signer, + pub payer: Signer, #[account(mut)] - pub message_account: Account>, - pub system_program: &'info Program, + pub message_account: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_update(accounts: &mut Update, message: &str) -> Result<(), ProgramError> { + let rent = Rent::get()?; accounts.message_account.set_inner( - message, + MessageAccountInner { message }, accounts.payer.to_account_view(), - None, + rent.lamports_per_byte(), + rent.exemption_threshold_raw(), ) } diff --git a/basics/realloc/quasar/src/lib.rs b/basics/realloc/quasar/src/lib.rs index 3373f864a..6b0a512b2 100644 --- a/basics/realloc/quasar/src/lib.rs +++ b/basics/realloc/quasar/src/lib.rs @@ -16,14 +16,14 @@ mod quasar_realloc { /// Create a message account with an initial message. #[instruction(discriminator = 0)] - pub fn initialize(ctx: Ctx, message: String) -> Result<(), ProgramError> { + pub fn initialize(ctx: Ctx, message: String<1024>) -> Result<(), ProgramError> { instructions::handle_initialize(&mut ctx.accounts, message) } /// Update the message, reallocating if the new message is longer. /// Quasar's `set_inner` handles realloc transparently. #[instruction(discriminator = 1)] - pub fn update(ctx: Ctx, message: String) -> Result<(), ProgramError> { + pub fn update(ctx: Ctx, message: String<1024>) -> Result<(), ProgramError> { instructions::handle_update(&mut ctx.accounts, message) } } diff --git a/basics/realloc/quasar/src/state.rs b/basics/realloc/quasar/src/state.rs index 746d56d9e..183de8eca 100644 --- a/basics/realloc/quasar/src/state.rs +++ b/basics/realloc/quasar/src/state.rs @@ -3,7 +3,7 @@ use quasar_lang::prelude::*; /// Message account with a dynamic-length message field. /// Quasar's `set_inner` automatically reallocs when the new message exceeds /// the current account size, making explicit realloc unnecessary. -#[account(discriminator = 1)] -pub struct MessageAccount<'a> { - pub message: String, +#[account(discriminator = 1, set_inner)] +pub struct MessageAccount { + pub message: String<1024>, } diff --git a/basics/realloc/quasar/src/tests.rs b/basics/realloc/quasar/src/tests.rs index 8382e85f3..25d35106e 100644 --- a/basics/realloc/quasar/src/tests.rs +++ b/basics/realloc/quasar/src/tests.rs @@ -20,20 +20,25 @@ fn empty(address: Pubkey) -> Account { } } -/// Build initialize instruction data. -/// Wire format: [disc=0] [message: u32 prefix + bytes] +/// Build initialize instruction data using Quasar's compact wire format. +/// `String<1024>` defaults to a u8 length prefix (the second `String` generic +/// argument is the prefix type and its default is `u8`). +/// +/// header: [disc: u8 = 0][message_len: u8] +/// tail: [message bytes] fn build_initialize(message: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 - data.extend_from_slice(&(message.len() as u32).to_le_bytes()); + let mut data = Vec::with_capacity(2 + message.len()); + data.push(0u8); // discriminator + data.push(message.len() as u8); data.extend_from_slice(message.as_bytes()); data } -/// Build update instruction data. -/// Wire format: [disc=1] [message: u32 prefix + bytes] +/// Build update instruction data using the same compact wire format. fn build_update(message: &str) -> Vec { - let mut data = vec![1u8]; // discriminator = 1 - data.extend_from_slice(&(message.len() as u32).to_le_bytes()); + let mut data = Vec::with_capacity(2 + message.len()); + data.push(1u8); // discriminator + data.push(message.len() as u8); data.extend_from_slice(message.as_bytes()); data } @@ -65,14 +70,13 @@ fn test_initialize() { let result = svm.process_instruction(&ix, &[signer(payer), empty(message_account)]); result.assert_success(); - // Verify: disc(1) + message (u32 prefix "Hello, World!") + // Verify: disc(1) + message (u8 prefix + bytes) let account = result.account(&message_account).unwrap(); assert_eq!(account.data[0], 1, "discriminator"); - // Default String uses u32 prefix, max 1024 - let msg_len = u32::from_le_bytes(account.data[1..5].try_into().unwrap()) as usize; + let msg_len = account.data[1] as usize; assert_eq!(msg_len, 13); - assert_eq!(&account.data[5..5 + msg_len], b"Hello, World!"); + assert_eq!(&account.data[2..2 + msg_len], b"Hello, World!"); } #[test] diff --git a/basics/rent/quasar/Cargo.toml b/basics/rent/quasar/Cargo.toml index 7b99dbfad..84c8f1eb4 100644 --- a/basics/rent/quasar/Cargo.toml +++ b/basics/rent/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/rent/quasar/src/instructions/create_system_account.rs b/basics/rent/quasar/src/instructions/create_system_account.rs index 1f26b493e..ccd087a15 100644 --- a/basics/rent/quasar/src/instructions/create_system_account.rs +++ b/basics/rent/quasar/src/instructions/create_system_account.rs @@ -1,40 +1,29 @@ -use quasar_lang::prelude::*; +use quasar_lang::{prelude::*, sysvars::Sysvar}; /// Accounts for creating a system account sized for address data. #[derive(Accounts)] -pub struct CreateSystemAccount<'info> { +pub struct CreateSystemAccount { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub new_account: &'info Signer, - pub system_program: &'info Program, + pub new_account: Signer, + pub system_program: Program, } #[inline(always)] -pub fn handle_create_system_account( - accounts: &CreateSystemAccount, name: &str, - address: &str, -) -> Result<(), ProgramError> { +pub fn handle_create_system_account(accounts: &mut CreateSystemAccount, name: &str, address: &str) -> Result<(), ProgramError> { // Calculate space needed for the serialised AddressData: // borsh-style: 4-byte length prefix + bytes for each String field. let space = 4 + name.len() + 4 + address.len(); log("Program invoked. Creating a system account..."); - // The owner of the new account is the system program. let system_program_address = Address::default(); + let rent = Rent::get()?; + let lamports = rent.minimum_balance_unchecked(space); - // Create the account with the computed space. - // create_account_with_minimum_balance automatically fetches Rent - // sysvar and calculates the minimum rent-exempt lamports. accounts.system_program - .create_account_with_minimum_balance( - accounts.payer, - accounts.new_account, - space as u64, - &system_program_address, - None, // fetch Rent sysvar automatically - )? + .create_account(&accounts.payer, &accounts.new_account, lamports, space as u64, &system_program_address) .invoke()?; log("Account created successfully."); diff --git a/basics/rent/quasar/src/lib.rs b/basics/rent/quasar/src/lib.rs index 854b3945f..931d0b02d 100644 --- a/basics/rent/quasar/src/lib.rs +++ b/basics/rent/quasar/src/lib.rs @@ -22,8 +22,8 @@ mod quasar_rent { #[instruction(discriminator = 0)] pub fn create_system_account( ctx: Ctx, - name: String, - address: String, + name: String<50>, + address: String<50>, ) -> Result<(), ProgramError> { instructions::handle_create_system_account(&mut ctx.accounts, name, address) } diff --git a/basics/rent/quasar/src/tests.rs b/basics/rent/quasar/src/tests.rs index 7340a67de..f27427e3d 100644 --- a/basics/rent/quasar/src/tests.rs +++ b/basics/rent/quasar/src/tests.rs @@ -20,18 +20,22 @@ fn empty(address: Pubkey) -> Account { } } -/// Build create_system_account instruction data (discriminator = 0). -/// Wire format: [disc=0] [name: String] [address: String] -/// Both String args are dynamic (u32 length prefix + bytes). +/// Build create_system_account instruction data using Quasar's compact +/// wire format (header then tail). `String<50>` defaults to a u8 length +/// prefix (the second `String` generic argument is the prefix type). +/// +/// header: [disc: u8 = 0][name_len: u8][address_len: u8] +/// tail: [name bytes][address bytes] fn build_create_system_account(name: &str, address: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 + let mut data = Vec::with_capacity(3 + name.len() + address.len()); - // Dynamic String: name - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); - data.extend_from_slice(name.as_bytes()); + // Header + data.push(0u8); // discriminator + data.push(name.len() as u8); + data.push(address.len() as u8); - // Dynamic String: address - data.extend_from_slice(&(address.len() as u32).to_le_bytes()); + // Tail + data.extend_from_slice(name.as_bytes()); data.extend_from_slice(address.as_bytes()); data diff --git a/basics/repository-layout/quasar/Cargo.toml b/basics/repository-layout/quasar/Cargo.toml index 5699b68bf..a476a5926 100644 --- a/basics/repository-layout/quasar/Cargo.toml +++ b/basics/repository-layout/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/repository-layout/quasar/src/instructions/carnival_context.rs b/basics/repository-layout/quasar/src/instructions/carnival_context.rs index 095d39230..33960b498 100644 --- a/basics/repository-layout/quasar/src/instructions/carnival_context.rs +++ b/basics/repository-layout/quasar/src/instructions/carnival_context.rs @@ -5,14 +5,15 @@ use super::{eat_food, get_on_ride, play_game}; /// Minimal accounts context — a signer submits the transaction. /// The instructions just process instruction data (no onchain state). #[derive(Accounts)] -pub struct CarnivalContext<'info> { +pub struct CarnivalContext { #[allow(dead_code)] - pub payer: &'info Signer, + pub payer: Signer, } #[inline(always)] pub fn handle_go_on_ride( - accounts: &CarnivalContext, name: &str, + _accounts: &mut CarnivalContext, + name: &str, height: u32, ticket_count: u32, ride_name: &str, @@ -22,7 +23,8 @@ pub fn handle_go_on_ride( #[inline(always)] pub fn handle_play_game( - accounts: &CarnivalContext, name: &str, + _accounts: &mut CarnivalContext, + name: &str, ticket_count: u32, game_name: &str, ) -> Result<(), ProgramError> { @@ -31,7 +33,8 @@ pub fn handle_play_game( #[inline(always)] pub fn handle_eat_food( - accounts: &CarnivalContext, name: &str, + _accounts: &mut CarnivalContext, + name: &str, ticket_count: u32, food_stand_name: &str, ) -> Result<(), ProgramError> { diff --git a/basics/repository-layout/quasar/src/instructions/eat_food.rs b/basics/repository-layout/quasar/src/instructions/eat_food.rs index f34dde13e..48592bb9f 100644 --- a/basics/repository-layout/quasar/src/instructions/eat_food.rs +++ b/basics/repository-layout/quasar/src/instructions/eat_food.rs @@ -12,7 +12,7 @@ pub fn eat_food( let mut i = 0; while i < stands.len() { - if stands[i].name_matches(food_stand_name) { + if food::food_stand_name_matches(&stands[i], food_stand_name) { log("Welcome to the food stand!"); if ticket_count < stands[i].tickets { diff --git a/basics/repository-layout/quasar/src/instructions/get_on_ride.rs b/basics/repository-layout/quasar/src/instructions/get_on_ride.rs index b0e670b02..66b85c5ee 100644 --- a/basics/repository-layout/quasar/src/instructions/get_on_ride.rs +++ b/basics/repository-layout/quasar/src/instructions/get_on_ride.rs @@ -15,7 +15,7 @@ pub fn get_on_ride( let mut i = 0; while i < rides.len() { - if rides[i].name_matches(ride_name) { + if ride::ride_name_matches(&rides[i], ride_name) { log("You're about to go on a ride!"); if ticket_count < rides[i].tickets { diff --git a/basics/repository-layout/quasar/src/instructions/play_game.rs b/basics/repository-layout/quasar/src/instructions/play_game.rs index 84e900c15..fdac0e9cf 100644 --- a/basics/repository-layout/quasar/src/instructions/play_game.rs +++ b/basics/repository-layout/quasar/src/instructions/play_game.rs @@ -12,7 +12,7 @@ pub fn play_game( let mut i = 0; while i < games.len() { - if games[i].name_matches(game_name) { + if game::game_name_matches(&games[i], game_name) { log("You're about to play a game!"); if ticket_count < games[i].tickets { diff --git a/basics/repository-layout/quasar/src/lib.rs b/basics/repository-layout/quasar/src/lib.rs index 43ecd62de..a60775c39 100644 --- a/basics/repository-layout/quasar/src/lib.rs +++ b/basics/repository-layout/quasar/src/lib.rs @@ -18,10 +18,10 @@ mod quasar_carnival { #[instruction(discriminator = 0)] pub fn go_on_ride( ctx: Ctx, - name: String, height: u32, ticket_count: u32, - ride_name: String, + name: String<50>, + ride_name: String<50>, ) -> Result<(), ProgramError> { instructions::handle_go_on_ride(&mut ctx.accounts, name, height, ticket_count, ride_name) } @@ -30,9 +30,9 @@ mod quasar_carnival { #[instruction(discriminator = 1)] pub fn play_game( ctx: Ctx, - name: String, ticket_count: u32, - game_name: String, + name: String<50>, + game_name: String<50>, ) -> Result<(), ProgramError> { instructions::handle_play_game(&mut ctx.accounts, name, ticket_count, game_name) } @@ -41,9 +41,9 @@ mod quasar_carnival { #[instruction(discriminator = 2)] pub fn eat_food( ctx: Ctx, - name: String, ticket_count: u32, - food_stand_name: String, + name: String<50>, + food_stand_name: String<50>, ) -> Result<(), ProgramError> { instructions::handle_eat_food(&mut ctx.accounts, name, ticket_count, food_stand_name) } diff --git a/basics/repository-layout/quasar/src/state/food.rs b/basics/repository-layout/quasar/src/state/food.rs index ecb564034..e8569a4c7 100644 --- a/basics/repository-layout/quasar/src/state/food.rs +++ b/basics/repository-layout/quasar/src/state/food.rs @@ -5,10 +5,8 @@ pub struct FoodStand { pub tickets: u32, } -impl FoodStand { - pub fn name_matches(&self, other: &str) -> bool { - self.name.as_bytes() == other.as_bytes() - } +pub fn food_stand_name_matches(stand: &FoodStand, other: &str) -> bool { + stand.name.as_bytes() == other.as_bytes() } /// Static list of food stands. diff --git a/basics/repository-layout/quasar/src/state/game.rs b/basics/repository-layout/quasar/src/state/game.rs index c7682a4b9..ded4a7d55 100644 --- a/basics/repository-layout/quasar/src/state/game.rs +++ b/basics/repository-layout/quasar/src/state/game.rs @@ -8,10 +8,8 @@ pub struct Game { const DEFAULT_TICKETS_TO_PLAY: u32 = 3; -impl Game { - pub fn name_matches(&self, other: &str) -> bool { - self.name.as_bytes() == other.as_bytes() - } +pub fn game_name_matches(game: &Game, other: &str) -> bool { + game.name.as_bytes() == other.as_bytes() } /// Static list of carnival games. diff --git a/basics/repository-layout/quasar/src/state/ride.rs b/basics/repository-layout/quasar/src/state/ride.rs index 5939b697a..5759a9087 100644 --- a/basics/repository-layout/quasar/src/state/ride.rs +++ b/basics/repository-layout/quasar/src/state/ride.rs @@ -7,11 +7,9 @@ pub struct Ride { pub min_height: u32, } -impl Ride { - /// Check if a ride name matches (byte comparison, no alloc). - pub fn name_matches(&self, other: &str) -> bool { - self.name.as_bytes() == other.as_bytes() - } +/// Check if a ride name matches (byte comparison, no alloc). +pub fn ride_name_matches(ride: &Ride, other: &str) -> bool { + ride.name.as_bytes() == other.as_bytes() } /// Static list of carnival rides. diff --git a/basics/repository-layout/quasar/src/tests.rs b/basics/repository-layout/quasar/src/tests.rs index 95921d411..90a993343 100644 --- a/basics/repository-layout/quasar/src/tests.rs +++ b/basics/repository-layout/quasar/src/tests.rs @@ -10,59 +10,63 @@ fn signer(address: Pubkey) -> Account { quasar_svm::token::create_keyed_system_account(&address, 10_000_000_000) } -/// Build go_on_ride instruction data (discriminator = 0). -/// Wire format: [disc=0] [ZC: height(u32), ticket_count(u32)] [name: String] [ride_name: String] +/// Build go_on_ride instruction data using Quasar's compact wire format +/// (header then tail). `String<50>` defaults to a u8 length prefix. +/// +/// header: [disc: u8 = 0][height: u32 LE][ticket_count: u32 LE][name_len: u8][ride_name_len: u8] +/// tail: [name bytes][ride_name bytes] fn build_go_on_ride(name: &str, height: u32, ticket_count: u32, ride_name: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 + let mut data = Vec::with_capacity(11 + name.len() + ride_name.len()); - // Fixed ZC fields: height, ticket_count + // Header + data.push(0u8); // discriminator data.extend_from_slice(&height.to_le_bytes()); data.extend_from_slice(&ticket_count.to_le_bytes()); + data.push(name.len() as u8); + data.push(ride_name.len() as u8); - // Dynamic String: name - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + // Tail data.extend_from_slice(name.as_bytes()); - - // Dynamic String: ride_name - data.extend_from_slice(&(ride_name.len() as u32).to_le_bytes()); data.extend_from_slice(ride_name.as_bytes()); data } -/// Build play_game instruction data (discriminator = 1). -/// Wire format: [disc=1] [ZC: ticket_count(u32)] [name: String] [game_name: String] +/// Build play_game instruction data using the same compact wire format. +/// +/// header: [disc: u8 = 1][ticket_count: u32 LE][name_len: u8][game_name_len: u8] +/// tail: [name bytes][game_name bytes] fn build_play_game(name: &str, ticket_count: u32, game_name: &str) -> Vec { - let mut data = vec![1u8]; // discriminator = 1 + let mut data = Vec::with_capacity(7 + name.len() + game_name.len()); - // Fixed ZC: ticket_count + // Header + data.push(1u8); // discriminator data.extend_from_slice(&ticket_count.to_le_bytes()); + data.push(name.len() as u8); + data.push(game_name.len() as u8); - // Dynamic String: name - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + // Tail data.extend_from_slice(name.as_bytes()); - - // Dynamic String: game_name - data.extend_from_slice(&(game_name.len() as u32).to_le_bytes()); data.extend_from_slice(game_name.as_bytes()); data } -/// Build eat_food instruction data (discriminator = 2). -/// Wire format: [disc=2] [ZC: ticket_count(u32)] [name: String] [food_stand_name: String] +/// Build eat_food instruction data using the same compact wire format. +/// +/// header: [disc: u8 = 2][ticket_count: u32 LE][name_len: u8][food_stand_name_len: u8] +/// tail: [name bytes][food_stand_name bytes] fn build_eat_food(name: &str, ticket_count: u32, food_stand_name: &str) -> Vec { - let mut data = vec![2u8]; // discriminator = 2 + let mut data = Vec::with_capacity(7 + name.len() + food_stand_name.len()); - // Fixed ZC: ticket_count + // Header + data.push(2u8); // discriminator data.extend_from_slice(&ticket_count.to_le_bytes()); + data.push(name.len() as u8); + data.push(food_stand_name.len() as u8); - // Dynamic String: name - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + // Tail data.extend_from_slice(name.as_bytes()); - - // Dynamic String: food_stand_name - data.extend_from_slice(&(food_stand_name.len() as u32).to_le_bytes()); data.extend_from_slice(food_stand_name.as_bytes()); data diff --git a/basics/transfer-sol/quasar/Cargo.toml b/basics/transfer-sol/quasar/Cargo.toml index afb62d252..dacb49696 100644 --- a/basics/transfer-sol/quasar/Cargo.toml +++ b/basics/transfer-sol/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] quasar-transfer-sol-client = { path = "target/client/rust/quasar-transfer-sol-client" } -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-account = { version = "3.4.0" } solana-address = { version = "2.2.0", features = ["decode"] } solana-instruction = { version = "3.2.0", features = ["bincode"] } diff --git a/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_cpi.rs b/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_cpi.rs index b74aafdad..cd85cf08f 100644 --- a/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_cpi.rs +++ b/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_cpi.rs @@ -2,17 +2,17 @@ use quasar_lang::prelude::*; /// Accounts for transferring SOL via system program CPI. #[derive(Accounts)] -pub struct TransferSolWithCpi<'info> { +pub struct TransferSolWithCpi { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub recipient: &'info UncheckedAccount, - pub system_program: &'info Program, + pub recipient: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_transfer_sol_with_cpi(accounts: &TransferSolWithCpi, amount: u64) -> Result<(), ProgramError> { +pub fn handle_transfer_sol_with_cpi(accounts: &mut TransferSolWithCpi, amount: u64) -> Result<(), ProgramError> { accounts.system_program - .transfer(accounts.payer, accounts.recipient, amount) + .transfer(&accounts.payer, &accounts.recipient, amount) .invoke() } diff --git a/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_program.rs b/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_program.rs index 5aea3d670..14dc016ed 100644 --- a/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_program.rs +++ b/basics/transfer-sol/quasar/src/instructions/transfer_sol_with_program.rs @@ -3,15 +3,15 @@ use quasar_lang::prelude::*; /// Accounts for transferring SOL by directly manipulating lamports. /// The payer account must be owned by this program for direct lamport access. #[derive(Accounts)] -pub struct TransferSolWithProgram<'info> { +pub struct TransferSolWithProgram { #[account(mut)] - pub payer: &'info UncheckedAccount, + pub payer: UncheckedAccount, #[account(mut)] - pub recipient: &'info UncheckedAccount, + pub recipient: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_sol_with_program(accounts: &TransferSolWithProgram, amount: u64) -> Result<(), ProgramError> { +pub fn handle_transfer_sol_with_program(accounts: &mut TransferSolWithProgram, amount: u64) -> Result<(), ProgramError> { let payer_view = accounts.payer.to_account_view(); let recipient_view = accounts.recipient.to_account_view(); set_lamports(payer_view, payer_view.lamports() - amount); diff --git a/compression/cnft-burn/quasar/Cargo.toml b/compression/cnft-burn/quasar/Cargo.toml index 69f8a46a3..497e22f2c 100644 --- a/compression/cnft-burn/quasar/Cargo.toml +++ b/compression/cnft-burn/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } # Direct dependency for invoke_with_bounds — needed for raw CPI with variable # proof accounts. quasar-lang re-exports types but not the invoke functions. solana-instruction-view = { version = "2", features = ["cpi"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-address = { version = "2.2.0", features = ["decode"] } diff --git a/compression/cnft-burn/quasar/src/instructions/burn_cnft.rs b/compression/cnft-burn/quasar/src/instructions/burn_cnft.rs index 5775c4b7e..e5eeab412 100644 --- a/compression/cnft-burn/quasar/src/instructions/burn_cnft.rs +++ b/compression/cnft-burn/quasar/src/instructions/burn_cnft.rs @@ -1,5 +1,5 @@ use crate::*; -use quasar_lang::cpi::{InstructionAccount, InstructionView}; +use quasar_lang::{cpi::{InstructionAccount, InstructionView}, remaining::RemainingAccounts}; /// Maximum number of proof nodes for the merkle tree. /// Concurrent merkle trees support up to depth 30, but typical depth is 14-20. @@ -10,32 +10,29 @@ const MAX_CPI_ACCOUNTS: usize = 7 + MAX_PROOF_NODES; /// Accounts for burning a compressed NFT via mpl-bubblegum CPI. #[derive(Accounts)] -pub struct BurnCnft<'info> { +pub struct BurnCnft { #[account(mut)] - pub leaf_owner: &'info Signer, + pub leaf_owner: Signer, /// Tree authority PDA (seeds checked by Bubblegum). #[account(mut)] - pub tree_authority: &'info UncheckedAccount, + pub tree_authority: UncheckedAccount, /// Merkle tree account modified by the compression program. #[account(mut)] - pub merkle_tree: &'info UncheckedAccount, + pub merkle_tree: UncheckedAccount, /// SPL Noop log wrapper. - pub log_wrapper: &'info UncheckedAccount, + pub log_wrapper: UncheckedAccount, /// SPL Account Compression program. #[account(address = SPL_ACCOUNT_COMPRESSION_ID)] - pub compression_program: &'info UncheckedAccount, + pub compression_program: UncheckedAccount, /// mpl-bubblegum program. #[account(address = MPL_BUBBLEGUM_ID)] - pub bubblegum_program: &'info UncheckedAccount, - pub system_program: &'info Program, + pub bubblegum_program: UncheckedAccount, + pub system_program: Program, } -pub fn handle_burn_cnft<'info>( - accounts: &BurnCnft<'info>, ctx: &CtxWithRemaining<'info, BurnCnft<'info>>, -) -> Result<(), ProgramError> { +pub fn handle_burn_cnft(accounts: &mut BurnCnft, data: &[u8], remaining: RemainingAccounts<'_>) -> Result<(), ProgramError> { // Parse instruction args from raw data: // root(32) + data_hash(32) + creator_hash(32) + nonce(8) + index(4) = 108 bytes - let data = ctx.data; if data.len() < 108 { return Err(ProgramError::InvalidInstructionData); } @@ -47,7 +44,6 @@ pub fn handle_burn_cnft<'info>( ix_data[8..116].copy_from_slice(&data[0..108]); // Collect remaining accounts (proof nodes) into a stack buffer - let remaining = ctx.remaining_accounts(); let placeholder = accounts.system_program.to_account_view().clone(); let mut proof_views: [AccountView; MAX_PROOF_NODES] = core::array::from_fn(|_| placeholder.clone()); diff --git a/compression/cnft-burn/quasar/src/lib.rs b/compression/cnft-burn/quasar/src/lib.rs index fb170d22c..f2427eefe 100644 --- a/compression/cnft-burn/quasar/src/lib.rs +++ b/compression/cnft-burn/quasar/src/lib.rs @@ -32,6 +32,8 @@ mod quasar_cnft_burn { #[instruction(discriminator = 0)] pub fn burn_cnft(ctx: CtxWithRemaining) -> Result<(), ProgramError> { - instructions::handle_burn_cnft(&ctx.accounts, &ctx) + let data = ctx.data; + let remaining = ctx.remaining_accounts(); + instructions::handle_burn_cnft(&mut ctx.accounts, data, remaining) } } diff --git a/compression/cnft-vault/quasar/Cargo.toml b/compression/cnft-vault/quasar/Cargo.toml index 2f89cfebb..bd5cb17ab 100644 --- a/compression/cnft-vault/quasar/Cargo.toml +++ b/compression/cnft-vault/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } # Direct dependency for invoke_signed_with_bounds — needed for raw CPI with # variable proof accounts. quasar-lang re-exports types but not the invoke fns. solana-instruction-view = { version = "2", features = ["cpi"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-address = { version = "2.2.0", features = ["decode"] } diff --git a/compression/cnft-vault/quasar/src/instructions/withdraw.rs b/compression/cnft-vault/quasar/src/instructions/withdraw.rs index 56014c0e1..c1bde7f46 100644 --- a/compression/cnft-vault/quasar/src/instructions/withdraw.rs +++ b/compression/cnft-vault/quasar/src/instructions/withdraw.rs @@ -1,5 +1,5 @@ use crate::*; -use quasar_lang::cpi::{InstructionAccount, InstructionView, Seed, Signer}; +use quasar_lang::{cpi::{InstructionAccount, InstructionView, Seed, Signer}, remaining::RemainingAccounts}; /// Maximum proof nodes for the merkle tree. const MAX_PROOF_NODES: usize = 24; @@ -12,27 +12,27 @@ const TRANSFER_ARGS_LEN: usize = 108; /// Accounts for withdrawing a single compressed NFT from the vault. #[derive(Accounts)] -pub struct Withdraw<'info> { +pub struct Withdraw { /// Tree authority PDA (seeds checked by Bubblegum). #[account(mut)] - pub tree_authority: &'info UncheckedAccount, + pub tree_authority: UncheckedAccount, /// Vault PDA that owns the cNFT — signs the transfer via invoke_signed. #[account(seeds = [b"cNFT-vault"], bump)] - pub leaf_owner: &'info UncheckedAccount, + pub leaf_owner: UncheckedAccount, /// New owner to receive the cNFT. - pub new_leaf_owner: &'info UncheckedAccount, + pub new_leaf_owner: UncheckedAccount, /// Merkle tree account. #[account(mut)] - pub merkle_tree: &'info UncheckedAccount, + pub merkle_tree: UncheckedAccount, /// SPL Noop log wrapper. - pub log_wrapper: &'info UncheckedAccount, + pub log_wrapper: UncheckedAccount, /// SPL Account Compression program. #[account(address = SPL_ACCOUNT_COMPRESSION_ID)] - pub compression_program: &'info UncheckedAccount, + pub compression_program: UncheckedAccount, /// mpl-bubblegum program. #[account(address = MPL_BUBBLEGUM_ID)] - pub bubblegum_program: &'info UncheckedAccount, - pub system_program: &'info Program, + pub bubblegum_program: UncheckedAccount, + pub system_program: Program, } /// Build mpl-bubblegum Transfer instruction data from raw args. @@ -43,10 +43,7 @@ fn build_transfer_data(args: &[u8]) -> [u8; 8 + TRANSFER_ARGS_LEN] { ix_data } -pub fn handle_withdraw_cnft<'info>( - accounts: &Withdraw<'info>, ctx: &CtxWithRemaining<'info, Withdraw<'info>>, -) -> Result<(), ProgramError> { - let data = ctx.data; +pub fn handle_withdraw_cnft(accounts: &mut Withdraw, data: &[u8], remaining: RemainingAccounts<'_>, leaf_owner_bump: u8) -> Result<(), ProgramError> { if data.len() < TRANSFER_ARGS_LEN { return Err(ProgramError::InvalidInstructionData); } @@ -54,7 +51,6 @@ pub fn handle_withdraw_cnft<'info>( let ix_data = build_transfer_data(&data[0..TRANSFER_ARGS_LEN]); // Collect proof nodes - let remaining = ctx.remaining_accounts(); let placeholder = accounts.system_program.to_account_view().clone(); let mut proof_views: [AccountView; MAX_PROOF_NODES] = core::array::from_fn(|_| placeholder.clone()); @@ -115,7 +111,7 @@ pub fn handle_withdraw_cnft<'info>( }; // PDA signer seeds: ["cNFT-vault", bump] - let bump_bytes = [ctx.bumps.leaf_owner]; + let bump_bytes = [leaf_owner_bump]; let seeds: [Seed; 2] = [ Seed::from(b"cNFT-vault" as &[u8]), Seed::from(&bump_bytes as &[u8]), diff --git a/compression/cnft-vault/quasar/src/instructions/withdraw_two.rs b/compression/cnft-vault/quasar/src/instructions/withdraw_two.rs index c2fc09a7a..72a58c77a 100644 --- a/compression/cnft-vault/quasar/src/instructions/withdraw_two.rs +++ b/compression/cnft-vault/quasar/src/instructions/withdraw_two.rs @@ -1,5 +1,5 @@ use crate::*; -use quasar_lang::cpi::{InstructionAccount, InstructionView, Seed, Signer}; +use quasar_lang::{cpi::{InstructionAccount, InstructionView, Seed, Signer}, remaining::RemainingAccounts}; /// Maximum proof nodes per tree. const MAX_PROOF_NODES: usize = 24; @@ -13,44 +13,41 @@ const TRANSFER_ARGS_LEN: usize = 108; /// Accounts for withdrawing two compressed NFTs from the vault in one transaction. /// Each cNFT can be from a different merkle tree. #[derive(Accounts)] -pub struct WithdrawTwo<'info> { +pub struct WithdrawTwo { /// Tree authority PDA for tree 1. #[account(mut)] - pub tree_authority1: &'info UncheckedAccount, + pub tree_authority1: UncheckedAccount, /// Vault PDA that owns the cNFTs — signs both transfers. #[account(seeds = [b"cNFT-vault"], bump)] - pub leaf_owner: &'info UncheckedAccount, + pub leaf_owner: UncheckedAccount, /// Recipient for cNFT 1. - pub new_leaf_owner1: &'info UncheckedAccount, + pub new_leaf_owner1: UncheckedAccount, /// Merkle tree for cNFT 1. #[account(mut)] - pub merkle_tree1: &'info UncheckedAccount, + pub merkle_tree1: UncheckedAccount, /// Tree authority PDA for tree 2. #[account(mut)] - pub tree_authority2: &'info UncheckedAccount, + pub tree_authority2: UncheckedAccount, /// Recipient for cNFT 2. - pub new_leaf_owner2: &'info UncheckedAccount, + pub new_leaf_owner2: UncheckedAccount, /// Merkle tree for cNFT 2. #[account(mut)] - pub merkle_tree2: &'info UncheckedAccount, + pub merkle_tree2: UncheckedAccount, /// SPL Noop log wrapper. - pub log_wrapper: &'info UncheckedAccount, + pub log_wrapper: UncheckedAccount, /// SPL Account Compression program. #[account(address = SPL_ACCOUNT_COMPRESSION_ID)] - pub compression_program: &'info UncheckedAccount, + pub compression_program: UncheckedAccount, /// mpl-bubblegum program. #[account(address = MPL_BUBBLEGUM_ID)] - pub bubblegum_program: &'info UncheckedAccount, - pub system_program: &'info Program, + pub bubblegum_program: UncheckedAccount, + pub system_program: Program, } #[allow(clippy::too_many_lines)] -pub fn handle_withdraw_two_cnfts<'info>( - accounts: &WithdrawTwo<'info>, ctx: &CtxWithRemaining<'info, WithdrawTwo<'info>>, -) -> Result<(), ProgramError> { +pub fn handle_withdraw_two_cnfts(accounts: &mut WithdrawTwo, data: &[u8], remaining: RemainingAccounts<'_>, leaf_owner_bump: u8) -> Result<(), ProgramError> { // Parse instruction args: // args1(108) + proof_1_length(1) + args2(108) + _proof_2_length(1) = 218 bytes - let data = ctx.data; if data.len() < 218 { return Err(ProgramError::InvalidInstructionData); } @@ -61,7 +58,7 @@ pub fn handle_withdraw_two_cnfts<'info>( // _proof_2_length at data[217] — not needed, remaining after proof1 is proof2 // PDA signer seeds - let bump_bytes = [ctx.bumps.leaf_owner]; + let bump_bytes = [leaf_owner_bump]; let seeds: [Seed; 2] = [ Seed::from(b"cNFT-vault" as &[u8]), Seed::from(&bump_bytes as &[u8]), @@ -69,7 +66,6 @@ pub fn handle_withdraw_two_cnfts<'info>( let signer = Signer::from(&seeds as &[Seed]); // Collect all remaining accounts (proof1 ++ proof2) - let remaining = ctx.remaining_accounts(); let placeholder = accounts.system_program.to_account_view().clone(); let mut all_proofs: [AccountView; MAX_PROOF_NODES * 2] = core::array::from_fn(|_| placeholder.clone()); diff --git a/compression/cnft-vault/quasar/src/lib.rs b/compression/cnft-vault/quasar/src/lib.rs index cf62058a7..c066b0245 100644 --- a/compression/cnft-vault/quasar/src/lib.rs +++ b/compression/cnft-vault/quasar/src/lib.rs @@ -33,12 +33,18 @@ mod quasar_cnft_vault { /// Withdraw a single compressed NFT from the vault PDA. #[instruction(discriminator = 0)] pub fn withdraw_cnft(ctx: CtxWithRemaining) -> Result<(), ProgramError> { - instructions::handle_withdraw_cnft(&ctx.accounts, &ctx) + let data = ctx.data; + let remaining = ctx.remaining_accounts(); + let leaf_owner_bump = ctx.bumps.leaf_owner; + instructions::handle_withdraw_cnft(&mut ctx.accounts, data, remaining, leaf_owner_bump) } /// Withdraw two compressed NFTs from the vault PDA in a single transaction. #[instruction(discriminator = 1)] pub fn withdraw_two_cnfts(ctx: CtxWithRemaining) -> Result<(), ProgramError> { - instructions::handle_withdraw_two_cnfts(&ctx.accounts, &ctx) + let data = ctx.data; + let remaining = ctx.remaining_accounts(); + let leaf_owner_bump = ctx.bumps.leaf_owner; + instructions::handle_withdraw_two_cnfts(&mut ctx.accounts, data, remaining, leaf_owner_bump) } } diff --git a/compression/cutils/quasar/Cargo.toml b/compression/cutils/quasar/Cargo.toml index ee04326cb..16379e000 100644 --- a/compression/cutils/quasar/Cargo.toml +++ b/compression/cutils/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } # Direct dependency for invoke_with_bounds — raw CPI with variable proof accounts. solana-instruction-view = { version = "2", features = ["cpi"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-address = { version = "2.2.0", features = ["decode"] } diff --git a/compression/cutils/quasar/src/instructions/mint.rs b/compression/cutils/quasar/src/instructions/mint.rs index 34232016b..9f95275b4 100644 --- a/compression/cutils/quasar/src/instructions/mint.rs +++ b/compression/cutils/quasar/src/instructions/mint.rs @@ -13,49 +13,48 @@ const MAX_IX_DATA: usize = 400; /// Accounts for minting a compressed NFT to a collection. #[derive(Accounts)] -pub struct Mint<'info> { - pub payer: &'info Signer, +pub struct Mint { + pub payer: Signer, /// Tree authority PDA (seeds checked by Bubblegum). #[account(mut)] - pub tree_authority: &'info UncheckedAccount, + pub tree_authority: UncheckedAccount, /// Owner of the newly minted cNFT. - pub leaf_owner: &'info UncheckedAccount, + pub leaf_owner: UncheckedAccount, /// Delegate for the newly minted cNFT. - pub leaf_delegate: &'info UncheckedAccount, + pub leaf_delegate: UncheckedAccount, /// Merkle tree to mint into. #[account(mut)] - pub merkle_tree: &'info UncheckedAccount, + pub merkle_tree: UncheckedAccount, /// Tree delegate (must be signer). - pub tree_delegate: &'info Signer, + pub tree_delegate: Signer, /// Collection authority (must be signer). - pub collection_authority: &'info Signer, + pub collection_authority: Signer, /// Collection authority record PDA (or Bubblegum program address). - pub collection_authority_record_pda: &'info UncheckedAccount, + pub collection_authority_record_pda: UncheckedAccount, /// Collection mint account. - pub collection_mint: &'info UncheckedAccount, + pub collection_mint: UncheckedAccount, /// Collection metadata account. #[account(mut)] - pub collection_metadata: &'info UncheckedAccount, + pub collection_metadata: UncheckedAccount, /// Edition account for the collection. - pub edition_account: &'info UncheckedAccount, + pub edition_account: UncheckedAccount, /// Bubblegum signer PDA. - pub bubblegum_signer: &'info UncheckedAccount, + pub bubblegum_signer: UncheckedAccount, /// SPL Noop log wrapper. - pub log_wrapper: &'info UncheckedAccount, + pub log_wrapper: UncheckedAccount, /// SPL Account Compression program. #[account(address = SPL_ACCOUNT_COMPRESSION_ID)] - pub compression_program: &'info UncheckedAccount, + pub compression_program: UncheckedAccount, /// Token Metadata program. - pub token_metadata_program: &'info UncheckedAccount, + pub token_metadata_program: UncheckedAccount, /// mpl-bubblegum program. #[account(address = MPL_BUBBLEGUM_ID)] - pub bubblegum_program: &'info UncheckedAccount, - pub system_program: &'info Program, + pub bubblegum_program: UncheckedAccount, + pub system_program: Program, } -pub fn handle_mint<'info>(accounts: &Mint<'info>, ctx: &Ctx<'info, Mint<'info>>) -> Result<(), ProgramError> { +pub fn handle_mint(accounts: &mut Mint, data: &[u8]) -> Result<(), ProgramError> { // Parse URI from instruction data: u32 length prefix + utf8 bytes (borsh String) - let data = ctx.data; if data.len() < 4 { return Err(ProgramError::InvalidInstructionData); } diff --git a/compression/cutils/quasar/src/instructions/verify.rs b/compression/cutils/quasar/src/instructions/verify.rs index 42b926a3d..76184326d 100644 --- a/compression/cutils/quasar/src/instructions/verify.rs +++ b/compression/cutils/quasar/src/instructions/verify.rs @@ -1,6 +1,6 @@ use crate::bubblegum_types::{get_asset_id, leaf_schema_v1_hash}; use crate::*; -use quasar_lang::cpi::{InstructionAccount, InstructionView}; +use quasar_lang::{cpi::{InstructionAccount, InstructionView}, remaining::RemainingAccounts}; /// Maximum proof nodes for the merkle tree. const MAX_PROOF_NODES: usize = 24; @@ -13,23 +13,20 @@ const VERIFY_LEAF_DISCRIMINATOR: [u8; 8] = [0x7c, 0xdc, 0x16, 0xdf, 0x68, 0x0a, /// Accounts for verifying a compressed NFT leaf in the merkle tree. #[derive(Accounts)] -pub struct Verify<'info> { - pub leaf_owner: &'info Signer, +pub struct Verify { + pub leaf_owner: Signer, /// Leaf delegate. - pub leaf_delegate: &'info UncheckedAccount, + pub leaf_delegate: UncheckedAccount, /// Merkle tree to verify against. - pub merkle_tree: &'info UncheckedAccount, + pub merkle_tree: UncheckedAccount, /// SPL Account Compression program. #[account(address = SPL_ACCOUNT_COMPRESSION_ID)] - pub compression_program: &'info UncheckedAccount, + pub compression_program: UncheckedAccount, } -pub fn handle_verify<'info>( - accounts: &Verify<'info>, ctx: &CtxWithRemaining<'info, Verify<'info>>, -) -> Result<(), ProgramError> { +pub fn handle_verify(accounts: &mut Verify, data: &[u8], remaining: RemainingAccounts<'_>) -> Result<(), ProgramError> { // Parse verify params from instruction data: // root(32) + data_hash(32) + creator_hash(32) + nonce(8) + index(4) = 108 bytes - let data = ctx.data; if data.len() < 108 { return Err(ProgramError::InvalidInstructionData); } @@ -59,7 +56,6 @@ pub fn handle_verify<'info>( ix_data[72..76].copy_from_slice(&index.to_le_bytes()); // Collect proof nodes - let remaining = ctx.remaining_accounts(); let placeholder = accounts.compression_program.to_account_view().clone(); let mut proof_views: [AccountView; MAX_PROOF_NODES] = core::array::from_fn(|_| placeholder.clone()); diff --git a/compression/cutils/quasar/src/lib.rs b/compression/cutils/quasar/src/lib.rs index cdead5023..e9b674c61 100644 --- a/compression/cutils/quasar/src/lib.rs +++ b/compression/cutils/quasar/src/lib.rs @@ -32,12 +32,15 @@ mod quasar_cutils { /// Mint a compressed NFT to a collection via MintToCollectionV1. #[instruction(discriminator = 0)] pub fn mint(ctx: Ctx) -> Result<(), ProgramError> { - instructions::handle_mint(&ctx.accounts, &ctx) + let data = ctx.data; + instructions::handle_mint(&mut ctx.accounts, data) } /// Verify a compressed NFT leaf exists in the merkle tree. #[instruction(discriminator = 1)] pub fn verify(ctx: CtxWithRemaining) -> Result<(), ProgramError> { - instructions::handle_verify(&ctx.accounts, &ctx) + let data = ctx.data; + let remaining = ctx.remaining_accounts(); + instructions::handle_verify(&mut ctx.accounts, data, remaining) } } diff --git a/oracles/pyth/quasar/Cargo.toml b/oracles/pyth/quasar/Cargo.toml index 948cd6576..ec4480da1 100644 --- a/oracles/pyth/quasar/Cargo.toml +++ b/oracles/pyth/quasar/Cargo.toml @@ -22,9 +22,9 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } solana-address = { version = "2.2.0", features = ["decode"] } diff --git a/oracles/pyth/quasar/src/instructions/read_price.rs b/oracles/pyth/quasar/src/instructions/read_price.rs index 6b5d08a45..9c28d9018 100644 --- a/oracles/pyth/quasar/src/instructions/read_price.rs +++ b/oracles/pyth/quasar/src/instructions/read_price.rs @@ -19,50 +19,42 @@ const MIN_DATA_LEN: usize = 101; /// Uses `UncheckedAccount` because Quasar does not have a built-in Pyth account type; /// the caller is responsible for passing a valid PriceUpdateV2 account. #[derive(Accounts)] -pub struct ReadPrice<'info> { +pub struct ReadPrice { /// The Pyth PriceUpdateV2 price update account. - pub price_update: &'info UncheckedAccount, + pub price_update: UncheckedAccount, } #[inline(always)] pub fn handle_read_price(accounts: &mut ReadPrice) -> Result<(), ProgramError> { let view = accounts.price_update.to_account_view(); - let data = view.data(); + let data = unsafe { core::slice::from_raw_parts(view.data_ptr(), view.data_len()) }; if data.len() < MIN_DATA_LEN { return Err(ProgramError::InvalidAccountData); } - let price = i64::from_le_bytes( + let _price = i64::from_le_bytes( data[PRICE_OFFSET..PRICE_OFFSET + 8] .try_into() .map_err(|_| ProgramError::InvalidAccountData)?, ); - let conf = u64::from_le_bytes( + let _conf = u64::from_le_bytes( data[CONF_OFFSET..CONF_OFFSET + 8] .try_into() .map_err(|_| ProgramError::InvalidAccountData)?, ); - let exponent = i32::from_le_bytes( + let _exponent = i32::from_le_bytes( data[EXPONENT_OFFSET..EXPONENT_OFFSET + 4] .try_into() .map_err(|_| ProgramError::InvalidAccountData)?, ); - let publish_time = i64::from_le_bytes( + let _publish_time = i64::from_le_bytes( data[PUBLISH_TIME_OFFSET..PUBLISH_TIME_OFFSET + 8] .try_into() .map_err(|_| ProgramError::InvalidAccountData)?, ); - log("Pyth price feed data:"); - log(" price (raw):"); - log_64(price as u64); - log(" confidence:"); - log_64(conf); - log(" exponent:"); - log_64(exponent as u64); - log(" publish_time:"); - log_64(publish_time as u64); + log("Pyth price feed data read successfully."); Ok(()) } diff --git a/tokens/create-token/quasar/Cargo.toml b/tokens/create-token/quasar/Cargo.toml index 510afb6db..3eef7659c 100644 --- a/tokens/create-token/quasar/Cargo.toml +++ b/tokens/create-token/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/create-token/quasar/src/lib.rs b/tokens/create-token/quasar/src/lib.rs index 7d0d92b82..b68466633 100644 --- a/tokens/create-token/quasar/src/lib.rs +++ b/tokens/create-token/quasar/src/lib.rs @@ -33,37 +33,37 @@ mod quasar_create_token { /// Accounts for creating a new token mint. /// Quasar's `#[account(init)]` handles the create_account + initialize_mint CPI. #[derive(Accounts)] -pub struct CreateToken<'info> { +pub struct CreateToken { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut, init, payer = payer, mint::decimals = 9, mint::authority = payer)] - pub mint: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, -} - -#[inline(always)] -pub fn handle_create_token(accounts: &CreateToken) -> Result<(), ProgramError> { - // Mint account is created and initialised by Quasar's account init. - Ok(()) + pub mint: Account, + pub rent: Sysvar, + pub token_program: Program, + pub system_program: Program, } /// Accounts for minting tokens to an existing token account. #[derive(Accounts)] -pub struct MintTokens<'info> { +pub struct MintTokens { #[account(mut)] - pub authority: &'info Signer, + pub authority: Signer, #[account(mut)] - pub mint: &'info mut Account, + pub mint: Account, #[account(mut)] - pub token_account: &'info mut Account, - pub token_program: &'info Program, + pub token_account: Account, + pub token_program: Program, +} + +#[inline(always)] +fn handle_create_token(_accounts: &mut CreateToken) -> Result<(), ProgramError> { + // Mint account is created and initialised by Quasar's account init. + Ok(()) } #[inline(always)] -pub fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64) -> Result<(), ProgramError> { +fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64) -> Result<(), ProgramError> { accounts.token_program - .mint_to(accounts.mint, accounts.token_account, accounts.authority, amount) + .mint_to(&accounts.mint, &accounts.token_account, &accounts.authority, amount) .invoke() } diff --git a/tokens/escrow/quasar/Cargo.toml b/tokens/escrow/quasar/Cargo.toml index 9c21b47a2..1e0e264cf 100644 --- a/tokens/escrow/quasar/Cargo.toml +++ b/tokens/escrow/quasar/Cargo.toml @@ -22,12 +22,12 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-address = { version = "2.2.0" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/escrow/quasar/src/instructions/make.rs b/tokens/escrow/quasar/src/instructions/make.rs index bfbb4144d..9ab4ec730 100644 --- a/tokens/escrow/quasar/src/instructions/make.rs +++ b/tokens/escrow/quasar/src/instructions/make.rs @@ -1,44 +1,44 @@ use { - crate::state::Escrow, + crate::state::{Escrow, EscrowInner}, quasar_lang::prelude::*, quasar_spl::{Mint, Token, TokenCpi}, }; #[derive(Accounts)] -pub struct Make<'info> { +pub struct Make { #[account(mut)] - pub maker: &'info Signer, - #[account(mut, init, payer = maker, seeds = [b"escrow", maker], bump)] - pub escrow: &'info mut Account, - pub mint_a: &'info Account, - pub mint_b: &'info Account, + pub maker: Signer, + #[account(mut, init, payer = maker, seeds = Escrow::seeds(maker), bump)] + pub escrow: Account, + pub mint_a: Account, + pub mint_b: Account, #[account(mut)] - pub maker_ta_a: &'info mut Account, + pub maker_ta_a: Account, #[account(mut, init_if_needed, payer = maker, token::mint = mint_b, token::authority = maker)] - pub maker_ta_b: &'info mut Account, + pub maker_ta_b: Account, #[account(mut, init_if_needed, payer = maker, token::mint = mint_a, token::authority = escrow)] - pub vault_ta_a: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub vault_ta_a: Account, + pub rent: Sysvar, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] pub fn handle_make_escrow(accounts: &mut Make, receive: u64, bumps: &MakeBumps) -> Result<(), ProgramError> { - accounts.escrow.set_inner( - *accounts.maker.address(), - *accounts.mint_a.address(), - *accounts.mint_b.address(), - *accounts.maker_ta_b.address(), + accounts.escrow.set_inner(EscrowInner { + maker: *accounts.maker.address(), + mint_a: *accounts.mint_a.address(), + mint_b: *accounts.mint_b.address(), + maker_ta_b: *accounts.maker_ta_b.address(), receive, - bumps.escrow, - ); + bump: bumps.escrow, + }); Ok(()) } #[inline(always)] pub fn handle_deposit_tokens(accounts: &mut Make, amount: u64) -> Result<(), ProgramError> { accounts.token_program - .transfer(accounts.maker_ta_a, accounts.vault_ta_a, accounts.maker, amount) + .transfer(&accounts.maker_ta_a, &accounts.vault_ta_a, &accounts.maker, amount) .invoke() } diff --git a/tokens/escrow/quasar/src/instructions/refund.rs b/tokens/escrow/quasar/src/instructions/refund.rs index 0de24d9d7..d1e5d1f5b 100644 --- a/tokens/escrow/quasar/src/instructions/refund.rs +++ b/tokens/escrow/quasar/src/instructions/refund.rs @@ -5,48 +5,42 @@ use { }; #[derive(Accounts)] -pub struct Refund<'info> { +pub struct Refund { #[account(mut)] - pub maker: &'info Signer, + pub maker: Signer, #[account( mut, has_one = maker, close = maker, - seeds = [b"escrow", maker], + seeds = Escrow::seeds(maker), bump = escrow.bump )] - pub escrow: &'info mut Account, - pub mint_a: &'info Account, + pub escrow: Account, + pub mint_a: Account, #[account(mut, init_if_needed, payer = maker, token::mint = mint_a, token::authority = maker)] - pub maker_ta_a: &'info mut Account, + pub maker_ta_a: Account, #[account(mut)] - pub vault_ta_a: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub vault_ta_a: Account, + pub rent: Sysvar, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_withdraw_tokens_and_close(accounts: &mut Refund, bumps: &RefundBumps) -> Result<(), ProgramError> { - let maker_key = accounts.escrow.maker; - let bump = [bumps.escrow]; - let seeds: &[Seed] = &[ - Seed::from(b"escrow" as &[u8]), - Seed::from(maker_key.as_ref()), - Seed::from(&bump as &[u8]), - ]; +pub fn handle_withdraw_tokens_and_close_refund(accounts: &mut Refund, bumps: &RefundBumps) -> Result<(), ProgramError> { + let seeds = accounts.escrow_seeds(bumps); accounts.token_program .transfer( - accounts.vault_ta_a, - accounts.maker_ta_a, - accounts.escrow, + &accounts.vault_ta_a, + &accounts.maker_ta_a, + &accounts.escrow, accounts.vault_ta_a.amount(), ) - .invoke_signed(seeds)?; + .invoke_signed(&seeds)?; accounts.token_program - .close_account(accounts.vault_ta_a, accounts.maker, accounts.escrow) - .invoke_signed(seeds)?; + .close_account(&accounts.vault_ta_a, &accounts.maker, &accounts.escrow) + .invoke_signed(&seeds)?; Ok(()) } diff --git a/tokens/escrow/quasar/src/instructions/take.rs b/tokens/escrow/quasar/src/instructions/take.rs index dd988a648..78b8e695c 100644 --- a/tokens/escrow/quasar/src/instructions/take.rs +++ b/tokens/escrow/quasar/src/instructions/take.rs @@ -5,69 +5,63 @@ use { }; #[derive(Accounts)] -pub struct Take<'info> { +pub struct Take { #[account(mut)] - pub taker: &'info Signer, + pub taker: Signer, #[account( mut, has_one = maker, has_one = maker_ta_b, constraint = escrow.receive > 0, close = taker, - seeds = [b"escrow", maker], + seeds = Escrow::seeds(maker), bump = escrow.bump )] - pub escrow: &'info mut Account, + pub escrow: Account, #[account(mut)] - pub maker: &'info UncheckedAccount, - pub mint_a: &'info Account, - pub mint_b: &'info Account, + pub maker: UncheckedAccount, + pub mint_a: Account, + pub mint_b: Account, #[account(mut, init_if_needed, payer = taker, token::mint = mint_a, token::authority = taker)] - pub taker_ta_a: &'info mut Account, + pub taker_ta_a: Account, #[account(mut)] - pub taker_ta_b: &'info mut Account, + pub taker_ta_b: Account, #[account(mut, init_if_needed, payer = taker, token::mint = mint_b, token::authority = maker)] - pub maker_ta_b: &'info mut Account, + pub maker_ta_b: Account, #[account(mut)] - pub vault_ta_a: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub vault_ta_a: Account, + pub rent: Sysvar, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] pub fn handle_transfer_tokens(accounts: &mut Take) -> Result<(), ProgramError> { accounts.token_program .transfer( - accounts.taker_ta_b, - accounts.maker_ta_b, - accounts.taker, + &accounts.taker_ta_b, + &accounts.maker_ta_b, + &accounts.taker, accounts.escrow.receive, ) .invoke() } #[inline(always)] -pub fn handle_withdraw_tokens_and_close(accounts: &mut Take, bumps: &TakeBumps) -> Result<(), ProgramError> { - let maker_key = accounts.escrow.maker; - let bump = [bumps.escrow]; - let seeds: &[Seed] = &[ - Seed::from(b"escrow" as &[u8]), - Seed::from(maker_key.as_ref()), - Seed::from(&bump as &[u8]), - ]; +pub fn handle_withdraw_tokens_and_close_take(accounts: &mut Take, bumps: &TakeBumps) -> Result<(), ProgramError> { + let seeds = accounts.escrow_seeds(bumps); accounts.token_program .transfer( - accounts.vault_ta_a, - accounts.taker_ta_a, - accounts.escrow, + &accounts.vault_ta_a, + &accounts.taker_ta_a, + &accounts.escrow, accounts.vault_ta_a.amount(), ) - .invoke_signed(seeds)?; + .invoke_signed(&seeds)?; accounts.token_program - .close_account(accounts.vault_ta_a, accounts.taker, accounts.escrow) - .invoke_signed(seeds)?; + .close_account(&accounts.vault_ta_a, &accounts.taker, &accounts.escrow) + .invoke_signed(&seeds)?; Ok(()) } diff --git a/tokens/escrow/quasar/src/lib.rs b/tokens/escrow/quasar/src/lib.rs index 4bf53a1d2..d779c4770 100644 --- a/tokens/escrow/quasar/src/lib.rs +++ b/tokens/escrow/quasar/src/lib.rs @@ -19,18 +19,18 @@ mod quasar_escrow { #[instruction(discriminator = 0)] pub fn make(ctx: Ctx, deposit: u64, receive: u64) -> Result<(), ProgramError> { - instructions::handle_make_escrow(&mut ctx.accounts, receive, &ctx.bumps)?; - instructions::handle_deposit_tokens(&mut ctx.accounts, deposit) + instructions::make::handle_make_escrow(&mut ctx.accounts, receive, &ctx.bumps)?; + instructions::make::handle_deposit_tokens(&mut ctx.accounts, deposit) } #[instruction(discriminator = 1)] pub fn take(ctx: Ctx) -> Result<(), ProgramError> { - instructions::handle_transfer_tokens(&mut ctx.accounts)?; - instructions::take::handle_withdraw_tokens_and_close(&mut ctx.accounts, &ctx.bumps) + instructions::take::handle_transfer_tokens(&mut ctx.accounts)?; + instructions::take::handle_withdraw_tokens_and_close_take(&mut ctx.accounts, &ctx.bumps) } #[instruction(discriminator = 2)] pub fn refund(ctx: Ctx) -> Result<(), ProgramError> { - instructions::refund::handle_withdraw_tokens_and_close(&mut ctx.accounts, &ctx.bumps) + instructions::refund::handle_withdraw_tokens_and_close_refund(&mut ctx.accounts, &ctx.bumps) } } diff --git a/tokens/escrow/quasar/src/state.rs b/tokens/escrow/quasar/src/state.rs index 77d218381..04c6b2d07 100644 --- a/tokens/escrow/quasar/src/state.rs +++ b/tokens/escrow/quasar/src/state.rs @@ -2,7 +2,8 @@ use quasar_lang::prelude::*; /// Escrow state: records the maker's desired receive amount and the /// associated mint/token-account addresses. -#[account(discriminator = 1)] +#[account(discriminator = 1, set_inner)] +#[seeds(b"escrow", maker: Address)] pub struct Escrow { pub maker: Address, pub mint_a: Address, diff --git a/tokens/external-delegate-token-master/quasar/Cargo.toml b/tokens/external-delegate-token-master/quasar/Cargo.toml index c82dfe38f..347832b68 100644 --- a/tokens/external-delegate-token-master/quasar/Cargo.toml +++ b/tokens/external-delegate-token-master/quasar/Cargo.toml @@ -22,13 +22,13 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } solana-define-syscall = "4.0" solana-keccak-hasher = "3.1" [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/external-delegate-token-master/quasar/src/lib.rs b/tokens/external-delegate-token-master/quasar/src/lib.rs index 492a1b820..d7923128e 100644 --- a/tokens/external-delegate-token-master/quasar/src/lib.rs +++ b/tokens/external-delegate-token-master/quasar/src/lib.rs @@ -62,32 +62,30 @@ mod quasar_external_delegate_token_master { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut, init, payer = authority)] - pub user_account: &'info mut Account, + pub user_account: Account, #[account(mut)] - pub authority: &'info Signer, - pub system_program: &'info Program, + pub authority: Signer, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { accounts.user_account .set_inner(*accounts.authority.address(), [0u8; 20]); Ok(()) } #[derive(Accounts)] -pub struct SetEthereumAddress<'info> { +pub struct SetEthereumAddress { #[account(mut)] - pub user_account: &'info mut Account, - pub authority: &'info Signer, + pub user_account: Account, + pub authority: Signer, } #[inline(always)] -pub fn handle_set_ethereum_address( - accounts: &mut SetEthereumAddress, ethereum_address: [u8; 20], -) -> Result<(), ProgramError> { +fn handle_set_ethereum_address(accounts: &mut SetEthereumAddress, ethereum_address: [u8; 20]) -> Result<(), ProgramError> { require_keys_eq!( accounts.user_account.authority, *accounts.authority.address(), @@ -98,22 +96,23 @@ pub fn handle_set_ethereum_address( } #[derive(Accounts)] -pub struct TransferTokens<'info> { - pub user_account: &'info Account, - pub authority: &'info Signer, +pub struct TransferTokens { + pub user_account: Account, + pub authority: Signer, #[account(mut)] - pub user_token_account: &'info mut Account, + pub user_token_account: Account, #[account(mut)] - pub recipient_token_account: &'info mut Account, + pub recipient_token_account: Account, /// PDA derived from user_account address. #[account(seeds = [user_account], bump)] - pub user_pda: &'info UncheckedAccount, - pub token_program: &'info Program, + pub user_pda: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_transfer_tokens( - accounts: &TransferTokens, amount: u64, +fn handle_transfer_tokens( + accounts: &mut TransferTokens, + amount: u64, signature: &[u8; 65], message: &[u8; 32], bumps: &TransferTokensBumps, @@ -134,33 +133,30 @@ pub fn handle_transfer_tokens( accounts.token_program .transfer( - accounts.user_token_account, - accounts.recipient_token_account, - accounts.user_pda, + &accounts.user_token_account, + &accounts.recipient_token_account, + &accounts.user_pda, amount, ) .invoke_signed(seeds) } #[derive(Accounts)] -pub struct AuthorityTransfer<'info> { - pub user_account: &'info Account, - pub authority: &'info Signer, +pub struct AuthorityTransfer { + pub user_account: Account, + pub authority: Signer, #[account(mut)] - pub user_token_account: &'info mut Account, + pub user_token_account: Account, #[account(mut)] - pub recipient_token_account: &'info mut Account, + pub recipient_token_account: Account, /// PDA derived from user_account address. #[account(seeds = [user_account], bump)] - pub user_pda: &'info UncheckedAccount, - pub token_program: &'info Program, + pub user_pda: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_authority_transfer( - accounts: &AuthorityTransfer, amount: u64, - bumps: &AuthorityTransferBumps, -) -> Result<(), ProgramError> { +fn handle_authority_transfer(accounts: &mut AuthorityTransfer, amount: u64, bumps: &AuthorityTransferBumps) -> Result<(), ProgramError> { require_keys_eq!( accounts.user_account.authority, *accounts.authority.address(), @@ -175,9 +171,9 @@ pub fn handle_authority_transfer( accounts.token_program .transfer( - accounts.user_token_account, - accounts.recipient_token_account, - accounts.user_pda, + &accounts.user_token_account, + &accounts.recipient_token_account, + &accounts.user_pda, amount, ) .invoke_signed(seeds) diff --git a/tokens/nft-minter/quasar/Cargo.toml b/tokens/nft-minter/quasar/Cargo.toml index 04f79cfe3..c6d67aca2 100644 --- a/tokens/nft-minter/quasar/Cargo.toml +++ b/tokens/nft-minter/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = { version = "0.0", features = ["metadata"] } +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master", features = ["metadata"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/nft-minter/quasar/src/lib.rs b/tokens/nft-minter/quasar/src/lib.rs index 50921d447..9127dcab8 100644 --- a/tokens/nft-minter/quasar/src/lib.rs +++ b/tokens/nft-minter/quasar/src/lib.rs @@ -30,35 +30,36 @@ mod quasar_nft_minter { /// All accounts needed to mint an NFT in one transaction. #[derive(Accounts)] -pub struct MintNft<'info> { +pub struct MintNft { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// Metadata PDA — initialised by the Metaplex program. #[account(mut)] - pub metadata_account: &'info UncheckedAccount, + pub metadata_account: UncheckedAccount, /// Master edition PDA — initialised by the Metaplex program. #[account(mut)] - pub edition_account: &'info UncheckedAccount, + pub edition_account: UncheckedAccount, /// NFT mint (decimals = 0). #[account(mut, init, payer = payer, mint::decimals = 0, mint::authority = payer, mint::freeze_authority = payer)] - pub mint_account: &'info mut Account, + pub mint_account: Account, /// Token account holding the NFT. #[account(mut, init_if_needed, payer = payer, token::mint = mint_account, token::authority = payer)] - pub associated_token_account: &'info mut Account, + pub associated_token_account: Account, - pub token_program: &'info Program, - pub token_metadata_program: &'info MetadataProgram, - pub system_program: &'info Program, - pub rent: &'info Sysvar, + pub token_program: Program, + pub token_metadata_program: MetadataProgram, + pub system_program: Program, + pub rent: Sysvar, } #[inline(always)] -pub fn handle_mint_nft( - accounts: &MintNft, nft_name: &str, +fn handle_mint_nft( + accounts: &mut MintNft, + nft_name: &str, nft_symbol: &str, nft_uri: &str, ) -> Result<(), ProgramError> { @@ -66,9 +67,9 @@ pub fn handle_mint_nft( log("Minting token"); accounts.token_program .mint_to( - accounts.mint_account, - accounts.associated_token_account, - accounts.payer, + &accounts.mint_account, + &accounts.associated_token_account, + &accounts.payer, 1u64, ) .invoke()?; @@ -77,13 +78,13 @@ pub fn handle_mint_nft( log("Creating metadata account"); accounts.token_metadata_program .create_metadata_accounts_v3( - accounts.metadata_account, - accounts.mint_account, - accounts.payer, - accounts.payer, - accounts.payer, - accounts.system_program, - accounts.rent, + &accounts.metadata_account, + &accounts.mint_account, + &accounts.payer, + &accounts.payer, + &accounts.payer, + &accounts.system_program, + &accounts.rent, nft_name, nft_symbol, nft_uri, @@ -97,15 +98,15 @@ pub fn handle_mint_nft( log("Creating master edition account"); accounts.token_metadata_program .create_master_edition_v3( - accounts.edition_account, - accounts.mint_account, - accounts.payer, // update_authority - accounts.payer, // mint_authority - accounts.payer, // payer - accounts.metadata_account, - accounts.token_program, - accounts.system_program, - accounts.rent, + &accounts.edition_account, + &accounts.mint_account, + &accounts.payer, // update_authority + &accounts.payer, // mint_authority + &accounts.payer, // payer + &accounts.metadata_account, + &accounts.token_program, + &accounts.system_program, + &accounts.rent, None, // max_supply = unlimited ) .invoke()?; diff --git a/tokens/nft-operations/quasar/Cargo.toml b/tokens/nft-operations/quasar/Cargo.toml index 629c249c9..0ea933855 100644 --- a/tokens/nft-operations/quasar/Cargo.toml +++ b/tokens/nft-operations/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = { version = "0.0", features = ["metadata"] } +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master", features = ["metadata"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/nft-operations/quasar/src/instructions/create_collection.rs b/tokens/nft-operations/quasar/src/instructions/create_collection.rs index 29ef6450b..e0f2032a7 100644 --- a/tokens/nft-operations/quasar/src/instructions/create_collection.rs +++ b/tokens/nft-operations/quasar/src/instructions/create_collection.rs @@ -8,33 +8,31 @@ use quasar_spl::{ /// /// The PDA `["authority"]` acts as mint authority and update authority. #[derive(Accounts)] -pub struct CreateCollection<'info> { +pub struct CreateCollection { #[account(mut)] - pub user: &'info Signer, + pub user: Signer, #[account(mut, init, payer = user, mint::decimals = 0, mint::authority = mint_authority, mint::freeze_authority = mint_authority)] - pub mint: &'info mut Account, + pub mint: Account, /// PDA used as mint authority and update authority. #[account(seeds = [b"authority"], bump)] - pub mint_authority: &'info UncheckedAccount, + pub mint_authority: UncheckedAccount, /// Metadata PDA — initialised by the Metaplex program. #[account(mut)] - pub metadata: &'info UncheckedAccount, + pub metadata: UncheckedAccount, /// Master edition PDA — initialised by the Metaplex program. #[account(mut)] - pub master_edition: &'info UncheckedAccount, + pub master_edition: UncheckedAccount, /// Token account to hold the collection NFT. #[account(mut, init_if_needed, payer = user, token::mint = mint, token::authority = user)] - pub destination: &'info mut Account, - pub system_program: &'info Program, - pub token_program: &'info Program, - pub token_metadata_program: &'info MetadataProgram, - pub rent: &'info Sysvar, + pub destination: Account, + pub system_program: Program, + pub token_program: Program, + pub token_metadata_program: MetadataProgram, + pub rent: Sysvar, } #[inline(always)] -pub fn handle_create_collection( - accounts: &CreateCollection, bumps: &CreateCollectionBumps, -) -> Result<(), ProgramError> { +pub fn handle_create_collection(accounts: &mut CreateCollection, bumps: &CreateCollectionBumps) -> Result<(), ProgramError> { let bump = [bumps.mint_authority]; let seeds: &[Seed] = &[ Seed::from(b"authority" as &[u8]), @@ -43,20 +41,20 @@ pub fn handle_create_collection( // Mint 1 token to the destination. accounts.token_program - .mint_to(accounts.mint, accounts.destination, accounts.mint_authority, 1u64) + .mint_to(&accounts.mint, &accounts.destination, &accounts.mint_authority, 1u64) .invoke_signed(seeds)?; log("Collection NFT minted!"); // Create metadata account. accounts.token_metadata_program .create_metadata_accounts_v3( - accounts.metadata, - accounts.mint, - accounts.mint_authority, - accounts.user, - accounts.mint_authority, - accounts.system_program, - accounts.rent, + &accounts.metadata, + &accounts.mint, + &accounts.mint_authority, + &accounts.user, + &accounts.mint_authority, + &accounts.system_program, + &accounts.rent, "DummyCollection", "DC", "", @@ -70,15 +68,15 @@ pub fn handle_create_collection( // Create master edition. accounts.token_metadata_program .create_master_edition_v3( - accounts.master_edition, - accounts.mint, - accounts.mint_authority, // update_authority - accounts.mint_authority, // mint_authority - accounts.user, // payer - accounts.metadata, - accounts.token_program, - accounts.system_program, - accounts.rent, + &accounts.master_edition, + &accounts.mint, + &accounts.mint_authority, // update_authority + &accounts.mint_authority, // mint_authority + &accounts.user, // payer + &accounts.metadata, + &accounts.token_program, + &accounts.system_program, + &accounts.rent, Some(0), // max_supply = 0 means unique 1/1 ) .invoke_signed(seeds)?; diff --git a/tokens/nft-operations/quasar/src/instructions/mint_nft.rs b/tokens/nft-operations/quasar/src/instructions/mint_nft.rs index 14264bbe2..b0a16944b 100644 --- a/tokens/nft-operations/quasar/src/instructions/mint_nft.rs +++ b/tokens/nft-operations/quasar/src/instructions/mint_nft.rs @@ -6,34 +6,34 @@ use quasar_spl::{ /// Accounts for minting an individual NFT with a collection reference. #[derive(Accounts)] -pub struct MintNft<'info> { +pub struct MintNft { #[account(mut)] - pub owner: &'info Signer, + pub owner: Signer, #[account(mut, init, payer = owner, mint::decimals = 0, mint::authority = mint_authority, mint::freeze_authority = mint_authority)] - pub mint: &'info mut Account, + pub mint: Account, /// Token account to hold the NFT. #[account(mut, init_if_needed, payer = owner, token::mint = mint, token::authority = owner)] - pub destination: &'info mut Account, + pub destination: Account, /// Metadata PDA — initialised by the Metaplex program. #[account(mut)] - pub metadata: &'info UncheckedAccount, + pub metadata: UncheckedAccount, /// Master edition PDA — initialised by the Metaplex program. #[account(mut)] - pub master_edition: &'info UncheckedAccount, + pub master_edition: UncheckedAccount, /// PDA used as mint authority and update authority. #[account(seeds = [b"authority"], bump)] - pub mint_authority: &'info UncheckedAccount, + pub mint_authority: UncheckedAccount, /// The collection mint (must already exist). #[account(mut)] - pub collection_mint: &'info Account, - pub system_program: &'info Program, - pub token_program: &'info Program, - pub token_metadata_program: &'info MetadataProgram, - pub rent: &'info Sysvar, + pub collection_mint: Account, + pub system_program: Program, + pub token_program: Program, + pub token_metadata_program: MetadataProgram, + pub rent: Sysvar, } #[inline(always)] -pub fn handle_mint_nft(accounts: &MintNft, bumps: &MintNftBumps) -> Result<(), ProgramError> { +pub fn handle_mint_nft(accounts: &mut MintNft, bumps: &MintNftBumps) -> Result<(), ProgramError> { let bump = [bumps.mint_authority]; let seeds: &[Seed] = &[ Seed::from(b"authority" as &[u8]), @@ -42,7 +42,7 @@ pub fn handle_mint_nft(accounts: &MintNft, bumps: &MintNftBumps) -> Result<(), P // Mint 1 token to the destination. accounts.token_program - .mint_to(accounts.mint, accounts.destination, accounts.mint_authority, 1u64) + .mint_to(&accounts.mint, &accounts.destination, &accounts.mint_authority, 1u64) .invoke_signed(seeds)?; log("NFT minted!"); @@ -51,13 +51,13 @@ pub fn handle_mint_nft(accounts: &MintNft, bumps: &MintNftBumps) -> Result<(), P // separately to verify it. accounts.token_metadata_program .create_metadata_accounts_v3( - accounts.metadata, - accounts.mint, - accounts.mint_authority, - accounts.owner, - accounts.mint_authority, - accounts.system_program, - accounts.rent, + &accounts.metadata, + &accounts.mint, + &accounts.mint_authority, + &accounts.owner, + &accounts.mint_authority, + &accounts.system_program, + &accounts.rent, "Mint Test", "YAY", "", @@ -70,15 +70,15 @@ pub fn handle_mint_nft(accounts: &MintNft, bumps: &MintNftBumps) -> Result<(), P // Create master edition. accounts.token_metadata_program .create_master_edition_v3( - accounts.master_edition, - accounts.mint, - accounts.mint_authority, // update_authority - accounts.mint_authority, // mint_authority - accounts.owner, // payer - accounts.metadata, - accounts.token_program, - accounts.system_program, - accounts.rent, + &accounts.master_edition, + &accounts.mint, + &accounts.mint_authority, // update_authority + &accounts.mint_authority, // mint_authority + &accounts.owner, // payer + &accounts.metadata, + &accounts.token_program, + &accounts.system_program, + &accounts.rent, Some(0), // max_supply = 0 means unique 1/1 ) .invoke_signed(seeds)?; diff --git a/tokens/nft-operations/quasar/src/instructions/verify_collection.rs b/tokens/nft-operations/quasar/src/instructions/verify_collection.rs index 9101bbc69..0306e5179 100644 --- a/tokens/nft-operations/quasar/src/instructions/verify_collection.rs +++ b/tokens/nft-operations/quasar/src/instructions/verify_collection.rs @@ -11,29 +11,27 @@ use quasar_spl::metadata::{MetadataCpi, MetadataProgram}; /// `UncheckedAccount` and rely on the Metaplex program itself to validate /// the accounts during CPI — the onchain program enforces correctness. #[derive(Accounts)] -pub struct VerifyCollectionMint<'info> { - pub authority: &'info Signer, +pub struct VerifyCollectionMint { + pub authority: Signer, /// The NFT's metadata account (will be updated with verified=true). #[account(mut)] - pub metadata: &'info UncheckedAccount, + pub metadata: UncheckedAccount, /// PDA used as collection authority. #[account(seeds = [b"authority"], bump)] - pub mint_authority: &'info UncheckedAccount, + pub mint_authority: UncheckedAccount, /// The collection mint. - pub collection_mint: &'info UncheckedAccount, + pub collection_mint: UncheckedAccount, /// The collection's metadata account. #[account(mut)] - pub collection_metadata: &'info UncheckedAccount, + pub collection_metadata: UncheckedAccount, /// The collection's master edition account. - pub collection_master_edition: &'info UncheckedAccount, - pub system_program: &'info Program, - pub token_metadata_program: &'info MetadataProgram, + pub collection_master_edition: UncheckedAccount, + pub system_program: Program, + pub token_metadata_program: MetadataProgram, } #[inline(always)] -pub fn handle_verify_collection( - accounts: &VerifyCollectionMint, bumps: &VerifyCollectionMintBumps, -) -> Result<(), ProgramError> { +pub fn handle_verify_collection(accounts: &mut VerifyCollectionMint, bumps: &VerifyCollectionMintBumps) -> Result<(), ProgramError> { let bump = [bumps.mint_authority]; let seeds: &[Seed] = &[ Seed::from(b"authority" as &[u8]), @@ -42,12 +40,12 @@ pub fn handle_verify_collection( accounts.token_metadata_program .verify_sized_collection_item( - accounts.metadata, - accounts.mint_authority, - accounts.authority, // payer - accounts.collection_mint, - accounts.collection_metadata, - accounts.collection_master_edition, + &accounts.metadata, + &accounts.mint_authority, + &accounts.authority, // payer + &accounts.collection_mint, + &accounts.collection_metadata, + &accounts.collection_master_edition, ) .invoke_signed(seeds)?; diff --git a/tokens/pda-mint-authority/quasar/Cargo.toml b/tokens/pda-mint-authority/quasar/Cargo.toml index 330e74acf..f4bf7ddd9 100644 --- a/tokens/pda-mint-authority/quasar/Cargo.toml +++ b/tokens/pda-mint-authority/quasar/Cargo.toml @@ -21,11 +21,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/pda-mint-authority/quasar/src/lib.rs b/tokens/pda-mint-authority/quasar/src/lib.rs index 23f8fc5f3..6a72cb367 100644 --- a/tokens/pda-mint-authority/quasar/src/lib.rs +++ b/tokens/pda-mint-authority/quasar/src/lib.rs @@ -1,22 +1,21 @@ #![cfg_attr(not(test), no_std)] -use quasar_lang::prelude::*; -use quasar_spl::{Mint, Token, TokenCpi}; +use quasar_lang::{prelude::*, sysvars::Sysvar}; +use quasar_spl::{initialize_mint2, Mint, Token, TokenCpi}; #[cfg(test)] mod tests; declare_id!("22222222222222222222222222222222222222222222"); +/// SPL Mint account size in bytes. +const MINT_SPACE: usize = 82; + /// Demonstrates using a PDA as the mint authority for an SPL token. /// -/// The mint account itself is at a PDA address derived from `["mint"]`. +/// The mint account is created at the PDA address derived from `["mint"]`. /// The same PDA serves as both the mint address AND the mint authority, /// so minting requires PDA signing. -/// -/// The Anchor version uses Metaplex for onchain metadata. Quasar does not have -/// a Metaplex integration crate, so this example focuses on the PDA-as-authority -/// pattern. #[program] mod quasar_pda_mint_authority { use super::*; @@ -24,7 +23,7 @@ mod quasar_pda_mint_authority { /// Create a token mint at a PDA. The PDA is its own mint authority. #[instruction(discriminator = 0)] pub fn create_mint(ctx: Ctx, _decimals: u8) -> Result<(), ProgramError> { - handle_create_mint(&mut ctx.accounts) + handle_create_mint(&mut ctx.accounts, ctx.bumps.mint) } /// Mint tokens using the PDA mint authority. @@ -34,49 +33,75 @@ mod quasar_pda_mint_authority { } } -/// Create the mint at a PDA. The mint authority is the mint PDA itself. +/// Create the mint at a PDA. Manually created and initialized to avoid +/// a borrow conflict from `mint::authority = mint` in the init constraint. #[derive(Accounts)] -pub struct CreateMint<'info> { +pub struct CreateMint { #[account(mut)] - pub payer: &'info Signer, - /// The mint account at PDA ["mint"]. Its authority is set to itself. - #[account(mut, init, payer = payer, seeds = [b"mint"], bump, mint::decimals = 9, mint::authority = mint)] - pub mint: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub payer: Signer, + /// The PDA that will become the mint (and its own authority). + #[account(mut, seeds = [b"mint"], bump)] + pub mint: UncheckedAccount, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_create_mint(accounts: &CreateMint) -> Result<(), ProgramError> { - // Mint is created and initialised by Quasar's #[account(init)]. - Ok(()) +fn handle_create_mint(accounts: &mut CreateMint, bump: u8) -> Result<(), ProgramError> { + let mint_address = *accounts.mint.address(); + let bump_bytes = [bump]; + let seeds: &[Seed] = &[ + Seed::from(b"mint" as &[u8]), + Seed::from(&bump_bytes as &[u8]), + ]; + + let rent = Rent::get()?; + let lamports = rent.minimum_balance_unchecked(MINT_SPACE); + + accounts.system_program + .create_account( + &accounts.payer, + &accounts.mint, + lamports, + MINT_SPACE as u64, + accounts.token_program.address(), + ) + .invoke_signed(seeds)?; + + initialize_mint2( + accounts.token_program.to_account_view(), + accounts.mint.to_account_view(), + 9, + &mint_address, + None, + ) + .invoke() } /// Mint tokens to a token account, signing with the PDA mint authority. #[derive(Accounts)] -pub struct MintTokens<'info> { +pub struct MintTokens { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// The PDA mint whose authority is itself. #[account(mut, seeds = [b"mint"], bump)] - pub mint: &'info mut Account, + pub mint: Account, /// Recipient token account (must already exist). #[account(mut)] - pub token_account: &'info mut Account, - pub token_program: &'info Program, + pub token_account: Account, + pub token_program: Program, } #[inline(always)] -pub fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64, mint_bump: u8) -> Result<(), ProgramError> { - // The PDA mint is its own authority. Build signer seeds. +fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64, mint_bump: u8) -> Result<(), ProgramError> { let bump = [mint_bump]; let seeds: &[Seed] = &[ Seed::from(b"mint" as &[u8]), Seed::from(&bump as &[u8]), ]; + let mint_view = accounts.mint.to_account_view().clone(); accounts.token_program - .mint_to(accounts.mint, accounts.token_account, accounts.mint, amount) + .mint_to(&mint_view, &accounts.token_account, &mint_view, amount) .invoke_signed(seeds) } diff --git a/tokens/pda-mint-authority/quasar/src/tests.rs b/tokens/pda-mint-authority/quasar/src/tests.rs index 03274a17a..1fa3244b8 100644 --- a/tokens/pda-mint-authority/quasar/src/tests.rs +++ b/tokens/pda-mint-authority/quasar/src/tests.rs @@ -75,16 +75,16 @@ fn test_create_mint() { let (mint_pda, _) = Pubkey::find_program_address(&[b"mint"], &crate::ID); let token_program = quasar_svm::SPL_TOKEN_PROGRAM_ID; let system_program = quasar_svm::system_program::ID; - let rent = quasar_svm::solana_sdk_ids::sysvar::rent::ID; let data = build_create_mint_data(9); + // Account order matches the `CreateMint` Accounts struct: + // payer, mint, token_program, system_program. let instruction = Instruction { program_id: crate::ID, accounts: vec![ solana_instruction::AccountMeta::new(payer.into(), true), solana_instruction::AccountMeta::new(mint_pda.into(), false), - solana_instruction::AccountMeta::new_readonly(rent.into(), false), solana_instruction::AccountMeta::new_readonly(token_program.into(), false), solana_instruction::AccountMeta::new_readonly(system_program.into(), false), ], diff --git a/tokens/spl-token-minter/quasar/Cargo.toml b/tokens/spl-token-minter/quasar/Cargo.toml index 092c37493..c04390da9 100644 --- a/tokens/spl-token-minter/quasar/Cargo.toml +++ b/tokens/spl-token-minter/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = { version = "0.0", features = ["metadata"] } +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master", features = ["metadata"] } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/spl-token-minter/quasar/src/instructions/create.rs b/tokens/spl-token-minter/quasar/src/instructions/create.rs index ba3f8b284..3291ceb17 100644 --- a/tokens/spl-token-minter/quasar/src/instructions/create.rs +++ b/tokens/spl-token-minter/quasar/src/instructions/create.rs @@ -9,9 +9,9 @@ use quasar_spl::{ /// The mint is initialised via Quasar's `#[account(init)]`. The metadata /// PDA is created by CPI-ing into the Metaplex Token Metadata program. #[derive(Accounts)] -pub struct CreateToken<'info> { +pub struct CreateToken { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account( mut, init, @@ -20,19 +20,20 @@ pub struct CreateToken<'info> { mint::authority = payer, mint::freeze_authority = payer, )] - pub mint_account: &'info mut Account, + pub mint_account: Account, /// The metadata PDA — will be initialised by the Metaplex program. #[account(mut)] - pub metadata_account: &'info UncheckedAccount, - pub token_program: &'info Program, - pub token_metadata_program: &'info MetadataProgram, - pub system_program: &'info Program, - pub rent: &'info Sysvar, + pub metadata_account: UncheckedAccount, + pub token_program: Program, + pub token_metadata_program: MetadataProgram, + pub system_program: Program, + pub rent: Sysvar, } #[inline(always)] pub fn handle_create_token( - accounts: &CreateToken, token_name: &str, + accounts: &mut CreateToken, + token_name: &str, token_symbol: &str, token_uri: &str, ) -> Result<(), ProgramError> { @@ -40,13 +41,13 @@ pub fn handle_create_token( accounts.token_metadata_program .create_metadata_accounts_v3( - accounts.metadata_account, - accounts.mint_account, - accounts.payer, // mint_authority - accounts.payer, // payer - accounts.payer, // update_authority - accounts.system_program, - accounts.rent, + &accounts.metadata_account, + &accounts.mint_account, + &accounts.payer, // mint_authority + &accounts.payer, // payer + &accounts.payer, // update_authority + &accounts.system_program, + &accounts.rent, token_name, token_symbol, token_uri, diff --git a/tokens/spl-token-minter/quasar/src/instructions/mint.rs b/tokens/spl-token-minter/quasar/src/instructions/mint.rs index 127797d00..697a658be 100644 --- a/tokens/spl-token-minter/quasar/src/instructions/mint.rs +++ b/tokens/spl-token-minter/quasar/src/instructions/mint.rs @@ -3,16 +3,16 @@ use quasar_spl::{Mint, Token, TokenCpi}; /// Accounts for minting tokens to a recipient's token account. #[derive(Accounts)] -pub struct MintToken<'info> { +pub struct MintToken { #[account(mut)] - pub mint_authority: &'info Signer, - pub recipient: &'info UncheckedAccount, + pub mint_authority: Signer, + pub recipient: UncheckedAccount, #[account(mut)] - pub mint_account: &'info mut Account, + pub mint_account: Account, #[account(mut, init_if_needed, payer = mint_authority, token::mint = mint_account, token::authority = recipient)] - pub associated_token_account: &'info mut Account, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub associated_token_account: Account, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] @@ -26,9 +26,9 @@ pub fn handle_mint_token(accounts: &mut MintToken, amount: u64) -> Result<(), Pr accounts.token_program .mint_to( - accounts.mint_account, - accounts.associated_token_account, - accounts.mint_authority, + &accounts.mint_account, + &accounts.associated_token_account, + &accounts.mint_authority, adjusted_amount, ) .invoke()?; diff --git a/tokens/token-extensions/basics/quasar/Cargo.toml b/tokens/token-extensions/basics/quasar/Cargo.toml index 108b7fdc4..46facab14 100644 --- a/tokens/token-extensions/basics/quasar/Cargo.toml +++ b/tokens/token-extensions/basics/quasar/Cargo.toml @@ -21,8 +21,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/basics/quasar/src/lib.rs b/tokens/token-extensions/basics/quasar/src/lib.rs index f128c56ee..5ab5ace02 100644 --- a/tokens/token-extensions/basics/quasar/src/lib.rs +++ b/tokens/token-extensions/basics/quasar/src/lib.rs @@ -46,18 +46,18 @@ mod quasar_token_2022_basics { /// Accounts for minting tokens via Token-2022. #[derive(Accounts)] -pub struct MintToken<'info> { +pub struct MintToken { #[account(mut)] - pub authority: &'info Signer, + pub authority: Signer, #[account(mut)] - pub mint: &'info mut UncheckedAccount, + pub mint: UncheckedAccount, #[account(mut)] - pub receiver: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub receiver: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_mint_token(accounts: &mut MintToken, amount: u64) -> Result<(), ProgramError> { +fn handle_mint_token(accounts: &mut MintToken, amount: u64) -> Result<(), ProgramError> { // SPL Token MintTo instruction: opcode 7, amount as u64 LE. let data = build_u64_data(7, amount); CpiCall::new( @@ -79,19 +79,19 @@ pub fn handle_mint_token(accounts: &mut MintToken, amount: u64) -> Result<(), Pr /// Accounts for transferring tokens via Token-2022 transfer_checked. #[derive(Accounts)] -pub struct TransferToken<'info> { +pub struct TransferToken { #[account(mut)] - pub sender: &'info Signer, + pub sender: Signer, #[account(mut)] - pub from: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub from: UncheckedAccount, + pub mint: UncheckedAccount, #[account(mut)] - pub to: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub to: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_transfer_token(accounts: &mut TransferToken, amount: u64) -> Result<(), ProgramError> { +fn handle_transfer_token(accounts: &mut TransferToken, amount: u64) -> Result<(), ProgramError> { // SPL Token TransferChecked instruction: opcode 12, amount as u64 LE, decimals as u8. let data = build_transfer_checked_data(amount, 6); CpiCall::new( diff --git a/tokens/token-extensions/cpi-guard/quasar/Cargo.toml b/tokens/token-extensions/cpi-guard/quasar/Cargo.toml index 48e1aa207..4d7009639 100644 --- a/tokens/token-extensions/cpi-guard/quasar/Cargo.toml +++ b/tokens/token-extensions/cpi-guard/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/cpi-guard/quasar/src/lib.rs b/tokens/token-extensions/cpi-guard/quasar/src/lib.rs index 85a4e4c25..40f3b75b4 100644 --- a/tokens/token-extensions/cpi-guard/quasar/src/lib.rs +++ b/tokens/token-extensions/cpi-guard/quasar/src/lib.rs @@ -35,19 +35,19 @@ mod quasar_cpi_guard { } #[derive(Accounts)] -pub struct CpiTransfer<'info> { +pub struct CpiTransfer { #[account(mut)] - pub sender: &'info Signer, + pub sender: Signer, #[account(mut)] - pub sender_token_account: &'info mut UncheckedAccount, - pub mint_account: &'info UncheckedAccount, + pub sender_token_account: UncheckedAccount, + pub mint_account: UncheckedAccount, #[account(mut)] - pub recipient_token_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub recipient_token_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_cpi_transfer(accounts: &mut CpiTransfer) -> Result<(), ProgramError> { +fn handle_cpi_transfer(accounts: &mut CpiTransfer) -> Result<(), ProgramError> { // TransferChecked: opcode 12, amount=1, decimals=9 let mut data = [0u8; 10]; data[0] = 12; diff --git a/tokens/token-extensions/default-account-state/quasar/Cargo.toml b/tokens/token-extensions/default-account-state/quasar/Cargo.toml index f5cd06339..2d4d4482b 100644 --- a/tokens/token-extensions/default-account-state/quasar/Cargo.toml +++ b/tokens/token-extensions/default-account-state/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/default-account-state/quasar/src/lib.rs b/tokens/token-extensions/default-account-state/quasar/src/lib.rs index 5fc2905fb..28b888d5a 100644 --- a/tokens/token-extensions/default-account-state/quasar/src/lib.rs +++ b/tokens/token-extensions/default-account-state/quasar/src/lib.rs @@ -45,26 +45,27 @@ mod quasar_default_account_state { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // 165 (base account) + 1 (account type) + 4 (TLV header) + 1 (DefaultAccountState data) = 171 bytes let mint_size: u64 = 171; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; // 1. Create account owned by Token-2022 - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), @@ -106,25 +107,26 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { } #[derive(Accounts)] -pub struct UpdateDefaultState<'info> { +pub struct UpdateDefaultState { #[account(mut)] - pub freeze_authority: &'info Signer, + pub freeze_authority: Signer, #[account(mut)] - pub mint_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub mint_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_update_default_state(accounts: &UpdateDefaultState, account_state: u8) -> Result<(), ProgramError> { +fn handle_update_default_state( + accounts: &mut UpdateDefaultState, + account_state: u8, +) -> Result<(), ProgramError> { // DefaultAccountState Update: opcode 28, sub-opcode 1, new state let data: [u8; 3] = [28, 1, account_state]; CpiCall::new( accounts.token_program.to_account_view().address(), [ InstructionAccount::writable(accounts.mint_account.to_account_view().address()), - InstructionAccount::readonly_signer( - accounts.freeze_authority.to_account_view().address(), - ), + InstructionAccount::readonly_signer(accounts.freeze_authority.to_account_view().address()), ], [ accounts.mint_account.to_account_view(), diff --git a/tokens/token-extensions/group/quasar/Cargo.toml b/tokens/token-extensions/group/quasar/Cargo.toml index b2b66939b..5c02b0cd8 100644 --- a/tokens/token-extensions/group/quasar/Cargo.toml +++ b/tokens/token-extensions/group/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/group/quasar/src/lib.rs b/tokens/token-extensions/group/quasar/src/lib.rs index 122dde04f..3f65707ce 100644 --- a/tokens/token-extensions/group/quasar/src/lib.rs +++ b/tokens/token-extensions/group/quasar/src/lib.rs @@ -31,30 +31,31 @@ mod quasar_group { #[instruction(discriminator = 0)] pub fn initialize_group(ctx: Ctx) -> Result<(), ProgramError> { - handle_initialize(&mut ctx.accounts) + handle_initialize_group(&mut ctx.accounts) } } #[derive(Accounts)] -pub struct InitializeGroup<'info> { +pub struct InitializeGroup { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &InitializeGroup) -> Result<(), ProgramError> { +fn handle_initialize_group(accounts: &mut InitializeGroup) -> Result<(), ProgramError> { // Mint + GroupPointer extension = 250 bytes let mint_size: u64 = 250; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/immutable-owner/quasar/Cargo.toml b/tokens/token-extensions/immutable-owner/quasar/Cargo.toml index b6345037c..f8f488857 100644 --- a/tokens/token-extensions/immutable-owner/quasar/Cargo.toml +++ b/tokens/token-extensions/immutable-owner/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/immutable-owner/quasar/src/lib.rs b/tokens/token-extensions/immutable-owner/quasar/src/lib.rs index f4fd7a16b..3e995b9d4 100644 --- a/tokens/token-extensions/immutable-owner/quasar/src/lib.rs +++ b/tokens/token-extensions/immutable-owner/quasar/src/lib.rs @@ -32,27 +32,28 @@ mod quasar_immutable_owner { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub token_account: &'info Signer, - pub mint_account: &'info UncheckedAccount, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub token_account: Signer, + pub mint_account: UncheckedAccount, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // 165 (base) + 1 (account type) + 4 (TLV header, ImmutableOwner is zero-size) = 170 bytes let account_size: u64 = 170; let lamports = Rent::get()?.try_minimum_balance(account_size as usize)?; // 1. Create account - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.token_account, + &accounts.payer, + &accounts.token_account, lamports, account_size, accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/interest-bearing/quasar/Cargo.toml b/tokens/token-extensions/interest-bearing/quasar/Cargo.toml index 602a1f489..6e9ec58dd 100644 --- a/tokens/token-extensions/interest-bearing/quasar/Cargo.toml +++ b/tokens/token-extensions/interest-bearing/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/interest-bearing/quasar/src/lib.rs b/tokens/token-extensions/interest-bearing/quasar/src/lib.rs index 51f48cea6..1f10c7dae 100644 --- a/tokens/token-extensions/interest-bearing/quasar/src/lib.rs +++ b/tokens/token-extensions/interest-bearing/quasar/src/lib.rs @@ -37,25 +37,26 @@ mod quasar_interest_bearing { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize, rate: i16) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize, rate: i16) -> Result<(), ProgramError> { // 165 (base) + 1 (account type) + 4 (TLV header) + 52 (InterestBearingConfig data) = 222 bytes let mint_size: u64 = 222; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), @@ -100,16 +101,16 @@ pub fn handle_initialize(accounts: &Initialize, rate: i16) -> Result<(), Program } #[derive(Accounts)] -pub struct UpdateRate<'info> { +pub struct UpdateRate { #[account(mut)] - pub authority: &'info Signer, + pub authority: Signer, #[account(mut)] - pub mint_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub mint_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_update_rate(accounts: &UpdateRate, rate: i16) -> Result<(), ProgramError> { +fn handle_update_rate(accounts: &mut UpdateRate, rate: i16) -> Result<(), ProgramError> { // InterestBearingMintUpdateRate: opcode 33, sub-opcode 1, rate (i16 LE) let mut data = [0u8; 4]; data[0] = 33; diff --git a/tokens/token-extensions/memo-transfer/quasar/Cargo.toml b/tokens/token-extensions/memo-transfer/quasar/Cargo.toml index b00779f7a..07f0ac8e7 100644 --- a/tokens/token-extensions/memo-transfer/quasar/Cargo.toml +++ b/tokens/token-extensions/memo-transfer/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/memo-transfer/quasar/src/lib.rs b/tokens/token-extensions/memo-transfer/quasar/src/lib.rs index b5852d5f0..049ec6adc 100644 --- a/tokens/token-extensions/memo-transfer/quasar/src/lib.rs +++ b/tokens/token-extensions/memo-transfer/quasar/src/lib.rs @@ -37,26 +37,27 @@ mod quasar_memo_transfer { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub token_account: &'info Signer, - pub mint_account: &'info UncheckedAccount, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub token_account: Signer, + pub mint_account: UncheckedAccount, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // Token account + MemoTransfer extension = 300 bytes let account_size: u64 = 300; let lamports = Rent::get()?.try_minimum_balance(account_size as usize)?; - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.token_account, + &accounts.payer, + &accounts.token_account, lamports, account_size, accounts.token_program.to_account_view().address(), @@ -99,16 +100,16 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { } #[derive(Accounts)] -pub struct Disable<'info> { +pub struct Disable { #[account(mut)] - pub owner: &'info Signer, + pub owner: Signer, #[account(mut)] - pub token_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub token_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_disable(accounts: &Disable) -> Result<(), ProgramError> { +fn handle_disable(accounts: &mut Disable) -> Result<(), ProgramError> { // MemoTransfer disable: opcode 30, sub-opcode 1 CpiCall::new( accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml b/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml index 5e93ac70d..c6c41957e 100644 --- a/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml +++ b/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/mint-close-authority/quasar/src/lib.rs b/tokens/token-extensions/mint-close-authority/quasar/src/lib.rs index 8a887f431..9a7986663 100644 --- a/tokens/token-extensions/mint-close-authority/quasar/src/lib.rs +++ b/tokens/token-extensions/mint-close-authority/quasar/src/lib.rs @@ -39,25 +39,26 @@ mod quasar_mint_close_authority { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // 165 (base) + 1 (account type) + 4 (TLV header) + 32 (MintCloseAuthority data) = 202 bytes let mint_size: u64 = 202; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), @@ -67,7 +68,7 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { // InitializeMintCloseAuthority: opcode 25, COption::Some flag (1 byte), close_authority pubkey (32 bytes) let mut ext_data = [0u8; 34]; ext_data[0] = 25; // InitializeMintCloseAuthority - ext_data[1] = 1; // COption::Some + ext_data[1] = 1; // COption::Some ext_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); CpiCall::new( @@ -99,16 +100,16 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { } #[derive(Accounts)] -pub struct Close<'info> { +pub struct Close { #[account(mut)] - pub authority: &'info Signer, + pub authority: Signer, #[account(mut)] - pub mint_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub mint_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_close(accounts: &Close) -> Result<(), ProgramError> { +fn handle_close(accounts: &mut Close) -> Result<(), ProgramError> { // CloseAccount: opcode 9 CpiCall::new( accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/non-transferable/quasar/Cargo.toml b/tokens/token-extensions/non-transferable/quasar/Cargo.toml index 23bf84a37..be7d11b69 100644 --- a/tokens/token-extensions/non-transferable/quasar/Cargo.toml +++ b/tokens/token-extensions/non-transferable/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/non-transferable/quasar/src/lib.rs b/tokens/token-extensions/non-transferable/quasar/src/lib.rs index df053282f..f4ed62ad6 100644 --- a/tokens/token-extensions/non-transferable/quasar/src/lib.rs +++ b/tokens/token-extensions/non-transferable/quasar/src/lib.rs @@ -32,26 +32,27 @@ mod quasar_non_transferable { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // Mint + NonTransferable extension = 170 bytes let mint_size: u64 = 170; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; // 1. Create account - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml b/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml index c4d507f10..470299022 100644 --- a/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml +++ b/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/permanent-delegate/quasar/src/lib.rs b/tokens/token-extensions/permanent-delegate/quasar/src/lib.rs index 43f07a4a7..c5085ed59 100644 --- a/tokens/token-extensions/permanent-delegate/quasar/src/lib.rs +++ b/tokens/token-extensions/permanent-delegate/quasar/src/lib.rs @@ -32,25 +32,26 @@ mod quasar_permanent_delegate { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { +fn handle_initialize(accounts: &mut Initialize) -> Result<(), ProgramError> { // 165 (base) + 1 (account type) + 4 (TLV header) + 32 (PermanentDelegate data) = 202 bytes let mint_size: u64 = 202; let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - accounts.system_program + accounts + .system_program .create_account( - accounts.payer, - accounts.mint_account, + &accounts.payer, + &accounts.mint_account, lamports, mint_size, accounts.token_program.to_account_view().address(), diff --git a/tokens/token-extensions/transfer-fee/quasar/Cargo.toml b/tokens/token-extensions/transfer-fee/quasar/Cargo.toml index 0aff4de50..907756375 100644 --- a/tokens/token-extensions/transfer-fee/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-fee/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-fee/quasar/src/lib.rs b/tokens/token-extensions/transfer-fee/quasar/src/lib.rs index 3b61b6e6f..82aa73350 100644 --- a/tokens/token-extensions/transfer-fee/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-fee/quasar/src/lib.rs @@ -59,176 +59,176 @@ mod quasar_transfer_fee { } #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize, basis_points: u16, max_fee: u64) -> Result<(), ProgramError> { - // 165 (base) + 1 (AccountType) + 4 (TLV header) + 108 (TransferFeeConfig data) = 278 bytes - let mint_size: u64 = 278; - let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - - accounts.system_program - .create_account( - accounts.payer, - accounts.mint_account, - lamports, - mint_size, +fn handle_initialize(accounts: &mut Initialize, basis_points: u16, max_fee: u64) -> Result<(), ProgramError> { + // 165 (base) + 1 (AccountType) + 4 (TLV header) + 108 (TransferFeeConfig data) = 278 bytes + let mint_size: u64 = 278; + let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; + + accounts.system_program + .create_account( + &accounts.payer, + &accounts.mint_account, + lamports, + mint_size, + accounts.token_program.to_account_view().address(), + ) + .invoke()?; + + // TransferFeeExtension opcode 26, sub-instruction 0 = InitializeTransferFeeConfig + // Data: [26, 0, COption_flag(1), config_authority(32), COption_flag(1), withdraw_authority(32), + // basis_points(u16 LE), max_fee(u64 LE)] + let mut ext_data = [0u8; 78]; + ext_data[0] = 26; // TransferFeeExtension + ext_data[1] = 0; // InitializeTransferFeeConfig sub-instruction + ext_data[2] = 1; // COption::Some for config_authority + ext_data[3..35].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + ext_data[35] = 1; // COption::Some for withdraw_authority + ext_data[36..68].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + ext_data[68..70].copy_from_slice(&basis_points.to_le_bytes()); + ext_data[70..78].copy_from_slice(&max_fee.to_le_bytes()); + + CpiCall::new( accounts.token_program.to_account_view().address(), + [InstructionAccount::writable( + accounts.mint_account.to_account_view().address(), + )], + [accounts.mint_account.to_account_view()], + ext_data, ) .invoke()?; - // TransferFeeExtension opcode 26, sub-instruction 0 = InitializeTransferFeeConfig - // Data: [26, 0, COption_flag(1), config_authority(32), COption_flag(1), withdraw_authority(32), - // basis_points(u16 LE), max_fee(u64 LE)] - let mut ext_data = [0u8; 78]; - ext_data[0] = 26; // TransferFeeExtension - ext_data[1] = 0; // InitializeTransferFeeConfig sub-instruction - ext_data[2] = 1; // COption::Some for config_authority - ext_data[3..35].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - ext_data[35] = 1; // COption::Some for withdraw_authority - ext_data[36..68].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - ext_data[68..70].copy_from_slice(&basis_points.to_le_bytes()); - ext_data[70..78].copy_from_slice(&max_fee.to_le_bytes()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [InstructionAccount::writable( - accounts.mint_account.to_account_view().address(), - )], - [accounts.mint_account.to_account_view()], - ext_data, - ) - .invoke()?; - - // InitializeMint2 - let mut mint_data = [0u8; 67]; - mint_data[0] = 20; - mint_data[1] = 2; - mint_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - mint_data[34] = 1; - mint_data[35..67].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [InstructionAccount::writable( - accounts.mint_account.to_account_view().address(), - )], - [accounts.mint_account.to_account_view()], - mint_data, - ) - .invoke() + // InitializeMint2 + let mut mint_data = [0u8; 67]; + mint_data[0] = 20; + mint_data[1] = 2; + mint_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + mint_data[34] = 1; + mint_data[35..67].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + + CpiCall::new( + accounts.token_program.to_account_view().address(), + [InstructionAccount::writable( + accounts.mint_account.to_account_view().address(), + )], + [accounts.mint_account.to_account_view()], + mint_data, + ) + .invoke() } #[derive(Accounts)] -pub struct Transfer<'info> { +pub struct Transfer { #[account(mut)] - pub sender: &'info Signer, + pub sender: Signer, #[account(mut)] - pub from: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub from: UncheckedAccount, + pub mint: UncheckedAccount, #[account(mut)] - pub to: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub to: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_transfer(accounts: &mut Transfer, amount: u64, fee: u64) -> Result<(), ProgramError> { - // TransferCheckedWithFee: opcode 37 - // Data: [37, amount (u64 LE), decimals (u8), fee (u64 LE)] - let mut data = [0u8; 18]; - data[0] = 37; - data[1..9].copy_from_slice(&amount.to_le_bytes()); - data[9] = 2; // decimals - data[10..18].copy_from_slice(&fee.to_le_bytes()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [ - InstructionAccount::writable(accounts.from.to_account_view().address()), - InstructionAccount::readonly(accounts.mint.to_account_view().address()), - InstructionAccount::writable(accounts.to.to_account_view().address()), - InstructionAccount::readonly_signer(accounts.sender.to_account_view().address()), - ], - [ - accounts.from.to_account_view(), - accounts.mint.to_account_view(), - accounts.to.to_account_view(), - accounts.sender.to_account_view(), - ], - data, - ) - .invoke() +fn handle_transfer(accounts: &mut Transfer, amount: u64, fee: u64) -> Result<(), ProgramError> { + // TransferCheckedWithFee: opcode 37 + // Data: [37, amount (u64 LE), decimals (u8), fee (u64 LE)] + let mut data = [0u8; 18]; + data[0] = 37; + data[1..9].copy_from_slice(&amount.to_le_bytes()); + data[9] = 2; // decimals + data[10..18].copy_from_slice(&fee.to_le_bytes()); + + CpiCall::new( + accounts.token_program.to_account_view().address(), + [ + InstructionAccount::writable(accounts.from.to_account_view().address()), + InstructionAccount::readonly(accounts.mint.to_account_view().address()), + InstructionAccount::writable(accounts.to.to_account_view().address()), + InstructionAccount::readonly_signer(accounts.sender.to_account_view().address()), + ], + [ + accounts.from.to_account_view(), + accounts.mint.to_account_view(), + accounts.to.to_account_view(), + accounts.sender.to_account_view(), + ], + data, + ) + .invoke() } #[derive(Accounts)] -pub struct UpdateFee<'info> { - pub authority: &'info Signer, +pub struct UpdateFee { + pub authority: Signer, #[account(mut)] - pub mint_account: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub mint_account: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_update_fee(accounts: &UpdateFee, basis_points: u16, max_fee: u64) -> Result<(), ProgramError> { - // SetTransferFee: opcode 26, sub-opcode 4 - // Actually: extension instruction layout is different. - // TransferFeeInstruction::SetTransferFee = 4 within type 26 - let mut data = [0u8; 12]; - data[0] = 26; - data[1] = 4; // SetTransferFee sub-instruction - data[2..4].copy_from_slice(&basis_points.to_le_bytes()); - data[4..12].copy_from_slice(&max_fee.to_le_bytes()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [ - InstructionAccount::writable(accounts.mint_account.to_account_view().address()), - InstructionAccount::readonly_signer(accounts.authority.to_account_view().address()), - ], - [ - accounts.mint_account.to_account_view(), - accounts.authority.to_account_view(), - ], - data, - ) - .invoke() +fn handle_update_fee(accounts: &mut UpdateFee, basis_points: u16, max_fee: u64) -> Result<(), ProgramError> { + // SetTransferFee: opcode 26, sub-opcode 4 + // Actually: extension instruction layout is different. + // TransferFeeInstruction::SetTransferFee = 4 within type 26 + let mut data = [0u8; 12]; + data[0] = 26; + data[1] = 4; // SetTransferFee sub-instruction + data[2..4].copy_from_slice(&basis_points.to_le_bytes()); + data[4..12].copy_from_slice(&max_fee.to_le_bytes()); + + CpiCall::new( + accounts.token_program.to_account_view().address(), + [ + InstructionAccount::writable(accounts.mint_account.to_account_view().address()), + InstructionAccount::readonly_signer(accounts.authority.to_account_view().address()), + ], + [ + accounts.mint_account.to_account_view(), + accounts.authority.to_account_view(), + ], + data, + ) + .invoke() } #[derive(Accounts)] -pub struct Withdraw<'info> { - pub authority: &'info Signer, +pub struct Withdraw { + pub authority: Signer, #[account(mut)] - pub mint_account: &'info mut UncheckedAccount, + pub mint_account: UncheckedAccount, #[account(mut)] - pub destination: &'info mut UncheckedAccount, - pub token_program: &'info Program, + pub destination: UncheckedAccount, + pub token_program: Program, } #[inline(always)] -pub fn handle_withdraw(accounts: &Withdraw) -> Result<(), ProgramError> { - // WithdrawWithheldTokensFromMint: opcode 26, sub-opcode 3 - let data: [u8; 2] = [26, 3]; - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [ - InstructionAccount::writable(accounts.mint_account.to_account_view().address()), - InstructionAccount::writable(accounts.destination.to_account_view().address()), - InstructionAccount::readonly_signer(accounts.authority.to_account_view().address()), - ], - [ - accounts.mint_account.to_account_view(), - accounts.destination.to_account_view(), - accounts.authority.to_account_view(), - ], - data, - ) - .invoke() +fn handle_withdraw(accounts: &mut Withdraw) -> Result<(), ProgramError> { + // WithdrawWithheldTokensFromMint: opcode 26, sub-opcode 3 + let data: [u8; 2] = [26, 3]; + + CpiCall::new( + accounts.token_program.to_account_view().address(), + [ + InstructionAccount::writable(accounts.mint_account.to_account_view().address()), + InstructionAccount::writable(accounts.destination.to_account_view().address()), + InstructionAccount::readonly_signer(accounts.authority.to_account_view().address()), + ], + [ + accounts.mint_account.to_account_view(), + accounts.destination.to_account_view(), + accounts.authority.to_account_view(), + ], + data, + ) + .invoke() } diff --git a/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/Cargo.toml index 11a0f9a48..5e3049aed 100644 --- a/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/src/lib.rs index b91114dff..ea3808630 100644 --- a/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/account-data-as-seed/quasar/src/lib.rs @@ -46,21 +46,21 @@ mod quasar_transfer_hook_account_data_as_seed { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetaList<'info> { +pub struct InitializeExtraAccountMetaList { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// ExtraAccountMetaList PDA: ["extra-account-metas", mint] #[account(mut)] - pub extra_account_meta_list: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, + pub mint: UncheckedAccount, /// Counter PDA: ["counter", payer_key] #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub counter_account: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccountMetaList) -> Result<(), ProgramError> { +pub fn handle_initialize_extra_account_meta_list(accounts: &mut InitializeExtraAccountMetaList) -> Result<(), ProgramError> { // ExtraAccountMetaList with 1 extra account. // ExtraAccountMeta for a PDA with seeds [Literal("counter"), AccountData(0, 32, 32)]: // The AccountData seed resolves the owner pubkey from account_index=0 @@ -94,8 +94,8 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou accounts.system_program .create_account( - accounts.payer, - &*accounts.extra_account_meta_list, + &accounts.payer, + &accounts.extra_account_meta_list, lamports, meta_list_size, &crate::ID, @@ -104,7 +104,7 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou // Write TLV data let view = unsafe { - &mut *(accounts.extra_account_meta_list as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.extra_account_meta_list as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; @@ -151,8 +151,8 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou accounts.system_program .create_account( - accounts.payer, - &*accounts.counter_account, + &accounts.payer, + &accounts.counter_account, counter_lamports, counter_size, &crate::ID, @@ -168,21 +168,21 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { - pub source_token: &'info UncheckedAccount, - pub mint: &'info UncheckedAccount, - pub destination_token: &'info UncheckedAccount, - pub owner: &'info UncheckedAccount, - pub extra_account_meta_list: &'info UncheckedAccount, +pub struct TransferHook { + pub source_token: UncheckedAccount, + pub mint: UncheckedAccount, + pub destination_token: UncheckedAccount, + pub owner: UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, /// Counter PDA resolved by Token-2022 using account data seeds #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, + pub counter_account: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_hook(accounts: &TransferHook) -> Result<(), ProgramError> { +pub fn handle_transfer_hook(accounts: &mut TransferHook) -> Result<(), ProgramError> { let view = unsafe { - &mut *(accounts.counter_account as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.counter_account as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/Cargo.toml index 12dd396a9..742727dc9 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/Cargo.toml @@ -13,13 +13,14 @@ check-cfg = ['cfg(target_os, values("solana"))'] crate-type = ["cdylib", "lib"] [features] -alloc = ["quasar-lang/alloc"] +# Removed `alloc` feature — the upstream `quasar-lang` master no longer +# exposes it, and nothing in this crate depends on alloc. client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/attach_to_mint.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/attach_to_mint.rs index 7f011f49f..962c9df31 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/attach_to_mint.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/attach_to_mint.rs @@ -6,19 +6,19 @@ use crate::constants::*; use crate::instructions::init_mint::Token2022; #[derive(Accounts)] -pub struct AttachToMint<'info> { +pub struct AttachToMint { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint: &'info UncheckedAccount, + pub mint: UncheckedAccount, #[account(mut)] - pub extra_metas_account: &'info mut UncheckedAccount, - pub system_program: &'info Program, - pub token_program: &'info Program, + pub extra_metas_account: UncheckedAccount, + pub system_program: Program, + pub token_program: Program, } #[inline(always)] -pub fn handle_attach_to_mint(accounts: &AttachToMint) -> Result<(), ProgramError> { +pub fn handle_attach_to_mint(accounts: &mut AttachToMint) -> Result<(), ProgramError> { let mint_key = accounts.mint.to_account_view().address(); let payer_key = accounts.payer.to_account_view().address(); let token_prog = accounts.token_program.to_account_view().address(); @@ -79,8 +79,8 @@ pub fn handle_attach_to_mint(accounts: &AttachToMint) -> Result<(), ProgramError accounts.system_program .create_account( - accounts.payer, - &*accounts.extra_metas_account, + &accounts.payer, + &accounts.extra_metas_account, lamports, meta_list_size, &crate::ID, @@ -89,7 +89,7 @@ pub fn handle_attach_to_mint(accounts: &AttachToMint) -> Result<(), ProgramError // Write ExtraAccountMeta TLV data let view = unsafe { - &mut *(accounts.extra_metas_account as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.extra_metas_account as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/change_mode.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/change_mode.rs index 1184189c6..3d6b342ff 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/change_mode.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/change_mode.rs @@ -1,4 +1,4 @@ -use quasar_lang::cpi::{BufCpiCall, InstructionAccount}; +use quasar_lang::cpi::DynCpiCall; use quasar_lang::prelude::*; use quasar_lang::sysvars::Sysvar; @@ -7,17 +7,17 @@ use crate::instructions::init_mint::Token2022; use crate::state::mode_to_metadata_value; #[derive(Accounts)] -pub struct ChangeMode<'info> { +pub struct ChangeMode { #[account(mut)] - pub authority: &'info Signer, + pub authority: Signer, #[account(mut)] - pub mint: &'info UncheckedAccount, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint: UncheckedAccount, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_change_mode(accounts: &ChangeMode, mode: u8, threshold: u64) -> Result<(), ProgramError> { +pub fn handle_change_mode(accounts: &mut ChangeMode, mode: u8, threshold: u64) -> Result<(), ProgramError> { let mode_value = mode_to_metadata_value(mode); let token_prog = accounts.token_program.to_account_view().address(); let mint_key = accounts.mint.to_account_view().address(); @@ -52,7 +52,7 @@ pub fn handle_change_mode(accounts: &ChangeMode, mode: u8, threshold: u64) -> Re if min_balance > current_lamports { let diff = min_balance - current_lamports; accounts.system_program - .transfer(accounts.authority, &*accounts.mint, diff) + .transfer(&accounts.authority, &accounts.mint, diff) .invoke()?; } @@ -65,7 +65,7 @@ fn emit_update_field( token_prog: &Address, mint_key: &Address, auth_key: &Address, - ctx: &ChangeMode<'_>, + ctx: &ChangeMode, key: &[u8], value: &[u8], ) -> Result<(), ProgramError> { @@ -86,24 +86,18 @@ fn emit_update_field( buf[pos..pos + value.len()].copy_from_slice(value); pos += value.len(); - BufCpiCall::new( - token_prog, - [ - InstructionAccount::writable(mint_key), - InstructionAccount::readonly_signer(auth_key), - ], - [ - ctx.mint.to_account_view(), - ctx.authority.to_account_view(), - ], - buf, - pos, - ) - .invoke() + let _ = (mint_key, auth_key); + let mut cpi = DynCpiCall::<2, MAX_META_IX>::new(token_prog); + // mint: writable, not signer + cpi.push_account(ctx.mint.to_account_view(), false, true)?; + // authority: signer, not writable + cpi.push_account(ctx.authority.to_account_view(), true, false)?; + cpi.set_data(&buf[..pos])?; + cpi.invoke() } /// Check if the mint's metadata already contains a "threshold" key. -fn has_threshold_in_metadata(ctx: &ChangeMode<'_>) -> Result { +fn has_threshold_in_metadata(ctx: &ChangeMode) -> Result { let mint_view = ctx.mint.to_account_view(); let data = mint_view.try_borrow()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_config.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_config.rs index d5b50b54b..17676b3a3 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_config.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_config.rs @@ -6,16 +6,16 @@ use crate::constants::CONFIG_SEED; use crate::state::{write_config, CONFIG_SIZE}; #[derive(Accounts)] -pub struct InitConfig<'info> { +pub struct InitConfig { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub config: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub config: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_init_config(accounts: &InitConfig) -> Result<(), ProgramError> { +pub fn handle_init_config(accounts: &mut InitConfig) -> Result<(), ProgramError> { let (config_pda, bump) = Address::find_program_address(&[CONFIG_SEED], &crate::ID); if accounts.config.to_account_view().address() != &config_pda { @@ -31,8 +31,8 @@ pub fn handle_init_config(accounts: &InitConfig) -> Result<(), ProgramError> { accounts.system_program .create_account( - accounts.payer, - &*accounts.config, + &accounts.payer, + &accounts.config, lamports, CONFIG_SIZE, &crate::ID, @@ -40,7 +40,7 @@ pub fn handle_init_config(accounts: &InitConfig) -> Result<(), ProgramError> { .invoke_signed(&seeds)?; let view = unsafe { - &mut *(accounts.config as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.config as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_mint.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_mint.rs index 14aac5596..da948f145 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_mint.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_mint.rs @@ -1,4 +1,4 @@ -use quasar_lang::cpi::{BufCpiCall, CpiCall, InstructionAccount, Seed}; +use quasar_lang::cpi::{CpiCall, DynCpiCall, InstructionAccount, Seed}; use quasar_lang::prelude::*; use quasar_lang::sysvars::Sysvar; @@ -15,22 +15,22 @@ impl Id for Token2022 { } #[derive(Accounts)] -pub struct InitMint<'info> { +pub struct InitMint { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// The mint account (must also be a signer for create_account). #[account(mut)] - pub mint: &'info Signer, + pub mint: Signer, /// ExtraAccountMetaList PDA: ["extra-account-metas", mint] #[account(mut)] - pub extra_metas_account: &'info mut UncheckedAccount, - pub system_program: &'info Program, - pub token_program: &'info Program, + pub extra_metas_account: UncheckedAccount, + pub system_program: Program, + pub token_program: Program, } #[inline(always)] pub fn handle_init_mint( - accounts: &InitMint, decimals: u8, + accounts: &mut InitMint, decimals: u8, freeze_authority: &Address, permanent_delegate: &Address, transfer_hook_authority: &Address, @@ -70,7 +70,8 @@ pub fn handle_init_mint( // Create the mint account owned by Token2022. accounts.system_program - .create_account(accounts.payer, accounts.mint, lamports, mint_size as u64, token_prog) + .create_account( + &accounts.payer, &accounts.mint, lamports, mint_size as u64, token_prog) .invoke()?; // Initialize PermanentDelegate extension: opcode 35 @@ -157,22 +158,15 @@ pub fn handle_init_mint( buf[pos..pos + uri.len()].copy_from_slice(uri); pos += uri.len(); - BufCpiCall::new( - token_prog, - [ - InstructionAccount::writable(mint_key), - InstructionAccount::readonly_signer(payer_key), - InstructionAccount::readonly_signer(payer_key), - ], - [ - accounts.mint.to_account_view(), - accounts.payer.to_account_view(), - accounts.payer.to_account_view(), - ], - buf, - pos, - ) - .invoke()?; + { + let mut cpi = DynCpiCall::<3, MAX_META_IX>::new(token_prog); + cpi.push_account(accounts.mint.to_account_view(), false, true)?; + cpi.push_account(accounts.payer.to_account_view(), true, false)?; + cpi.push_account(accounts.payer.to_account_view(), true, false)?; + cpi.set_data(&buf[..pos])?; + cpi.invoke()?; + } + let _ = mint_key; // TokenMetadataUpdateField for "AB" key: opcode 44, sub-opcode 1 emit_update_field_cpi(accounts, b"AB", mode_value)?; @@ -197,7 +191,7 @@ pub fn handle_init_mint( /// Emit a Token-2022 TokenMetadataUpdateField CPI. /// Opcode 44, sub-opcode 1, followed by Field::Key (discriminator 2, then borsh /// string for key, then borsh string for value). -fn emit_update_field_cpi(ctx: &InitMint<'_>, key: &[u8], value: &[u8]) -> Result<(), ProgramError> { +fn emit_update_field_cpi(ctx: &InitMint, key: &[u8], value: &[u8]) -> Result<(), ProgramError> { let token_prog = ctx.token_program.to_account_view().address(); let mint_key = ctx.mint.to_account_view().address(); let payer_key = ctx.payer.to_account_view().address(); @@ -221,25 +215,17 @@ fn emit_update_field_cpi(ctx: &InitMint<'_>, key: &[u8], value: &[u8]) -> Result buf[pos..pos + value.len()].copy_from_slice(value); pos += value.len(); - BufCpiCall::new( - token_prog, - [ - InstructionAccount::writable(mint_key), - InstructionAccount::readonly_signer(payer_key), - ], - [ - ctx.mint.to_account_view(), - ctx.payer.to_account_view(), - ], - buf, - pos, - ) - .invoke() + let _ = (mint_key, payer_key); + let mut cpi = DynCpiCall::<2, MAX_META_IX>::new(token_prog); + cpi.push_account(ctx.mint.to_account_view(), false, true)?; + cpi.push_account(ctx.payer.to_account_view(), true, false)?; + cpi.set_data(&buf[..pos])?; + cpi.invoke() } /// Top up the mint account if its balance is below the rent minimum for its /// current data size. -fn top_up_rent(ctx: &InitMint<'_>) -> Result<(), ProgramError> { +fn top_up_rent(ctx: &InitMint) -> Result<(), ProgramError> { let mint_view = ctx.mint.to_account_view(); let data_len = mint_view.data_len(); let min_balance = Rent::get()?.try_minimum_balance(data_len)?; @@ -248,7 +234,7 @@ fn top_up_rent(ctx: &InitMint<'_>) -> Result<(), ProgramError> { if min_balance > current_lamports { let diff = min_balance - current_lamports; ctx.system_program - .transfer(ctx.payer, ctx.mint, diff) + .transfer(&ctx.payer, &ctx.mint, diff) .invoke()?; } Ok(()) @@ -256,7 +242,7 @@ fn top_up_rent(ctx: &InitMint<'_>) -> Result<(), ProgramError> { /// Create the ExtraAccountMetaList PDA and populate it with the ABWallet /// extra account meta (PDA seeded by [AB_WALLET_SEED, AccountData(2, 32, 32)]). -fn init_extra_metas(ctx: &InitMint<'_>) -> Result<(), ProgramError> { +fn init_extra_metas(ctx: &mut InitMint) -> Result<(), ProgramError> { let mint_key = ctx.mint.to_account_view().address(); // Meta list with 1 extra account = 51 bytes @@ -279,11 +265,12 @@ fn init_extra_metas(ctx: &InitMint<'_>) -> Result<(), ProgramError> { ]; ctx.system_program - .create_account(ctx.payer, &*ctx.extra_metas_account, lamports, meta_list_size, &crate::ID) + .create_account( + &ctx.payer, &ctx.extra_metas_account, lamports, meta_list_size, &crate::ID) .invoke_signed(&seeds)?; let view = unsafe { - &mut *(ctx.extra_metas_account as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut ctx.extra_metas_account as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_wallet.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_wallet.rs index c794db52e..e3af0187c 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_wallet.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/init_wallet.rs @@ -7,18 +7,18 @@ use crate::errors; use crate::state::{read_config_authority, write_ab_wallet, AB_WALLET_SIZE, CONFIG_SIZE}; #[derive(Accounts)] -pub struct InitWallet<'info> { +pub struct InitWallet { #[account(mut)] - pub authority: &'info Signer, - pub config: &'info UncheckedAccount, - pub wallet: &'info UncheckedAccount, + pub authority: Signer, + pub config: UncheckedAccount, + pub wallet: UncheckedAccount, #[account(mut)] - pub ab_wallet: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub ab_wallet: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_init_wallet(accounts: &InitWallet, allowed: bool) -> Result<(), ProgramError> { +pub fn handle_init_wallet(accounts: &mut InitWallet, allowed: bool) -> Result<(), ProgramError> { // Verify config PDA let (config_pda, _) = Address::find_program_address(&[CONFIG_SEED], &crate::ID); if accounts.config.to_account_view().address() != &config_pda { @@ -57,8 +57,8 @@ pub fn handle_init_wallet(accounts: &InitWallet, allowed: bool) -> Result<(), Pr accounts.system_program .create_account( - accounts.authority, - &*accounts.ab_wallet, + &accounts.authority, + &accounts.ab_wallet, lamports, AB_WALLET_SIZE, &crate::ID, @@ -67,7 +67,7 @@ pub fn handle_init_wallet(accounts: &InitWallet, allowed: bool) -> Result<(), Pr // Write wallet data let view = unsafe { - &mut *(accounts.ab_wallet as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.ab_wallet as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/remove_wallet.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/remove_wallet.rs index a9f6bfc2b..a9d31f872 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/remove_wallet.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/remove_wallet.rs @@ -5,16 +5,16 @@ use crate::errors; use crate::state::{read_config_authority, CONFIG_SIZE}; #[derive(Accounts)] -pub struct RemoveWallet<'info> { +pub struct RemoveWallet { #[account(mut)] - pub authority: &'info Signer, - pub config: &'info UncheckedAccount, + pub authority: Signer, + pub config: UncheckedAccount, #[account(mut)] - pub ab_wallet: &'info mut UncheckedAccount, + pub ab_wallet: UncheckedAccount, } #[inline(always)] -pub fn handle_remove_wallet(accounts: &RemoveWallet) -> Result<(), ProgramError> { +pub fn handle_remove_wallet(accounts: &mut RemoveWallet) -> Result<(), ProgramError> { // Verify config PDA let (config_pda, _) = Address::find_program_address(&[CONFIG_SEED], &crate::ID); if accounts.config.to_account_view().address() != &config_pda { @@ -44,7 +44,7 @@ pub fn handle_remove_wallet(accounts: &RemoveWallet) -> Result<(), ProgramError> // Zero the account data let mview = unsafe { - &mut *(accounts.ab_wallet as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.ab_wallet as *mut UncheckedAccount as *mut AccountView) }; let mut data = mview.try_borrow_mut()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/tx_hook.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/tx_hook.rs index d55e96ba8..4a5362b45 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/tx_hook.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/instructions/tx_hook.rs @@ -13,17 +13,17 @@ use crate::state::{read_wallet_allowed, MODE_ALLOW, MODE_BLOCK, MODE_MIXED, AB_W /// [4] extra_account_meta_list /// [5] ab_wallet — resolved from extra account metas (PDA for destination owner) #[derive(Accounts)] -pub struct TxHook<'info> { - pub source_token_account: &'info UncheckedAccount, - pub mint: &'info UncheckedAccount, - pub destination_token_account: &'info UncheckedAccount, - pub owner_delegate: &'info UncheckedAccount, - pub meta_list: &'info UncheckedAccount, - pub ab_wallet: &'info UncheckedAccount, +pub struct TxHook { + pub source_token_account: UncheckedAccount, + pub mint: UncheckedAccount, + pub destination_token_account: UncheckedAccount, + pub owner_delegate: UncheckedAccount, + pub meta_list: UncheckedAccount, + pub ab_wallet: UncheckedAccount, } #[inline(always)] -pub fn handle_tx_hook(accounts: &TxHook, amount: u64) -> Result<(), ProgramError> { +pub fn handle_tx_hook(accounts: &mut TxHook, amount: u64) -> Result<(), ProgramError> { let mint_view = accounts.mint.to_account_view(); let mint_data = mint_view.try_borrow()?; diff --git a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/lib.rs index 74b3df3f1..0ad2df70b 100644 --- a/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/allow-block-list-token/quasar/src/lib.rs @@ -36,7 +36,7 @@ mod quasar_abl_token { /// name: [u8; 32], name_len: u8 /// symbol: [u8; 10], symbol_len: u8 /// uri: [u8; 128], uri_len: u8 - #[instruction(discriminator = [0, 0, 0, 0, 0, 0, 0, 0])] + #[instruction(discriminator = [1, 0, 0, 0, 0, 0, 0, 0])] pub fn init_mint( ctx: Ctx, decimals: u8, diff --git a/tokens/token-extensions/transfer-hook/counter/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/counter/quasar/Cargo.toml index f638977bf..9d50e2b7e 100644 --- a/tokens/token-extensions/transfer-hook/counter/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/counter/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/counter/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/counter/quasar/src/lib.rs index 28b66c913..00bc481c5 100644 --- a/tokens/token-extensions/transfer-hook/counter/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/counter/quasar/src/lib.rs @@ -45,134 +45,118 @@ mod quasar_transfer_hook_counter { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetaList<'info> { +pub struct InitializeExtraAccountMetaList { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// ExtraAccountMetaList PDA: ["extra-account-metas", mint] #[account(mut)] - pub extra_account_meta_list: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, + pub mint: UncheckedAccount, /// Counter PDA: ["counter"] #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub counter_account: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccountMetaList) -> Result<(), ProgramError> { - // ExtraAccountMetaList with 1 extra account: - // [8 bytes: Execute discriminator] - // [4 bytes: data length] - // [4 bytes: PodSlice count = 1] - // [35 bytes: ExtraAccountMeta entry for the counter PDA] - // Total = 8 + 4 + 4 + 35 = 51 bytes - let meta_list_size: u64 = 51; - let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; - - // Derive ExtraAccountMetaList PDA - let mint_address = accounts.mint.to_account_view().address(); - let (expected_pda, bump) = Address::find_program_address( - &[b"extra-account-metas", mint_address.as_ref()], - &crate::ID, - ); - - let meta_list_address = accounts.extra_account_meta_list.to_account_view().address(); - if meta_list_address != &expected_pda { - return Err(ProgramError::InvalidSeeds); - } - - // Create ExtraAccountMetaList PDA - let bump_bytes = [bump]; - let seeds = [ - Seed::from(b"extra-account-metas" as &[u8]), - Seed::from(mint_address.as_ref()), - Seed::from(&bump_bytes as &[u8]), - ]; - - accounts.system_program - .create_account( - accounts.payer, - &*accounts.extra_account_meta_list, - lamports, - meta_list_size, - &crate::ID, - ) - .invoke_signed(&seeds)?; - - // Write TLV data with the counter PDA as an extra account - let view = unsafe { - &mut *(accounts.extra_account_meta_list as *const UncheckedAccount as *mut UncheckedAccount - as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - - // Execute discriminator (TLV type tag) - data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); - // Data length: 4 (count) + 35 (one ExtraAccountMeta) = 39 - data[8..12].copy_from_slice(&39u32.to_le_bytes()); - // PodSlice count: 1 entry - data[12..16].copy_from_slice(&1u32.to_le_bytes()); - - // ExtraAccountMeta for counter PDA (35 bytes): - // [0]: discriminator (1 = PDA from seeds) - // [1]: address_config (32 bytes encoding the seeds) - // [33]: is_signer (0) - // [34]: is_writable (1) - // - // For a PDA with seeds = [Literal("counter")], the address_config - // uses the ExtraAccountMeta seed encoding format. The seeds are: - // Seed::Literal { bytes: b"counter" } - // Encoded as: [length: 1 byte][data: N bytes] - // - // The full ExtraAccountMeta seed-based encoding: - // discriminator = 1 (PDA) - // address_config[0] = 1 (number of seeds) - // address_config[1] = 0 (seed type: literal) - // address_config[2] = 7 (seed length) - // address_config[3..10] = b"counter" - // address_config[10..32] = zeroes (padding) - // is_signer = 0 - // is_writable = 1 - data[16] = 1; // discriminator: PDA from seeds - let mut config = [0u8; 32]; - config[0] = 1; // number of seeds - config[1] = 0; // seed type: literal - config[2] = 7; // seed length - config[3..10].copy_from_slice(b"counter"); - data[17..49].copy_from_slice(&config); - data[49] = 0; // is_signer = false - data[50] = 1; // is_writable = true - - // Also create the counter PDA (8 bytes for u64 counter + 8 bytes discriminator) - let counter_size: u64 = 16; - let counter_lamports = Rent::get()?.try_minimum_balance(counter_size as usize)?; - - let (counter_pda, counter_bump) = - Address::find_program_address(&[b"counter"], &crate::ID); - - let counter_address = accounts.counter_account.to_account_view().address(); - if counter_address != &counter_pda { - return Err(ProgramError::InvalidSeeds); - } - - let counter_bump_bytes = [counter_bump]; - let counter_seeds = [ - Seed::from(b"counter" as &[u8]), - Seed::from(&counter_bump_bytes as &[u8]), - ]; - - accounts.system_program - .create_account( - accounts.payer, - &*accounts.counter_account, - counter_lamports, - counter_size, +fn handle_initialize_extra_account_meta_list( + accounts: &mut InitializeExtraAccountMetaList, +) -> Result<(), ProgramError> { + // ExtraAccountMetaList with 1 extra account: + // [8 bytes: Execute discriminator] + // [4 bytes: data length] + // [4 bytes: PodSlice count = 1] + // [35 bytes: ExtraAccountMeta entry for the counter PDA] + // Total = 8 + 4 + 4 + 35 = 51 bytes + let meta_list_size: u64 = 51; + let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; + + // Derive ExtraAccountMetaList PDA + let mint_address = accounts.mint.to_account_view().address(); + let (expected_pda, bump) = Address::find_program_address( + &[b"extra-account-metas", mint_address.as_ref()], &crate::ID, - ) - .invoke_signed(&counter_seeds)?; - - log("Extra account meta list and counter initialized"); - Ok(()) + ); + + let meta_list_address = accounts.extra_account_meta_list.to_account_view().address(); + if meta_list_address != &expected_pda { + return Err(ProgramError::InvalidSeeds); + } + + // Create ExtraAccountMetaList PDA + let bump_bytes = [bump]; + let seeds = [ + Seed::from(b"extra-account-metas" as &[u8]), + Seed::from(mint_address.as_ref()), + Seed::from(&bump_bytes as &[u8]), + ]; + + accounts + .system_program + .create_account( + &accounts.payer, + &accounts.extra_account_meta_list, + lamports, + meta_list_size, + &crate::ID, + ) + .invoke_signed(&seeds)?; + + // Write TLV data with the counter PDA as an extra account + let view = unsafe { + &mut *(&mut accounts.extra_account_meta_list as *mut UncheckedAccount + as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + + // Execute discriminator (TLV type tag) + data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); + // Data length: 4 (count) + 35 (one ExtraAccountMeta) = 39 + data[8..12].copy_from_slice(&39u32.to_le_bytes()); + // PodSlice count: 1 entry + data[12..16].copy_from_slice(&1u32.to_le_bytes()); + + data[16] = 1; // discriminator: PDA from seeds + let mut config = [0u8; 32]; + config[0] = 1; // number of seeds + config[1] = 0; // seed type: literal + config[2] = 7; // seed length + config[3..10].copy_from_slice(b"counter"); + data[17..49].copy_from_slice(&config); + data[49] = 0; // is_signer = false + data[50] = 1; // is_writable = true + + // Also create the counter PDA (8 bytes for u64 counter + 8 bytes discriminator) + let counter_size: u64 = 16; + let counter_lamports = Rent::get()?.try_minimum_balance(counter_size as usize)?; + + let (counter_pda, counter_bump) = + Address::find_program_address(&[b"counter"], &crate::ID); + + let counter_address = accounts.counter_account.to_account_view().address(); + if counter_address != &counter_pda { + return Err(ProgramError::InvalidSeeds); + } + + let counter_bump_bytes = [counter_bump]; + let counter_seeds = [ + Seed::from(b"counter" as &[u8]), + Seed::from(&counter_bump_bytes as &[u8]), + ]; + + accounts + .system_program + .create_account( + &accounts.payer, + &accounts.counter_account, + counter_lamports, + counter_size, + &crate::ID, + ) + .invoke_signed(&counter_seeds)?; + + log("Extra account meta list and counter initialized"); + Ok(()) } // --------------------------------------------------------------------------- @@ -180,47 +164,47 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { +pub struct TransferHook { /// Source token account - pub source_token: &'info UncheckedAccount, + pub source_token: UncheckedAccount, /// Mint - pub mint: &'info UncheckedAccount, + pub mint: UncheckedAccount, /// Destination token account - pub destination_token: &'info UncheckedAccount, + pub destination_token: UncheckedAccount, /// Source token account owner - pub owner: &'info UncheckedAccount, + pub owner: UncheckedAccount, /// ExtraAccountMetaList PDA - pub extra_account_meta_list: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, /// Counter PDA (extra account resolved by Token-2022) #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, + pub counter_account: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_hook(accounts: &TransferHook) -> Result<(), ProgramError> { - // Read the current counter from the account data - let view = unsafe { - &mut *(accounts.counter_account as *const UncheckedAccount as *mut UncheckedAccount - as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - - // Counter is at offset 8 (after 8-byte Anchor-style discriminator) - // In our case we just use the first 8 bytes as the counter - if data.len() < 16 { - return Err(ProgramError::AccountDataTooSmall); - } - - let mut counter_bytes = [0u8; 8]; - counter_bytes.copy_from_slice(&data[8..16]); - let counter = u64::from_le_bytes(counter_bytes); - - let new_counter = counter - .checked_add(1) - .ok_or(ProgramError::ArithmeticOverflow)?; - - data[8..16].copy_from_slice(&new_counter.to_le_bytes()); - - log("Transfer hook: counter incremented"); - Ok(()) +fn handle_transfer_hook(accounts: &mut TransferHook) -> Result<(), ProgramError> { + // Read the current counter from the account data + let view = unsafe { + &mut *(&mut accounts.counter_account as *mut UncheckedAccount + as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + + // Counter is at offset 8 (after 8-byte Anchor-style discriminator) + // In our case we just use the first 8 bytes as the counter + if data.len() < 16 { + return Err(ProgramError::AccountDataTooSmall); + } + + let mut counter_bytes = [0u8; 8]; + counter_bytes.copy_from_slice(&data[8..16]); + let counter = u64::from_le_bytes(counter_bytes); + + let new_counter = counter + .checked_add(1) + .ok_or(ProgramError::ArithmeticOverflow)?; + + data[8..16].copy_from_slice(&new_counter.to_le_bytes()); + + log("Transfer hook: counter incremented"); + Ok(()) } diff --git a/tokens/token-extensions/transfer-hook/hello-world/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/hello-world/quasar/Cargo.toml index 2166fba4a..1429a14da 100644 --- a/tokens/token-extensions/transfer-hook/hello-world/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/hello-world/quasar/Cargo.toml @@ -20,8 +20,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/hello-world/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/hello-world/quasar/src/lib.rs index 27ab88289..387afb332 100644 --- a/tokens/token-extensions/transfer-hook/hello-world/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/hello-world/quasar/src/lib.rs @@ -62,69 +62,69 @@ mod quasar_transfer_hook_hello_world { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub mint_account: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &Initialize, decimals: u8) -> Result<(), ProgramError> { - // Mint with TransferHook extension: - // 165 (base account + padding) + 1 (account type) + 4 (TLV header) + 64 (extension) = 234 - let mint_size: u64 = 234; - let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; - - // 1. Create account owned by Token-2022 - accounts.system_program - .create_account( - accounts.payer, - accounts.mint_account, - lamports, - mint_size, +fn handle_initialize(accounts: &mut Initialize, decimals: u8) -> Result<(), ProgramError> { + // Mint with TransferHook extension: + // 165 (base account + padding) + 1 (account type) + 4 (TLV header) + 64 (extension) = 234 + let mint_size: u64 = 234; + let lamports = Rent::get()?.try_minimum_balance(mint_size as usize)?; + + // 1. Create account owned by Token-2022 + accounts.system_program + .create_account( + &accounts.payer, + &accounts.mint_account, + lamports, + mint_size, + accounts.token_program.to_account_view().address(), + ) + .invoke()?; + + // 2. InitializeTransferHook extension + // Layout: [36u8 (TransferHookExtension), 0u8 (Initialize), + // authority(32), program_id(32)] + let mut ext_data = [0u8; 66]; + ext_data[0] = 36; // TokenInstruction::TransferHookExtension + ext_data[1] = 0; // TransferHookInstruction::Initialize + ext_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + ext_data[34..66].copy_from_slice(crate::ID.as_ref()); + + CpiCall::new( accounts.token_program.to_account_view().address(), + [InstructionAccount::writable( + accounts.mint_account.to_account_view().address(), + )], + [accounts.mint_account.to_account_view()], + ext_data, ) .invoke()?; - // 2. InitializeTransferHook extension - // Layout: [36u8 (TransferHookExtension), 0u8 (Initialize), - // authority(32), program_id(32)] - let mut ext_data = [0u8; 66]; - ext_data[0] = 36; // TokenInstruction::TransferHookExtension - ext_data[1] = 0; // TransferHookInstruction::Initialize - ext_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - ext_data[34..66].copy_from_slice(crate::ID.as_ref()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [InstructionAccount::writable( - accounts.mint_account.to_account_view().address(), - )], - [accounts.mint_account.to_account_view()], - ext_data, - ) - .invoke()?; - - // 3. InitializeMint2: opcode 20 - let mut mint_data = [0u8; 67]; - mint_data[0] = 20; - mint_data[1] = decimals; - mint_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - mint_data[34] = 1; // has freeze authority - mint_data[35..67].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - - CpiCall::new( - accounts.token_program.to_account_view().address(), - [InstructionAccount::writable( - accounts.mint_account.to_account_view().address(), - )], - [accounts.mint_account.to_account_view()], - mint_data, - ) - .invoke() + // 3. InitializeMint2: opcode 20 + let mut mint_data = [0u8; 67]; + mint_data[0] = 20; + mint_data[1] = decimals; + mint_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + mint_data[34] = 1; // has freeze authority + mint_data[35..67].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + + CpiCall::new( + accounts.token_program.to_account_view().address(), + [InstructionAccount::writable( + accounts.mint_account.to_account_view().address(), + )], + [accounts.mint_account.to_account_view()], + mint_data, + ) + .invoke() } // --------------------------------------------------------------------------- @@ -132,75 +132,79 @@ pub fn handle_initialize(accounts: &Initialize, decimals: u8) -> Result<(), Prog // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetaList<'info> { +pub struct InitializeExtraAccountMetaList { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, /// ExtraAccountMetaList PDA seeded by ["extra-account-metas", mint] #[account(mut)] - pub extra_account_meta_list: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, - pub system_program: &'info Program, + pub extra_account_meta_list: UncheckedAccount, + pub mint: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccountMetaList) -> Result<(), ProgramError> { - use quasar_lang::cpi::Seed; - - // ExtraAccountMetaList with 0 extra accounts: - // [8 bytes: Execute discriminator] - // [4 bytes: data length = 4] - // [4 bytes: PodSlice count = 0] - // Total = 16 bytes - let meta_list_size: u64 = 16; - let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; - - // Derive PDA - let mint_address = accounts.mint.to_account_view().address(); - let (expected_pda, bump) = Address::find_program_address( - &[b"extra-account-metas", mint_address.as_ref()], - &crate::ID, - ); - - let meta_list_address = accounts.extra_account_meta_list.to_account_view().address(); - if meta_list_address != &expected_pda { - return Err(ProgramError::InvalidSeeds); - } - - // Create PDA account owned by this program - let bump_bytes = [bump]; - let seeds = [ - Seed::from(b"extra-account-metas" as &[u8]), - Seed::from(mint_address.as_ref()), - Seed::from(&bump_bytes as &[u8]), - ]; - - accounts.system_program - .create_account( - accounts.payer, - &*accounts.extra_account_meta_list, - lamports, - meta_list_size, +fn handle_initialize_extra_account_meta_list( + accounts: &mut InitializeExtraAccountMetaList, +) -> Result<(), ProgramError> { + use quasar_lang::cpi::Seed; + + // ExtraAccountMetaList with 0 extra accounts: + // [8 bytes: Execute discriminator] + // [4 bytes: data length = 4] + // [4 bytes: PodSlice count = 0] + // Total = 16 bytes + let meta_list_size: u64 = 16; + let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; + + // Derive PDA + let mint_address = accounts.mint.to_account_view().address(); + let (expected_pda, bump) = Address::find_program_address( + &[b"extra-account-metas", mint_address.as_ref()], &crate::ID, - ) - .invoke_signed(&seeds)?; - - // Write TLV data into the account. - // SAFETY: Account was just created (16 bytes) and is owned by this program. - // UncheckedAccount is #[repr(transparent)] over AccountView, so the cast is safe. - let view = unsafe { - &mut *(accounts.extra_account_meta_list as *const UncheckedAccount as *mut UncheckedAccount - as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - // Execute discriminator (type tag in TLV) - data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); - // Data length: 4 bytes for the PodSlice count field - data[8..12].copy_from_slice(&4u32.to_le_bytes()); - // PodSlice count: 0 entries - data[12..16].copy_from_slice(&0u32.to_le_bytes()); - - log("Extra account meta list initialized"); - Ok(()) + ); + + let meta_list_address = accounts.extra_account_meta_list.to_account_view().address(); + if meta_list_address != &expected_pda { + return Err(ProgramError::InvalidSeeds); + } + + // Create PDA account owned by this program + let bump_bytes = [bump]; + let seeds = [ + Seed::from(b"extra-account-metas" as &[u8]), + Seed::from(mint_address.as_ref()), + Seed::from(&bump_bytes as &[u8]), + ]; + + accounts + .system_program + .create_account( + &accounts.payer, + &accounts.extra_account_meta_list, + lamports, + meta_list_size, + &crate::ID, + ) + .invoke_signed(&seeds)?; + + // Write TLV data into the account. The account was just created + // (16 bytes) and is owned by this program, so the borrow is safe. + // SAFETY: `UncheckedAccount` is `#[repr(transparent)]` over + // `AccountView`, so the reference cast is sound. + let view: &mut AccountView = unsafe { + &mut *(&mut accounts.extra_account_meta_list as *mut UncheckedAccount + as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + // Execute discriminator (type tag in TLV) + data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); + // Data length: 4 bytes for the PodSlice count field + data[8..12].copy_from_slice(&4u32.to_le_bytes()); + // PodSlice count: 0 entries + data[12..16].copy_from_slice(&0u32.to_le_bytes()); + + log("Extra account meta list initialized"); + Ok(()) } // --------------------------------------------------------------------------- @@ -208,26 +212,26 @@ pub fn handle_initialize_extra_account_meta_list(accounts: &InitializeExtraAccou // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { +pub struct TransferHook { /// Source token account - pub source_token: &'info UncheckedAccount, + pub source_token: UncheckedAccount, /// Mint - pub mint: &'info UncheckedAccount, + pub mint: UncheckedAccount, /// Destination token account - pub destination_token: &'info UncheckedAccount, + pub destination_token: UncheckedAccount, /// Source token account owner - pub owner: &'info UncheckedAccount, + pub owner: UncheckedAccount, /// ExtraAccountMetaList PDA - pub extra_account_meta_list: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_hook(accounts: &TransferHook) -> Result<(), ProgramError> { - // In production, verify the source token's TransferHookAccount.transferring - // flag is set. The Token-2022 program sets this before invoking the hook - // and clears it after, preventing standalone invocation. - // - // For this hello-world example, we simply log a message. - log("Hello Transfer Hook!"); - Ok(()) +fn handle_transfer_hook(_accounts: &mut TransferHook) -> Result<(), ProgramError> { + // In production, verify the source token's TransferHookAccount.transferring + // flag is set. The Token-2022 program sets this before invoking the hook + // and clears it after, preventing standalone invocation. + // + // For this hello-world example, we simply log a message. + log("Hello Transfer Hook!"); + Ok(()) } diff --git a/tokens/token-extensions/transfer-hook/transfer-cost/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/transfer-cost/quasar/Cargo.toml index d8b3bb9cb..428b1ad8c 100644 --- a/tokens/token-extensions/transfer-hook/transfer-cost/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/transfer-cost/quasar/Cargo.toml @@ -18,8 +18,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/transfer-cost/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/transfer-cost/quasar/src/lib.rs index 51ff8c549..0fd5b9400 100644 --- a/tokens/token-extensions/transfer-hook/transfer-cost/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/transfer-cost/quasar/src/lib.rs @@ -33,7 +33,7 @@ mod quasar_transfer_hook_cost { pub fn initialize_extra_account_meta_list( ctx: Ctx, ) -> Result<(), ProgramError> { - handle_initialize(&mut ctx.accounts) + handle_initialize_extra_account_meta_list(&mut ctx.accounts) } /// Transfer hook handler — validates the amount and increments the counter. @@ -50,84 +50,87 @@ mod quasar_transfer_hook_cost { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetaList<'info> { +pub struct InitializeExtraAccountMetaList { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub extra_account_meta_list: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, + pub mint: UncheckedAccount, #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub counter_account: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<(), ProgramError> { - // Create ExtraAccountMetaList PDA with 1 extra account: counter - let meta_list_size: u64 = 51; - let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; - - let mint_address = accounts.mint.to_account_view().address(); - let (expected_pda, bump) = Address::find_program_address( - &[b"extra-account-metas", mint_address.as_ref()], - &crate::ID, - ); - if accounts.extra_account_meta_list.to_account_view().address() != &expected_pda { - return Err(ProgramError::InvalidSeeds); - } - - let bump_bytes = [bump]; - let seeds = [ - Seed::from(b"extra-account-metas" as &[u8]), - Seed::from(mint_address.as_ref()), - Seed::from(&bump_bytes as &[u8]), - ]; - accounts.system_program - .create_account(accounts.payer, &*accounts.extra_account_meta_list, lamports, meta_list_size, &crate::ID) - .invoke_signed(&seeds)?; - - // Write TLV data - let view = unsafe { - &mut *(accounts.extra_account_meta_list as *const UncheckedAccount - as *mut UncheckedAccount as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); - data[8..12].copy_from_slice(&39u32.to_le_bytes()); - data[12..16].copy_from_slice(&1u32.to_le_bytes()); - - // ExtraAccountMeta: counter PDA with seeds = [Literal("counter")] - data[16] = 1; - let mut config = [0u8; 32]; - config[0] = 1; - config[1] = 0; // literal - config[2] = 7; - config[3..10].copy_from_slice(b"counter"); - data[17..49].copy_from_slice(&config); - data[49] = 0; - data[50] = 1; // writable - - // Create counter PDA: 1 byte for counter (u8) - let counter_size: u64 = 9; // 8 discriminator + 1 counter - let counter_lamports = Rent::get()?.try_minimum_balance(counter_size as usize)?; - - let (counter_pda, counter_bump) = - Address::find_program_address(&[b"counter"], &crate::ID); - if accounts.counter_account.to_account_view().address() != &counter_pda { - return Err(ProgramError::InvalidSeeds); - } - - let counter_bump_bytes = [counter_bump]; - let counter_seeds = [ - Seed::from(b"counter" as &[u8]), - Seed::from(&counter_bump_bytes as &[u8]), - ]; - accounts.system_program - .create_account(accounts.payer, &*accounts.counter_account, counter_lamports, counter_size, &crate::ID) - .invoke_signed(&counter_seeds)?; - - log("Transfer cost hook initialized"); - Ok(()) +fn handle_initialize_extra_account_meta_list( + accounts: &mut InitializeExtraAccountMetaList, +) -> Result<(), ProgramError> { + // Create ExtraAccountMetaList PDA with 1 extra account: counter + let meta_list_size: u64 = 51; + let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; + + let mint_address = accounts.mint.to_account_view().address(); + let (expected_pda, bump) = Address::find_program_address( + &[b"extra-account-metas", mint_address.as_ref()], + &crate::ID, + ); + if accounts.extra_account_meta_list.to_account_view().address() != &expected_pda { + return Err(ProgramError::InvalidSeeds); + } + + let bump_bytes = [bump]; + let seeds = [ + Seed::from(b"extra-account-metas" as &[u8]), + Seed::from(mint_address.as_ref()), + Seed::from(&bump_bytes as &[u8]), + ]; + accounts + .system_program + .create_account(&accounts.payer, &accounts.extra_account_meta_list, lamports, meta_list_size, &crate::ID) + .invoke_signed(&seeds)?; + + // Write TLV data + let view = unsafe { + &mut *(&mut accounts.extra_account_meta_list as *mut UncheckedAccount as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); + data[8..12].copy_from_slice(&39u32.to_le_bytes()); + data[12..16].copy_from_slice(&1u32.to_le_bytes()); + + // ExtraAccountMeta: counter PDA with seeds = [Literal("counter")] + data[16] = 1; + let mut config = [0u8; 32]; + config[0] = 1; + config[1] = 0; // literal + config[2] = 7; + config[3..10].copy_from_slice(b"counter"); + data[17..49].copy_from_slice(&config); + data[49] = 0; + data[50] = 1; // writable + + // Create counter PDA: 1 byte for counter (u8) + let counter_size: u64 = 9; // 8 discriminator + 1 counter + let counter_lamports = Rent::get()?.try_minimum_balance(counter_size as usize)?; + + let (counter_pda, counter_bump) = + Address::find_program_address(&[b"counter"], &crate::ID); + if accounts.counter_account.to_account_view().address() != &counter_pda { + return Err(ProgramError::InvalidSeeds); + } + + let counter_bump_bytes = [counter_bump]; + let counter_seeds = [ + Seed::from(b"counter" as &[u8]), + Seed::from(&counter_bump_bytes as &[u8]), + ]; + accounts + .system_program + .create_account(&accounts.payer, &accounts.counter_account, counter_lamports, counter_size, &crate::ID) + .invoke_signed(&counter_seeds)?; + + log("Transfer cost hook initialized"); + Ok(()) } // --------------------------------------------------------------------------- @@ -135,47 +138,47 @@ pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<() // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { - pub source_token: &'info UncheckedAccount, - pub mint: &'info UncheckedAccount, - pub destination_token: &'info UncheckedAccount, - pub owner: &'info UncheckedAccount, - pub extra_account_meta_list: &'info UncheckedAccount, +pub struct TransferHook { + pub source_token: UncheckedAccount, + pub mint: UncheckedAccount, + pub destination_token: UncheckedAccount, + pub owner: UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, #[account(mut)] - pub counter_account: &'info mut UncheckedAccount, + pub counter_account: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_hook(accounts: &TransferHook, amount: u64) -> Result<(), ProgramError> { - // Validate amount - if amount > 50 { - log("Warning: large transfer amount"); - } - - // Increment transfer counter - let view = unsafe { - &mut *(accounts.counter_account as *const UncheckedAccount as *mut UncheckedAccount - as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - - if data.len() < 9 { - return Err(ProgramError::AccountDataTooSmall); - } - - let counter = data[8]; - let new_counter = counter - .checked_add(1) - .ok_or(ProgramError::ArithmeticOverflow)?; - data[8] = new_counter; - - // In the full Anchor version, this would also: - // 1. Transfer WSOL from sender's ATA to delegate's ATA - // using the delegate PDA as the authority - // 2. The WSOL amount equals the token transfer amount - // This requires several additional accounts (WSOL mint, - // token program, ATA program, delegate PDA, and both ATAs). - - log("Transfer cost hook: counter incremented"); - Ok(()) +fn handle_transfer_hook(accounts: &mut TransferHook, amount: u64) -> Result<(), ProgramError> { + // Validate amount + if amount > 50 { + log("Warning: large transfer amount"); + } + + // Increment transfer counter + let view = unsafe { + &mut *(&mut accounts.counter_account as *mut UncheckedAccount + as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + + if data.len() < 9 { + return Err(ProgramError::AccountDataTooSmall); + } + + let counter = data[8]; + let new_counter = counter + .checked_add(1) + .ok_or(ProgramError::ArithmeticOverflow)?; + data[8] = new_counter; + + // In the full Anchor version, this would also: + // 1. Transfer WSOL from sender's ATA to delegate's ATA + // using the delegate PDA as the authority + // 2. The WSOL amount equals the token transfer amount + // This requires several additional accounts (WSOL mint, + // token program, ATA program, delegate PDA, and both ATAs). + + log("Transfer cost hook: counter incremented"); + Ok(()) } diff --git a/tokens/token-extensions/transfer-hook/transfer-switch/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/transfer-switch/quasar/Cargo.toml index f46cc30a9..efa045273 100644 --- a/tokens/token-extensions/transfer-hook/transfer-switch/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/transfer-switch/quasar/Cargo.toml @@ -18,8 +18,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/transfer-switch/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/transfer-switch/quasar/src/lib.rs index 4e7c8b77b..58861212c 100644 --- a/tokens/token-extensions/transfer-hook/transfer-switch/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/transfer-switch/quasar/src/lib.rs @@ -34,7 +34,7 @@ mod quasar_transfer_hook_switch { pub fn initialize_extra_account_metas_list( ctx: Ctx, ) -> Result<(), ProgramError> { - handle_initialize(&mut ctx.accounts) + handle_initialize_extra_account_metas_list(&mut ctx.accounts) } /// Toggle the transfer switch for a wallet. @@ -61,17 +61,17 @@ mod quasar_transfer_hook_switch { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct ConfigureAdmin<'info> { +pub struct ConfigureAdmin { #[account(mut)] - pub admin: &'info Signer, - pub new_admin: &'info UncheckedAccount, + pub admin: Signer, + pub new_admin: UncheckedAccount, #[account(mut)] - pub admin_config: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub admin_config: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_configure_admin(accounts: &ConfigureAdmin) -> Result<(), ProgramError> { +fn handle_configure_admin(accounts: &mut ConfigureAdmin) -> Result<(), ProgramError> { let view = accounts.admin_config.to_account_view(); let data = view.try_borrow()?; @@ -86,8 +86,7 @@ pub fn handle_configure_admin(accounts: &ConfigureAdmin) -> Result<(), ProgramEr drop(data); // Create or reuse admin_config PDA - let (admin_config_pda, bump) = - Address::find_program_address(&[b"admin-config"], &crate::ID); + let (admin_config_pda, bump) = Address::find_program_address(&[b"admin-config"], &crate::ID); if accounts.admin_config.to_account_view().address() != &admin_config_pda { return Err(ProgramError::InvalidSeeds); } @@ -101,14 +100,15 @@ pub fn handle_configure_admin(accounts: &ConfigureAdmin) -> Result<(), ProgramEr Seed::from(b"admin-config" as &[u8]), Seed::from(&bump_bytes as &[u8]), ]; - accounts.system_program - .create_account(accounts.admin, &*accounts.admin_config, lamports, size, &crate::ID) + accounts + .system_program + .create_account(&accounts.admin, &accounts.admin_config, lamports, size, &crate::ID) .invoke_signed(&seeds)?; } // Write new admin let mview = unsafe { - &mut *(accounts.admin_config as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.admin_config as *mut UncheckedAccount as *mut AccountView) }; let mut data = mview.try_borrow_mut()?; @@ -125,62 +125,63 @@ pub fn handle_configure_admin(accounts: &ConfigureAdmin) -> Result<(), ProgramEr // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetas<'info> { +pub struct InitializeExtraAccountMetas { #[account(mut)] - pub payer: &'info Signer, - pub token_mint: &'info UncheckedAccount, + pub payer: Signer, + pub token_mint: UncheckedAccount, #[account(mut)] - pub extra_account_metas_list: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub extra_account_metas_list: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &InitializeExtraAccountMetas) -> Result<(), ProgramError> { - // 1 extra account: wallet switch PDA seeded by [AccountKey(index=3)] (sender/owner) - let meta_list_size: u64 = 51; // 8 + 4 + 4 + 35 - let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; - - let mint_address = accounts.token_mint.to_account_view().address(); - let (expected_pda, bump) = Address::find_program_address( - &[b"extra-account-metas", mint_address.as_ref()], - &crate::ID, - ); - if accounts.extra_account_metas_list.to_account_view().address() != &expected_pda { - return Err(ProgramError::InvalidSeeds); - } +fn handle_initialize_extra_account_metas_list( + accounts: &mut InitializeExtraAccountMetas, +) -> Result<(), ProgramError> { + // 1 extra account: wallet switch PDA seeded by [AccountKey(index=3)] (sender/owner) + let meta_list_size: u64 = 51; // 8 + 4 + 4 + 35 + let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; + + let mint_address = accounts.token_mint.to_account_view().address(); + let (expected_pda, bump) = Address::find_program_address( + &[b"extra-account-metas", mint_address.as_ref()], + &crate::ID, + ); + if accounts.extra_account_metas_list.to_account_view().address() != &expected_pda { + return Err(ProgramError::InvalidSeeds); + } - let bump_bytes = [bump]; - let seeds = [ - Seed::from(b"extra-account-metas" as &[u8]), - Seed::from(mint_address.as_ref()), - Seed::from(&bump_bytes as &[u8]), - ]; + let bump_bytes = [bump]; + let seeds = [ + Seed::from(b"extra-account-metas" as &[u8]), + Seed::from(mint_address.as_ref()), + Seed::from(&bump_bytes as &[u8]), + ]; - accounts.system_program - .create_account(accounts.payer, &*accounts.extra_account_metas_list, lamports, meta_list_size, &crate::ID) - .invoke_signed(&seeds)?; + accounts.system_program + .create_account(&accounts.payer, &accounts.extra_account_metas_list, lamports, meta_list_size, &crate::ID) + .invoke_signed(&seeds)?; - let view = unsafe { - &mut *(accounts.extra_account_metas_list as *const UncheckedAccount - as *mut UncheckedAccount as *mut AccountView) - }; - let mut data = view.try_borrow_mut()?; - data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); - data[8..12].copy_from_slice(&39u32.to_le_bytes()); - data[12..16].copy_from_slice(&1u32.to_le_bytes()); - - // ExtraAccountMeta: PDA seeded by [AccountKey(index=3)] — the sender/owner - data[16] = 1; // PDA from seeds - let mut config = [0u8; 32]; - config[0] = 1; // 1 seed - config[1] = 2; // seed type: account key - config[2] = 3; // account index 3 (owner/sender) - data[17..49].copy_from_slice(&config); - data[49] = 0; // not signer - data[50] = 0; // not writable (just reading switch state) - - log("Extra account metas list initialized"); - Ok(()) + let view = unsafe { + &mut *(&mut accounts.extra_account_metas_list as *mut UncheckedAccount as *mut AccountView) + }; + let mut data = view.try_borrow_mut()?; + data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); + data[8..12].copy_from_slice(&39u32.to_le_bytes()); + data[12..16].copy_from_slice(&1u32.to_le_bytes()); + + // ExtraAccountMeta: PDA seeded by [AccountKey(index=3)] — the sender/owner + data[16] = 1; // PDA from seeds + let mut config = [0u8; 32]; + config[0] = 1; // 1 seed + config[1] = 2; // seed type: account key + config[2] = 3; // account index 3 (owner/sender) + data[17..49].copy_from_slice(&config); + data[49] = 0; // not signer + data[50] = 0; // not writable (just reading switch state) + + log("Extra account metas list initialized"); + Ok(()) } // --------------------------------------------------------------------------- @@ -188,18 +189,18 @@ pub fn handle_initialize(accounts: &InitializeExtraAccountMetas) -> Result<(), P // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct Switch<'info> { +pub struct Switch { #[account(mut)] - pub admin: &'info Signer, - pub wallet: &'info UncheckedAccount, - pub admin_config: &'info UncheckedAccount, + pub admin: Signer, + pub wallet: UncheckedAccount, + pub admin_config: UncheckedAccount, #[account(mut)] - pub wallet_switch: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub wallet_switch: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_switch(accounts: &Switch, on: bool) -> Result<(), ProgramError> { +fn handle_switch(accounts: &mut Switch, on: bool) -> Result<(), ProgramError> { // Verify admin let config_view = accounts.admin_config.to_account_view(); let config_data = config_view.try_borrow()?; @@ -229,13 +230,14 @@ pub fn handle_switch(accounts: &Switch, on: bool) -> Result<(), ProgramError> { Seed::from(wallet_address.as_ref()), Seed::from(&switch_bump_bytes as &[u8]), ]; - accounts.system_program - .create_account(accounts.admin, &*accounts.wallet_switch, lamports, size, &crate::ID) + accounts + .system_program + .create_account(&accounts.admin, &accounts.wallet_switch, lamports, size, &crate::ID) .invoke_signed(&switch_seeds)?; } let mview = unsafe { - &mut *(accounts.wallet_switch as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.wallet_switch as *mut UncheckedAccount as *mut AccountView) }; let mut data = mview.try_borrow_mut()?; @@ -251,18 +253,18 @@ pub fn handle_switch(accounts: &Switch, on: bool) -> Result<(), ProgramError> { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { - pub source_token_account: &'info UncheckedAccount, - pub token_mint: &'info UncheckedAccount, - pub receiver_token_account: &'info UncheckedAccount, - pub wallet: &'info UncheckedAccount, - pub extra_account_metas_list: &'info UncheckedAccount, +pub struct TransferHook { + pub source_token_account: UncheckedAccount, + pub token_mint: UncheckedAccount, + pub receiver_token_account: UncheckedAccount, + pub wallet: UncheckedAccount, + pub extra_account_metas_list: UncheckedAccount, /// Wallet switch PDA resolved by Token-2022 - pub wallet_switch: &'info UncheckedAccount, + pub wallet_switch: UncheckedAccount, } #[inline(always)] -pub fn handle_transfer_hook(accounts: &TransferHook) -> Result<(), ProgramError> { +fn handle_transfer_hook(accounts: &mut TransferHook) -> Result<(), ProgramError> { let switch_view = accounts.wallet_switch.to_account_view(); let data = switch_view.try_borrow()?; diff --git a/tokens/token-extensions/transfer-hook/whitelist/quasar/Cargo.toml b/tokens/token-extensions/transfer-hook/whitelist/quasar/Cargo.toml index d733505f5..3d77ee491 100644 --- a/tokens/token-extensions/transfer-hook/whitelist/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-hook/whitelist/quasar/Cargo.toml @@ -18,8 +18,8 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" } solana-instruction = { version = "3.2.0" } [dev-dependencies] diff --git a/tokens/token-extensions/transfer-hook/whitelist/quasar/src/lib.rs b/tokens/token-extensions/transfer-hook/whitelist/quasar/src/lib.rs index f58370958..dc3afc0da 100644 --- a/tokens/token-extensions/transfer-hook/whitelist/quasar/src/lib.rs +++ b/tokens/token-extensions/transfer-hook/whitelist/quasar/src/lib.rs @@ -49,20 +49,20 @@ mod quasar_transfer_hook_whitelist { // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct InitializeExtraAccountMetaList<'info> { +pub struct InitializeExtraAccountMetaList { #[account(mut)] - pub payer: &'info Signer, + pub payer: Signer, #[account(mut)] - pub extra_account_meta_list: &'info mut UncheckedAccount, - pub mint: &'info UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, + pub mint: UncheckedAccount, /// Whitelist PDA: ["white_list"] #[account(mut)] - pub white_list: &'info mut UncheckedAccount, - pub system_program: &'info Program, + pub white_list: UncheckedAccount, + pub system_program: Program, } #[inline(always)] -pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<(), ProgramError> { +pub fn handle_initialize(accounts: &mut InitializeExtraAccountMetaList) -> Result<(), ProgramError> { // Create ExtraAccountMetaList PDA (1 extra account: whitelist) let meta_list_size: u64 = 51; // 8 + 4 + 4 + 35 let lamports = Rent::get()?.try_minimum_balance(meta_list_size as usize)?; @@ -85,13 +85,12 @@ pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<() ]; accounts.system_program - .create_account(accounts.payer, &*accounts.extra_account_meta_list, lamports, meta_list_size, &crate::ID) + .create_account(&accounts.payer, &accounts.extra_account_meta_list, lamports, meta_list_size, &crate::ID) .invoke_signed(&seeds)?; // Write TLV data let view = unsafe { - &mut *(accounts.extra_account_meta_list as *const UncheckedAccount - as *mut UncheckedAccount as *mut AccountView) + &mut *(&mut accounts.extra_account_meta_list as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; data[0..8].copy_from_slice(&EXECUTE_DISCRIMINATOR); @@ -127,12 +126,12 @@ pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<() ]; accounts.system_program - .create_account(accounts.payer, &*accounts.white_list, wl_lamports, wl_size, &crate::ID) + .create_account(&accounts.payer, &accounts.white_list, wl_lamports, wl_size, &crate::ID) .invoke_signed(&wl_seeds)?; // Write authority (payer) to whitelist account let wl_view = unsafe { - &mut *(accounts.white_list as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.white_list as *mut UncheckedAccount as *mut AccountView) }; let mut wl_data = wl_view.try_borrow_mut()?; @@ -148,13 +147,13 @@ pub fn handle_initialize(accounts: &InitializeExtraAccountMetaList) -> Result<() // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct TransferHook<'info> { - pub source_token: &'info UncheckedAccount, - pub mint: &'info UncheckedAccount, - pub destination_token: &'info UncheckedAccount, - pub owner: &'info UncheckedAccount, - pub extra_account_meta_list: &'info UncheckedAccount, - pub white_list: &'info UncheckedAccount, +pub struct TransferHook { + pub source_token: UncheckedAccount, + pub mint: UncheckedAccount, + pub destination_token: UncheckedAccount, + pub owner: UncheckedAccount, + pub extra_account_meta_list: UncheckedAccount, + pub white_list: UncheckedAccount, } #[inline(always)] @@ -199,17 +198,17 @@ pub fn handle_transfer_hook(accounts: &TransferHook) -> Result<(), ProgramError> // --------------------------------------------------------------------------- #[derive(Accounts)] -pub struct AddToWhitelist<'info> { - pub signer: &'info Signer, - pub new_account: &'info UncheckedAccount, +pub struct AddToWhitelist { + pub signer: Signer, + pub new_account: UncheckedAccount, #[account(mut)] - pub white_list: &'info mut UncheckedAccount, + pub white_list: UncheckedAccount, } #[inline(always)] -pub fn handle_add_to_whitelist(accounts: &AddToWhitelist) -> Result<(), ProgramError> { +pub fn handle_add_to_whitelist(accounts: &mut AddToWhitelist) -> Result<(), ProgramError> { let view = unsafe { - &mut *(accounts.white_list as *const UncheckedAccount as *mut UncheckedAccount + &mut *(&mut accounts.white_list as *mut UncheckedAccount as *mut AccountView) }; let mut data = view.try_borrow_mut()?; diff --git a/tokens/token-fundraiser/quasar/Cargo.toml b/tokens/token-fundraiser/quasar/Cargo.toml index 301b33bd3..b8bee4098 100644 --- a/tokens/token-fundraiser/quasar/Cargo.toml +++ b/tokens/token-fundraiser/quasar/Cargo.toml @@ -21,11 +21,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-fundraiser/quasar/src/instructions/check_contributions.rs b/tokens/token-fundraiser/quasar/src/instructions/check_contributions.rs index d315a0dad..5731db714 100644 --- a/tokens/token-fundraiser/quasar/src/instructions/check_contributions.rs +++ b/tokens/token-fundraiser/quasar/src/instructions/check_contributions.rs @@ -5,50 +5,44 @@ use { }; #[derive(Accounts)] -pub struct CheckContributions<'info> { +pub struct CheckContributions { #[account(mut)] - pub maker: &'info Signer, + pub maker: Signer, #[account( mut, has_one = maker, close = maker, - seeds = [b"fundraiser", maker], + seeds = Fundraiser::seeds(maker), bump = fundraiser.bump )] - pub fundraiser: &'info mut Account, + pub fundraiser: Account, #[account(mut)] - pub vault: &'info mut Account, + pub vault: Account, #[account(mut)] - pub maker_ta: &'info mut Account, - pub token_program: &'info Program, + pub maker_ta: Account, + pub token_program: Program, } #[inline(always)] -pub fn handle_check_contributions(accounts: &mut CheckContributions, fundraiser_bump: u8) -> Result<(), ProgramError> { +pub fn handle_check_contributions(accounts: &mut CheckContributions, bumps: &CheckContributionsBumps) -> Result<(), ProgramError> { // Verify the target was met require!( accounts.fundraiser.current_amount >= accounts.fundraiser.amount_to_raise, ProgramError::Custom(0) // TargetNotMet ); - let maker_key = accounts.fundraiser.maker; - let bump = [fundraiser_bump]; - let seeds: &[Seed] = &[ - Seed::from(b"fundraiser" as &[u8]), - Seed::from(maker_key.as_ref()), - Seed::from(&bump as &[u8]), - ]; + let seeds = accounts.fundraiser_seeds(bumps); // Transfer all vault funds to the maker let vault_amount = accounts.vault.amount(); accounts.token_program - .transfer(accounts.vault, accounts.maker_ta, accounts.fundraiser, vault_amount) - .invoke_signed(seeds)?; + .transfer(&accounts.vault, &accounts.maker_ta, &accounts.fundraiser, vault_amount) + .invoke_signed(&seeds)?; // Close the vault token account accounts.token_program - .close_account(accounts.vault, accounts.maker, accounts.fundraiser) - .invoke_signed(seeds)?; + .close_account(&accounts.vault, &accounts.maker, &accounts.fundraiser) + .invoke_signed(&seeds)?; Ok(()) } diff --git a/tokens/token-fundraiser/quasar/src/instructions/contribute.rs b/tokens/token-fundraiser/quasar/src/instructions/contribute.rs index a0470b277..fa5d06c29 100644 --- a/tokens/token-fundraiser/quasar/src/instructions/contribute.rs +++ b/tokens/token-fundraiser/quasar/src/instructions/contribute.rs @@ -5,18 +5,18 @@ use { }; #[derive(Accounts)] -pub struct Contribute<'info> { +pub struct Contribute { #[account(mut)] - pub contributor: &'info Signer, + pub contributor: Signer, #[account(mut)] - pub fundraiser: &'info mut Account, + pub fundraiser: Account, #[account(mut)] - pub contributor_account: &'info mut Account, + pub contributor_account: Account, #[account(mut)] - pub contributor_ta: &'info mut Account, + pub contributor_ta: Account, #[account(mut)] - pub vault: &'info mut Account, - pub token_program: &'info Program, + pub vault: Account, + pub token_program: Program, } #[inline(always)] @@ -25,7 +25,7 @@ pub fn handle_contribute(accounts: &mut Contribute, amount: u64) -> Result<(), P // Transfer tokens from contributor to vault accounts.token_program - .transfer(accounts.contributor_ta, accounts.vault, accounts.contributor, amount) + .transfer(&accounts.contributor_ta, &accounts.vault, &accounts.contributor, amount) .invoke()?; // Update fundraiser state diff --git a/tokens/token-fundraiser/quasar/src/instructions/initialize.rs b/tokens/token-fundraiser/quasar/src/instructions/initialize.rs index 3f8ee0df6..6fa0e4d39 100644 --- a/tokens/token-fundraiser/quasar/src/instructions/initialize.rs +++ b/tokens/token-fundraiser/quasar/src/instructions/initialize.rs @@ -1,40 +1,41 @@ use { - crate::state::Fundraiser, + crate::state::{Fundraiser, FundraiserInner}, quasar_lang::prelude::*, quasar_spl::{Mint, Token}, }; #[derive(Accounts)] -pub struct Initialize<'info> { +pub struct Initialize { #[account(mut)] - pub maker: &'info Signer, - pub mint_to_raise: &'info Account, - #[account(mut, init, payer = maker, seeds = [b"fundraiser", maker], bump)] - pub fundraiser: &'info mut Account, + pub maker: Signer, + pub mint_to_raise: Account, + #[account(mut, init, payer = maker, seeds = Fundraiser::seeds(maker), bump)] + pub fundraiser: Account, #[account(mut, init_if_needed, payer = maker, token::mint = mint_to_raise, token::authority = fundraiser)] - pub vault: &'info mut Account, - pub rent: &'info Sysvar, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub vault: Account, + pub rent: Sysvar, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] pub fn handle_initialize( - accounts: &mut Initialize, amount_to_raise: u64, + accounts: &mut Initialize, + amount_to_raise: u64, duration: u16, bump: u8, ) -> Result<(), ProgramError> { // Validate minimum raise amount require!(amount_to_raise > 0, ProgramError::InvalidArgument); - accounts.fundraiser.set_inner( - *accounts.maker.address(), - *accounts.mint_to_raise.address(), + accounts.fundraiser.set_inner(FundraiserInner { + maker: *accounts.maker.address(), + mint_to_raise: *accounts.mint_to_raise.address(), amount_to_raise, - 0, // current_amount starts at 0 - 0, // time_started — would be Clock::get() onchain + current_amount: 0, + time_started: 0, duration, bump, - ); + }); Ok(()) } diff --git a/tokens/token-fundraiser/quasar/src/instructions/refund.rs b/tokens/token-fundraiser/quasar/src/instructions/refund.rs index 135cf7dc1..aadbe0bb7 100644 --- a/tokens/token-fundraiser/quasar/src/instructions/refund.rs +++ b/tokens/token-fundraiser/quasar/src/instructions/refund.rs @@ -1,46 +1,40 @@ use { - crate::state::{Contributor, Fundraiser}, + crate::state::{Contributor, ContributorInner, Fundraiser}, quasar_lang::prelude::*, quasar_spl::{Token, TokenCpi}, }; #[derive(Accounts)] -pub struct Refund<'info> { +pub struct Refund { #[account(mut)] - pub contributor: &'info Signer, - pub maker: &'info UncheckedAccount, + pub contributor: Signer, + pub maker: UncheckedAccount, #[account( mut, has_one = maker, - seeds = [b"fundraiser", maker], + seeds = Fundraiser::seeds(maker), bump = fundraiser.bump )] - pub fundraiser: &'info mut Account, + pub fundraiser: Account, #[account(mut)] - pub contributor_account: &'info mut Account, + pub contributor_account: Account, #[account(mut)] - pub contributor_ta: &'info mut Account, + pub contributor_ta: Account, #[account(mut)] - pub vault: &'info mut Account, - pub token_program: &'info Program, + pub vault: Account, + pub token_program: Program, } #[inline(always)] -pub fn handle_refund(accounts: &mut Refund, fundraiser_bump: u8) -> Result<(), ProgramError> { +pub fn handle_refund(accounts: &mut Refund, bumps: &RefundBumps) -> Result<(), ProgramError> { let refund_amount = accounts.contributor_account.amount; - let maker_key = accounts.fundraiser.maker; - let bump = [fundraiser_bump]; - let seeds: &[Seed] = &[ - Seed::from(b"fundraiser" as &[u8]), - Seed::from(maker_key.as_ref()), - Seed::from(&bump as &[u8]), - ]; + let seeds = accounts.fundraiser_seeds(bumps); // Transfer contributor's tokens back from vault accounts.token_program - .transfer(accounts.vault, accounts.contributor_ta, accounts.fundraiser, refund_amount) - .invoke_signed(seeds)?; + .transfer(&accounts.vault, &accounts.contributor_ta, &accounts.fundraiser, refund_amount) + .invoke_signed(&seeds)?; // Update fundraiser state accounts.fundraiser.current_amount = accounts.fundraiser.current_amount @@ -48,7 +42,7 @@ pub fn handle_refund(accounts: &mut Refund, fundraiser_bump: u8) -> Result<(), P .ok_or(ProgramError::ArithmeticOverflow)?; // Zero out contributor amount - accounts.contributor_account.set_inner(0); + accounts.contributor_account.set_inner(ContributorInner { amount: 0 }); Ok(()) } diff --git a/tokens/token-fundraiser/quasar/src/lib.rs b/tokens/token-fundraiser/quasar/src/lib.rs index 7ec183a48..cb00e6c1d 100644 --- a/tokens/token-fundraiser/quasar/src/lib.rs +++ b/tokens/token-fundraiser/quasar/src/lib.rs @@ -36,12 +36,12 @@ mod quasar_token_fundraiser { /// Maker withdraws all funds once the target is met. #[instruction(discriminator = 2)] pub fn check_contributions(ctx: Ctx) -> Result<(), ProgramError> { - instructions::handle_check_contributions(&mut ctx.accounts, ctx.bumps.fundraiser) + instructions::handle_check_contributions(&mut ctx.accounts, &ctx.bumps) } /// Contributors reclaim their tokens if the fundraiser fails. #[instruction(discriminator = 3)] pub fn refund(ctx: Ctx) -> Result<(), ProgramError> { - instructions::handle_refund(&mut ctx.accounts, ctx.bumps.fundraiser) + instructions::handle_refund(&mut ctx.accounts, &ctx.bumps) } } diff --git a/tokens/token-fundraiser/quasar/src/state.rs b/tokens/token-fundraiser/quasar/src/state.rs index a90abfa36..9bbe003dc 100644 --- a/tokens/token-fundraiser/quasar/src/state.rs +++ b/tokens/token-fundraiser/quasar/src/state.rs @@ -1,7 +1,8 @@ use quasar_lang::prelude::*; /// State for the fundraiser: records the maker, target mint, amounts, and timing. -#[account(discriminator = 1)] +#[account(discriminator = 1, set_inner)] +#[seeds(b"fundraiser", maker: Address)] pub struct Fundraiser { pub maker: Address, pub mint_to_raise: Address, @@ -13,7 +14,7 @@ pub struct Fundraiser { } /// Tracks how much a specific contributor has given. -#[account(discriminator = 2)] +#[account(discriminator = 2, set_inner)] pub struct Contributor { pub amount: u64, } diff --git a/tokens/token-swap/quasar/Cargo.toml b/tokens/token-swap/quasar/Cargo.toml index d4a759f1f..fc8297ff8 100644 --- a/tokens/token-swap/quasar/Cargo.toml +++ b/tokens/token-swap/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-swap/quasar/src/instructions/create_amm.rs b/tokens/token-swap/quasar/src/instructions/create_amm.rs index 2807c04b2..2f2cd6be4 100644 --- a/tokens/token-swap/quasar/src/instructions/create_amm.rs +++ b/tokens/token-swap/quasar/src/instructions/create_amm.rs @@ -6,14 +6,14 @@ use {crate::state::Amm, quasar_lang::prelude::*}; /// In Quasar, we use a simpler fixed seed `["amm"]` since the Quasar derive /// macro seeds reference account addresses, not instruction data. #[derive(Accounts)] -pub struct CreateAmm<'info> { +pub struct CreateAmm { #[account(mut, init, payer = payer, seeds = [b"amm"], bump)] - pub amm: &'info mut Account, + pub amm: Account, /// Admin authority for the AMM. - pub admin: &'info UncheckedAccount, + pub admin: UncheckedAccount, #[account(mut)] - pub payer: &'info Signer, - pub system_program: &'info Program, + pub payer: Signer, + pub system_program: Program, } #[inline(always)] diff --git a/tokens/token-swap/quasar/src/instructions/create_pool.rs b/tokens/token-swap/quasar/src/instructions/create_pool.rs index a25e4acb2..c75e01b41 100644 --- a/tokens/token-swap/quasar/src/instructions/create_pool.rs +++ b/tokens/token-swap/quasar/src/instructions/create_pool.rs @@ -10,14 +10,14 @@ use { /// pool_authority = [amm, mint_a, mint_b, "authority"], /// mint_liquidity = [amm, mint_a, mint_b, "liquidity"]. #[derive(Accounts)] -pub struct CreatePool<'info> { +pub struct CreatePool { #[account(seeds = [b"amm"], bump)] - pub amm: &'info Account, + pub amm: Account, #[account(mut, init, payer = payer, seeds = [amm, mint_a, mint_b], bump)] - pub pool: &'info mut Account, + pub pool: Account, /// Pool authority PDA — signs for pool token operations. #[account(seeds = [amm, mint_a, mint_b, crate::AUTHORITY_SEED], bump)] - pub pool_authority: &'info UncheckedAccount, + pub pool_authority: UncheckedAccount, /// Liquidity token mint — created at a PDA. #[account( mut, @@ -28,20 +28,20 @@ pub struct CreatePool<'info> { mint::decimals = 6, mint::authority = pool_authority, )] - pub mint_liquidity: &'info mut Account, - pub mint_a: &'info Account, - pub mint_b: &'info Account, + pub mint_liquidity: Account, + pub mint_a: Account, + pub mint_b: Account, /// Pool's token A account. #[account(mut, init_if_needed, payer = payer, token::mint = mint_a, token::authority = pool_authority)] - pub pool_account_a: &'info mut Account, + pub pool_account_a: Account, /// Pool's token B account. #[account(mut, init_if_needed, payer = payer, token::mint = mint_b, token::authority = pool_authority)] - pub pool_account_b: &'info mut Account, + pub pool_account_b: Account, #[account(mut)] - pub payer: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, - pub rent: &'info Sysvar, + pub payer: Signer, + pub token_program: Program, + pub system_program: Program, + pub rent: Sysvar, } #[inline(always)] diff --git a/tokens/token-swap/quasar/src/instructions/deposit_liquidity.rs b/tokens/token-swap/quasar/src/instructions/deposit_liquidity.rs index 79d7aa835..a8ec95cb0 100644 --- a/tokens/token-swap/quasar/src/instructions/deposit_liquidity.rs +++ b/tokens/token-swap/quasar/src/instructions/deposit_liquidity.rs @@ -9,39 +9,39 @@ use { /// Seeds reference the amm, mint_a, and mint_b account addresses — these /// must be provided as separate account inputs. #[derive(Accounts)] -pub struct DepositLiquidity<'info> { +pub struct DepositLiquidity { #[account(seeds = [b"amm"], bump)] - pub amm: &'info Account, + pub amm: Account, #[account(seeds = [amm, mint_a, mint_b], bump)] - pub pool: &'info Account, + pub pool: Account, /// Pool authority PDA. #[account(seeds = [amm, mint_a, mint_b, crate::AUTHORITY_SEED], bump)] - pub pool_authority: &'info UncheckedAccount, + pub pool_authority: UncheckedAccount, /// Depositor (must be signer to authorise transfers). - pub depositor: &'info Signer, + pub depositor: Signer, #[account(mut, seeds = [amm, mint_a, mint_b, crate::LIQUIDITY_SEED], bump)] - pub mint_liquidity: &'info mut Account, - pub mint_a: &'info Account, - pub mint_b: &'info Account, + pub mint_liquidity: Account, + pub mint_a: Account, + pub mint_b: Account, /// Pool's token A vault. #[account(mut)] - pub pool_account_a: &'info mut Account, + pub pool_account_a: Account, /// Pool's token B vault. #[account(mut)] - pub pool_account_b: &'info mut Account, + pub pool_account_b: Account, /// Depositor's LP token account. #[account(mut, init_if_needed, payer = payer, token::mint = mint_liquidity, token::authority = depositor)] - pub depositor_account_liquidity: &'info mut Account, + pub depositor_account_liquidity: Account, /// Depositor's token A account. #[account(mut)] - pub depositor_account_a: &'info mut Account, + pub depositor_account_a: Account, /// Depositor's token B account. #[account(mut)] - pub depositor_account_b: &'info mut Account, + pub depositor_account_b: Account, #[account(mut)] - pub payer: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub payer: Signer, + pub token_program: Program, + pub system_program: Program, } /// Integer square root via Newton's method. @@ -60,7 +60,8 @@ fn isqrt(n: u128) -> u64 { #[inline(always)] pub fn handle_deposit_liquidity( - accounts: &mut DepositLiquidity, amount_a: u64, + accounts: &mut DepositLiquidity, + amount_a: u64, amount_b: u64, bumps: &DepositLiquidityBumps, ) -> Result<(), ProgramError> { @@ -107,12 +108,12 @@ pub fn handle_deposit_liquidity( // Transfer token A to the pool. accounts.token_program - .transfer(accounts.depositor_account_a, accounts.pool_account_a, accounts.depositor, amount_a) + .transfer(&accounts.depositor_account_a, &accounts.pool_account_a, &accounts.depositor, amount_a) .invoke()?; // Transfer token B to the pool. accounts.token_program - .transfer(accounts.depositor_account_b, accounts.pool_account_b, accounts.depositor, amount_b) + .transfer(&accounts.depositor_account_b, &accounts.pool_account_b, &accounts.depositor, amount_b) .invoke()?; // Mint LP tokens to the depositor (signed by pool authority). @@ -127,9 +128,9 @@ pub fn handle_deposit_liquidity( accounts.token_program .mint_to( - accounts.mint_liquidity, - accounts.depositor_account_liquidity, - accounts.pool_authority, + &accounts.mint_liquidity, + &accounts.depositor_account_liquidity, + &accounts.pool_authority, liquidity, ) .invoke_signed(seeds)?; diff --git a/tokens/token-swap/quasar/src/instructions/swap_exact_tokens_for_tokens.rs b/tokens/token-swap/quasar/src/instructions/swap_exact_tokens_for_tokens.rs index 330b25725..92cdc9118 100644 --- a/tokens/token-swap/quasar/src/instructions/swap_exact_tokens_for_tokens.rs +++ b/tokens/token-swap/quasar/src/instructions/swap_exact_tokens_for_tokens.rs @@ -6,34 +6,35 @@ use { /// Accounts for swapping tokens using the constant-product formula. #[derive(Accounts)] -pub struct SwapExactTokensForTokens<'info> { +pub struct SwapExactTokensForTokens { #[account(seeds = [b"amm"], bump)] - pub amm: &'info Account, + pub amm: Account, #[account(seeds = [amm, mint_a, mint_b], bump)] - pub pool: &'info Account, + pub pool: Account, /// Pool authority PDA. #[account(seeds = [amm, mint_a, mint_b, crate::AUTHORITY_SEED], bump)] - pub pool_authority: &'info UncheckedAccount, - pub trader: &'info Signer, - pub mint_a: &'info Account, - pub mint_b: &'info Account, + pub pool_authority: UncheckedAccount, + pub trader: Signer, + pub mint_a: Account, + pub mint_b: Account, #[account(mut)] - pub pool_account_a: &'info mut Account, + pub pool_account_a: Account, #[account(mut)] - pub pool_account_b: &'info mut Account, + pub pool_account_b: Account, #[account(mut, init_if_needed, payer = payer, token::mint = mint_a, token::authority = trader)] - pub trader_account_a: &'info mut Account, + pub trader_account_a: Account, #[account(mut, init_if_needed, payer = payer, token::mint = mint_b, token::authority = trader)] - pub trader_account_b: &'info mut Account, + pub trader_account_b: Account, #[account(mut)] - pub payer: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub payer: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] pub fn handle_swap_exact_tokens_for_tokens( - accounts: &mut SwapExactTokensForTokens, swap_a: bool, + accounts: &mut SwapExactTokensForTokens, + swap_a: bool, input_amount: u64, min_output_amount: u64, bumps: &SwapExactTokensForTokensBumps, @@ -99,20 +100,20 @@ pub fn handle_swap_exact_tokens_for_tokens( if swap_a { // Trader sends token A to pool. accounts.token_program - .transfer(accounts.trader_account_a, accounts.pool_account_a, accounts.trader, input) + .transfer(&accounts.trader_account_a, &accounts.pool_account_a, &accounts.trader, input) .invoke()?; // Pool sends token B to trader (signed). accounts.token_program - .transfer(accounts.pool_account_b, accounts.trader_account_b, accounts.pool_authority, output) + .transfer(&accounts.pool_account_b, &accounts.trader_account_b, &accounts.pool_authority, output) .invoke_signed(seeds)?; } else { // Pool sends token A to trader (signed). accounts.token_program - .transfer(accounts.pool_account_a, accounts.trader_account_a, accounts.pool_authority, output) + .transfer(&accounts.pool_account_a, &accounts.trader_account_a, &accounts.pool_authority, output) .invoke_signed(seeds)?; // Trader sends token B to pool. accounts.token_program - .transfer(accounts.trader_account_b, accounts.pool_account_b, accounts.trader, input) + .transfer(&accounts.trader_account_b, &accounts.pool_account_b, &accounts.trader, input) .invoke()?; } diff --git a/tokens/token-swap/quasar/src/instructions/withdraw_liquidity.rs b/tokens/token-swap/quasar/src/instructions/withdraw_liquidity.rs index 2516ebe0f..6fc9ecf69 100644 --- a/tokens/token-swap/quasar/src/instructions/withdraw_liquidity.rs +++ b/tokens/token-swap/quasar/src/instructions/withdraw_liquidity.rs @@ -6,40 +6,41 @@ use { /// Accounts for withdrawing liquidity from a pool. #[derive(Accounts)] -pub struct WithdrawLiquidity<'info> { +pub struct WithdrawLiquidity { #[account(seeds = [b"amm"], bump)] - pub amm: &'info Account, + pub amm: Account, #[account(seeds = [amm, mint_a, mint_b], bump)] - pub pool: &'info Account, + pub pool: Account, /// Pool authority PDA. #[account(seeds = [amm, mint_a, mint_b, crate::AUTHORITY_SEED], bump)] - pub pool_authority: &'info UncheckedAccount, - pub depositor: &'info Signer, + pub pool_authority: UncheckedAccount, + pub depositor: Signer, #[account(mut, seeds = [amm, mint_a, mint_b, crate::LIQUIDITY_SEED], bump)] - pub mint_liquidity: &'info mut Account, + pub mint_liquidity: Account, #[account(mut)] - pub mint_a: &'info mut Account, + pub mint_a: Account, #[account(mut)] - pub mint_b: &'info mut Account, + pub mint_b: Account, #[account(mut)] - pub pool_account_a: &'info mut Account, + pub pool_account_a: Account, #[account(mut)] - pub pool_account_b: &'info mut Account, + pub pool_account_b: Account, #[account(mut)] - pub depositor_account_liquidity: &'info mut Account, + pub depositor_account_liquidity: Account, #[account(mut, init_if_needed, payer = payer, token::mint = mint_a, token::authority = depositor)] - pub depositor_account_a: &'info mut Account, + pub depositor_account_a: Account, #[account(mut, init_if_needed, payer = payer, token::mint = mint_b, token::authority = depositor)] - pub depositor_account_b: &'info mut Account, + pub depositor_account_b: Account, #[account(mut)] - pub payer: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, + pub payer: Signer, + pub token_program: Program, + pub system_program: Program, } #[inline(always)] pub fn handle_withdraw_liquidity( - accounts: &mut WithdrawLiquidity, amount: u64, + accounts: &mut WithdrawLiquidity, + amount: u64, bumps: &WithdrawLiquidityBumps, ) -> Result<(), ProgramError> { let bump = [bumps.pool_authority]; @@ -68,17 +69,17 @@ pub fn handle_withdraw_liquidity( // Transfer token A from pool to depositor. accounts.token_program - .transfer(accounts.pool_account_a, accounts.depositor_account_a, accounts.pool_authority, amount_a) + .transfer(&accounts.pool_account_a, &accounts.depositor_account_a, &accounts.pool_authority, amount_a) .invoke_signed(seeds)?; // Transfer token B from pool to depositor. accounts.token_program - .transfer(accounts.pool_account_b, accounts.depositor_account_b, accounts.pool_authority, amount_b) + .transfer(&accounts.pool_account_b, &accounts.depositor_account_b, &accounts.pool_authority, amount_b) .invoke_signed(seeds)?; // Burn LP tokens. accounts.token_program - .burn(accounts.depositor_account_liquidity, accounts.mint_liquidity, accounts.depositor, amount) + .burn(&accounts.depositor_account_liquidity, &accounts.mint_liquidity, &accounts.depositor, amount) .invoke()?; Ok(()) diff --git a/tokens/token-swap/quasar/src/lib.rs b/tokens/token-swap/quasar/src/lib.rs index 8895660d5..21ecd409c 100644 --- a/tokens/token-swap/quasar/src/lib.rs +++ b/tokens/token-swap/quasar/src/lib.rs @@ -67,6 +67,12 @@ mod quasar_token_swap { input_amount: u64, min_output_amount: u64, ) -> Result<(), ProgramError> { - instructions::handle_swap_exact_tokens_for_tokens(&mut ctx.accounts, swap_a, input_amount, min_output_amount, &ctx.bumps) + instructions::handle_swap_exact_tokens_for_tokens( + &mut ctx.accounts, + swap_a, + input_amount, + min_output_amount, + &ctx.bumps, + ) } } diff --git a/tokens/transfer-tokens/quasar/Cargo.toml b/tokens/transfer-tokens/quasar/Cargo.toml index e61a66e99..b7c4aace9 100644 --- a/tokens/transfer-tokens/quasar/Cargo.toml +++ b/tokens/transfer-tokens/quasar/Cargo.toml @@ -22,11 +22,11 @@ client = [] debug = [] [dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" +quasar-lang = { git = "https://github.com/blueshift-gg/quasar" } +quasar-spl = { git = "https://github.com/blueshift-gg/quasar" } solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/transfer-tokens/quasar/src/lib.rs b/tokens/transfer-tokens/quasar/src/lib.rs index 354a75bbe..3f148405d 100644 --- a/tokens/transfer-tokens/quasar/src/lib.rs +++ b/tokens/transfer-tokens/quasar/src/lib.rs @@ -32,39 +32,39 @@ mod quasar_transfer_tokens { /// Accounts for minting tokens to a recipient. #[derive(Accounts)] -pub struct MintTokens<'info> { +pub struct MintTokens { #[account(mut)] - pub mint_authority: &'info Signer, + pub mint_authority: Signer, #[account(mut)] - pub mint: &'info mut Account, + pub mint: Account, /// The recipient's token account. Must already exist. #[account(mut)] - pub recipient_token_account: &'info mut Account, - pub token_program: &'info Program, + pub recipient_token_account: Account, + pub token_program: Program, } #[inline(always)] -pub fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64) -> Result<(), ProgramError> { +fn handle_mint_tokens(accounts: &mut MintTokens, amount: u64) -> Result<(), ProgramError> { accounts.token_program - .mint_to(accounts.mint, accounts.recipient_token_account, accounts.mint_authority, amount) + .mint_to(&accounts.mint, &accounts.recipient_token_account, &accounts.mint_authority, amount) .invoke() } /// Accounts for transferring tokens between two token accounts. #[derive(Accounts)] -pub struct TransferTokens<'info> { +pub struct TransferTokens { #[account(mut)] - pub sender: &'info Signer, + pub sender: Signer, #[account(mut)] - pub sender_token_account: &'info mut Account, + pub sender_token_account: Account, #[account(mut)] - pub recipient_token_account: &'info mut Account, - pub token_program: &'info Program, + pub recipient_token_account: Account, + pub token_program: Program, } #[inline(always)] -pub fn handle_transfer_tokens(accounts: &mut TransferTokens, amount: u64) -> Result<(), ProgramError> { +fn handle_transfer_tokens(accounts: &mut TransferTokens, amount: u64) -> Result<(), ProgramError> { accounts.token_program - .transfer(accounts.sender_token_account, accounts.recipient_token_account, accounts.sender, amount) + .transfer(&accounts.sender_token_account, &accounts.recipient_token_account, &accounts.sender, amount) .invoke() }