diff --git a/.github/.ghaignore b/.github/.ghaignore index bcff41972..8bca3632f 100644 --- a/.github/.ghaignore +++ b/.github/.ghaignore @@ -29,6 +29,20 @@ tokens/escrow/anchor # not live tokens/token-2022/group/anchor +tokens/token-2022/group/quasar + +# CPI quasar project uses subdirectories (hand/ and lever/) instead of a root Quasar.toml +basics/cross-program-invocation/quasar + +# has Cargo.toml but no Quasar.toml +tokens/spl-token-minter/quasar +tokens/external-delegate-token-master/quasar +tokens/nft-minter/quasar +tokens/nft-operations/quasar +tokens/token-swap/quasar + +# build failed - outdated quasar-lang API (no AccountView.data, no log_64) +oracles/pyth/quasar # error in tests tokens/external-delegate-token-master/anchor diff --git a/.github/workflows/solana-native.yml b/.github/workflows/native.yml similarity index 99% rename from .github/workflows/solana-native.yml rename to .github/workflows/native.yml index 9877d114d..3b403adc4 100644 --- a/.github/workflows/solana-native.yml +++ b/.github/workflows/native.yml @@ -38,7 +38,7 @@ jobs: native: - added|modified: '**/native/**' workflow: - - added|modified: '.github/workflows/solana-native.yml' + - added|modified: '.github/workflows/native.yml' - name: Analyze Changes id: analyze run: | diff --git a/.github/workflows/solana-pinocchio.yml b/.github/workflows/pinocchio.yml similarity index 99% rename from .github/workflows/solana-pinocchio.yml rename to .github/workflows/pinocchio.yml index 32cf78bf9..6085cd1f8 100644 --- a/.github/workflows/solana-pinocchio.yml +++ b/.github/workflows/pinocchio.yml @@ -38,7 +38,7 @@ jobs: pinocchio: - added|modified: '**/pinocchio/**' workflow: - - added|modified: '.github/workflows/solana-pinocchio.yml' + - added|modified: '.github/workflows/pinocchio.yml' - name: Analyze Changes id: analyze run: | diff --git a/.github/workflows/solana-quasar.yml b/.github/workflows/quasar.yml similarity index 99% rename from .github/workflows/solana-quasar.yml rename to .github/workflows/quasar.yml index 4a05e5519..b766e05d8 100644 --- a/.github/workflows/solana-quasar.yml +++ b/.github/workflows/quasar.yml @@ -40,7 +40,7 @@ jobs: quasar: - added|modified: '**/quasar/**' workflow: - - added|modified: '.github/workflows/solana-quasar.yml' + - added|modified: '.github/workflows/quasar.yml' - name: Analyze Changes id: analyze run: | diff --git a/.gitignore b/.gitignore index 8a05c56b2..2033a3263 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ node_modules/ **/*/.anchor **/*/.DS_Store **/*/target -**/*/tests/fixtures +**/*/tests/fixtures/* +!**/*/tests/fixtures/*.so **/*.rs.bk **/*/test-ledger **/*/yarn.lock diff --git a/basics/create-account/anchor/programs/create-system-account/src/lib.rs b/basics/create-account/anchor/programs/create-system-account/src/lib.rs index 558f85895..921c357b3 100644 --- a/basics/create-account/anchor/programs/create-system-account/src/lib.rs +++ b/basics/create-account/anchor/programs/create-system-account/src/lib.rs @@ -25,8 +25,8 @@ pub mod create_system_account { to: context.accounts.new_account.to_account_info(), // To pubkey }, ), - lamports, // Lamports - 0, // Space + lamports, // Lamports + 0, // Space &context.accounts.system_program.key(), // Owner Program )?; diff --git a/basics/cross-program-invocation/anchor/programs/hand/tests/test_hand.rs b/basics/cross-program-invocation/anchor/programs/hand/tests/test_hand.rs index 8d58fefea..0bb83e1a1 100644 --- a/basics/cross-program-invocation/anchor/programs/hand/tests/test_hand.rs +++ b/basics/cross-program-invocation/anchor/programs/hand/tests/test_hand.rs @@ -54,9 +54,13 @@ fn test_pull_lever_cpi() { // include_bytes!() runs at compile time, and during `anchor build` the IDL generation // step compiles tests before the .so files exist. Since this is a cross-program // dependency (not our own program), lever.so may not be built yet at compile time. - let lever_bytes = std::fs::read("target/deploy/lever.so").expect("lever.so not found — run `anchor build` first"); + let lever_bytes = std::fs::read(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../target/deploy/lever.so" + )) + .expect("lever.so not found — run `anchor build` first"); svm.add_program(hand_program_id, hand_bytes).unwrap(); - svm.add_program(lever_program_id, lever_bytes).unwrap(); + svm.add_program(lever_program_id, &lever_bytes).unwrap(); let payer = create_wallet(&mut svm, 10_000_000_000).unwrap(); let power_keypair = Keypair::new(); diff --git a/basics/pda-rent-payer/anchor/programs/anchor-program-example/src/instructions/create_new_account.rs b/basics/pda-rent-payer/anchor/programs/anchor-program-example/src/instructions/create_new_account.rs index acbe9b274..5069c0d2f 100644 --- a/basics/pda-rent-payer/anchor/programs/anchor-program-example/src/instructions/create_new_account.rs +++ b/basics/pda-rent-payer/anchor/programs/anchor-program-example/src/instructions/create_new_account.rs @@ -34,8 +34,8 @@ pub fn handle_create_new_account(context: Context) -> Result<( }, ) .with_signer(signer_seeds), - lamports, // Lamports - 0, // Space + lamports, // Lamports + 0, // Space &context.accounts.system_program.key(), // Owner Program )?; Ok(()) diff --git a/basics/program-derived-addresses/anchor/programs/anchor-program-example/src/instructions/increment.rs b/basics/program-derived-addresses/anchor/programs/anchor-program-example/src/instructions/increment.rs index ede08d717..fe25bf02d 100644 --- a/basics/program-derived-addresses/anchor/programs/anchor-program-example/src/instructions/increment.rs +++ b/basics/program-derived-addresses/anchor/programs/anchor-program-example/src/instructions/increment.rs @@ -15,7 +15,7 @@ pub struct IncrementPageVisits<'info> { page_visits: Account<'info, PageVisits>, } -pub fn handle_increment_page_visits(mut context: Context) -> Result<()> { +pub fn handle_increment_page_visits(context: Context) -> Result<()> { let page_visits = &mut context.accounts.page_visits; page_visits.increment(); Ok(()) diff --git a/tokens/create-token/anchor/prepare.mjs b/tokens/create-token/anchor/prepare.mjs index fb6b26225..afef70398 100644 --- a/tokens/create-token/anchor/prepare.mjs +++ b/tokens/create-token/anchor/prepare.mjs @@ -7,7 +7,7 @@ import { $ } from "zx"; const programs = [ { id: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - name: "token_metadata.so", + name: "mpl_token_metadata.so", }, ]; diff --git a/tokens/create-token/anchor/tests/fixtures/mpl_token_metadata.so b/tokens/create-token/anchor/tests/fixtures/mpl_token_metadata.so new file mode 100644 index 000000000..fdebe231b Binary files /dev/null and b/tokens/create-token/anchor/tests/fixtures/mpl_token_metadata.so differ diff --git a/tokens/token-2022/default-account-state/quasar/src/lib.rs b/tokens/token-2022/default-account-state/quasar/src/lib.rs index f4cac8c0d..5fc2905fb 100644 --- a/tokens/token-2022/default-account-state/quasar/src/lib.rs +++ b/tokens/token-2022/default-account-state/quasar/src/lib.rs @@ -56,8 +56,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { - // Mint + DefaultAccountState extension = 234 bytes - let mint_size: u64 = 234; + // 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 @@ -85,11 +85,13 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { .invoke()?; // 3. InitializeMint2: opcode 20, decimals, mint_authority, freeze_authority_option, freeze_authority + // COption is encoded as 1-byte flag (1 = Some, 0 = None) + 32-byte pubkey + // Total: 1 (opcode) + 1 (decimals) + 32 (mint_authority) + 1 (COption flag) + 32 (freeze_authority) = 67 bytes let mut mint_data = [0u8; 67]; mint_data[0] = 20; // InitializeMint2 mint_data[1] = 2; // 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[34] = 1; // COption::Some flag (1-byte format used by quasar-svm token-2022) mint_data[35..67].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); CpiCall::new( diff --git a/tokens/token-2022/immutable-owner/quasar/src/lib.rs b/tokens/token-2022/immutable-owner/quasar/src/lib.rs index 6dbdee80c..f4fd7a16b 100644 --- a/tokens/token-2022/immutable-owner/quasar/src/lib.rs +++ b/tokens/token-2022/immutable-owner/quasar/src/lib.rs @@ -44,8 +44,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { - // Token account + ImmutableOwner extension = 301 bytes - let account_size: u64 = 301; + // 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 @@ -59,14 +59,14 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { ) .invoke()?; - // 2. Initialize ImmutableOwner extension: opcode 34 + // 2. Initialize ImmutableOwner extension: opcode 22 (no additional data) CpiCall::new( accounts.token_program.to_account_view().address(), [InstructionAccount::writable( accounts.token_account.to_account_view().address(), )], [accounts.token_account.to_account_view()], - [34u8], + [22u8], ) .invoke()?; diff --git a/tokens/token-2022/interest-bearing/quasar/src/lib.rs b/tokens/token-2022/interest-bearing/quasar/src/lib.rs index 05e3b7a06..51f48cea6 100644 --- a/tokens/token-2022/interest-bearing/quasar/src/lib.rs +++ b/tokens/token-2022/interest-bearing/quasar/src/lib.rs @@ -48,8 +48,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize, rate: i16) -> Result<(), ProgramError> { - // Mint + InterestBearingConfig extension = 234 bytes - let mint_size: u64 = 234; + // 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 diff --git a/tokens/token-2022/memo-transfer/anchor/tests/fixtures/spl_memo.so b/tokens/token-2022/memo-transfer/anchor/tests/fixtures/spl_memo.so new file mode 100644 index 000000000..88385a01d Binary files /dev/null and b/tokens/token-2022/memo-transfer/anchor/tests/fixtures/spl_memo.so differ diff --git a/tokens/token-2022/metadata/quasar/Cargo.toml b/tokens/token-2022/metadata/quasar/Cargo.toml deleted file mode 100644 index f8e6c3542..000000000 --- a/tokens/token-2022/metadata/quasar/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "quasar-token-2022-metadata" -version = "0.1.0" -edition = "2021" - -[workspace] - -[lints.rust.unexpected_cfgs] -level = "warn" -check-cfg = [ - 'cfg(target_os, values("solana"))', -] - -[lib] -crate-type = ["cdylib", "lib"] - -[features] -alloc = ["quasar-lang/alloc"] -client = [] -debug = [] - -[dependencies] -quasar-lang = "0.0" -quasar-spl = "0.0" -solana-instruction = { version = "3.2.0" } - -[dev-dependencies] -quasar-svm = { version = "0.1" } -spl-token-interface = { version = "2.0.0" } -solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-2022/metadata/quasar/Quasar.toml b/tokens/token-2022/metadata/quasar/Quasar.toml deleted file mode 100644 index d68b1240e..000000000 --- a/tokens/token-2022/metadata/quasar/Quasar.toml +++ /dev/null @@ -1,21 +0,0 @@ -[project] -name = "quasar_token_2022_metadata" - -[toolchain] -type = "solana" - -[testing] -language = "rust" - -[testing.rust] -framework = "quasar-svm" - -[testing.rust.test] -program = "cargo" -args = [ - "test", - "tests::", -] - -[clients] -languages = ["rust"] diff --git a/tokens/token-2022/metadata/quasar/src/lib.rs b/tokens/token-2022/metadata/quasar/src/lib.rs deleted file mode 100644 index b039514e5..000000000 --- a/tokens/token-2022/metadata/quasar/src/lib.rs +++ /dev/null @@ -1,193 +0,0 @@ -#![cfg_attr(not(test), no_std)] - -use quasar_lang::{ - cpi::{CpiCall, InstructionAccount}, - prelude::*, - sysvars::Sysvar, -}; - -#[cfg(test)] -mod tests; - -declare_id!("22222222222222222222222222222222222222222222"); - -pub struct Token2022Program; -impl Id for Token2022Program { - const ID: Address = Address::new_from_array([ - 6, 221, 246, 225, 238, 117, 143, 222, 24, 66, 93, 188, 228, 108, 205, 218, - 182, 26, 252, 77, 131, 185, 13, 39, 254, 189, 249, 40, 216, 161, 139, 252, - ]); -} - -/// Maximum length for name, symbol, and URI fields. -const MAX_NAME: usize = 32; -const MAX_SYMBOL: usize = 10; -const MAX_URI: usize = 128; - -/// Demonstrates the Token-2022 MetadataPointer + TokenMetadata extensions. -/// Creates a mint with embedded on-chain metadata (name, symbol, URI). -/// -/// Uses fixed-size byte arrays for the metadata fields since Quasar -/// deserializes all instruction arguments at entry. -#[program] -mod quasar_metadata { - use super::*; - - /// Create a mint with MetadataPointer extension, then initialize - /// token metadata via Token-2022's native metadata instruction. - /// - /// * `name` — token name, right-padded with zeroes - /// * `name_len` — actual byte length of the name - /// * `symbol` — ticker, right-padded with zeroes - /// * `symbol_len` — actual byte length of the symbol - /// * `uri` — metadata URI, right-padded with zeroes - /// * `uri_len` — actual byte length of the URI - #[instruction(discriminator = 0)] - pub fn initialize( - ctx: Ctx, - name: [u8; MAX_NAME], - name_len: u8, - symbol: [u8; MAX_SYMBOL], - symbol_len: u8, - uri: [u8; MAX_URI], - uri_len: u8, - ) -> Result<(), ProgramError> { - let nl = name_len as usize; - let sl = symbol_len as usize; - let ul = uri_len as usize; - if nl > MAX_NAME || sl > MAX_SYMBOL || ul > MAX_URI { - return Err(ProgramError::InvalidInstructionData); - } - handle_initialize(&mut ctx.accounts, &name[..nl], &symbol[..sl], &uri[..ul]) - } -} - -#[derive(Accounts)] -pub struct Initialize<'info> { - #[account(mut)] - pub payer: &'info Signer, - #[account(mut)] - pub mint_account: &'info Signer, - pub token_program: &'info Program, - pub system_program: &'info Program, -} - -#[inline(always)] -pub fn handle_initialize( - accounts: &Initialize, name: &[u8], - symbol: &[u8], - uri: &[u8], -) -> Result<(), ProgramError> { - // Calculate the total metadata size. - // MetadataPointer (64 bytes) + TLV overhead + actual metadata - // Metadata format: 4 (TLV header) + 32 (update_auth) + 32 (mint) - // + 4 + name.len + 4 + symbol.len + 4 + uri.len + 4 + 0 (additional metadata) - let metadata_data_len = 32 + 32 + 4 + name.len() + 4 + symbol.len() + 4 + uri.len() + 4; - let total_ext_data = 4 + metadata_data_len; // TLV: 2 type + 2 length + data - // Mint base (82) + padding (82) + AccountType (1) + MetadataPointer ext (68) + metadata TLV - let mint_size = 82 + 82 + 1 + 68 + total_ext_data; - let lamports = Rent::get()?.try_minimum_balance(mint_size)?; - - accounts.system_program - .create_account( - accounts.payer, - accounts.mint_account, - lamports, - mint_size as u64, - accounts.token_program.to_account_view().address(), - ) - .invoke()?; - - // InitializeMetadataPointer: opcode 39, sub-opcode 0. - let mut mp_data = [0u8; 66]; - mp_data[0] = 39; - mp_data[1] = 0; - mp_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - mp_data[34..66] - .copy_from_slice(accounts.mint_account.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()], - mp_data, - ) - .invoke()?; - - // InitializeMint2. - let mut mint_data = [0u8; 67]; - mint_data[0] = 20; // InitializeMint2 - mint_data[1] = 2; // decimals - mint_data[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - mint_data[34] = 0; // no freeze authority - - 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()?; - - // TokenMetadataInitialize: TokenInstruction::TokenMetadataExtension = 44 - // Sub-instruction: Initialize = 0 - // Layout: [44, 0, update_authority(32), mint(32), - // name_len(u32 LE), name, symbol_len(u32 LE), symbol, - // uri_len(u32 LE), uri] - const MAX_META_IX: usize = 512; - let mut buf = [0u8; MAX_META_IX]; - let mut pos = 0usize; - buf[pos] = 44; - pos += 1; - buf[pos] = 0; - pos += 1; - // update_authority - buf[pos..pos + 32].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - pos += 32; - // mint - buf[pos..pos + 32] - .copy_from_slice(accounts.mint_account.to_account_view().address().as_ref()); - pos += 32; - // name - buf[pos..pos + 4].copy_from_slice(&(name.len() as u32).to_le_bytes()); - pos += 4; - buf[pos..pos + name.len()].copy_from_slice(name); - pos += name.len(); - // symbol - buf[pos..pos + 4].copy_from_slice(&(symbol.len() as u32).to_le_bytes()); - pos += 4; - buf[pos..pos + symbol.len()].copy_from_slice(symbol); - pos += symbol.len(); - // uri - buf[pos..pos + 4].copy_from_slice(&(uri.len() as u32).to_le_bytes()); - pos += 4; - buf[pos..pos + uri.len()].copy_from_slice(uri); - pos += uri.len(); - - quasar_lang::cpi::BufCpiCall::new( - accounts.token_program.to_account_view().address(), - [ - InstructionAccount::writable( - accounts.mint_account.to_account_view().address(), - ), - InstructionAccount::readonly_signer( - accounts.payer.to_account_view().address(), - ), - InstructionAccount::readonly_signer( - accounts.payer.to_account_view().address(), - ), - ], - [ - accounts.mint_account.to_account_view(), - accounts.payer.to_account_view(), - accounts.payer.to_account_view(), - ], - buf, - pos, - ) - .invoke() -} diff --git a/tokens/token-2022/metadata/quasar/src/tests.rs b/tokens/token-2022/metadata/quasar/src/tests.rs deleted file mode 100644 index e6947e161..000000000 --- a/tokens/token-2022/metadata/quasar/src/tests.rs +++ /dev/null @@ -1,67 +0,0 @@ -extern crate std; -use { - alloc::vec, - quasar_svm::{Account, Instruction, Pubkey, QuasarSvm}, - std::println, -}; - -fn setup() -> QuasarSvm { - let elf = std::fs::read("target/deploy/quasar_token_2022_metadata.so").unwrap(); - QuasarSvm::new().with_program(&crate::ID, &elf) -} - -fn signer(address: Pubkey) -> Account { - quasar_svm::token::create_keyed_system_account(&address, 10_000_000_000) -} - -fn empty(address: Pubkey) -> Account { - Account { - address, - lamports: 0, - data: vec![], - owner: quasar_svm::system_program::ID, - executable: false, - } -} - -#[test] -fn test_initialize() { - let mut svm = setup(); - - let payer = Pubkey::new_unique(); - let mint = Pubkey::new_unique(); - let token_program = quasar_svm::SPL_TOKEN_2022_PROGRAM_ID; - let system_program = quasar_svm::system_program::ID; - - let name = b"Test Token"; - let symbol = b"TEST"; - let uri = b"https://example.com/token.json"; - - let mut data = vec![0u8]; // discriminator = 0 - data.extend_from_slice(&(name.len() as u16).to_le_bytes()); - data.extend_from_slice(&(symbol.len() as u16).to_le_bytes()); - data.extend_from_slice(&(uri.len() as u16).to_le_bytes()); - data.extend_from_slice(name); - data.extend_from_slice(symbol); - data.extend_from_slice(uri); - - let instruction = Instruction { - program_id: crate::ID, - accounts: vec![ - solana_instruction::AccountMeta::new(payer.into(), true), - solana_instruction::AccountMeta::new(mint.into(), true), - solana_instruction::AccountMeta::new_readonly(token_program.into(), false), - solana_instruction::AccountMeta::new_readonly(system_program.into(), false), - ], - data, - }; - - let result = svm.process_instruction( - &instruction, - &[signer(payer), empty(mint)], - ); - - result.print_logs(); - assert!(result.is_ok(), "initialize failed: {:?}", result.raw_result); - println!(" INITIALIZE CU: {}", result.compute_units_consumed); -} diff --git a/tokens/token-2022/mint-close-authority/quasar/src/lib.rs b/tokens/token-2022/mint-close-authority/quasar/src/lib.rs index c93db5e40..8a887f431 100644 --- a/tokens/token-2022/mint-close-authority/quasar/src/lib.rs +++ b/tokens/token-2022/mint-close-authority/quasar/src/lib.rs @@ -50,8 +50,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { - // Mint + MintCloseAuthority extension = 218 bytes - let mint_size: u64 = 218; + // 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 @@ -64,10 +64,11 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { ) .invoke()?; - // InitializeMintCloseAuthority: opcode 25, close_authority pubkey - let mut ext_data = [0u8; 33]; - ext_data[0] = 25; - ext_data[1..33].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); + // 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[2..34].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); CpiCall::new( accounts.token_program.to_account_view().address(), diff --git a/tokens/token-2022/non-transferable/quasar/src/lib.rs b/tokens/token-2022/non-transferable/quasar/src/lib.rs index 672ec9623..df053282f 100644 --- a/tokens/token-2022/non-transferable/quasar/src/lib.rs +++ b/tokens/token-2022/non-transferable/quasar/src/lib.rs @@ -58,14 +58,14 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { ) .invoke()?; - // 2. Initialize NonTransferable extension: opcode 35 + // 2. Initialize NonTransferable extension: opcode 32 (InitializeNonTransferableMint, no data) CpiCall::new( accounts.token_program.to_account_view().address(), [InstructionAccount::writable( accounts.mint_account.to_account_view().address(), )], [accounts.mint_account.to_account_view()], - [35u8], + [32u8], ) .invoke()?; diff --git a/tokens/token-2022/permanent-delegate/quasar/src/lib.rs b/tokens/token-2022/permanent-delegate/quasar/src/lib.rs index dfed0388f..43f07a4a7 100644 --- a/tokens/token-2022/permanent-delegate/quasar/src/lib.rs +++ b/tokens/token-2022/permanent-delegate/quasar/src/lib.rs @@ -43,8 +43,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { - // Mint + PermanentDelegate extension = 218 bytes - let mint_size: u64 = 218; + // 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 @@ -57,10 +57,9 @@ pub fn handle_initialize(accounts: &Initialize) -> Result<(), ProgramError> { ) .invoke()?; - // InitializePermanentDelegate: opcode 35, delegate pubkey - // Actually the correct opcode is 38 (PermanentDelegate) + // InitializePermanentDelegate: opcode 35, delegate pubkey (32 bytes, not COption) let mut ext_data = [0u8; 33]; - ext_data[0] = 38; + ext_data[0] = 35; ext_data[1..33].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); CpiCall::new( diff --git a/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/instructions/initialize.rs b/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/instructions/initialize.rs index 5d6c3d5ee..4dd0b522b 100644 --- a/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/instructions/initialize.rs +++ b/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/instructions/initialize.rs @@ -87,28 +87,28 @@ pub fn handle_process_initialize( Some(&context.accounts.payer.key()), // freeze authority )?; - context.accounts.check_mint_data()?; + handle_check_mint_data(&context.accounts)?; Ok(()) } // helper to demonstrate how to read mint extension data within a program -pub fn handle_check_mint_data(accounts: &mut Initialize) -> Result<()> { - let mint = &accounts.mint_account.to_account_info(); - let mint_data = mint.data.borrow(); - let mint_with_extension = StateWithExtensions::::unpack(&mint_data)?; - let extension_data = mint_with_extension.get_extension::()?; +pub fn handle_check_mint_data(accounts: &Initialize) -> Result<()> { + let mint = &accounts.mint_account.to_account_info(); + let mint_data = mint.data.borrow(); + let mint_with_extension = StateWithExtensions::::unpack(&mint_data)?; + let extension_data = mint_with_extension.get_extension::()?; - assert_eq!( - extension_data.transfer_fee_config_authority, - OptionalNonZeroPubkey::try_from(Some(accounts.payer.key()))? - ); + assert_eq!( + extension_data.transfer_fee_config_authority, + OptionalNonZeroPubkey::try_from(Some(accounts.payer.key()))? + ); - assert_eq!( - extension_data.withdraw_withheld_authority, - OptionalNonZeroPubkey::try_from(Some(accounts.payer.key()))? - ); + assert_eq!( + extension_data.withdraw_withheld_authority, + OptionalNonZeroPubkey::try_from(Some(accounts.payer.key()))? + ); - msg!("{:?}", extension_data); - Ok(()) - } + msg!("{:?}", extension_data); + Ok(()) +} diff --git a/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/lib.rs b/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/lib.rs index cd6784cda..cd27f2ce3 100644 --- a/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/lib.rs +++ b/tokens/token-2022/transfer-fee/anchor/programs/transfer-fee/src/lib.rs @@ -14,11 +14,11 @@ pub mod transfer_fee { transfer_fee_basis_points: u16, maximum_fee: u64, ) -> Result<()> { - process_initialize(context, transfer_fee_basis_points, maximum_fee) + handle_process_initialize(context, transfer_fee_basis_points, maximum_fee) } pub fn transfer(context: Context, amount: u64) -> Result<()> { - process_transfer(context, amount) + handle_process_transfer(context, amount) } pub fn harvest<'info>(context: Context<'info, Harvest<'info>>) -> Result<()> { @@ -26,7 +26,7 @@ pub mod transfer_fee { } pub fn withdraw(context: Context) -> Result<()> { - process_withdraw(context) + handle_process_withdraw(context) } pub fn update_fee( @@ -34,6 +34,6 @@ pub mod transfer_fee { transfer_fee_basis_points: u16, maximum_fee: u64, ) -> Result<()> { - process_update_fee(context, transfer_fee_basis_points, maximum_fee) + handle_process_update_fee(context, transfer_fee_basis_points, maximum_fee) } } diff --git a/tokens/token-2022/transfer-fee/quasar/src/lib.rs b/tokens/token-2022/transfer-fee/quasar/src/lib.rs index 305f1a578..3b61b6e6f 100644 --- a/tokens/token-2022/transfer-fee/quasar/src/lib.rs +++ b/tokens/token-2022/transfer-fee/quasar/src/lib.rs @@ -70,8 +70,8 @@ pub struct Initialize<'info> { #[inline(always)] pub fn handle_initialize(accounts: &Initialize, basis_points: u16, max_fee: u64) -> Result<(), ProgramError> { - // Mint + TransferFeeConfig extension = 378 bytes - let mint_size: u64 = 378; + // 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 @@ -84,14 +84,18 @@ pub fn handle_initialize(accounts: &Initialize, basis_points: u16, max_fee: u64) ) .invoke()?; - // TransferFeeInitialize: opcode 26 - // Data: [26, config_authority (32), withdraw_authority (32), basis_points (u16 LE), max_fee (u64 LE)] - let mut ext_data = [0u8; 75]; - ext_data[0] = 26; - ext_data[1..33].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - ext_data[33..65].copy_from_slice(accounts.payer.to_account_view().address().as_ref()); - ext_data[65..67].copy_from_slice(&basis_points.to_le_bytes()); - ext_data[67..75].copy_from_slice(&max_fee.to_le_bytes()); + // 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(), diff --git a/tokens/token-2022/transfer-hook/account-data-as-seed/anchor/programs/transfer-hook/src/lib.rs b/tokens/token-2022/transfer-hook/account-data-as-seed/anchor/programs/transfer-hook/src/lib.rs index 38ba3a44b..18a27a540 100644 --- a/tokens/token-2022/transfer-hook/account-data-as-seed/anchor/programs/transfer-hook/src/lib.rs +++ b/tokens/token-2022/transfer-hook/account-data-as-seed/anchor/programs/transfer-hook/src/lib.rs @@ -41,7 +41,7 @@ pub mod transfer_hook { pub fn initialize_extra_account_meta_list( mut context: Context, ) -> Result<()> { - let extra_account_metas = InitializeExtraAccountMetaList::extra_account_metas()?; + let extra_account_metas = handle_extra_account_metas()?; // initialize ExtraAccountMetaList account with extra accounts // .map_err() needed because spl-tlv-account-resolution uses solana-program-error 2.x @@ -108,7 +108,7 @@ pub struct InitializeExtraAccountMetaList<'info> { bump, // size_of returns Result with spl's ProgramError — unwrap is safe for known-good input space = ExtraAccountMetaList::size_of( - InitializeExtraAccountMetaList::extra_account_metas_count() + handle_extra_account_metas_count() ).unwrap(), payer = payer )] diff --git a/tokens/token-2022/transfer-hook/allow-block-list-token/pnpm-lock.yaml b/tokens/token-2022/transfer-hook/allow-block-list-token/pnpm-lock.yaml index 86e88fcf3..669a20099 100644 --- a/tokens/token-2022/transfer-hook/allow-block-list-token/pnpm-lock.yaml +++ b/tokens/token-2022/transfer-hook/allow-block-list-token/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@anchor-lang/core': - specifier: 1.0.0-rc.5 - version: 1.0.0-rc.5(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + specifier: 1.0.0 + version: 1.0.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) '@radix-ui/react-dialog': specifier: ^1.1.14 version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -124,18 +124,18 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@anchor-lang/borsh@1.0.0-rc.5': - resolution: {integrity: sha512-17a+xOmvrn7zSIqlbsjqgz4f64vQEvAmZ7qyQuETCHSskC23LTtjRI0DqAl/r/vC6kosPJGWyOr9ddVIqUVtww==} + '@anchor-lang/borsh@1.0.0': + resolution: {integrity: sha512-kiUd4S/iGKZ4aZvHtX07vNiNnHa/mI/IHmw+0y0sWlvGpPsAWsLXXMrohII5vNCdgZrw+5vVXH9kt836yP9YmQ==} engines: {node: '>=10'} peerDependencies: '@solana/web3.js': ^1.69.0 - '@anchor-lang/core@1.0.0-rc.5': - resolution: {integrity: sha512-4iPy4RiEFn6obzYY7zx8IaGAXz2fvJ0uCTF6agAcUBjGNZeypfEb4ZZh6TfLnJy78Lh06JeB7XGqKsaBCMEmQA==} + '@anchor-lang/core@1.0.0': + resolution: {integrity: sha512-YHJQCJNQwF1M1M5VNNOj1DuR7B9v7f/6I9NkFYty7HAbpb3+1HpuDD7nOqI+X3CafXzteWGWZE2kn+Ts7PBKNQ==} engines: {node: '>=17'} - '@anchor-lang/errors@1.0.0-rc.5': - resolution: {integrity: sha512-kLx7oLGVCRhtWeS9PQWGkzZTDpNrGkiJQBrx1rAhEiFemL4YumhUuEbXaaEVuLBt7qZcT1eBPN4LQxYGj3QWyw==} + '@anchor-lang/errors@1.0.0': + resolution: {integrity: sha512-j3ymePewd9Bi6OcXATViRS0IPdPBT8qW4LVM3/hNePH/rZdgi8qDkToiDGuR1fFccfn7t+BrNGudHvcs6JWCFQ==} engines: {node: '>=10'} '@babel/code-frame@7.27.1': @@ -4226,16 +4226,16 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@anchor-lang/borsh@1.0.0-rc.5(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10))': + '@anchor-lang/borsh@1.0.0(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10))': dependencies: '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) bn.js: 5.2.2 buffer-layout: 1.2.2 - '@anchor-lang/core@1.0.0-rc.5(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': + '@anchor-lang/core@1.0.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: - '@anchor-lang/borsh': 1.0.0-rc.5(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)) - '@anchor-lang/errors': 1.0.0-rc.5 + '@anchor-lang/borsh': 1.0.0(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)) + '@anchor-lang/errors': 1.0.0 '@noble/hashes': 1.8.0 '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) bn.js: 5.2.2 @@ -4253,7 +4253,7 @@ snapshots: - typescript - utf-8-validate - '@anchor-lang/errors@1.0.0-rc.5': {} + '@anchor-lang/errors@1.0.0': {} '@babel/code-frame@7.27.1': dependencies: