diff --git a/js/compressed-token/src/v3/instructions/mint-to.ts b/js/compressed-token/src/v3/instructions/mint-to.ts index 99eda509d6..1612905b3c 100644 --- a/js/compressed-token/src/v3/instructions/mint-to.ts +++ b/js/compressed-token/src/v3/instructions/mint-to.ts @@ -18,7 +18,7 @@ export interface CreateMintToInstructionParams { amount: number | bigint; /** Mint authority (must be signer) */ authority: PublicKey; - /** Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) */ + /** Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) */ maxTopUp?: number; /** Optional fee payer for rent top-ups. If not provided, authority pays. */ feePayer?: PublicKey; diff --git a/program-libs/token-interface/src/instructions/mint_action/builder.rs b/program-libs/token-interface/src/instructions/mint_action/builder.rs index 0048d773fb..889c22d3b7 100644 --- a/program-libs/token-interface/src/instructions/mint_action/builder.rs +++ b/program-libs/token-interface/src/instructions/mint_action/builder.rs @@ -28,7 +28,7 @@ impl MintActionCompressedInstructionData { leaf_index: mint_with_context.leaf_index, prove_by_index: mint_with_context.prove_by_index, root_index: mint_with_context.root_index, - max_top_up: 0, // No limit by default + max_top_up: u16::MAX, // No limit by default create_mint: None, actions: Vec::new(), proof, @@ -47,7 +47,7 @@ impl MintActionCompressedInstructionData { leaf_index: 0, // New mint has no existing leaf prove_by_index: false, // Using address proof, not validity proof root_index: address_merkle_tree_root_index, - max_top_up: 0, // No limit by default + max_top_up: u16::MAX, // No limit by default create_mint: Some(CreateMint::default()), actions: Vec::new(), proof: Some(proof), @@ -66,7 +66,7 @@ impl MintActionCompressedInstructionData { leaf_index: 0, // New mint has no existing leaf prove_by_index: false, // Using address proof, not validity proof root_index: address_merkle_tree_root_index, - max_top_up: 0, // No limit by default + max_top_up: u16::MAX, // No limit by default create_mint: Some(CreateMint::default()), actions: Vec::new(), proof: None, // Proof is verified with execution not write diff --git a/program-libs/token-interface/src/instructions/mint_action/instruction_data.rs b/program-libs/token-interface/src/instructions/mint_action/instruction_data.rs index 86311b79b6..fc7721acd2 100644 --- a/program-libs/token-interface/src/instructions/mint_action/instruction_data.rs +++ b/program-libs/token-interface/src/instructions/mint_action/instruction_data.rs @@ -47,7 +47,7 @@ pub struct MintActionCompressedInstructionData { /// If mint already exists, root index of validity proof /// If proof by index not used. pub root_index: u16, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: u16, pub create_mint: Option, pub actions: Vec, diff --git a/program-libs/token-interface/src/instructions/transfer2/instruction_data.rs b/program-libs/token-interface/src/instructions/transfer2/instruction_data.rs index e120d610f8..e68b12213b 100644 --- a/program-libs/token-interface/src/instructions/transfer2/instruction_data.rs +++ b/program-libs/token-interface/src/instructions/transfer2/instruction_data.rs @@ -20,7 +20,7 @@ pub struct CompressedTokenInstructionDataTransfer2 { /// Placeholder currently unimplemented. pub lamports_change_account_owner_index: u8, pub output_queue: u8, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: u16, pub cpi_context: Option, pub compressions: Option>, diff --git a/program-tests/compressed-token-test/tests/compress_only/ata_decompress.rs b/program-tests/compressed-token-test/tests/compress_only/ata_decompress.rs index 541d6f14d1..b48517e4de 100644 --- a/program-tests/compressed-token-test/tests/compress_only/ata_decompress.rs +++ b/program-tests/compressed-token-test/tests/compress_only/ata_decompress.rs @@ -950,7 +950,7 @@ async fn test_ata_decompress_with_mismatched_amount_fails() { out_tlv: None, compressions: Some(compressions), cpi_context: None, - max_top_up: 0, + max_top_up: u16::MAX, // No limit on top-ups }; // Serialize instruction data diff --git a/program-tests/compressed-token-test/tests/light_token/transfer_checked.rs b/program-tests/compressed-token-test/tests/light_token/transfer_checked.rs index a9c1559f57..ed3be69cb3 100644 --- a/program-tests/compressed-token-test/tests/light_token/transfer_checked.rs +++ b/program-tests/compressed-token-test/tests/light_token/transfer_checked.rs @@ -162,7 +162,7 @@ async fn test_transfer_requires_checked_for_restricted_extensions() { destination: account_b_pubkey, amount: transfer_amount, authority: owner.pubkey(), - max_top_up: Some(0), // 0 = no limit, but includes system program for compressible + max_top_up: Some(u16::MAX), // u16::MAX = no limit, includes system program for compressible fee_payer: None, } .instruction() @@ -186,7 +186,7 @@ async fn test_transfer_requires_checked_for_restricted_extensions() { amount: transfer_amount, decimals: 9, authority: owner.pubkey(), - max_top_up: Some(0), // 0 = no limit, but includes system program for compressible + max_top_up: Some(u16::MAX), // u16::MAX = no limit, includes system program for compressible fee_payer: None, } .instruction() diff --git a/program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs b/program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs index 38e040e90f..beafaba7fa 100644 --- a/program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs +++ b/program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs @@ -277,7 +277,7 @@ fn build_compressions_only_instruction( out_tlv: None, compressions, cpi_context: None, - max_top_up: 0, // No limit + max_top_up: u16::MAX, // No limit }; // Serialize instruction data diff --git a/programs/compressed-token/program/docs/compressed_token/MINT_ACTION.md b/programs/compressed-token/program/docs/compressed_token/MINT_ACTION.md index c496920ad7..2a3f3d0f91 100644 --- a/programs/compressed-token/program/docs/compressed_token/MINT_ACTION.md +++ b/programs/compressed-token/program/docs/compressed_token/MINT_ACTION.md @@ -36,7 +36,7 @@ Key concepts integrated: - `leaf_index`: u32 - Merkle tree leaf index of existing compressed mint (only used if create_mint is None) - `prove_by_index`: bool - Use proof-by-index for existing mint validation (only used if create_mint is None) - `root_index`: u16 - Root index for address proof (create) or validity proof (update). Not used if proof by index. - - `max_top_up`: u16 - Maximum lamports for rent and top-up combined, in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). Transaction fails if exceeded. (0 = no limit) + - `max_top_up`: u16 - Maximum lamports for rent and top-up combined, in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) - `create_mint`: Option - Configuration for creating new compressed mint (None for existing mint operations) - `actions`: Vec - Ordered list of actions to execute - `proof`: Option - ZK proof for compressed account validation (required unless prove_by_index=true) diff --git a/programs/compressed-token/program/docs/compressed_token/TRANSFER2.md b/programs/compressed-token/program/docs/compressed_token/TRANSFER2.md index 1d21fce21b..c98e28aaf0 100644 --- a/programs/compressed-token/program/docs/compressed_token/TRANSFER2.md +++ b/programs/compressed-token/program/docs/compressed_token/TRANSFER2.md @@ -47,7 +47,7 @@ - `lamports_change_account_merkle_tree_index`: u8 - Merkle tree index for lamport change account (placeholder, unimplemented) - `lamports_change_account_owner_index`: u8 - Owner index for lamport change account (placeholder, unimplemented) - `output_queue`: u8 - Output queue index for compressed account outputs - - `max_top_up`: u16 - Maximum lamports for rent and top-up combined, in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). Transaction fails if exceeded. (0 = no limit) + - `max_top_up`: u16 - Maximum lamports for rent and top-up combined, in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) - `cpi_context`: Optional CompressedCpiContext - Required for CPI operations; write mode: set either first_set_context or set_context (not both); execute mode: provide with all flags false - `compressions`: Optional Vec - Compress/decompress operations - `proof`: Optional CompressedProof - Required for ZK validation of compressed inputs; not needed for proof by index or when no compressed inputs exist diff --git a/programs/compressed-token/program/docs/ctoken/APPROVE.md b/programs/compressed-token/program/docs/ctoken/APPROVE.md index c0bbca6e77..f274907301 100644 --- a/programs/compressed-token/program/docs/ctoken/APPROVE.md +++ b/programs/compressed-token/program/docs/ctoken/APPROVE.md @@ -14,13 +14,13 @@ If the CToken account has a compressible extension and requires a rent top-up, t - **NOT SPL-compatible (system program required):** Compressible accounts that need rent top-up based on current slot **description:** -Delegates a specified amount to a delegate authority on a decompressed ctoken account (account layout `CToken` defined in program-libs/token-interface/src/state/ctoken/ctoken_struct.rs). After the SPL approve operation, automatically tops up compressible accounts (extension layout `CompressionInfo` defined in program-libs/compressible/src/compression_info.rs) with additional lamports if needed to prevent accounts from becoming compressible during normal operations. The instruction supports a max_top_up parameter (0 = no limit) that enforces transaction failure if the calculated top-up exceeds this limit. Uses pinocchio-token-program for SPL-compatible approve semantics. Supports backwards-compatible instruction data format (8 bytes legacy vs 10 bytes with max_top_up). +Delegates a specified amount to a delegate authority on a decompressed ctoken account (account layout `CToken` defined in program-libs/token-interface/src/state/ctoken/ctoken_struct.rs). After the SPL approve operation, automatically tops up compressible accounts (extension layout `CompressionInfo` defined in program-libs/compressible/src/compression_info.rs) with additional lamports if needed to prevent accounts from becoming compressible during normal operations. The instruction supports a max_top_up parameter (u16::MAX = no limit, 0 = no top-ups allowed) that enforces transaction failure if the calculated top-up exceeds this limit. Uses pinocchio-token-program for SPL-compatible approve semantics. Supports backwards-compatible instruction data format (8 bytes legacy vs 10 bytes with max_top_up). **Instruction data:** Path: programs/compressed-token/program/src/ctoken/approve_revoke.rs (lines 14-15, 98-106) - Bytes 0-7: `amount` (u64, little-endian) - Number of tokens to delegate -- Bytes 8-9 (optional): `max_top_up` (u16, little-endian) - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit, default for legacy format. +- Bytes 8-9 (optional): `max_top_up` (u16, little-endian) - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit (default for legacy format), 0 = no top-ups allowed. **Accounts:** 1. source @@ -57,13 +57,13 @@ Path: programs/compressed-token/program/src/ctoken/approve_revoke.rs (lines 14-1 4. **Process compressible top-up (cold path):** - Parse max_top_up from instruction data: - - If 8 bytes: legacy format, set max_top_up = 0 (no limit) + - If 8 bytes: legacy format, set max_top_up = u16::MAX (no limit) - If 10 bytes: parse max_top_up from last 2 bytes - Return InvalidInstructionData for any other length - Read CompressionInfo directly from account bytes using bytemuck (no full CToken deserialization) - Calculate transfer_amount using `top_up_lamports_from_account_info_unchecked` - If transfer_amount > 0: - - If max_top_up > 0 and transfer_amount > max_top_up: return MaxTopUpExceeded + - If max_top_up != u16::MAX and transfer_amount > max_top_up: return MaxTopUpExceeded - Get payer account (index 2), return MissingPayer if not present - Transfer lamports from payer to source via CPI @@ -114,7 +114,7 @@ let transfer_amount = top_up_lamports_from_account_info_unchecked(account, &mut if transfer_amount > 0 { // max_top_up is in units of 1,000 lamports (max ~65.5M lamports). - if max_top_up > 0 && transfer_amount > (max_top_up as u64).saturating_mul(1000) { + if max_top_up != u16::MAX && transfer_amount > (max_top_up as u64).saturating_mul(1000) { return Err(CTokenError::MaxTopUpExceeded.into()); } let payer = payer.ok_or(CTokenError::MissingPayer)?; @@ -130,12 +130,12 @@ if transfer_amount > 0 { Extended instruction data format (10 bytes total): - Bytes 0-7: amount (u64) -- Bytes 8-9: max_top_up (u16, 0 = no limit) +- Bytes 8-9: max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) **Enforcement**: ```rust // max_top_up is in units of 1,000 lamports (max ~65.5M lamports). -if max_top_up > 0 && transfer_amount > (max_top_up as u64).saturating_mul(1000) { +if max_top_up != u16::MAX && transfer_amount > (max_top_up as u64).saturating_mul(1000) { return Err(CTokenError::MaxTopUpExceeded.into()); } ``` diff --git a/programs/compressed-token/program/docs/ctoken/BURN.md b/programs/compressed-token/program/docs/ctoken/BURN.md index 528dabac32..c10e65df40 100644 --- a/programs/compressed-token/program/docs/ctoken/BURN.md +++ b/programs/compressed-token/program/docs/ctoken/BURN.md @@ -5,7 +5,7 @@ **path:** programs/compressed-token/program/src/ctoken/burn.rs **description:** -Burns tokens from a decompressed CToken account and decreases the CMint supply, fully compatible with SPL Token burn semantics. Account layout `CToken` is defined in `program-libs/token-interface/src/state/ctoken/ctoken_struct.rs`. Account layout `CompressedMint` (CMint) is defined in `program-libs/token-interface/src/state/mint/compressed_mint.rs`. Extension layout `CompressionInfo` is defined in `program-libs/compressible/src/compression_info.rs` and is embedded in both CToken and CMint structs. Uses pinocchio-token-program to process the burn (handles balance/supply updates, authority check, frozen check). After the burn, automatically tops up compressible accounts with additional lamports if needed. Top-up is calculated for both CMint and source CToken based on current slot and account balance. Top-up prevents accounts from becoming compressible during normal operations. Enforces max_top_up limit if provided (transaction fails if exceeded). Supports max_top_up parameter to limit rent top-up costs (0 = no limit). Instruction data is backwards-compatible: 8-byte format (legacy, no max_top_up enforcement) and 10-byte format (with max_top_up). This instruction only works with CMints (compressed mints). CMints do not support restricted Token-2022 extensions (Pausable, TransferFee, TransferHook, PermanentDelegate, DefaultAccountState) - only TokenMetadata is allowed. To burn tokens from spl or T22 mints, use Transfer2 with decompress mode to convert to SPL tokens first, then burn via SPL Token-2022. +Burns tokens from a decompressed CToken account and decreases the CMint supply, fully compatible with SPL Token burn semantics. Account layout `CToken` is defined in `program-libs/token-interface/src/state/ctoken/ctoken_struct.rs`. Account layout `CompressedMint` (CMint) is defined in `program-libs/token-interface/src/state/mint/compressed_mint.rs`. Extension layout `CompressionInfo` is defined in `program-libs/compressible/src/compression_info.rs` and is embedded in both CToken and CMint structs. Uses pinocchio-token-program to process the burn (handles balance/supply updates, authority check, frozen check). After the burn, automatically tops up compressible accounts with additional lamports if needed. Top-up is calculated for both CMint and source CToken based on current slot and account balance. Top-up prevents accounts from becoming compressible during normal operations. Enforces max_top_up limit if provided (transaction fails if exceeded). Supports max_top_up parameter to limit rent top-up costs (u16::MAX = no limit, 0 = no top-ups allowed). Instruction data is backwards-compatible: 8-byte format (legacy, no max_top_up enforcement) and 10-byte format (with max_top_up). This instruction only works with CMints (compressed mints). CMints do not support restricted Token-2022 extensions (Pausable, TransferFee, TransferHook, PermanentDelegate, DefaultAccountState) - only TokenMetadata is allowed. To burn tokens from spl or T22 mints, use Transfer2 with decompress mode to convert to SPL tokens first, then burn via SPL Token-2022. **Instruction data:** @@ -15,7 +15,7 @@ Format 1 (8 bytes, legacy): Format 2 (10 bytes): - Bytes 0-7: `amount` (u64, little-endian) - Number of tokens to burn -- Bytes 8-9: `max_top_up` (u16, little-endian) - Maximum lamports for combined CMint + CToken top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. +- Bytes 8-9: `max_top_up` (u16, little-endian) - Maximum lamports for combined CMint + CToken top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. **Accounts:** 1. source CToken @@ -53,7 +53,7 @@ Format 2 (10 bytes): 2. **Parse instruction data:** - Require at least 8 bytes for amount - Parse max_top_up: - - If instruction_data.len() == 8: max_top_up = 0 (no limit, legacy format) + - If instruction_data.len() == 8: max_top_up = u16::MAX (no limit, legacy format) - If instruction_data.len() == 10: parse u16 from bytes 8-9 as max_top_up - Otherwise: return InvalidInstructionData @@ -95,7 +95,7 @@ Format 2 (10 bytes): d. **Validate budget:** - If no compressible accounts were found (current_slot == 0), exit early - If both top-up amounts are 0, exit early - - If max_top_up != 0 and lamports_budget == 0, fail with MaxTopUpExceeded + - If max_top_up != u16::MAX and lamports_budget == 0, fail with MaxTopUpExceeded e. **Execute transfers:** - Fail with MissingPayer if payer account is not provided diff --git a/programs/compressed-token/program/docs/ctoken/BURN_CHECKED.md b/programs/compressed-token/program/docs/ctoken/BURN_CHECKED.md index 0e47c0cd83..5d82b00561 100644 --- a/programs/compressed-token/program/docs/ctoken/BURN_CHECKED.md +++ b/programs/compressed-token/program/docs/ctoken/BURN_CHECKED.md @@ -17,7 +17,7 @@ Format 1 (9 bytes, legacy): Format 2 (11 bytes): - Bytes 0-7: `amount` (u64, little-endian) - Number of tokens to burn - Byte 8: `decimals` (u8) - Expected token decimals -- Bytes 9-10: `max_top_up` (u16, little-endian) - Maximum lamports for combined CMint + CToken top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. +- Bytes 9-10: `max_top_up` (u16, little-endian) - Maximum lamports for combined CMint + CToken top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. **Accounts:** 1. source CToken @@ -56,7 +56,7 @@ Format 2 (11 bytes): 2. **Parse instruction data:** - Require at least 9 bytes (amount + decimals) - Parse max_top_up: - - If instruction_data.len() == 9: max_top_up = 0 (no limit, legacy format) + - If instruction_data.len() == 9: max_top_up = u16::MAX (no limit, legacy format) - If instruction_data.len() == 11: parse u16 from bytes 9-10 as max_top_up - Otherwise: return InvalidInstructionData @@ -103,7 +103,7 @@ Format 2 (11 bytes): d. **Validate budget:** - If no compressible accounts were found (current_slot == 0), exit early - If both top-up amounts are 0, exit early - - If max_top_up != 0 and lamports_budget == 0, fail with MaxTopUpExceeded + - If max_top_up != u16::MAX and lamports_budget == 0, fail with MaxTopUpExceeded - If payer is None but top-up is needed, fail with MissingPayer e. **Execute transfers:** diff --git a/programs/compressed-token/program/docs/ctoken/MINT_TO.md b/programs/compressed-token/program/docs/ctoken/MINT_TO.md index 0b59e50cb8..8130953051 100644 --- a/programs/compressed-token/program/docs/ctoken/MINT_TO.md +++ b/programs/compressed-token/program/docs/ctoken/MINT_TO.md @@ -5,7 +5,7 @@ **path:** programs/compressed-token/program/src/ctoken/mint_to.rs **description:** -Mints tokens from a decompressed CMint account to a destination CToken account, fully compatible with SPL Token mint_to semantics. Uses pinocchio-token-program to process the mint_to operation which handles balance/supply updates, authority validation, and frozen account checks. After minting, automatically tops up compressible accounts with additional lamports if needed to prevent accounts from becoming compressible during normal operations. Both CMint and destination CToken can receive top-ups based on their current slot and account balance. Supports max_top_up parameter to limit rent top-up costs where 0 means no limit. Instruction data is backwards-compatible with two formats: 8-byte format for legacy compatibility without max_top_up enforcement and 10-byte format with max_top_up. This instruction only works with CMints (compressed mints). CMints do not support restricted Token-2022 extensions (Pausable, TransferFee, TransferHook, PermanentDelegate, DefaultAccountState) - only TokenMetadata is allowed. +Mints tokens from a decompressed CMint account to a destination CToken account, fully compatible with SPL Token mint_to semantics. Uses pinocchio-token-program to process the mint_to operation which handles balance/supply updates, authority validation, and frozen account checks. After minting, automatically tops up compressible accounts with additional lamports if needed to prevent accounts from becoming compressible during normal operations. Both CMint and destination CToken can receive top-ups based on their current slot and account balance. Supports max_top_up parameter to limit rent top-up costs where u16::MAX means no limit, 0 means no top-ups allowed. Instruction data is backwards-compatible with two formats: 8-byte format for legacy compatibility without max_top_up enforcement and 10-byte format with max_top_up. This instruction only works with CMints (compressed mints). CMints do not support restricted Token-2022 extensions (Pausable, TransferFee, TransferHook, PermanentDelegate, DefaultAccountState) - only TokenMetadata is allowed. Account layouts: - `CToken` defined in: program-libs/token-interface/src/state/ctoken/ctoken_struct.rs @@ -17,7 +17,7 @@ Path: programs/compressed-token/program/src/ctoken/mint_to.rs (see `process_ctok Byte layout: - Bytes 0-7: `amount` (u64, little-endian) - Number of tokens to mint -- Bytes 8-9: `max_top_up` (u16, little-endian, optional) - Maximum lamports for top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. +- Bytes 8-9: `max_top_up` (u16, little-endian, optional) - Maximum lamports for top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. Format variants: - 8-byte format: amount only, no max_top_up enforcement @@ -60,7 +60,7 @@ Format variants: 2. **Parse instruction data:** - Require at least 8 bytes for amount - Parse max_top_up from bytes 8-10 if present (10-byte format) - - Default to 0 (no limit) if only 8 bytes provided (legacy format) + - Default to u16::MAX (no limit) if only 8 bytes provided (legacy format) - Return InvalidInstructionData if length is invalid (not 8 or 10 bytes) 3. **Process mint_to (inline via pinocchio-token-program library):** diff --git a/programs/compressed-token/program/docs/ctoken/MINT_TO_CHECKED.md b/programs/compressed-token/program/docs/ctoken/MINT_TO_CHECKED.md index 99041cbe14..1972531b62 100644 --- a/programs/compressed-token/program/docs/ctoken/MINT_TO_CHECKED.md +++ b/programs/compressed-token/program/docs/ctoken/MINT_TO_CHECKED.md @@ -5,7 +5,7 @@ **path:** programs/compressed-token/program/src/ctoken/mint_to.rs **description:** -Mints tokens from a decompressed CMint account to a destination CToken account with decimals validation, fully compatible with SPL Token MintToChecked semantics. Uses pinocchio-token-program to process the mint_to_checked operation which handles balance/supply updates, authority validation, frozen account checks, and decimals validation. After minting, automatically tops up compressible accounts with additional lamports if needed to prevent accounts from becoming compressible during normal operations. Both CMint and destination CToken can receive top-ups based on their current slot and account balance. Supports max_top_up parameter to limit rent top-up costs where 0 means no limit. +Mints tokens from a decompressed CMint account to a destination CToken account with decimals validation, fully compatible with SPL Token MintToChecked semantics. Uses pinocchio-token-program to process the mint_to_checked operation which handles balance/supply updates, authority validation, frozen account checks, and decimals validation. After minting, automatically tops up compressible accounts with additional lamports if needed to prevent accounts from becoming compressible during normal operations. Both CMint and destination CToken can receive top-ups based on their current slot and account balance. Supports max_top_up parameter to limit rent top-up costs where u16::MAX means no limit, 0 means no top-ups allowed. Account layouts: - `CToken` defined in: program-libs/token-interface/src/state/ctoken/ctoken_struct.rs @@ -19,7 +19,7 @@ Shared implementation: programs/compressed-token/program/src/ctoken/burn.rs (fun Byte layout: - Bytes 0-7: `amount` (u64, little-endian) - Number of tokens to mint - Byte 8: `decimals` (u8) - Expected token decimals -- Bytes 9-10: `max_top_up` (u16, little-endian, optional) - Maximum lamports for top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. +- Bytes 9-10: `max_top_up` (u16, little-endian, optional) - Maximum lamports for top-ups in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. Format variants: - 9 bytes: amount + decimals (legacy, no max_top_up enforcement) @@ -63,7 +63,7 @@ Format variants: 2. **Parse instruction data:** - Require at least 9 bytes (amount + decimals) - Parse max_top_up from bytes 9-11 if present (11-byte format) - - Default to 0 (no limit) if only 9 bytes provided (legacy format) + - Default to u16::MAX (no limit) if only 9 bytes provided (legacy format) - Return InvalidInstructionData if length is invalid (not 9 or 11 bytes) 3. **Process mint_to_checked (inline via pinocchio-token-program library):** diff --git a/programs/compressed-token/program/docs/ctoken/REVOKE.md b/programs/compressed-token/program/docs/ctoken/REVOKE.md index 850c20b400..90a5001d36 100644 --- a/programs/compressed-token/program/docs/ctoken/REVOKE.md +++ b/programs/compressed-token/program/docs/ctoken/REVOKE.md @@ -15,13 +15,13 @@ If the CToken account has a compressible extension and requires a rent top-up, t - **NOT SPL-compatible (payer required):** Compressible accounts that need rent top-up based on current slot **description:** -Revokes any previously granted delegation on a decompressed ctoken account (account layout `CToken` defined in program-libs/token-interface/src/state/ctoken/ctoken_struct.rs). After the revoke operation, automatically tops up compressible accounts (extension layout `CompressionInfo` defined in program-libs/compressible/src/compression_info.rs) with additional lamports if needed to prevent accounts from becoming compressible during normal operations. The instruction supports a max_top_up parameter (0 = no limit) that enforces transaction failure if the calculated top-up exceeds this limit. Uses pinocchio-token-program for SPL-compatible revoke semantics. Supports backwards-compatible instruction data format (0 bytes legacy vs 2 bytes with max_top_up). The revoke operation follows SPL Token rules exactly (clears delegate and delegated_amount). +Revokes any previously granted delegation on a decompressed ctoken account (account layout `CToken` defined in program-libs/token-interface/src/state/ctoken/ctoken_struct.rs). After the revoke operation, automatically tops up compressible accounts (extension layout `CompressionInfo` defined in program-libs/compressible/src/compression_info.rs) with additional lamports if needed to prevent accounts from becoming compressible during normal operations. The instruction supports a max_top_up parameter (u16::MAX = no limit, 0 = no top-ups allowed) that enforces transaction failure if the calculated top-up exceeds this limit. Uses pinocchio-token-program for SPL-compatible revoke semantics. Supports backwards-compatible instruction data format (0 bytes legacy vs 2 bytes with max_top_up). The revoke operation follows SPL Token rules exactly (clears delegate and delegated_amount). **Instruction data:** Path: programs/compressed-token/program/src/ctoken/approve_revoke.rs (lines 49-59 for revoke, lines 86-124 for top-up processing) -- Empty (0 bytes): legacy format, no max_top_up enforcement (max_top_up = 0, no limit) -- Bytes 0-1 (optional): `max_top_up` (u16, little-endian) - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. +- Empty (0 bytes): legacy format, no max_top_up enforcement (max_top_up = u16::MAX, no limit) +- Bytes 0-1 (optional): `max_top_up` (u16, little-endian) - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. **Accounts:** 1. source @@ -50,12 +50,12 @@ Path: programs/compressed-token/program/src/ctoken/approve_revoke.rs (lines 49-5 - Fast path: if account data length is 165 bytes (no extensions), skip top-up - Otherwise, process compressible top-up: - Parse instruction data to get max_top_up: - - If 0 bytes: legacy format, set max_top_up = 0 (no limit) + - If 0 bytes: legacy format, set max_top_up = u16::MAX (no limit) - If 2 bytes: parse max_top_up (u16, little-endian) - Return InvalidInstructionData for any other length - Calculate required top-up using `top_up_lamports_from_account_info_unchecked` - If transfer_amount > 0: - - If max_top_up > 0 and transfer_amount > max_top_up: return MaxTopUpExceeded + - If max_top_up != u16::MAX and transfer_amount > max_top_up: return MaxTopUpExceeded - Get payer from accounts[1], return MissingPayer if not present - Transfer lamports from payer to source via CPI diff --git a/programs/compressed-token/program/docs/ctoken/TRANSFER.md b/programs/compressed-token/program/docs/ctoken/TRANSFER.md index 788dd31619..2cee1f3357 100644 --- a/programs/compressed-token/program/docs/ctoken/TRANSFER.md +++ b/programs/compressed-token/program/docs/ctoken/TRANSFER.md @@ -32,7 +32,7 @@ After discriminator byte, the following formats are supported: - **8 bytes (legacy):** amount (u64) - No max_top_up enforcement - **10 bytes (extended):** amount (u64) + max_top_up (u16) - `amount`: u64 - Number of tokens to transfer - - `max_top_up`: u16 - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. + - `max_top_up`: u16 - Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. **Accounts:** 1. source @@ -78,7 +78,7 @@ After discriminator byte, the following formats are supported: 4. **Parse max_top_up (extended path only):** - If 10 bytes, parse max_top_up from bytes [8..10] - - If 8 bytes, set max_top_up = 0 (legacy, no limit) + - If 8 bytes, set max_top_up = u16::MAX (legacy, no limit) - Any other length returns InvalidInstructionData 5. **Process transfer extensions:** @@ -104,7 +104,7 @@ After discriminator byte, the following formats are supported: - Error if flags mismatch (InvalidInstructionData) d. **Perform compressible top-up:** - - Check max_top_up budget if set (non-zero) + - Check max_top_up budget if not unlimited (not u16::MAX) - Execute multi_transfer_lamports from authority to accounts 6. **Process SPL transfer:** diff --git a/programs/compressed-token/program/docs/ctoken/TRANSFER_CHECKED.md b/programs/compressed-token/program/docs/ctoken/TRANSFER_CHECKED.md index 7dd29c875e..18172bca14 100644 --- a/programs/compressed-token/program/docs/ctoken/TRANSFER_CHECKED.md +++ b/programs/compressed-token/program/docs/ctoken/TRANSFER_CHECKED.md @@ -23,7 +23,7 @@ Transfers tokens between decompressed ctoken solana accounts with mint decimals **Instruction data:** - **9 bytes (legacy):** amount (u64) + decimals (u8) - **11 bytes (with max_top_up):** amount (u64) + decimals (u8) + max_top_up (u16) - - max_top_up: Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). 0 = no limit. + - max_top_up: Maximum lamports for top-up in units of 1,000 lamports (e.g., max_top_up=1 means 1,000 lamports, max_top_up=65535 means ~65.5M lamports). u16::MAX = no limit, 0 = no top-ups allowed. **Accounts:** 1. source @@ -77,12 +77,12 @@ Transfers tokens between decompressed ctoken solana accounts with mint decimals 3. **Validate instruction data:** - Must be at least 9 bytes (amount + decimals) - If 11 bytes, parse max_top_up from bytes [9..11] - - If 9 bytes, set max_top_up = 0 (legacy, no limit) + - If 9 bytes, set max_top_up = u16::MAX (legacy, no limit) - Any other length returns InvalidInstructionData 4. **Parse max_top_up parameter:** - - 0 = no limit on top-up lamports - - Non-zero = maximum combined lamports for source + destination top-up + - u16::MAX = no limit on top-up lamports, 0 = no top-ups allowed + - Values in [1, u16::MAX-1] = maximum combined lamports for source + destination top-up - Transaction fails if calculated top-up exceeds max_top_up 5. **Process transfer extensions:** @@ -107,7 +107,7 @@ Transfers tokens between decompressed ctoken solana accounts with mint decimals - Get current slot from Clock sysvar (lazy loaded once) - Call calculate_top_up_lamports for each account - Transfer lamports from authority to accounts if top-up needed: - - Check max_top_up budget if set (non-zero) + - Check max_top_up budget if not unlimited (not u16::MAX) - Execute multi_transfer_lamports atomically - Return (signer_is_validated, extension_decimals) tuple diff --git a/programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs b/programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs index 58ea675a01..a174da195f 100644 --- a/programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs +++ b/programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs @@ -177,7 +177,8 @@ pub fn process_actions<'a>( // Execute transfers if any exist if !transfers.is_empty() { // Check budget wasn't exhausted (0 means exceeded max_top_up) - if max_top_up != 0 && lamports_budget == 0 { + // u16::MAX means no limit, 0 means no top-ups allowed + if max_top_up != u16::MAX && lamports_budget == 0 { return Err(TokenError::MaxTopUpExceeded.into()); } diff --git a/programs/compressed-token/program/src/compressed_token/transfer2/compression/mod.rs b/programs/compressed-token/program/src/compressed_token/transfer2/compression/mod.rs index 95e1beb9cf..12579533c3 100644 --- a/programs/compressed-token/program/src/compressed_token/transfer2/compression/mod.rs +++ b/programs/compressed-token/program/src/compressed_token/transfer2/compression/mod.rs @@ -37,7 +37,7 @@ const ID: &[u8; 32] = &LIGHT_CPI_SIGNER.program_id; /// Process native compressions/decompressions with token accounts /// /// # Arguments -/// * `max_top_up` - Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) +/// * `max_top_up` - Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) /// * `compression_to_input` - Lookup array mapping compression index to input index for decompress operations #[profile] pub fn process_token_compression<'a>( @@ -177,7 +177,8 @@ pub fn process_token_compression<'a>( if !transfers.is_empty() { // Check budget wasn't exhausted (0 means exceeded max_top_up) - if max_top_up != 0 && lamports_budget == 0 { + // u16::MAX means no limit, 0 means no top-ups allowed + if max_top_up != u16::MAX && lamports_budget == 0 { return Err(TokenError::MaxTopUpExceeded.into()); } multi_transfer_lamports(fee_payer, &transfers).map_err(convert_program_error)? diff --git a/programs/compressed-token/program/src/ctoken/approve_revoke.rs b/programs/compressed-token/program/src/ctoken/approve_revoke.rs index 261ee344a9..2dd09e99b1 100644 --- a/programs/compressed-token/program/src/ctoken/approve_revoke.rs +++ b/programs/compressed-token/program/src/ctoken/approve_revoke.rs @@ -23,7 +23,7 @@ const REVOKE_PAYER_IDX: usize = 1; /// /// Instruction data format (backwards compatible): /// - 8 bytes: amount (legacy, no max_top_up enforcement) -/// - 10 bytes: amount + max_top_up (u16, 0 = no limit) +/// - 10 bytes: amount + max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) #[inline(always)] pub fn process_ctoken_approve( accounts: &[AccountInfo], @@ -45,7 +45,7 @@ pub fn process_ctoken_approve( /// /// Instruction data format (backwards compatible): /// - 0 bytes: legacy, no max_top_up enforcement -/// - 2 bytes: max_top_up (u16, 0 = no limit) +/// - 2 bytes: max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) #[inline(always)] pub fn process_ctoken_revoke( accounts: &[AccountInfo], @@ -95,8 +95,9 @@ fn process_compressible_top_up( { let payer = accounts.get(PAYER_IDX); + // u16::MAX means no limit, 0 means no top-ups allowed let max_top_up = match instruction_data.len() { - len if len == BASE_LEN => 0u16, + len if len == BASE_LEN => u16::MAX, // Legacy: no max_top_up limit len if len == BASE_LEN + 2 => u16::from_le_bytes( instruction_data[BASE_LEN..BASE_LEN + 2] .try_into() @@ -111,8 +112,10 @@ fn process_compressible_top_up( }; if transfer_amount > 0 { + // u16::MAX means no limit, 0 means no top-ups allowed // max_top_up is in units of 1,000 lamports (max ~65.5M lamports). - if max_top_up > 0 && transfer_amount > (max_top_up as u64).saturating_mul(1000) { + if max_top_up != u16::MAX && transfer_amount > (max_top_up as u64).saturating_mul(1000) + { return Err(TokenError::MaxTopUpExceeded.into()); } let payer = payer.ok_or(TokenError::MissingPayer)?; diff --git a/programs/compressed-token/program/src/ctoken/burn.rs b/programs/compressed-token/program/src/ctoken/burn.rs index acd5f4358c..7e8613e827 100644 --- a/programs/compressed-token/program/src/ctoken/burn.rs +++ b/programs/compressed-token/program/src/ctoken/burn.rs @@ -25,7 +25,7 @@ const FEE_PAYER_IDX: usize = 4; /// /// Instruction data format (same as CTokenTransfer/CTokenMintTo): /// - 8 bytes: amount (legacy, no max_top_up enforcement) -/// - 10 bytes: amount + max_top_up (u16, 0 = no limit) +/// - 10 bytes: amount + max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) /// /// Account layout: /// 0: source CToken account (writable) @@ -50,7 +50,7 @@ pub fn process_ctoken_burn( /// /// Instruction data format: /// - 9 bytes: amount (8) + decimals (1) - legacy, no max_top_up enforcement -/// - 11 bytes: amount (8) + decimals (1) + max_top_up (2, u16, 0 = no limit) +/// - 11 bytes: amount (8) + decimals (1) + max_top_up (2, u16, u16::MAX = no limit, 0 = no top-ups allowed) /// /// Account layout (same as burn): /// 0: source CToken account (writable) @@ -104,8 +104,9 @@ pub(crate) fn process_ctoken_supply_change_inner< return Err(ProgramError::InvalidInstructionData); } + // u16::MAX means no limit, 0 means no top-ups allowed let max_top_up = match instruction_data.len() { - len if len == BASE_LEN => 0u16, + len if len == BASE_LEN => u16::MAX, // Legacy: no max_top_up limit len if len == BASE_LEN + 2 => u16::from_le_bytes( instruction_data[BASE_LEN..BASE_LEN + 2] .try_into() diff --git a/programs/compressed-token/program/src/ctoken/mint_to.rs b/programs/compressed-token/program/src/ctoken/mint_to.rs index 0b98e194a4..7f75d3afc4 100644 --- a/programs/compressed-token/program/src/ctoken/mint_to.rs +++ b/programs/compressed-token/program/src/ctoken/mint_to.rs @@ -15,7 +15,7 @@ pub(crate) const MINT_CTOKEN_IDX: usize = 1; /// /// Instruction data format (same as CTokenTransfer): /// - 8 bytes: amount (legacy, no max_top_up enforcement) -/// - 10 bytes: amount + max_top_up (u16, 0 = no limit) +/// - 10 bytes: amount + max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) /// /// Account layout: /// 0: CMint account (writable) @@ -40,7 +40,7 @@ pub fn process_ctoken_mint_to( /// /// Instruction data format: /// - 9 bytes: amount (8) + decimals (1) - legacy, no max_top_up enforcement -/// - 11 bytes: amount (8) + decimals (1) + max_top_up (2, u16, 0 = no limit) +/// - 11 bytes: amount (8) + decimals (1) + max_top_up (2, u16, u16::MAX = no limit, 0 = no top-ups allowed) /// /// Account layout (same as mint_to): /// 0: CMint account (writable) diff --git a/programs/compressed-token/program/src/ctoken/transfer/checked.rs b/programs/compressed-token/program/src/ctoken/transfer/checked.rs index cc1330cabe..e7815a5cd3 100644 --- a/programs/compressed-token/program/src/ctoken/transfer/checked.rs +++ b/programs/compressed-token/program/src/ctoken/transfer/checked.rs @@ -26,7 +26,7 @@ const ACCOUNT_FEE_PAYER: usize = 5; /// /// Instruction data format (backwards compatible): /// - 9 bytes: amount + decimals (legacy, no max_top_up enforcement) -/// - 11 bytes: amount + decimals + max_top_up (u16, 0 = no limit) +/// - 11 bytes: amount + decimals + max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) #[profile] #[inline(always)] pub fn process_ctoken_transfer_checked( @@ -67,9 +67,9 @@ pub fn process_ctoken_transfer_checked( let authority = &accounts[ACCOUNT_AUTHORITY]; // Parse max_top_up based on instruction data length - // 0 means no limit + // u16::MAX means no limit, 0 means no top-ups allowed let max_top_up = match instruction_data.len() { - 9 => 0u16, // Legacy: no max_top_up + 9 => u16::MAX, // Legacy: no max_top_up limit 11 => u16::from_le_bytes( instruction_data[9..11] .try_into() diff --git a/programs/compressed-token/program/src/ctoken/transfer/default.rs b/programs/compressed-token/program/src/ctoken/transfer/default.rs index 443b44906a..6920561407 100644 --- a/programs/compressed-token/program/src/ctoken/transfer/default.rs +++ b/programs/compressed-token/program/src/ctoken/transfer/default.rs @@ -20,7 +20,7 @@ const ACCOUNT_FEE_PAYER: usize = 4; /// /// Instruction data format (backwards compatible): /// - 8 bytes: amount (legacy, no max_top_up enforcement) -/// - 10 bytes: amount + max_top_up (u16, 0 = no limit) +/// - 10 bytes: amount + max_top_up (u16, u16::MAX = no limit, 0 = no top-ups allowed) #[profile] #[inline(always)] pub fn process_ctoken_transfer( @@ -58,9 +58,9 @@ pub fn process_ctoken_transfer( } // Parse max_top_up based on instruction data length - // 0 means no limit + // u16::MAX means no limit, 0 means no top-ups allowed let max_top_up = match instruction_data.len() { - 8 => 0u16, // Legacy: no max_top_up + 8 => u16::MAX, // Legacy: no max_top_up limit 10 => u16::from_le_bytes( instruction_data[8..10] .try_into() diff --git a/programs/compressed-token/program/src/ctoken/transfer/shared.rs b/programs/compressed-token/program/src/ctoken/transfer/shared.rs index a5ecb126d5..8fc8d70ba8 100644 --- a/programs/compressed-token/program/src/ctoken/transfer/shared.rs +++ b/programs/compressed-token/program/src/ctoken/transfer/shared.rs @@ -120,7 +120,7 @@ pub fn process_transfer_extensions_transfer_checked( /// /// # Arguments /// * `transfer_accounts` - Account references for source, destination, authority, and optional mint -/// * `max_top_up` - Maximum lamports for top-up. Transaction fails if exceeded. (0 = no limit) +/// * `max_top_up` - Maximum lamports for top-up. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) /// * `deny_restricted_extensions` - If true, reject source accounts with restricted T22 extensions /// /// Returns: @@ -167,10 +167,11 @@ fn transfer_top_up( max_top_up: u16, ) -> Result<(), ProgramError> { if sender_top_up > 0 || recipient_top_up > 0 { - // Check budget if max_top_up is set (non-zero) + // Check budget if limit is set (not u16::MAX) + // 0 means no top-ups allowed, u16::MAX means no limit // max_top_up is in units of 1,000 lamports (max ~65.5M lamports). let total_top_up = sender_top_up.saturating_add(recipient_top_up); - if max_top_up != 0 && total_top_up > (max_top_up as u64).saturating_mul(1000) { + if max_top_up != u16::MAX && total_top_up > (max_top_up as u64).saturating_mul(1000) { return Err(TokenError::MaxTopUpExceeded.into()); } diff --git a/programs/compressed-token/program/src/shared/compressible_top_up.rs b/programs/compressed-token/program/src/shared/compressible_top_up.rs index b66767693f..542a259c42 100644 --- a/programs/compressed-token/program/src/shared/compressible_top_up.rs +++ b/programs/compressed-token/program/src/shared/compressible_top_up.rs @@ -22,7 +22,7 @@ use super::{ /// * `cmint` - The CMint account (may or may not have Compressible extension) /// * `ctoken` - The CToken account (may or may not have Compressible extension) /// * `payer` - The fee payer for top-ups -/// * `max_top_up` - Maximum lamports for top-ups combined (0 = no limit) +/// * `max_top_up` - Maximum lamports for top-ups combined (u16::MAX = no limit, 0 = no top-ups allowed) #[inline(always)] #[profile] #[allow(unused)] @@ -74,7 +74,8 @@ pub fn calculate_and_execute_compressible_top_ups<'a>( } // Check budget wasn't exhausted (0 means exceeded max_top_up) - if max_top_up != 0 && lamports_budget == 0 { + // u16::MAX means no limit, 0 means no top-ups allowed + if max_top_up != u16::MAX && lamports_budget == 0 { return Err(TokenError::MaxTopUpExceeded.into()); } let payer = payer.ok_or(TokenError::MissingPayer)?; diff --git a/programs/compressed-token/program/tests/check_extensions.rs b/programs/compressed-token/program/tests/check_extensions.rs index c81be9a925..4525601cc1 100644 --- a/programs/compressed-token/program/tests/check_extensions.rs +++ b/programs/compressed-token/program/tests/check_extensions.rs @@ -224,7 +224,7 @@ fn create_test_inputs(config: &TestConfig) -> Vec { lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions, proof: None, diff --git a/programs/compressed-token/program/tests/extensions_metadata.rs b/programs/compressed-token/program/tests/extensions_metadata.rs index bb5c6620dd..83d7ffbca6 100644 --- a/programs/compressed-token/program/tests/extensions_metadata.rs +++ b/programs/compressed-token/program/tests/extensions_metadata.rs @@ -165,7 +165,7 @@ fn serialize_actions(actions: &[Action]) -> Vec { leaf_index: 0, prove_by_index: false, root_index: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit actions: actions.to_vec(), proof: None, cpi_context: Some(CpiContext { diff --git a/programs/compressed-token/program/tests/mint.rs b/programs/compressed-token/program/tests/mint.rs index d53aec7da8..c082f4d7a9 100644 --- a/programs/compressed-token/program/tests/mint.rs +++ b/programs/compressed-token/program/tests/mint.rs @@ -144,7 +144,7 @@ fn test_rnd_create_compressed_mint_account() { actions: vec![], // No actions for basic test proof: None, cpi_context: None, - max_top_up: 0, + max_top_up: u16::MAX, // No limit }; // Step 4: Serialize instruction data to test zero-copy diff --git a/programs/registry/src/compressible/compressed_token/compress_and_close.rs b/programs/registry/src/compressible/compressed_token/compress_and_close.rs index aa923aca5f..3886d4711a 100644 --- a/programs/registry/src/compressible/compressed_token/compress_and_close.rs +++ b/programs/registry/src/compressible/compressed_token/compress_and_close.rs @@ -227,7 +227,7 @@ pub fn compress_and_close_ctoken_accounts_with_indices<'info>( out_tlv: if has_any_tlv { Some(out_tlv) } else { None }, compressions: Some(compressions), cpi_context: None, - max_top_up: 0, + max_top_up: u16::MAX, // No limit }; // Serialize instruction data let serialized = instruction_data diff --git a/sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs b/sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs index 67a78e893c..bfb71b43c8 100644 --- a/sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs +++ b/sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs @@ -17,17 +17,30 @@ use crate::{ AnchorSerialize, }; -#[derive(Debug, Default, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] pub struct Transfer2Config { pub cpi_context: Option, pub with_transaction_hash: bool, pub sol_pool_pda: bool, pub sol_decompression_recipient: Option, pub filter_zero_amount_outputs: bool, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: u16, } +impl Default for Transfer2Config { + fn default() -> Self { + Self { + cpi_context: None, + with_transaction_hash: false, + sol_pool_pda: false, + sol_decompression_recipient: None, + filter_zero_amount_outputs: false, + max_top_up: u16::MAX, // Default to no limit for backwards compatibility + } + } +} + impl Transfer2Config { pub fn new() -> Self { Default::default() @@ -54,7 +67,7 @@ impl Transfer2Config { self } - /// Set maximum per-account top-up lamports (0 = no limit) + /// Set maximum per-account top-up lamports (u16::MAX = no limit, 0 = no top-ups allowed) pub fn with_max_top_up(mut self, max_top_up: u16) -> Self { self.max_top_up = max_top_up; self diff --git a/sdk-libs/event/tests/parse_test.rs b/sdk-libs/event/tests/parse_test.rs index be470958db..8d4b0abbc9 100644 --- a/sdk-libs/event/tests/parse_test.rs +++ b/sdk-libs/event/tests/parse_test.rs @@ -51,7 +51,7 @@ fn create_transfer2_with_ata(owner_index: u8, is_ata: bool) -> Vec { lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions: None, proof: None, @@ -123,7 +123,7 @@ fn create_transfer2_with_multiple_outputs( lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions: None, proof: None, diff --git a/sdk-libs/instruction-decoder/src/programs/ctoken.rs b/sdk-libs/instruction-decoder/src/programs/ctoken.rs index 34200ad30e..0736c66fcf 100644 --- a/sdk-libs/instruction-decoder/src/programs/ctoken.rs +++ b/sdk-libs/instruction-decoder/src/programs/ctoken.rs @@ -135,7 +135,7 @@ pub fn format_transfer2( // Top-level fields let _ = writeln!(output, "output_queue: {}", resolve(data.output_queue)); - if data.max_top_up > 0 { + if data.max_top_up != u16::MAX { let _ = writeln!(output, "max_top_up: {}", data.max_top_up); } if data.with_transaction_hash { @@ -754,7 +754,7 @@ pub fn format_mint_action( } } let _ = writeln!(output, "root_index: {}", data.root_index); - if data.max_top_up > 0 { + if data.max_top_up != u16::MAX { let _ = writeln!(output, "max_top_up: {}", data.max_top_up); } diff --git a/sdk-libs/sdk-types/src/interface/cpi/create_mints.rs b/sdk-libs/sdk-types/src/interface/cpi/create_mints.rs index 7d8c412a78..59c36d41d8 100644 --- a/sdk-libs/sdk-types/src/interface/cpi/create_mints.rs +++ b/sdk-libs/sdk-types/src/interface/cpi/create_mints.rs @@ -398,7 +398,7 @@ impl<'a, AI: AccountInfoTrait + Clone> CreateMintsCpi<'a, AI> { leaf_index: 0, prove_by_index: false, root_index: self.params.address_merkle_tree_root_index, - max_top_up: 0, + max_top_up: u16::MAX, // No limit create_mint: Some(CreateMint::default()), actions: vec![Action::DecompressMint(*decompress_action)], proof: Some(self.params.proof), @@ -447,7 +447,7 @@ impl<'a, AI: AccountInfoTrait + Clone> CreateMintsCpi<'a, AI> { leaf_index: base_leaf_index + self.params.cpi_context_offset as u32 + index as u32, prove_by_index: true, root_index: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit create_mint: None, actions: vec![Action::DecompressMint(*decompress_action)], proof: None, diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs b/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs index ad7a7475fe..66cc8eb141 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs @@ -445,7 +445,7 @@ where lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions: Some(compressions), proof: params.proof.0, diff --git a/sdk-libs/token-pinocchio/src/instruction/transfer_from_spl.rs b/sdk-libs/token-pinocchio/src/instruction/transfer_from_spl.rs index 00c7b51060..3532fac001 100644 --- a/sdk-libs/token-pinocchio/src/instruction/transfer_from_spl.rs +++ b/sdk-libs/token-pinocchio/src/instruction/transfer_from_spl.rs @@ -111,7 +111,7 @@ impl<'info> TransferFromSplCpi<'info> { lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions: Some(vec![wrap_from_spl, unwrap_to_destination]), proof: None, diff --git a/sdk-libs/token-pinocchio/src/instruction/transfer_to_spl.rs b/sdk-libs/token-pinocchio/src/instruction/transfer_to_spl.rs index 0976853601..e3f2015cea 100644 --- a/sdk-libs/token-pinocchio/src/instruction/transfer_to_spl.rs +++ b/sdk-libs/token-pinocchio/src/instruction/transfer_to_spl.rs @@ -107,7 +107,7 @@ impl<'info> TransferToSplCpi<'info> { lamports_change_account_merkle_tree_index: 0, lamports_change_account_owner_index: 0, output_queue: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit cpi_context: None, compressions: Some(vec![compress_to_pool, decompress_to_spl]), proof: None, diff --git a/sdk-libs/token-sdk/src/instruction/burn.rs b/sdk-libs/token-sdk/src/instruction/burn.rs index cabcc98644..f7300e2867 100644 --- a/sdk-libs/token-sdk/src/instruction/burn.rs +++ b/sdk-libs/token-sdk/src/instruction/burn.rs @@ -31,8 +31,8 @@ pub struct Burn { pub amount: u64, /// Owner of the Light Token account pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) - /// When set to a non-zero value, includes max_top_up in instruction data + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) + /// When set (Some), includes max_top_up in instruction data pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option, @@ -64,7 +64,7 @@ pub struct BurnCpi<'info> { pub amount: u64, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>, diff --git a/sdk-libs/token-sdk/src/instruction/burn_checked.rs b/sdk-libs/token-sdk/src/instruction/burn_checked.rs index ef21ab0a72..d4f5163764 100644 --- a/sdk-libs/token-sdk/src/instruction/burn_checked.rs +++ b/sdk-libs/token-sdk/src/instruction/burn_checked.rs @@ -34,8 +34,8 @@ pub struct BurnChecked { pub decimals: u8, /// Owner of the Light Token account pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) - /// When set to a non-zero value, includes max_top_up in instruction data + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) + /// When set (Some), includes max_top_up in instruction data pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option, @@ -69,7 +69,7 @@ pub struct BurnCheckedCpi<'info> { pub decimals: u8, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>, diff --git a/sdk-libs/token-sdk/src/instruction/create_mints.rs b/sdk-libs/token-sdk/src/instruction/create_mints.rs index d1a9629cdf..b29a73a8fb 100644 --- a/sdk-libs/token-sdk/src/instruction/create_mints.rs +++ b/sdk-libs/token-sdk/src/instruction/create_mints.rs @@ -413,7 +413,7 @@ impl<'a, 'info> CreateMintsCpi<'a, 'info> { leaf_index: 0, prove_by_index: false, root_index: self.params.address_merkle_tree_root_index, - max_top_up: 0, + max_top_up: u16::MAX, // No limit create_mint: Some(CreateMint::default()), actions: vec![Action::DecompressMint(*decompress_action)], proof: Some(self.params.proof), @@ -472,7 +472,7 @@ impl<'a, 'info> CreateMintsCpi<'a, 'info> { leaf_index: base_leaf_index + index as u32, prove_by_index: true, root_index: 0, - max_top_up: 0, + max_top_up: u16::MAX, // No limit create_mint: None, actions: vec![Action::DecompressMint(*decompress_action)], proof: None, diff --git a/sdk-libs/token-sdk/src/instruction/mint_to.rs b/sdk-libs/token-sdk/src/instruction/mint_to.rs index a882be6751..ef6480017f 100644 --- a/sdk-libs/token-sdk/src/instruction/mint_to.rs +++ b/sdk-libs/token-sdk/src/instruction/mint_to.rs @@ -31,8 +31,8 @@ pub struct MintTo { pub amount: u64, /// Mint authority pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) - /// When set to a non-zero value, includes max_top_up in instruction data + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) + /// When set (Some), includes max_top_up in instruction data pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option, @@ -64,7 +64,7 @@ pub struct MintToCpi<'info> { pub amount: u64, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>, diff --git a/sdk-libs/token-sdk/src/instruction/mint_to_checked.rs b/sdk-libs/token-sdk/src/instruction/mint_to_checked.rs index 021cfb55da..775d506314 100644 --- a/sdk-libs/token-sdk/src/instruction/mint_to_checked.rs +++ b/sdk-libs/token-sdk/src/instruction/mint_to_checked.rs @@ -34,8 +34,8 @@ pub struct MintToChecked { pub decimals: u8, /// Mint authority pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) - /// When set to a non-zero value, includes max_top_up in instruction data + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) + /// When set (Some), includes max_top_up in instruction data pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option, @@ -69,7 +69,7 @@ pub struct MintToCheckedCpi<'info> { pub decimals: u8, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>, diff --git a/sdk-libs/token-sdk/src/instruction/transfer.rs b/sdk-libs/token-sdk/src/instruction/transfer.rs index 4edf532f56..90985229a2 100644 --- a/sdk-libs/token-sdk/src/instruction/transfer.rs +++ b/sdk-libs/token-sdk/src/instruction/transfer.rs @@ -27,7 +27,7 @@ pub struct Transfer { pub destination: Pubkey, pub amount: u64, pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) /// When set, includes max_top_up in instruction data and adds system program account for compressible top-up pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. @@ -61,7 +61,7 @@ pub struct TransferCpi<'info> { pub amount: u64, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>, diff --git a/sdk-libs/token-sdk/src/instruction/transfer_checked.rs b/sdk-libs/token-sdk/src/instruction/transfer_checked.rs index 17c04ddefd..0a8b088f38 100644 --- a/sdk-libs/token-sdk/src/instruction/transfer_checked.rs +++ b/sdk-libs/token-sdk/src/instruction/transfer_checked.rs @@ -32,8 +32,8 @@ pub struct TransferChecked { pub amount: u64, pub decimals: u8, pub authority: Pubkey, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) - /// When set to a non-zero value, includes max_top_up in instruction data + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) + /// When set (Some), includes max_top_up in instruction data pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option, @@ -70,7 +70,7 @@ pub struct TransferCheckedCpi<'info> { pub decimals: u8, pub authority: AccountInfo<'info>, pub system_program: AccountInfo<'info>, - /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit) + /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (u16::MAX = no limit, 0 = no top-ups allowed) pub max_top_up: Option, /// Optional fee payer for rent top-ups. If not provided, authority pays. pub fee_payer: Option>,