diff --git a/associated-token-account/program-test/tests/extended_mint.rs b/associated-token-account/program-test/tests/extended_mint.rs index 43e1b92c59e..747644814b9 100644 --- a/associated-token-account/program-test/tests/extended_mint.rs +++ b/associated-token-account/program-test/tests/extended_mint.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] mod program_test; @@ -34,7 +35,8 @@ async fn test_associated_token_account_with_transfer_fees() { let rent = banks_client.get_rent().await.unwrap(); // create extended mint - // ... in the future, a mint can be pre-loaded in program_test.rs like the regular mint + // ... in the future, a mint can be pre-loaded in program_test.rs like the + // regular mint let mint_account = Keypair::new(); let token_mint_address = mint_account.pubkey(); let mint_authority = Keypair::new(); diff --git a/associated-token-account/program-test/tests/process_create_associated_token_account.rs b/associated-token-account/program-test/tests/process_create_associated_token_account.rs index c3cc488499c..f535d661c1f 100644 --- a/associated-token-account/program-test/tests/process_create_associated_token_account.rs +++ b/associated-token-account/program-test/tests/process_create_associated_token_account.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] mod program_test; @@ -86,8 +87,8 @@ async fn test_create_with_fewer_lamports() { .unwrap(); let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - // Transfer lamports into `associated_token_address` before creating it - enough to be - // rent-exempt for 0 data, but not for an initialized token account + // Transfer lamports into `associated_token_address` before creating it - enough + // to be rent-exempt for 0 data, but not for an initialized token account let mut transaction = Transaction::new_with_payer( &[system_instruction::transfer( &payer.pubkey(), diff --git a/associated-token-account/program-test/tests/program_test.rs b/associated-token-account/program-test/tests/program_test.rs index 64760d66009..7008931e7ef 100644 --- a/associated-token-account/program-test/tests/program_test.rs +++ b/associated-token-account/program-test/tests/program_test.rs @@ -35,7 +35,8 @@ pub fn program_test(token_mint_address: Pubkey, use_latest_spl_token: bool) -> P "token-mint-data.bin", ); - // Dial down the BPF compute budget to detect if the program gets bloated in the future + // Dial down the BPF compute budget to detect if the program gets bloated in the + // future pc.set_compute_max_units(60_000); pc @@ -75,7 +76,8 @@ pub fn program_test_2022( "token-mint-data.bin", ); - // Dial down the BPF compute budget to detect if the program gets bloated in the future + // Dial down the BPF compute budget to detect if the program gets bloated in the + // future pc.set_compute_max_units(50_000); pc diff --git a/associated-token-account/program-test/tests/recover_nested.rs b/associated-token-account/program-test/tests/recover_nested.rs index db1f947232e..86374a2eacc 100644 --- a/associated-token-account/program-test/tests/recover_nested.rs +++ b/associated-token-account/program-test/tests/recover_nested.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] mod program_test; diff --git a/associated-token-account/program-test/tests/spl_token_create.rs b/associated-token-account/program-test/tests/spl_token_create.rs index 32f08d03b6d..903d12fb4d2 100644 --- a/associated-token-account/program-test/tests/spl_token_create.rs +++ b/associated-token-account/program-test/tests/spl_token_create.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] mod program_test; diff --git a/associated-token-account/program/src/instruction.rs b/associated-token-account/program/src/instruction.rs index cdbe21909e4..efacd97dd97 100644 --- a/associated-token-account/program/src/instruction.rs +++ b/associated-token-account/program/src/instruction.rs @@ -13,8 +13,8 @@ use { /// Instructions supported by the AssociatedTokenAccount program #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum AssociatedTokenAccountInstruction { - /// Creates an associated token account for the given wallet address and token mint - /// Returns an error if the account exists. + /// Creates an associated token account for the given wallet address and + /// token mint Returns an error if the account exists. /// /// 0. `[writeable,signer]` Funding account (must be a system account) /// 1. `[writeable]` Associated token account address to be created @@ -23,9 +23,9 @@ pub enum AssociatedTokenAccountInstruction { /// 4. `[]` System program /// 5. `[]` SPL Token program Create, - /// Creates an associated token account for the given wallet address and token mint, - /// if it doesn't already exist. Returns an error if the account exists, - /// but with a different owner. + /// Creates an associated token account for the given wallet address and + /// token mint, if it doesn't already exist. Returns an error if the + /// account exists, but with a different owner. /// /// 0. `[writeable,signer]` Funding account (must be a system account) /// 1. `[writeable]` Associated token account address to be created @@ -50,7 +50,8 @@ pub enum AssociatedTokenAccountInstruction { /// 2. `[writeable]` Wallet's associated token account /// 3. `[]` Owner associated token account address, must be owned by `5` /// 4. `[]` Token mint for the owner associated token account - /// 5. `[writeable, signer]` Wallet address for the owner associated token account + /// 5. `[writeable, signer]` Wallet address for the owner associated token + /// account /// 6. `[]` SPL Token program RecoverNested, } diff --git a/associated-token-account/program/src/lib.rs b/associated-token-account/program/src/lib.rs index d5906816f22..927f9d48185 100644 --- a/associated-token-account/program/src/lib.rs +++ b/associated-token-account/program/src/lib.rs @@ -8,7 +8,8 @@ pub mod instruction; pub mod processor; pub mod tools; -// Export current SDK types for downstream users building with a different SDK version +// Export current SDK types for downstream users building with a different SDK +// version pub use solana_program; use solana_program::{ instruction::{AccountMeta, Instruction}, @@ -32,7 +33,8 @@ pub(crate) fn get_associated_token_address_and_bump_seed( ) } -/// Derives the associated token account address for the given wallet address and token mint +/// Derives the associated token account address for the given wallet address +/// and token mint pub fn get_associated_token_address( wallet_address: &Pubkey, token_mint_address: &Pubkey, @@ -44,7 +46,8 @@ pub fn get_associated_token_address( ) } -/// Derives the associated token account address for the given wallet address, token mint and token program id +/// Derives the associated token account address for the given wallet address, +/// token mint and token program id pub fn get_associated_token_address_with_program_id( wallet_address: &Pubkey, token_mint_address: &Pubkey, @@ -75,7 +78,8 @@ fn get_associated_token_address_and_bump_seed_internal( ) } -/// Create an associated token account for the given wallet address and token mint +/// Create an associated token account for the given wallet address and token +/// mint /// /// Accounts expected by this instruction: /// @@ -85,7 +89,6 @@ fn get_associated_token_address_and_bump_seed_internal( /// 3. `[]` The token mint for the new associated token account /// 4. `[]` System program /// 5. `[]` SPL Token program -/// #[deprecated( since = "1.0.5", note = "please use `instruction::create_associated_token_account` instead" diff --git a/associated-token-account/program/src/tools/account.rs b/associated-token-account/program/src/tools/account.rs index 14158f70bf4..2001e227e50 100644 --- a/associated-token-account/program/src/tools/account.rs +++ b/associated-token-account/program/src/tools/account.rs @@ -14,7 +14,8 @@ use { std::convert::TryInto, }; -/// Creates associated token account using Program Derived Address for the given seeds +/// Creates associated token account using Program Derived Address for the given +/// seeds pub fn create_pda_account<'a>( payer: &AccountInfo<'a>, rent: &Rent, @@ -71,8 +72,8 @@ pub fn create_pda_account<'a>( } } -/// Determines the required initial data length for a new token account based on the extensions -/// initialized on the Mint +/// Determines the required initial data length for a new token account based on +/// the extensions initialized on the Mint pub fn get_account_len<'a>( mint: &AccountInfo<'a>, spl_token_program: &AccountInfo<'a>, diff --git a/binary-option/program/src/lib.rs b/binary-option/program/src/lib.rs index 9c104343293..e75cd473b86 100644 --- a/binary-option/program/src/lib.rs +++ b/binary-option/program/src/lib.rs @@ -7,7 +7,8 @@ pub mod spl_utils; pub mod state; pub mod system_utils; pub mod validation_utils; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("betw959P4WToez4DkuXwNsJszqbpe3HuY56AcG5yevx"); diff --git a/binary-option/program/src/processor.rs b/binary-option/program/src/processor.rs index c9f9c82b316..43286e33f66 100644 --- a/binary-option/program/src/processor.rs +++ b/binary-option/program/src/processor.rs @@ -542,8 +542,9 @@ pub fn process_trade( binary_option.decrement_supply(n_b)?; } } - // Delegate the burn authority to the PDA, so a private key is unnecessary on collection - // This can probably be optimized to reduce the number of instructions needed at some point + // Delegate the burn authority to the PDA, so a private key is unnecessary on + // collection This can probably be optimized to reduce the number of + // instructions needed at some point spl_approve( token_program_info, buyer_long_token_account_info, @@ -589,8 +590,9 @@ pub fn process_trade( pub fn process_settle(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { // This should NEVER be called directly (otherwise this is literally a rug) - // The `pool_owner_info` needs to approve this action, so the recommended use case is to have a higher - // level program own the pool and use an oracle to resolve settlements + // The `pool_owner_info` needs to approve this action, so the recommended use + // case is to have a higher level program own the pool and use an oracle to + // resolve settlements let account_info_iter = &mut accounts.iter(); let binary_option_account_info = next_account_info(account_info_iter)?; let winning_mint_account_info = next_account_info(account_info_iter)?; diff --git a/binary-oracle-pair/program/src/instruction.rs b/binary-oracle-pair/program/src/instruction.rs index 60c6c2c739d..d5c5cd6ab1d 100644 --- a/binary-oracle-pair/program/src/instruction.rs +++ b/binary-oracle-pair/program/src/instruction.rs @@ -44,7 +44,8 @@ pub enum PoolInstruction { /// 0. `[]` Pool /// 1. `[]` Authority /// 2. `[s]` User transfer authority - /// 3. `[w]` Token SOURCE Account, amount is transferable by pool authority with allowances. + /// 3. `[w]` Token SOURCE Account, amount is transferable by pool + /// authority with allowances. /// 4. `[w]` Deposit token account /// 5. `[w]` token_P PASS mint /// 6. `[w]` token_F FAIL mint @@ -55,12 +56,13 @@ pub enum PoolInstruction { Deposit(u64), /// Withdraw from the pool. - /// If current slot is < mint_end slot, 1 Pass AND 1 Fail token convert to 1 deposit - /// If current slot is > decide_end_slot slot && decide == Some(true), 1 Pass convert to 1 deposit - /// otherwise 1 Fail converts to 1 deposit + /// If current slot is < mint_end slot, 1 Pass AND 1 Fail token convert to + /// 1 deposit If current slot is > decide_end_slot slot && decide == + /// Some(true), 1 Pass convert to 1 deposit otherwise 1 Fail converts + /// to 1 deposit /// - /// Pass tokens convert 1:1 to the deposit token iff decision is set to Some(true) - /// AND current slot is > decide_end_slot. + /// Pass tokens convert 1:1 to the deposit token iff decision is set to + /// Some(true) AND current slot is > decide_end_slot. /// /// 0. `[]` Pool /// 1. `[]` Authority @@ -76,7 +78,8 @@ pub enum PoolInstruction { Withdraw(u64), /// Trigger the decision. - /// Call only succeeds once and if current slot > mint_end slot AND < decide_end slot + /// Call only succeeds once and if current slot > mint_end slot AND < + /// decide_end slot /// 0. `[]` Pool /// 1. `[s]` Decider pubkey /// 2. `[]` Sysvar Clock diff --git a/binary-oracle-pair/program/src/lib.rs b/binary-oracle-pair/program/src/lib.rs index 7b20c3b9bcf..a82bffaea06 100644 --- a/binary-oracle-pair/program/src/lib.rs +++ b/binary-oracle-pair/program/src/lib.rs @@ -9,7 +9,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; // Binary Oracle Pair id diff --git a/examples/rust/cross-program-invocation/tests/functional.rs b/examples/rust/cross-program-invocation/tests/functional.rs index 0f97572c659..ebf253cd989 100644 --- a/examples/rust/cross-program-invocation/tests/functional.rs +++ b/examples/rust/cross-program-invocation/tests/functional.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] use { diff --git a/examples/rust/sysvar/src/processor.rs b/examples/rust/sysvar/src/processor.rs index a03793a086a..8dc13c15fc6 100644 --- a/examples/rust/sysvar/src/processor.rs +++ b/examples/rust/sysvar/src/processor.rs @@ -34,7 +34,8 @@ pub fn process_instruction( let rent_via_account = Rent::from_account_info(rent_sysvar_info)?; // Both produce the same sysvar assert_eq!(rent_via_sysvar, rent_via_account); - // Can't print `exemption_threshold` because BPF does not support printing floats + // Can't print `exemption_threshold` because BPF does not support printing + // floats msg!( "Rent: lamports_per_byte_year: {:?}, burn_percent: {:?}", rent_via_sysvar.lamports_per_byte_year, diff --git a/feature-proposal/program/src/instruction.rs b/feature-proposal/program/src/instruction.rs index c00e5bfbfc5..bcde8424a0d 100644 --- a/feature-proposal/program/src/instruction.rs +++ b/feature-proposal/program/src/instruction.rs @@ -18,38 +18,45 @@ use { pub enum FeatureProposalInstruction { /// Propose a new feature. /// - /// This instruction will create a variety of accounts to support the feature proposal, all - /// funded by account 0: - /// * A new token mint with a supply of `tokens_to_mint`, owned by the program and never - /// modified again - /// * A new "distributor" token account that holds the total supply, owned by account 0. - /// * A new "acceptance" token account that holds 0 tokens, owned by the program. Tokens - /// transfers to this address are irrevocable and permanent. - /// * A new feature id account that has been funded and allocated (as described in + /// This instruction will create a variety of accounts to support the + /// feature proposal, all funded by account 0: + /// * A new token mint with a supply of `tokens_to_mint`, owned by the + /// program and never modified again + /// * A new "distributor" token account that holds the total supply, owned + /// by account 0. + /// * A new "acceptance" token account that holds 0 tokens, owned by the + /// program. Tokens transfers to this address are irrevocable and + /// permanent. + /// * A new feature id account that has been funded and allocated (as + /// described in /// `solana_program::feature`) /// - /// On successful execution of the instruction, the feature proposer is expected to distribute - /// the tokens in the distributor token account out to all participating parties. + /// On successful execution of the instruction, the feature proposer is + /// expected to distribute the tokens in the distributor token account + /// out to all participating parties. /// - /// Based on the provided acceptance criteria, if `AcceptanceCriteria::tokens_required` - /// tokens are transferred into the acceptance token account before - /// `AcceptanceCriteria::deadline` then the proposal is eligible to be accepted. + /// Based on the provided acceptance criteria, if + /// `AcceptanceCriteria::tokens_required` tokens are transferred into + /// the acceptance token account before `AcceptanceCriteria::deadline` + /// then the proposal is eligible to be accepted. /// - /// The `FeatureProposalInstruction::Tally` instruction must be executed, by any party, to - /// complete the feature acceptance process. + /// The `FeatureProposalInstruction::Tally` instruction must be executed, by + /// any party, to complete the feature acceptance process. /// /// Accounts expected by this instruction: /// /// 0. `[writeable,signer]` Funding account (must be a system account) /// 1. `[writeable,signer]` Unallocated feature proposal account to create /// 2. `[writeable]` Token mint address from `get_mint_address` - /// 3. `[writeable]` Distributor token account address from `get_distributor_token_address` - /// 4. `[writeable]` Acceptance token account address from `get_acceptance_token_address` - /// 5. `[writeable]` Feature id account address from `get_feature_id_address` + /// 3. `[writeable]` Distributor token account address from + /// `get_distributor_token_address` + /// 4. `[writeable]` Acceptance token account address from + /// `get_acceptance_token_address` + /// 5. `[writeable]` Feature id account address from + /// `get_feature_id_address` /// 6. `[]` System program /// 7. `[]` SPL Token program /// 8. `[]` Rent sysvar - /// Propose { /// Total number of tokens to mint for this proposal #[allow(dead_code)] // not dead code.. @@ -60,8 +67,8 @@ pub enum FeatureProposalInstruction { acceptance_criteria: AcceptanceCriteria, }, - /// `Tally` is a permission-less instruction to check the acceptance criteria for the feature - /// proposal, which may result in: + /// `Tally` is a permission-less instruction to check the acceptance + /// criteria for the feature proposal, which may result in: /// * No action /// * Feature proposal acceptance /// * Feature proposal expiration @@ -69,8 +76,10 @@ pub enum FeatureProposalInstruction { /// Accounts expected by this instruction: /// /// 0. `[writeable]` Feature proposal account - /// 1. `[]` Acceptance token account address from `get_acceptance_token_address` - /// 2. `[writeable]` Derived feature id account address from `get_feature_id_address` + /// 1. `[]` Acceptance token account address from + /// `get_acceptance_token_address` + /// 2. `[writeable]` Derived feature id account address from + /// `get_feature_id_address` /// 3. `[]` System program /// 4. `[]` Clock sysvar Tally, diff --git a/feature-proposal/program/src/lib.rs b/feature-proposal/program/src/lib.rs index fd1d4115a04..52b44bb0bc4 100644 --- a/feature-proposal/program/src/lib.rs +++ b/feature-proposal/program/src/lib.rs @@ -7,7 +7,8 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current SDK types for downstream users building with a different SDK version +// Export current SDK types for downstream users building with a different SDK +// version pub use solana_program; use solana_program::{program_pack::Pack, pubkey::Pubkey}; @@ -47,14 +48,14 @@ pub fn get_mint_address(feature_proposal_address: &Pubkey) -> Pubkey { get_mint_address_with_seed(feature_proposal_address).0 } -/// Derive the SPL Token token address associated with a feature proposal that receives the initial -/// minted tokens +/// Derive the SPL Token token address associated with a feature proposal that +/// receives the initial minted tokens pub fn get_distributor_token_address(feature_proposal_address: &Pubkey) -> Pubkey { get_distributor_token_address_with_seed(feature_proposal_address).0 } -/// Derive the SPL Token token address associated with a feature proposal that users send their -/// tokens to accept the proposal +/// Derive the SPL Token token address associated with a feature proposal that +/// users send their tokens to accept the proposal pub fn get_acceptance_token_address(feature_proposal_address: &Pubkey) -> Pubkey { get_acceptance_token_address_with_seed(feature_proposal_address).0 } @@ -64,13 +65,14 @@ pub fn get_feature_id_address(feature_proposal_address: &Pubkey) -> Pubkey { get_feature_id_address_with_seed(feature_proposal_address).0 } -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount +/// Convert the UI representation of a token amount (using the decimals field +/// defined in its mint) to the raw amount pub fn ui_amount_to_amount(ui_amount: f64) -> u64 { (ui_amount * 10_usize.pow(spl_token::native_mint::DECIMALS as u32) as f64) as u64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount(amount: u64) -> f64 { amount as f64 / 10_usize.pow(spl_token::native_mint::DECIMALS as u32) as f64 } diff --git a/feature-proposal/program/src/processor.rs b/feature-proposal/program/src/processor.rs index 3ba486978e2..6aa00a610f8 100644 --- a/feature-proposal/program/src/processor.rs +++ b/feature-proposal/program/src/processor.rs @@ -265,8 +265,8 @@ pub fn process_instruction( &[mint_signer_seeds], )?; - // Fully fund the feature id account so the `Tally` instruction will not require any - // lamports from the caller + // Fully fund the feature id account so the `Tally` instruction will not require + // any lamports from the caller msg!("Funding feature id account"); invoke( &system_instruction::transfer( diff --git a/feature-proposal/program/src/state.rs b/feature-proposal/program/src/state.rs index a5bde3fdaa3..082e4fcd3f3 100644 --- a/feature-proposal/program/src/state.rs +++ b/feature-proposal/program/src/state.rs @@ -12,11 +12,13 @@ use { /// Criteria for accepting a feature proposal #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] pub struct AcceptanceCriteria { - /// The balance of the feature proposal's token account must be greater than this amount, and - /// tallied before the deadline for the feature to be accepted. + /// The balance of the feature proposal's token account must be greater than + /// this amount, and tallied before the deadline for the feature to be + /// accepted. pub tokens_required: u64, - /// If the required tokens are not tallied by this deadline then the proposal will expire. + /// If the required tokens are not tallied by this deadline then the + /// proposal will expire. pub deadline: UnixTimestamp, } @@ -29,7 +31,8 @@ pub enum FeatureProposal { Pending(AcceptanceCriteria), /// Feature proposal was accepted and the feature is now active Accepted { - /// The balance of the feature proposal's token account at the time of activation. + /// The balance of the feature proposal's token account at the time of + /// activation. #[allow(dead_code)] // not dead code.. tokens_upon_acceptance: u64, }, diff --git a/feature-proposal/program/tests/functional.rs b/feature-proposal/program/tests/functional.rs index d9928c3e859..a8101d9b63f 100644 --- a/feature-proposal/program/tests/functional.rs +++ b/feature-proposal/program/tests/functional.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] use { @@ -129,8 +130,8 @@ async fn test_basic() { transaction.sign(&[&payer, &feature_proposal], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); - // Fetch a new blockhash to avoid the second Tally transaction having the same signature as the - // first Tally transaction + // Fetch a new blockhash to avoid the second Tally transaction having the same + // signature as the first Tally transaction let recent_blockhash = banks_client .get_new_latest_blockhash(&recent_blockhash) .await diff --git a/governance/addin-api/src/max_voter_weight.rs b/governance/addin-api/src/max_voter_weight.rs index 205b84a12b7..bde3b2d883b 100644 --- a/governance/addin-api/src/max_voter_weight.rs +++ b/governance/addin-api/src/max_voter_weight.rs @@ -7,31 +7,38 @@ use { }; /// MaxVoterWeightRecord account -/// The account is used as an api interface to provide max voting power to the governance program from external addin contracts +/// The account is used as an api interface to provide max voting power to the +/// governance program from external addin contracts #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct MaxVoterWeightRecord { - /// VoterWeightRecord discriminator sha256("account:MaxVoterWeightRecord")[..8] - /// Note: The discriminator size must match the addin implementing program discriminator size - /// to ensure it's stored in the private space of the account data and it's unique + /// VoterWeightRecord discriminator + /// sha256("account:MaxVoterWeightRecord")[..8] Note: The discriminator + /// size must match the addin implementing program discriminator size to + /// ensure it's stored in the private space of the account data and it's + /// unique pub account_discriminator: [u8; 8], /// The Realm the MaxVoterWeightRecord belongs to pub realm: Pubkey, /// Governing Token Mint the MaxVoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + /// Note: The addin can take deposits of any tokens and is not restricted to + /// the community or council tokens only // The mint here is to link the record to either community or council mint of the realm pub governing_token_mint: Pubkey, /// Max voter weight - /// The max voter weight provided by the addin for the given realm and governing_token_mint + /// The max voter weight provided by the addin for the given realm and + /// governing_token_mint pub max_voter_weight: u64, /// The slot when the max voting weight expires /// It should be set to None if the weight never expires - /// If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight + /// If the max vote weight decays with time, for example for time locked + /// based weights, then the expiry must be set As a pattern Revise + /// instruction to update the max weight should be invoked before governance + /// instruction within the same transaction and the expiry set to the + /// current slot to provide up to date weight pub max_voter_weight_expiry: Option, /// Reserved space for future versions diff --git a/governance/addin-api/src/voter_weight.rs b/governance/addin-api/src/voter_weight.rs index ada1a10edab..f13526f8fdc 100644 --- a/governance/addin-api/src/voter_weight.rs +++ b/governance/addin-api/src/voter_weight.rs @@ -27,46 +27,57 @@ pub enum VoterWeightAction { } /// VoterWeightRecord account -/// The account is used as an api interface to provide voting power to the governance program from external addin contracts +/// The account is used as an api interface to provide voting power to the +/// governance program from external addin contracts #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoterWeightRecord { /// VoterWeightRecord discriminator sha256("account:VoterWeightRecord")[..8] - /// Note: The discriminator size must match the addin implementing program discriminator size - /// to ensure it's stored in the private space of the account data and it's unique + /// Note: The discriminator size must match the addin implementing program + /// discriminator size to ensure it's stored in the private space of the + /// account data and it's unique pub account_discriminator: [u8; 8], /// The Realm the VoterWeightRecord belongs to pub realm: Pubkey, /// Governing Token Mint the VoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + /// Note: The addin can take deposits of any tokens and is not restricted to + /// the community or council tokens only // The mint here is to link the record to either community or council mint of the realm pub governing_token_mint: Pubkey, /// The owner of the governing token and voter - /// This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner + /// This is the actual owner (voter) and corresponds to + /// TokenOwnerRecord.governing_token_owner pub governing_token_owner: Pubkey, /// Voter's weight - /// The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter) + /// The weight of the voter provided by the addin for the given realm, + /// governing_token_mint and governing_token_owner (voter) pub voter_weight: u64, /// The slot when the voting weight expires /// It should be set to None if the weight never expires - /// If the voter weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight + /// If the voter weight decays with time, for example for time locked based + /// weights, then the expiry must be set As a common pattern Revise + /// instruction to update the weight should be invoked before governance + /// instruction within the same transaction and the expiry set to the + /// current slot to provide up to date weight pub voter_weight_expiry: Option, /// The governance action the voter's weight pertains to - /// It allows to provided voter's weight specific to the particular action the weight is evaluated for - /// When the action is provided then the governance program asserts the executing action is the same as specified by the addin + /// It allows to provided voter's weight specific to the particular action + /// the weight is evaluated for When the action is provided then the + /// governance program asserts the executing action is the same as specified + /// by the addin pub weight_action: Option, /// The target the voter's weight action pertains to - /// It allows to provided voter's weight specific to the target the weight is evaluated for - /// For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target - /// When the target is provided then the governance program asserts the target is the same as specified by the addin + /// It allows to provided voter's weight specific to the target the weight + /// is evaluated for For example when addin supplies weight to vote on a + /// particular proposal then it must specify the proposal as the action + /// target When the target is provided then the governance program + /// asserts the target is the same as specified by the addin pub weight_action_target: Option, /// Reserved space for future versions diff --git a/governance/addin-mock/program/src/instruction.rs b/governance/addin-mock/program/src/instruction.rs index 5bd232268a0..676909a138c 100644 --- a/governance/addin-mock/program/src/instruction.rs +++ b/governance/addin-mock/program/src/instruction.rs @@ -12,7 +12,8 @@ use { }; /// Instructions supported by the VoterWeight addin program -/// This program is a mock program used by spl-governance for testing and not real addin +/// This program is a mock program used by spl-governance for testing and not +/// real addin #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] #[allow(clippy::large_enum_variant)] pub enum VoterWeightAddinInstruction { diff --git a/governance/addin-mock/program/src/lib.rs b/governance/addin-mock/program/src/lib.rs index 53b71f4a339..45f09c7507d 100644 --- a/governance/addin-mock/program/src/lib.rs +++ b/governance/addin-mock/program/src/lib.rs @@ -8,5 +8,6 @@ pub mod processor; //pub mod state; // pub mod tools; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/governance/chat/program/src/instruction.rs b/governance/chat/program/src/instruction.rs index b062cc45dc8..c95c78c5f06 100644 --- a/governance/chat/program/src/instruction.rs +++ b/governance/chat/program/src/instruction.rs @@ -19,14 +19,14 @@ pub enum GovernanceChatInstruction { /// /// 0. `[]` Governance program id /// 1. `[]` Realm account of the Proposal - /// 2. `[]` Governance account the Proposal is for - /// 3. `[]` Proposal account + /// 2. `[]` Governance account the Proposal is for + /// 3. `[]` Proposal account /// 4. `[]` TokenOwnerRecord account for the message author /// 5. `[signer]` Governance Authority (TokenOwner or Governance Delegate) /// 6. `[writable, signer]` ChatMessage account - /// 7. `[signer]` Payer - /// 8. `[]` System program - /// 9. `[]` ReplyTo Message account (optional) + /// 7. `[signer]` Payer + /// 8. `[]` System program + /// 9. `[]` ReplyTo Message account (optional) /// 10. `[]` Optional Voter Weight Record PostMessage { #[allow(dead_code)] diff --git a/governance/chat/program/src/lib.rs b/governance/chat/program/src/lib.rs index 6d882a08ac4..d361d608183 100644 --- a/governance/chat/program/src/lib.rs +++ b/governance/chat/program/src/lib.rs @@ -8,5 +8,6 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/governance/chat/program/src/processor.rs b/governance/chat/program/src/processor.rs index a8535167e71..df4f1b2eb38 100644 --- a/governance/chat/program/src/processor.rs +++ b/governance/chat/program/src/processor.rs @@ -89,7 +89,8 @@ pub fn process_post_message( token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - // deserialize proposal to assert it belongs to the given governance and hence belongs to the same realm as the token owner + // deserialize proposal to assert it belongs to the given governance and hence + // belongs to the same realm as the token owner let _proposal_data = get_proposal_data_for_governance( governance_program_id, proposal_info, @@ -110,8 +111,9 @@ pub fn process_post_message( )?; // The owner needs to have at least voter weight of 1 to comment on proposals - // Note: It can be either community or council token and is irrelevant to the proposal's governing token - // Note: 1 is currently hardcoded but if different level is required then it should be added to realm config + // Note: It can be either community or council token and is irrelevant to the + // proposal's governing token Note: 1 is currently hardcoded but if + // different level is required then it should be added to realm config if voter_weight < 1 { return Err(GovernanceChatError::NotEnoughTokensToCommentProposal.into()); } diff --git a/governance/chat/program/src/state.rs b/governance/chat/program/src/state.rs index 92fcd3f9202..b995e5bf252 100644 --- a/governance/chat/program/src/state.rs +++ b/governance/chat/program/src/state.rs @@ -26,7 +26,8 @@ pub enum MessageBody { Text(String), /// Emoticon encoded using utf-8 characters - /// In the UI reactions are displayed together under the parent message (as opposed to hierarchical replies) + /// In the UI reactions are displayed together under the parent message (as + /// opposed to hierarchical replies) Reaction(String), } @@ -63,7 +64,8 @@ impl AccountMaxSize for ChatMessage { } } -/// Checks whether Chat account exists, is initialized and owned by governance-chat program +/// Checks whether Chat account exists, is initialized and owned by +/// governance-chat program pub fn assert_is_valid_chat_message( program_id: &Pubkey, chat_message_info: &AccountInfo, diff --git a/governance/program/src/addins/max_voter_weight.rs b/governance/program/src/addins/max_voter_weight.rs index 18dc51f93cf..7840c60f6bd 100644 --- a/governance/program/src/addins/max_voter_weight.rs +++ b/governance/program/src/addins/max_voter_weight.rs @@ -34,7 +34,8 @@ pub fn get_max_voter_weight_record_data( get_account_data::(program_id, max_voter_weight_record_info) } -/// Deserializes MaxVoterWeightRecord account, checks owner program and asserts it's for the given realm and governing_token_mint +/// Deserializes MaxVoterWeightRecord account, checks owner program and asserts +/// it's for the given realm and governing_token_mint pub fn get_max_voter_weight_record_data_for_realm_and_governing_token_mint( program_id: &Pubkey, max_voter_weight_record_info: &AccountInfo, diff --git a/governance/program/src/addins/voter_weight.rs b/governance/program/src/addins/voter_weight.rs index 24a6c534cbf..91608f74c82 100644 --- a/governance/program/src/addins/voter_weight.rs +++ b/governance/program/src/addins/voter_weight.rs @@ -10,7 +10,8 @@ use { spl_governance_tools::account::get_account_data, }; -/// Asserts the VoterWeightRecord hasn't expired and matches the given action and target if specified +/// Asserts the VoterWeightRecord hasn't expired and matches the given action +/// and target if specified pub fn assert_is_valid_voter_weight( voter_weight_record: &VoterWeightRecord, weight_action: VoterWeightAction, @@ -50,7 +51,9 @@ pub fn get_voter_weight_record_data( get_account_data::(program_id, voter_weight_record_info) } -/// Deserializes VoterWeightRecord account, checks owner program and asserts it's for the same realm, mint and token owner as the provided TokenOwnerRecord +/// Deserializes VoterWeightRecord account, checks owner program and asserts +/// it's for the same realm, mint and token owner as the provided +/// TokenOwnerRecord pub fn get_voter_weight_record_data_for_token_owner_record( program_id: &Pubkey, voter_weight_record_info: &AccountInfo, diff --git a/governance/program/src/error.rs b/governance/program/src/error.rs index 818082757ce..e4b1ddeaa6b 100644 --- a/governance/program/src/error.rs +++ b/governance/program/src/error.rs @@ -15,7 +15,8 @@ use { pub enum GovernanceError { /// Invalid instruction passed to program #[error("Invalid instruction passed to program")] - InvalidInstruction = 500, // Start Governance custom errors from 500 to avoid conflicts with programs invoked via CPI + InvalidInstruction = 500, /* Start Governance custom errors from 500 to avoid conflicts + * with programs invoked via CPI */ /// Realm with the given name and governing mints already exists #[error("Realm with the given name and governing mints already exists")] @@ -85,7 +86,8 @@ pub enum GovernanceError { #[error("Invalid Governance config: Vote threshold percentage out of range")] InvalidVoteThresholdPercentage, // 517 - /// Proposal for the given Governance, Governing Token Mint and index already exists + /// Proposal for the given Governance, Governing Token Mint and index + /// already exists #[error("Proposal for the given Governance, Governing Token Mint and index already exists")] ProposalAlreadyExists, // 518 @@ -229,7 +231,8 @@ pub enum GovernanceError { #[error("Invalid ProgramData account Data")] InvalidProgramDataAccountData, // 552 - /// Provided upgrade authority doesn't match current program upgrade authority + /// Provided upgrade authority doesn't match current program upgrade + /// authority #[error("Provided upgrade authority doesn't match current program upgrade authority")] InvalidUpgradeAuthority, // 553 diff --git a/governance/program/src/instruction.rs b/governance/program/src/instruction.rs index ffc21708f7e..924803fbf74 100644 --- a/governance/program/src/instruction.rs +++ b/governance/program/src/instruction.rs @@ -39,21 +39,24 @@ use { #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] #[allow(clippy::large_enum_variant)] pub enum GovernanceInstruction { - /// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint + /// Creates Governance Realm account which aggregates governances for given + /// Community Mint and optional Council Mint /// /// 0. `[writable]` Governance Realm account. PDA seeds:['governance',name] /// 1. `[]` Realm authority /// 2. `[]` Community Token Mint - /// 3. `[writable]` Community Token Holding account. PDA seeds: ['governance',realm,community_mint] - /// The account will be created with the Realm PDA as its owner + /// 3. `[writable]` Community Token Holding account. PDA seeds: + /// ['governance',realm,community_mint] The account will be created with + /// the Realm PDA as its owner /// 4. `[signer]` Payer /// 5. `[]` System /// 6. `[]` SPL Token /// 7. `[]` Sysvar Rent /// 8. `[]` Council Token Mint - optional - /// 9. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint] - /// The account will be created with the Realm PDA as its owner + /// 9. `[writable]` Council Token Holding account - optional unless council + /// is used. PDA seeds: ['governance',realm,council_mint] The account + /// will be created with the Realm PDA as its owner /// 10. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm] @@ -72,18 +75,24 @@ pub enum GovernanceInstruction { config_args: RealmConfigArgs, }, - /// Deposits governing tokens (Community or Council) to Governance Realm and establishes your voter weight to be used for voting within the Realm - /// Note: If subsequent (top up) deposit is made and there are active votes for the Voter then the vote weights won't be updated automatically - /// It can be done by relinquishing votes on active Proposals and voting again with the new weight + /// Deposits governing tokens (Community or Council) to Governance Realm and + /// establishes your voter weight to be used for voting within the Realm + /// Note: If subsequent (top up) deposit is made and there are active votes + /// for the Voter then the vote weights won't be updated automatically + /// It can be done by relinquishing votes on active Proposals and voting + /// again with the new weight /// /// 0. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint] - /// 2. `[writable]` Governing Token Source account. It can be either spl-token TokenAccount or MintAccount - /// Tokens will be transferred or minted to the Holding account + /// 1. `[writable]` Governing Token Holding account. PDA seeds: + /// ['governance',realm, governing_token_mint] + /// 2. `[writable]` Governing Token Source account. It can be either + /// spl-token TokenAccount or MintAccount Tokens will be transferred or + /// minted to the Holding account /// 3. `[signer]` Governing Token Owner account - /// 4. `[signer]` Governing Token Source account authority - /// It should be owner for TokenAccount and mint_authority for MintAccount - /// 5. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] + /// 4. `[signer]` Governing Token Source account authority It should be + /// owner for TokenAccount and mint_authority for MintAccount + /// 5. `[writable]` TokenOwnerRecord account. PDA seeds: + /// ['governance',realm, governing_token_mint, governing_token_owner] /// 6. `[signer]` Payer /// 7. `[]` System /// 8. `[]` SPL Token program @@ -94,23 +103,30 @@ pub enum GovernanceInstruction { amount: u64, }, - /// Withdraws governing tokens (Community or Council) from Governance Realm and downgrades your voter weight within the Realm - /// Note: It's only possible to withdraw tokens if the Voter doesn't have any outstanding active votes - /// If there are any outstanding votes then they must be relinquished before tokens could be withdrawn + /// Withdraws governing tokens (Community or Council) from Governance Realm + /// and downgrades your voter weight within the Realm Note: It's only + /// possible to withdraw tokens if the Voter doesn't have any outstanding + /// active votes If there are any outstanding votes then they must be + /// relinquished before tokens could be withdrawn /// /// 0. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint] - /// 2. `[writable]` Governing Token Destination account. All tokens will be transferred to this account + /// 1. `[writable]` Governing Token Holding account. PDA seeds: + /// ['governance',realm, governing_token_mint] + /// 2. `[writable]` Governing Token Destination account. All tokens will be + /// transferred to this account /// 3. `[signer]` Governing Token Owner account - /// 4. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] + /// 4. `[writable]` TokenOwnerRecord account. PDA seeds: + /// ['governance',realm, governing_token_mint, governing_token_owner] /// 5. `[]` SPL Token program /// 6. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] WithdrawGoverningTokens {}, - /// Sets Governance Delegate for the given Realm and Governing Token Mint (Community or Council) - /// The Delegate would have voting rights and could vote on behalf of the Governing Token Owner - /// The Delegate would also be able to create Proposals on behalf of the Governing Token Owner - /// Note: This doesn't take voting rights from the Token Owner who still can vote and change governance_delegate + /// Sets Governance Delegate for the given Realm and Governing Token Mint + /// (Community or Council) The Delegate would have voting rights and + /// could vote on behalf of the Governing Token Owner The Delegate would + /// also be able to create Proposals on behalf of the Governing Token Owner + /// Note: This doesn't take voting rights from the Token Owner who still can + /// vote and change governance_delegate /// /// 0. `[signer]` Current Governance Delegate or Governing Token owner /// 1. `[writable]` Token Owner Record @@ -120,13 +136,17 @@ pub enum GovernanceInstruction { new_governance_delegate: Option, }, - /// Creates Governance account which can be used to govern any arbitrary Solana account or asset + /// Creates Governance account which can be used to govern any arbitrary + /// Solana account or asset /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Account Governance account. PDA seeds: ['account-governance', realm, governed_account] - /// 2. `[]` Account governed by this Governance - /// Note: The account doesn't have to exist and can be only used as a unique identifier for the Governance account - /// 3. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + /// 1. `[writable]` Account Governance account. PDA seeds: + /// ['account-governance', realm, governed_account] + /// 2. `[]` Account governed by this Governance Note: The account doesn't + /// have to exist and can be only used as a unique identifier for the + /// Governance account + /// 3. `[]` Governing TokenOwnerRecord account (Used only if not signed by + /// RealmAuthority) /// 4. `[signer]` Payer /// 5. `[]` System program /// 6. `[]` Sysvar Rent @@ -142,11 +162,15 @@ pub enum GovernanceInstruction { /// Creates Program Governance account which governs an upgradable program /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Program Governance account. PDA seeds: ['program-governance', realm, governed_program] + /// 1. `[writable]` Program Governance account. PDA seeds: + /// ['program-governance', realm, governed_program] /// 2. `[]` Program governed by this Governance account - /// 3. `[writable]` Program Data account of the Program governed by this Governance account - /// 4. `[signer]` Current Upgrade Authority account of the Program governed by this Governance account - /// 5. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + /// 3. `[writable]` Program Data account of the Program governed by this + /// Governance account + /// 4. `[signer]` Current Upgrade Authority account of the Program + /// governed by this Governance account + /// 5. `[]` Governing TokenOwnerRecord account (Used only if not signed by + /// RealmAuthority) /// 6. `[signer]` Payer /// 7. `[]` bpf_upgradeable_loader program /// 8. `[]` System program @@ -160,27 +184,34 @@ pub enum GovernanceInstruction { config: GovernanceConfig, #[allow(dead_code)] - /// Indicates whether Program's upgrade_authority should be transferred to the Governance PDA - /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current upgrade_authority signed the transaction nonetheless + /// Indicates whether Program's upgrade_authority should be transferred + /// to the Governance PDA If it's set to false then it can be + /// done at a later time However the instruction would validate + /// the current upgrade_authority signed the transaction nonetheless transfer_upgrade_authority: bool, }, - /// Creates Proposal account for Transactions which will be executed at some point in the future + /// Creates Proposal account for Transactions which will be executed at some + /// point in the future /// /// 0. `[]` Realm account the created Proposal belongs to - /// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_seed] + /// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, + /// governing_token_mint, proposal_seed] /// 2. `[writable]` Governance account /// 3. `[writable]` TokenOwnerRecord account of the Proposal owner /// 4. `[]` Governing Token Mint the Proposal is created for - /// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 5. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// 6. `[signer]` Payer /// 7. `[]` System program /// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] /// 9. `[]` Optional Voter Weight Record - /// 10.`[writable]` Optional ProposalDeposit account. PDA seeds: ['proposal-deposit', proposal, deposit payer] - /// Proposal deposit is required when there are more active proposals than the configured deposit exempt amount - /// The deposit is paid by the Payer of the transaction and can be reclaimed using RefundProposalDeposit once the Proposal is no longer active + /// 10.`[writable]` Optional ProposalDeposit account. PDA seeds: + /// ['proposal-deposit', proposal, deposit payer] Proposal deposit + /// is required when there are more active proposals than the configured + /// deposit exempt amount The deposit is paid by the Payer of the + /// transaction and can be reclaimed using RefundProposalDeposit once the + /// Proposal is no longer active CreateProposal { #[allow(dead_code)] /// UTF-8 encoded name of the proposal @@ -201,7 +232,8 @@ pub enum GovernanceInstruction { #[allow(dead_code)] /// Indicates whether the proposal has the deny option /// A proposal without the rejecting option is a non binding survey - /// Only proposals with the rejecting option can have executable transactions + /// Only proposals with the rejecting option can have executable + /// transactions use_deny_option: bool, #[allow(dead_code)] @@ -209,7 +241,8 @@ pub enum GovernanceInstruction { proposal_seed: Pubkey, }, - /// Adds a signatory to the Proposal which means this Proposal can't leave Draft state until yet another Signatory signs + /// Adds a signatory to the Proposal which means this Proposal can't leave + /// Draft state until yet another Signatory signs /// /// 0. `[]` Governance account /// 1. `[writable]` Proposal account associated with the governance @@ -218,7 +251,8 @@ pub enum GovernanceInstruction { /// 4. `[]` System program /// Either: /// - 5. `[]` TokenOwnerRecord account of the Proposal owner - /// 6. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 6. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// /// - 5. `[]` RequiredSignatory account associated with the governance. AddSignatory { @@ -230,15 +264,19 @@ pub enum GovernanceInstruction { /// Formerly RemoveSignatory. Exists for backwards-compatibility. Legacy1, - /// Inserts Transaction with a set of instructions for the Proposal at the given index position - /// New Transaction must be inserted at the end of the range indicated by Proposal transactions_next_index - /// If a Transaction replaces an existing Transaction at a given index then the old one must be removed using RemoveTransaction first + /// Inserts Transaction with a set of instructions for the Proposal at the + /// given index position New Transaction must be inserted at the end of + /// the range indicated by Proposal transactions_next_index + /// If a Transaction replaces an existing Transaction at a given index then + /// the old one must be removed using RemoveTransaction first /// 0. `[]` Governance account /// 1. `[writable]` Proposal account /// 2. `[]` TokenOwnerRecord account of the Proposal owner - /// 3. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 4. `[writable]` ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index] + /// 3. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) + /// 4. `[writable]` ProposalTransaction, account. PDA seeds: + /// ['governance', proposal, option_index, index] /// 5. `[signer]` Payer /// 6. `[]` System program /// 7. `[]` Rent sysvar @@ -250,7 +288,8 @@ pub enum GovernanceInstruction { /// Transaction index to be inserted at. index: u16, #[allow(dead_code)] - /// Waiting time (in seconds) between vote period ending and this being eligible for execution + /// Waiting time (in seconds) between vote period ending and this being + /// eligible for execution hold_up_time: u32, #[allow(dead_code)] @@ -262,9 +301,11 @@ pub enum GovernanceInstruction { /// /// 0. `[writable]` Proposal account /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 2. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// 3. `[writable]` ProposalTransaction, account - /// 4. `[writable]` Beneficiary Account which would receive lamports from the disposed ProposalTransaction account + /// 4. `[writable]` Beneficiary Account which would receive lamports from + /// the disposed ProposalTransaction account RemoveTransaction, /// Cancels Proposal by changing its state to Canceled @@ -273,40 +314,51 @@ pub enum GovernanceInstruction { /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord account of the Proposal owner - /// 4. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 4. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) CancelProposal, /// Signs off Proposal indicating the Signatory approves the Proposal /// When the last Signatory signs off the Proposal it enters Voting state - /// Note: Adding signatories to a Proposal is a quality and not a security gate and - /// it's entirely at the discretion of the Proposal owner - /// If Proposal owner doesn't designate any signatories then can sign off the Proposal themself + /// Note: Adding signatories to a Proposal is a quality and not a security + /// gate and it's entirely at the discretion of the Proposal owner + /// If Proposal owner doesn't designate any signatories then can sign off + /// the Proposal themself /// /// 0. `[]` Realm account /// 1. `[]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[signer]` Signatory account signing off the Proposal - /// Or Proposal owner if the owner hasn't appointed any signatories - /// 4. `[]` TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal - /// Or `[writable]` SignatoryRecord account, required when non owner sings off the Proposal + /// 3. `[signer]` Signatory account signing off the Proposal Or Proposal + /// owner if the owner hasn't appointed any signatories + /// 4. `[]` TokenOwnerRecord for the Proposal owner, required when the + /// owner signs off the Proposal Or `[writable]` SignatoryRecord + /// account, required when non owner sings off the Proposal SignOffProposal, - /// Uses your voter weight (deposited Community or Council tokens) to cast a vote on a Proposal - /// By doing so you indicate you approve or disapprove of running the Proposal set of transactions - /// If you tip the consensus then the transactions can begin to be run after their hold up time + /// Uses your voter weight (deposited Community or Council tokens) to cast + /// a vote on a Proposal By doing so you indicate you approve or + /// disapprove of running the Proposal set of transactions If you tip + /// the consensus then the transactions can begin to be run after their hold + /// up time /// /// 0. `[]` Realm account /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord of the Proposal owner - /// 4. `[writable]` TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] - /// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 6. `[writable]` Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record] - /// 7. `[]` The Governing Token Mint which is used to cast the vote (vote_governing_token_mint) - /// The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes - /// For Veto vote the voting token mint is the mint of the opposite voting population - /// Council mint to veto Community proposals and Community mint to veto Council proposals - /// Note: In the current version only Council veto is supported + /// 4. `[writable]` TokenOwnerRecord of the voter. PDA seeds: + /// ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] + /// 5. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) + /// 6. `[writable]` Proposal VoteRecord account. PDA seeds: + /// ['governance',proposal,token_owner_record] + /// 7. `[]` The Governing Token Mint which is used to cast the vote + /// (vote_governing_token_mint) The voting token mint is the + /// governing_token_mint of the Proposal for Approve, Deny and Abstain + /// votes For Veto vote the voting token mint is the mint of the + /// opposite voting population Council mint to veto Community proposals + /// and Community mint to veto Council proposals Note: In the current + /// version only Council veto is supported /// 8. `[signer]` Payer /// 9. `[]` System program /// 10. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] @@ -318,7 +370,8 @@ pub enum GovernanceInstruction { vote: Vote, }, - /// Finalizes vote in case the Vote was not automatically tipped within max_voting_time period + /// Finalizes vote in case the Vote was not automatically tipped within + /// max_voting_time period /// /// 0. `[]` Realm account /// 1. `[writable]` Governance account @@ -329,27 +382,36 @@ pub enum GovernanceInstruction { /// 6. `[]` Optional Max Voter Weight Record FinalizeVote {}, - /// Relinquish Vote removes voter weight from a Proposal and removes it from voter's active votes - /// If the Proposal is still being voted on then the voter's weight won't count towards the vote outcome - /// If the Proposal is already in decided state then the instruction has no impact on the Proposal - /// and only allows voters to prune their outstanding votes in case they wanted to withdraw Governing tokens from the Realm + /// Relinquish Vote removes voter weight from a Proposal and removes it + /// from voter's active votes If the Proposal is still being voted on + /// then the voter's weight won't count towards the vote outcome If the + /// Proposal is already in decided state then the instruction has no impact + /// on the Proposal and only allows voters to prune their outstanding + /// votes in case they wanted to withdraw Governing tokens from the Realm /// /// 0. `[]` Realm account /// 1. `[]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] - /// 4. `[writable]` Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record] - /// 5. `[]` The Governing Token Mint which was used to cast the vote (vote_governing_token_mint) - /// 6. `[signer]` Optional Governance Authority (Token Owner or Governance Delegate) - /// It's required only when Proposal is still being voted on - /// 7. `[writable]` Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed - /// It's required only when Proposal is still being voted on + /// 3. `[writable]` TokenOwnerRecord account. PDA seeds: + /// ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] + /// 4. `[writable]` Proposal VoteRecord account. PDA seeds: + /// ['governance',proposal, token_owner_record] + /// 5. `[]` The Governing Token Mint which was used to cast the vote + /// (vote_governing_token_mint) + /// 6. `[signer]` Optional Governance Authority (Token Owner or Governance + /// Delegate) It's required only when Proposal is still being voted on + /// 7. `[writable]` Optional Beneficiary account which would receive + /// lamports when VoteRecord Account is disposed It's required only + /// when Proposal is still being voted on RelinquishVote, /// Executes a Transaction in the Proposal - /// Anybody can execute transaction once Proposal has been voted Yes and transaction_hold_up time has passed - /// The actual transaction being executed will be signed by Governance PDA the Proposal belongs to - /// For example to execute Program upgrade the ProgramGovernance PDA would be used as the singer + /// Anybody can execute transaction once Proposal has been voted Yes and + /// transaction_hold_up time has passed The actual transaction being + /// executed will be signed by Governance PDA the Proposal belongs to + /// For example to execute Program upgrade the ProgramGovernance PDA would + /// be used as the singer /// /// 0. `[]` Governance account /// 1. `[writable]` Proposal account @@ -360,10 +422,13 @@ pub enum GovernanceInstruction { /// Creates Mint Governance account which governs a mint /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Mint Governance account. PDA seeds: ['mint-governance', realm, governed_mint] + /// 1. `[writable]` Mint Governance account. PDA seeds: + /// ['mint-governance', realm, governed_mint] /// 2. `[writable]` Mint governed by this Governance account - /// 3. `[signer]` Current Mint authority (MintTokens and optionally FreezeAccount) - /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + /// 3. `[signer]` Current Mint authority (MintTokens and optionally + /// FreezeAccount) + /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by + /// RealmAuthority) /// 5. `[signer]` Payer /// 6. `[]` SPL Token program /// 7. `[]` System program @@ -377,19 +442,24 @@ pub enum GovernanceInstruction { config: GovernanceConfig, #[allow(dead_code)] - /// Indicates whether Mint's authorities (MintTokens, FreezeAccount) should be transferred to the Governance PDA - /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current mint authority signed the transaction nonetheless + /// Indicates whether Mint's authorities (MintTokens, FreezeAccount) + /// should be transferred to the Governance PDA If it's set to + /// false then it can be done at a later time However the + /// instruction would validate the current mint authority signed the + /// transaction nonetheless transfer_mint_authorities: bool, }, /// Creates Token Governance account which governs a token account /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Token Governance account. PDA seeds: ['token-governance', realm, governed_token] + /// 1. `[writable]` Token Governance account. PDA seeds: + /// ['token-governance', realm, governed_token] /// 2. `[writable]` Token account governed by this Governance account - /// 3. `[signer]` Current token account authority (AccountOwner and optionally CloseAccount) - /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + /// 3. `[signer]` Current token account authority (AccountOwner and + /// optionally CloseAccount) + /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by + /// RealmAuthority) /// 5. `[signer]` Payer /// 6. `[]` SPL Token program /// 7. `[]` System program @@ -403,9 +473,11 @@ pub enum GovernanceInstruction { config: GovernanceConfig, #[allow(dead_code)] - /// Indicates whether the token account authorities (AccountOwner and optionally CloseAccount) should be transferred to the Governance PDA + /// Indicates whether the token account authorities (AccountOwner and + /// optionally CloseAccount) should be transferred to the Governance PDA /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current token owner signed the transaction nonetheless + /// However the instruction would validate the current token owner + /// signed the transaction nonetheless transfer_account_authorities: bool, }, @@ -420,13 +492,16 @@ pub enum GovernanceInstruction { }, /// Flags a transaction and its parent Proposal with error status - /// It can be used by Proposal owner in case the transaction is permanently broken and can't be executed - /// Note: This instruction is a workaround because currently it's not possible to catch errors from CPI calls - /// and the Governance program has no way to know when instruction failed and flag it automatically + /// It can be used by Proposal owner in case the transaction is permanently + /// broken and can't be executed Note: This instruction is a workaround + /// because currently it's not possible to catch errors from CPI calls + /// and the Governance program has no way to know when instruction + /// failed and flag it automatically /// /// 0. `[writable]` Proposal account /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 2. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// 3. `[writable]` ProposalTransaction account to flag FlagTransactionError, @@ -434,7 +509,8 @@ pub enum GovernanceInstruction { /// /// 0. `[writable]` Realm account /// 1. `[signer]` Current Realm authority - /// 2. `[]` New realm authority. Must be one of the realm governances when set + /// 2. `[]` New realm authority. Must be one of the realm governances when + /// set SetRealmAuthority { #[allow(dead_code)] /// Set action ( SetUnchecked, SetChecked, Remove) @@ -444,14 +520,17 @@ pub enum GovernanceInstruction { /// Sets realm config /// 0. `[writable]` Realm account /// 1. `[signer]` Realm authority - /// 2. `[]` Council Token Mint - optional - /// Note: In the current version it's only possible to remove council mint (set it to None) - /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer - /// If that's required then it must be done before executing this instruction - /// 3. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint] - /// The account will be created with the Realm PDA as its owner + /// 2. `[]` Council Token Mint - optional Note: In the current version + /// it's only possible to remove council mint (set it to None) After + /// setting council to None it won't be possible to withdraw the tokens + /// from the Realm any longer If that's required then it must be done + /// before executing this instruction + /// 3. `[writable]` Council Token Holding account - optional unless + /// council is used. PDA seeds: ['governance',realm,council_mint] The + /// account will be created with the Realm PDA as its owner /// 4. `[]` System - /// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', + /// realm] /// /// 6. `[]` Optional Community Voter Weight Addin Program Id /// 7. `[]` Optional Max Community Voter Weight Addin Program Id @@ -459,7 +538,8 @@ pub enum GovernanceInstruction { /// 8. `[]` Optional Council Voter Weight Addin Program Id /// 9. `[]` Optional Max Council Voter Weight Addin Program Id /// - /// 10. `[signer]` Optional Payer. Required if RealmConfig doesn't exist and needs to be created + /// 10. `[signer]` Optional Payer. Required if RealmConfig doesn't exist + /// and needs to be created SetRealmConfig { #[allow(dead_code)] /// Realm config args @@ -467,18 +547,21 @@ pub enum GovernanceInstruction { }, /// Creates TokenOwnerRecord with 0 deposit amount - /// It's used to register TokenOwner when voter weight addin is used and the Governance program doesn't take deposits + /// It's used to register TokenOwner when voter weight addin is used and the + /// Governance program doesn't take deposits /// /// 0. `[]` Realm account /// 1. `[]` Governing Token Owner account - /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] + /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: + /// ['governance',realm, governing_token_mint, governing_token_owner] /// 3. `[]` Governing Token Mint /// 4. `[signer]` Payer /// 5. `[]` System CreateTokenOwnerRecord {}, /// Updates ProgramMetadata account - /// The instruction dumps information implied by the program's code into a persistent account + /// The instruction dumps information implied by the program's code into a + /// persistent account /// /// 0. `[writable]` ProgramMetadata account. PDA seeds: ['metadata'] /// 1. `[signer]` Payer @@ -486,24 +569,32 @@ pub enum GovernanceInstruction { UpdateProgramMetadata {}, /// Creates native SOL treasury account for a Governance account - /// The account has no data and can be used as a payer for instructions signed by Governance PDAs or as a native SOL treasury + /// The account has no data and can be used as a payer for instructions + /// signed by Governance PDAs or as a native SOL treasury /// /// 0. `[]` Governance account the treasury account is for - /// 1. `[writable]` NativeTreasury account. PDA seeds: ['native-treasury', governance] + /// 1. `[writable]` NativeTreasury account. PDA seeds: ['native-treasury', + /// governance] /// 2. `[signer]` Payer /// 3. `[]` System CreateNativeTreasury, - /// Revokes (burns) membership governing tokens for the given TokenOwnerRecord and hence takes away governance power from the TokenOwner - /// Note: If there are active votes for the TokenOwner then the vote weights won't be updated automatically + /// Revokes (burns) membership governing tokens for the given + /// TokenOwnerRecord and hence takes away governance power from the + /// TokenOwner Note: If there are active votes for the TokenOwner then + /// the vote weights won't be updated automatically /// /// 0. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint] - /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] + /// 1. `[writable]` Governing Token Holding account. PDA seeds: + /// ['governance',realm, governing_token_mint] + /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: + /// ['governance',realm, governing_token_mint, governing_token_owner] /// 3. `[writable]` GoverningTokenMint /// 4. `[signer]` Revoke authority which can be either of: - /// 1) GoverningTokenMint mint_authority to forcefully revoke the membership tokens - /// 2) GoverningTokenOwner who voluntarily revokes their own membership + /// 1) GoverningTokenMint mint_authority to forcefully revoke + /// the membership tokens + /// 2) GoverningTokenOwner who voluntarily revokes their own + /// membership /// 5. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] /// 6. `[]` SPL Token program RevokeGoverningTokens { @@ -512,18 +603,24 @@ pub enum GovernanceInstruction { amount: u64, }, - /// Refunds ProposalDeposit once the given proposal is no longer active (Draft, SigningOff, Voting) - /// Once the condition is met the instruction is permissionless and returns the deposit amount to the deposit payer + /// Refunds ProposalDeposit once the given proposal is no longer active + /// (Draft, SigningOff, Voting) Once the condition is met the + /// instruction is permissionless and returns the deposit amount to the + /// deposit payer /// /// 0. `[]` Proposal account - /// 1. `[writable]` ProposalDeposit account. PDA seeds: ['proposal-deposit', proposal, deposit payer] + /// 1. `[writable]` ProposalDeposit account. PDA seeds: + /// ['proposal-deposit', proposal, deposit payer] /// 2. `[writable]` Proposal deposit payer (beneficiary) account RefundProposalDeposit {}, - /// Transitions an off-chain or manually executable Proposal from Succeeded into Completed state + /// Transitions an off-chain or manually executable Proposal from Succeeded + /// into Completed state /// - /// Upon a successful vote on an off-chain or manually executable proposal it remains in Succeeded state - /// Once the external actions are executed the Proposal owner can use the instruction to manually transition it to Completed state + /// Upon a successful vote on an off-chain or manually executable proposal + /// it remains in Succeeded state Once the external actions are executed + /// the Proposal owner can use the instruction to manually transition it to + /// Completed state /// /// /// 0. `[writable]` Proposal account @@ -531,7 +628,8 @@ pub enum GovernanceInstruction { /// 2. `[signer]` CompleteProposal authority (Token Owner or Delegate) CompleteProposal {}, - /// Adds a required signatory to the Governance, which will be applied to all proposals created with it + /// Adds a required signatory to the Governance, which will be applied to + /// all proposals created with it /// /// 0. `[writable, signer]` The Governance account the config is for /// 1. `[writable]` RequiredSignatory Account @@ -547,7 +645,8 @@ pub enum GovernanceInstruction { /// /// 0. `[writable, signer]` The Governance account the config is for /// 1. `[writable]` RequiredSignatory Account - /// 2. `[writable]` Beneficiary Account which would receive lamports from the disposed RequiredSignatory Account + /// 2. `[writable]` Beneficiary Account which would receive lamports from + /// the disposed RequiredSignatory Account RemoveRequiredSignatory, } @@ -761,7 +860,8 @@ pub fn create_governance( let governed_account_address = if let Some(governed_account) = governed_account { *governed_account } else { - // If the governed account is not provided then generate a unique identifier for the Governance account + // If the governed account is not provided then generate a unique identifier for + // the Governance account Pubkey::new_unique() }; @@ -959,8 +1059,9 @@ pub fn create_proposal( with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None); - // Deposit is only required when there are more active proposal then the configured exempt amount - // Note: We always pass the account because the actual value is not known here without passing Governance account data + // Deposit is only required when there are more active proposal then the + // configured exempt amount Note: We always pass the account because the + // actual value is not known here without passing Governance account data let proposal_deposit_address = get_proposal_deposit_address(program_id, &proposal_address, payer); accounts.push(AccountMeta::new(proposal_deposit_address, false)); @@ -1030,7 +1131,8 @@ pub fn add_signatory( } #[derive(Debug, Copy, Clone)] -/// Enum to specify the authority by which the instruction should add a signatory +/// Enum to specify the authority by which the instruction should add a +/// signatory pub enum AddSignatoryAuthority { /// Proposal owners can add optional signatories to a proposal ProposalOwner { @@ -1039,7 +1141,8 @@ pub enum AddSignatoryAuthority { /// Token owner record of the Proposal owner token_owner_record: Pubkey, }, - /// Anyone can add signatories that are required by the governance to a proposal + /// Anyone can add signatories that are required by the governance to a + /// proposal None, } @@ -1444,8 +1547,9 @@ pub fn set_realm_config( accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - // Always pass realm_config_address because it's needed when use_community_voter_weight_addin is set to true - // but also when it's set to false and the addin is being removed from the realm + // Always pass realm_config_address because it's needed when + // use_community_voter_weight_addin is set to true but also when it's set to + // false and the addin is being removed from the realm let realm_config_address = get_realm_config_address(program_id, realm); accounts.push(AccountMeta::new(realm_config_address, false)); @@ -1741,7 +1845,8 @@ pub fn refund_proposal_deposit( } } -/// Creates CompleteProposal instruction to move proposal from Succeeded to Completed +/// Creates CompleteProposal instruction to move proposal from Succeeded to +/// Completed pub fn complete_proposal( program_id: &Pubkey, // Accounts diff --git a/governance/program/src/lib.rs b/governance/program/src/lib.rs index ae30d26e75e..7fd08c7b074 100644 --- a/governance/program/src/lib.rs +++ b/governance/program/src/lib.rs @@ -10,10 +10,12 @@ pub mod processor; pub mod state; pub mod tools; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; /// Seed prefix for Governance PDAs -/// Note: This prefix is used for the initial set of PDAs and shouldn't be used for any new accounts -/// All new PDAs should use a unique prefix to guarantee uniqueness for each account +/// Note: This prefix is used for the initial set of PDAs and shouldn't be used +/// for any new accounts All new PDAs should use a unique prefix to guarantee +/// uniqueness for each account pub const PROGRAM_AUTHORITY_SEED: &[u8] = b"governance"; diff --git a/governance/program/src/processor/mod.rs b/governance/program/src/processor/mod.rs index 2803bd200cb..c41e884a674 100644 --- a/governance/program/src/processor/mod.rs +++ b/governance/program/src/processor/mod.rs @@ -76,7 +76,8 @@ pub fn process_instruction( input: &[u8], ) -> ProgramResult { msg!("VERSION:{:?}", env!("CARGO_PKG_VERSION")); - // Use try_from_slice_unchecked to support forward compatibility of newer UI with older program + // Use try_from_slice_unchecked to support forward compatibility of newer UI + // with older program let instruction: GovernanceInstruction = try_from_slice_unchecked(input).map_err(|_| ProgramError::InvalidInstructionData)?; diff --git a/governance/program/src/processor/process_add_signatory.rs b/governance/program/src/processor/process_add_signatory.rs index 26bdee43f74..82ae9ca7c32 100644 --- a/governance/program/src/processor/process_add_signatory.rs +++ b/governance/program/src/processor/process_add_signatory.rs @@ -47,7 +47,8 @@ pub fn process_add_signatory( return Err(GovernanceError::SignatoryRecordAlreadyExists.into()); } - // All required signatories must be added before additional signatories can be added + // All required signatories must be added before additional signatories can be + // added if proposal_data.signatories_count < governance_data.required_signatories_count { let required_signatory_info = next_account_info(account_info_iter)?; // 5 let required_signatory_data = get_required_signatory_data_for_governance( diff --git a/governance/program/src/processor/process_cast_vote.rs b/governance/program/src/processor/process_cast_vote.rs index 7a0f93fba95..e331d87e7fb 100644 --- a/governance/program/src/processor/process_cast_vote.rs +++ b/governance/program/src/processor/process_cast_vote.rs @@ -69,9 +69,10 @@ pub fn process_cast_vote( let vote_kind = get_vote_kind(&vote); - // Get the governing_token_mint which the Proposal should be configured with as the voting population for the given vote - // For Approve, Deny and Abstain votes it's the same as vote_governing_token_mint - // For Veto it's the governing token mint of the opposite voting population + // Get the governing_token_mint which the Proposal should be configured with as + // the voting population for the given vote For Approve, Deny and Abstain + // votes it's the same as vote_governing_token_mint For Veto it's the + // governing token mint of the opposite voting population let proposal_governing_token_mint = realm_data.get_proposal_governing_token_mint_for_vote( vote_governing_token_mint_info.key, &vote_kind, @@ -174,7 +175,8 @@ pub fn process_cast_vote( &proposal_data.token_owner_record, )?; - // If the voter is also the proposal owner then update the voter record which is serialized for the voter later on + // If the voter is also the proposal owner then update the voter record which is + // serialized for the voter later on if proposal_owner_record_info.key == voter_token_owner_record_info.key { voter_token_owner_record_data.decrease_outstanding_proposal_count(); } else { diff --git a/governance/program/src/processor/process_create_mint_governance.rs b/governance/program/src/processor/process_create_mint_governance.rs index 0478dd81ef8..dfd62300753 100644 --- a/governance/program/src/processor/process_create_mint_governance.rs +++ b/governance/program/src/processor/process_create_mint_governance.rs @@ -101,7 +101,8 @@ pub fn process_create_mint_governance( // If the mint has freeze_authority then transfer it as well let mint_data = Mint::unpack(&governed_mint_info.data.borrow())?; // Note: The code assumes mint_authority==freeze_authority - // If this is not the case then the caller should set freeze_authority accordingly before making the transfer + // If this is not the case then the caller should set freeze_authority + // accordingly before making the transfer if mint_data.freeze_authority.is_some() { set_spl_token_account_authority( governed_mint_info, diff --git a/governance/program/src/processor/process_create_proposal.rs b/governance/program/src/processor/process_create_proposal.rs index 72f492d4200..9f2f320aee0 100644 --- a/governance/program/src/processor/process_create_proposal.rs +++ b/governance/program/src/processor/process_create_proposal.rs @@ -82,7 +82,8 @@ pub fn process_create_proposal( realm_info.key, )?; - // Proposal owner (TokenOwner) or its governance_delegate must sign this transaction + // Proposal owner (TokenOwner) or its governance_delegate must sign this + // transaction proposal_owner_record_data .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; @@ -98,7 +99,8 @@ pub fn process_create_proposal( governance_info.key, )?; - // Ensure proposal owner (TokenOwner) has enough tokens to create proposal and no outstanding proposals + // Ensure proposal owner (TokenOwner) has enough tokens to create proposal and + // no outstanding proposals proposal_owner_record_data.assert_can_create_proposal( &realm_data, &governance_data.config, diff --git a/governance/program/src/processor/process_create_token_governance.rs b/governance/program/src/processor/process_create_token_governance.rs index 9fdd6513f70..89abec02089 100644 --- a/governance/program/src/processor/process_create_token_governance.rs +++ b/governance/program/src/processor/process_create_token_governance.rs @@ -99,7 +99,8 @@ pub fn process_create_token_governance( // If the token account has close_authority then transfer it as well let token_account_data = Account::unpack(&governed_token_info.data.borrow())?; // Note: The code assumes owner==close_authority - // If this is not the case then the caller should set close_authority accordingly before making the transfer + // If this is not the case then the caller should set close_authority + // accordingly before making the transfer if token_account_data.close_authority.is_some() { set_spl_token_account_authority( governed_token_info, diff --git a/governance/program/src/processor/process_deposit_governing_tokens.rs b/governance/program/src/processor/process_deposit_governing_tokens.rs index 7b3271c07cb..c138e5469cc 100644 --- a/governance/program/src/processor/process_deposit_governing_tokens.rs +++ b/governance/program/src/processor/process_deposit_governing_tokens.rs @@ -92,7 +92,8 @@ pub fn process_deposit_governing_tokens( ); if token_owner_record_info.data_is_empty() { - // Deposited tokens can only be withdrawn by the owner so let's make sure the owner signed the transaction + // Deposited tokens can only be withdrawn by the owner so let's make sure the + // owner signed the transaction if !governing_token_owner_info.is_signer { return Err(GovernanceError::GoverningTokenOwnerMustSign.into()); } diff --git a/governance/program/src/processor/process_execute_transaction.rs b/governance/program/src/processor/process_execute_transaction.rs index 68ce104cfde..580d67ff43c 100644 --- a/governance/program/src/processor/process_execute_transaction.rs +++ b/governance/program/src/processor/process_execute_transaction.rs @@ -49,10 +49,12 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] .iter() .map(Instruction::from); - // In the current implementation accounts for all instructions are passed to each instruction invocation - // This is an overhead but shouldn't be a showstopper because if we can invoke the parent instruction with that many accounts - // then we should also be able to invoke all the nested ones - // TODO: Optimize the invocation to split the provided accounts for each individual instruction + // In the current implementation accounts for all instructions are passed to + // each instruction invocation This is an overhead but shouldn't be a + // showstopper because if we can invoke the parent instruction with that many + // accounts then we should also be able to invoke all the nested ones + // TODO: Optimize the invocation to split the provided accounts for each + // individual instruction let instruction_account_infos = account_info_iter.as_slice(); let mut signers_seeds: Vec<&[&[u8]]> = vec![]; @@ -65,7 +67,8 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] signers_seeds.push(&governance_seeds[..]); - // Sign the transaction using the governance treasury PDA if required by the instruction + // Sign the transaction using the governance treasury PDA if required by the + // instruction let mut treasury_seeds = get_native_treasury_address_seeds(governance_info.key).to_vec(); let (treasury_address, treasury_bump_seed) = Pubkey::find_program_address(&treasury_seeds, program_id); @@ -92,8 +95,10 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] let option = &mut proposal_data.options[proposal_transaction_data.option_index as usize]; option.transactions_executed_count = option.transactions_executed_count.checked_add(1).unwrap(); - // Checking for Executing and ExecutingWithErrors states because instruction can still be executed after being flagged with error - // The check for instructions_executed_count ensures Proposal can't be transitioned to Completed state from ExecutingWithErrors + // Checking for Executing and ExecutingWithErrors states because instruction can + // still be executed after being flagged with error The check for + // instructions_executed_count ensures Proposal can't be transitioned to + // Completed state from ExecutingWithErrors if (proposal_data.state == ProposalState::Executing || proposal_data.state == ProposalState::ExecutingWithErrors) && proposal_data diff --git a/governance/program/src/processor/process_flag_transaction_error.rs b/governance/program/src/processor/process_flag_transaction_error.rs index 68a572488a2..0a4c6c6c157 100644 --- a/governance/program/src/processor/process_flag_transaction_error.rs +++ b/governance/program/src/processor/process_flag_transaction_error.rs @@ -50,8 +50,9 @@ pub fn process_flag_transaction_error( token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - // If this is the first instruction to be executed then set executing_at timestamp - // It indicates when we started executing instructions for the Proposal and the fact we only flag it as error is irrelevant here + // If this is the first instruction to be executed then set executing_at + // timestamp It indicates when we started executing instructions for the + // Proposal and the fact we only flag it as error is irrelevant here if proposal_data.state == ProposalState::Succeeded { proposal_data.executing_at = Some(clock.unix_timestamp); } diff --git a/governance/program/src/processor/process_insert_transaction.rs b/governance/program/src/processor/process_insert_transaction.rs index e73f520a269..2a1f0580bbb 100644 --- a/governance/program/src/processor/process_insert_transaction.rs +++ b/governance/program/src/processor/process_insert_transaction.rs @@ -75,7 +75,8 @@ pub fn process_insert_transaction( match instruction_index.cmp(&option.transactions_next_index) { Ordering::Greater => return Err(GovernanceError::InvalidTransactionIndex.into()), // If the index is the same as instructions_next_index then we are adding a new instruction - // If the index is below instructions_next_index then we are inserting into an existing empty space + // If the index is below instructions_next_index then we are inserting into an existing + // empty space Ordering::Equal => { option.transactions_next_index = option.transactions_next_index.checked_add(1).unwrap(); } diff --git a/governance/program/src/processor/process_refund_proposal_deposit.rs b/governance/program/src/processor/process_refund_proposal_deposit.rs index dde7ddd13f6..552554f2d46 100644 --- a/governance/program/src/processor/process_refund_proposal_deposit.rs +++ b/governance/program/src/processor/process_refund_proposal_deposit.rs @@ -29,7 +29,8 @@ pub fn process_refund_proposal_deposit( proposal_data.assert_can_refund_proposal_deposit()?; - // Assert we are disposing a deposit which belongs to the Proposal and the deposit payer + // Assert we are disposing a deposit which belongs to the Proposal and the + // deposit payer let _proposal_deposit_data = get_proposal_deposit_data_for_proposal_and_deposit_payer( program_id, proposal_deposit_info, diff --git a/governance/program/src/processor/process_relinquish_vote.rs b/governance/program/src/processor/process_relinquish_vote.rs index ae5cdfaa097..4224832c5dd 100644 --- a/governance/program/src/processor/process_relinquish_vote.rs +++ b/governance/program/src/processor/process_relinquish_vote.rs @@ -65,17 +65,21 @@ pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> let clock = Clock::get()?; - // If the Proposal is still being voted on then the token owner vote will be withdrawn and it won't count towards the vote outcome - // Note: If there is no tipping point the proposal can be still in Voting state but already past the configured max voting time (base + cool off voting time) - // It means it awaits manual finalization (FinalizeVote) and it should no longer be possible to withdraw the vote + // If the Proposal is still being voted on then the token owner vote will be + // withdrawn and it won't count towards the vote outcome Note: If there is + // no tipping point the proposal can be still in Voting state but already past + // the configured max voting time (base + cool off voting time) + // It means it awaits manual finalization (FinalizeVote) and it should no + // longer be possible to withdraw the vote if proposal_data.state == ProposalState::Voting && !proposal_data.has_voting_max_time_ended(&governance_data.config, clock.unix_timestamp) { let governance_authority_info = next_account_info(account_info_iter)?; // 5 let beneficiary_info = next_account_info(account_info_iter)?; // 6 - // Note: It's only required to sign by governing_authority if relinquishing the vote results in vote change - // If the Proposal is already decided then anybody can prune active votes for token owner + // Note: It's only required to sign by governing_authority if relinquishing the + // vote results in vote change If the Proposal is already decided then + // anybody can prune active votes for token owner token_owner_record_data .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; @@ -112,9 +116,10 @@ pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> dispose_account(vote_record_info, beneficiary_info)?; } else { - // After Proposal voting time ends and it's not tipped then it enters implicit (time based) Finalizing state - // and releasing tokens in this state should be disallowed - // In other words releasing tokens is only possible once Proposal is manually finalized using FinalizeVote + // After Proposal voting time ends and it's not tipped then it enters implicit + // (time based) Finalizing state and releasing tokens in this state + // should be disallowed In other words releasing tokens is only possible + // once Proposal is manually finalized using FinalizeVote if proposal_data.state == ProposalState::Voting { return Err(GovernanceError::CannotRelinquishInFinalizingState.into()); } @@ -123,7 +128,8 @@ pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> vote_record_data.serialize(&mut vote_record_info.data.borrow_mut()[..])?; } - // If the Proposal has been already voted on then we only have to decrease unrelinquished_votes_count + // If the Proposal has been already voted on then we only have to decrease + // unrelinquished_votes_count token_owner_record_data.unrelinquished_votes_count = token_owner_record_data .unrelinquished_votes_count .checked_sub(1) diff --git a/governance/program/src/processor/process_revoke_governing_tokens.rs b/governance/program/src/processor/process_revoke_governing_tokens.rs index cf9ea250bd9..b5040f31634 100644 --- a/governance/program/src/processor/process_revoke_governing_tokens.rs +++ b/governance/program/src/processor/process_revoke_governing_tokens.rs @@ -58,13 +58,15 @@ pub fn process_revoke_governing_tokens( governing_token_mint_info.key, )?; - // If the governing token owner voluntarily revokes their own membership then the owner must sign the transaction + // If the governing token owner voluntarily revokes their own membership then + // the owner must sign the transaction if *revoke_authority_info.key == token_owner_record_data.governing_token_owner { if !revoke_authority_info.is_signer { return Err(GovernanceError::GoverningTokenOwnerMustSign.into()); } } else { - // If its a forceful membership revocation then the governing_token_mint authority must sign the transaction + // If its a forceful membership revocation then the governing_token_mint + // authority must sign the transaction assert_spl_token_mint_authority_is_signer( governing_token_mint_info, revoke_authority_info, diff --git a/governance/program/src/processor/process_set_governance_config.rs b/governance/program/src/processor/process_set_governance_config.rs index ce6086f17b2..ae7d3691532 100644 --- a/governance/program/src/processor/process_set_governance_config.rs +++ b/governance/program/src/processor/process_set_governance_config.rs @@ -33,9 +33,10 @@ pub fn process_set_governance_config( let mut governance_data = get_governance_data(program_id, governance_info)?; - // Note: Config change leaves voting proposals in unpredictable state and it's DAOs responsibility - // to ensure the changes are made when there are no proposals in voting state - // For example changing approval quorum could accidentally make proposals to succeed which would otherwise be defeated + // Note: Config change leaves voting proposals in unpredictable state and it's + // DAOs responsibility to ensure the changes are made when there are no + // proposals in voting state For example changing approval quorum could + // accidentally make proposals to succeed which would otherwise be defeated governance_data.config = config; diff --git a/governance/program/src/processor/process_set_realm_config.rs b/governance/program/src/processor/process_set_realm_config.rs index 0a0f02a7c57..347f265568e 100644 --- a/governance/program/src/processor/process_set_realm_config.rs +++ b/governance/program/src/processor/process_set_realm_config.rs @@ -41,9 +41,11 @@ pub fn process_set_realm_config( return Err(GovernanceError::RealmAuthorityMustSign.into()); } - // Note: Config change leaves voting proposals in unpredictable state and it's DAOs responsibility - // to ensure the changes are made when there are no proposals in voting state - // For example changing voter-weight or max-voter-weight addin could accidentally make proposals to succeed which would otherwise be defeated + // Note: Config change leaves voting proposals in unpredictable state and it's + // DAOs responsibility to ensure the changes are made when there are no + // proposals in voting state For example changing voter-weight or + // max-voter-weight addin could accidentally make proposals to succeed which + // would otherwise be defeated assert_valid_realm_config_args(&realm_config_args)?; @@ -52,9 +54,10 @@ pub fn process_set_realm_config( let council_token_mint_info = next_account_info(account_info_iter)?; // 2 let _council_token_holding_info = next_account_info(account_info_iter)?; // 3 - // Council mint can only be at present set to None (removed) and changing it to other mint is not supported - // It might be implemented in future versions but it needs careful planning - // It can potentially open a can of warms like what happens with existing deposits or pending proposals + // Council mint can only be at present set to None (removed) and changing it to + // other mint is not supported It might be implemented in future + // versions but it needs careful planning It can potentially open a can + // of warms like what happens with existing deposits or pending proposals if let Some(council_token_mint) = realm_data.config.council_mint { // Council mint can't be changed to different one if council_token_mint != *council_token_mint_info.key { @@ -66,7 +69,8 @@ pub fn process_set_realm_config( } } else { // Remove council mint from realm - // Note: In the current implementation this also makes it impossible to withdraw council tokens + // Note: In the current implementation this also makes it impossible to withdraw + // council tokens realm_data.config.council_mint = None; } @@ -97,7 +101,8 @@ pub fn process_set_realm_config( // Update or create RealmConfigAccount if realm_config_info.data_is_empty() { - // For older Realm accounts (pre program V3) RealmConfigAccount might not exist yet and we have to create it + // For older Realm accounts (pre program V3) RealmConfigAccount might not exist + // yet and we have to create it // We need the payer to pay for the new account if it's created let payer_info = next_account_info(account_info_iter)?; // 10 diff --git a/governance/program/src/processor/process_sign_off_proposal.rs b/governance/program/src/processor/process_sign_off_proposal.rs index 69a7c3b4eea..5c50f1a3e81 100644 --- a/governance/program/src/processor/process_sign_off_proposal.rs +++ b/governance/program/src/processor/process_sign_off_proposal.rs @@ -47,7 +47,8 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) return Err(GovernanceError::MissingRequiredSignatories.into()); } - // If the owner of the proposal hasn't appointed any signatories then can sign off the proposal themself + // If the owner of the proposal hasn't appointed any signatories then can sign + // off the proposal themself if proposal_data.signatories_count == 0 { let proposal_owner_record_info = next_account_info(account_info_iter)?; // 4 @@ -57,7 +58,8 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) &proposal_data.token_owner_record, )?; - // Proposal owner (TokenOwner) or its governance_delegate must be the signatory and sign this transaction + // Proposal owner (TokenOwner) or its governance_delegate must be the signatory + // and sign this transaction proposal_owner_record_data.assert_token_owner_or_delegate_is_signer(signatory_info)?; proposal_data.signing_off_at = Some(clock.unix_timestamp); diff --git a/governance/program/src/processor/process_update_program_metadata.rs b/governance/program/src/processor/process_update_program_metadata.rs index fc255dc939c..adfbe2812ab 100644 --- a/governance/program/src/processor/process_update_program_metadata.rs +++ b/governance/program/src/processor/process_update_program_metadata.rs @@ -35,7 +35,8 @@ pub fn process_update_program_metadata( const VERSION: &str = env!("CARGO_PKG_VERSION"); - // Put the metadata info into the logs to make it possible to extract it using Tx simulation + // Put the metadata info into the logs to make it possible to extract it using + // Tx simulation msg!("PROGRAM-VERSION:{:?}", VERSION); if program_metadata_info.data_is_empty() { diff --git a/governance/program/src/state/enums.rs b/governance/program/src/state/enums.rs index c36b80e8afd..fb5a8f00274 100644 --- a/governance/program/src/state/enums.rs +++ b/governance/program/src/state/enums.rs @@ -9,7 +9,8 @@ pub enum GovernanceAccountType { #[default] Uninitialized, - /// Top level aggregation for governances with Community Token (and optional Council Token) + /// Top level aggregation for governances with Community Token (and optional + /// Council Token) RealmV1, /// Token Owner Record for given governing token owner within a Realm @@ -21,16 +22,19 @@ pub enum GovernanceAccountType { /// Program Governance account ProgramGovernanceV1, - /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts + /// Proposal account for Governance account. A single Governance account can + /// have multiple Proposal accounts ProposalV1, /// Proposal Signatory account SignatoryRecordV1, - /// Vote record account for a given Proposal. Proposal can have 0..n voting records + /// Vote record account for a given Proposal. Proposal can have 0..n voting + /// records VoteRecordV1, - /// ProposalInstruction account which holds an instruction to execute for Proposal + /// ProposalInstruction account which holds an instruction to execute for + /// Proposal ProposalInstructionV1, /// Mint Governance account @@ -42,25 +46,29 @@ pub enum GovernanceAccountType { /// Realm config account (introduced in V2) RealmConfig, - /// Vote record account for a given Proposal. Proposal can have 0..n voting records - /// V2 adds support for multi option votes + /// Vote record account for a given Proposal. Proposal can have 0..n voting + /// records V2 adds support for multi option votes VoteRecordV2, - /// ProposalTransaction account which holds instructions to execute for Proposal within a single Transaction - /// V2 replaces ProposalInstruction and adds index for proposal option and multiple instructions + /// ProposalTransaction account which holds instructions to execute for + /// Proposal within a single Transaction V2 replaces ProposalInstruction + /// and adds index for proposal option and multiple instructions ProposalTransactionV2, - /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts - /// V2 adds support for multiple vote options + /// Proposal account for Governance account. A single Governance account can + /// have multiple Proposal accounts V2 adds support for multiple vote + /// options ProposalV2, /// Program metadata account (introduced in V2) - /// It stores information about the particular SPL-Governance program instance + /// It stores information about the particular SPL-Governance program + /// instance ProgramMetadata, - /// Top level aggregation for governances with Community Token (and optional Council Token) - /// V2 adds the following fields: - /// 1) use_community_voter_weight_addin and use_max_community_voter_weight_addin to RealmConfig + /// Top level aggregation for governances with Community Token (and optional + /// Council Token) V2 adds the following fields: + /// 1) use_community_voter_weight_addin and + /// use_max_community_voter_weight_addin to RealmConfig /// 2) voting_proposal_count / replaced with legacy1 in V3 /// 3) extra reserved space reserved_v2 RealmV2, @@ -104,7 +112,8 @@ pub enum ProposalState { Draft, /// SigningOff - The Proposal is being signed off by Signatories - /// Proposal enters the state when first Signatory Sings and leaves it when last Signatory signs + /// Proposal enters the state when first Signatory Sings and leaves it when + /// last Signatory signs SigningOff, /// Taking votes @@ -114,7 +123,8 @@ pub enum ProposalState { Succeeded, /// Voting on Proposal succeeded and now instructions are being executed - /// Proposal enter this state when first instruction is executed and leaves when the last instruction is executed + /// Proposal enter this state when first instruction is executed and leaves + /// when the last instruction is executed Executing, /// Completed @@ -127,7 +137,8 @@ pub enum ProposalState { Defeated, /// Same as Executing but indicates some instructions failed to execute - /// Proposal can't be transitioned from ExecutingWithErrors to Completed state + /// Proposal can't be transitioned from ExecutingWithErrors to Completed + /// state ExecutingWithErrors, /// The Proposal was vetoed @@ -136,28 +147,33 @@ pub enum ProposalState { /// The type of the vote threshold used to resolve a vote on a Proposal /// -/// Note: In the current version only YesVotePercentage and Disabled thresholds are supported +/// Note: In the current version only YesVotePercentage and Disabled thresholds +/// are supported #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteThreshold { - /// Voting threshold of Yes votes in % required to tip the vote (Approval Quorum) - /// It's the percentage of tokens out of the entire pool of governance tokens eligible to vote - /// Note: If the threshold is below or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as Defeated - /// In other words a '+1 vote' tie breaker is always required to have a successful vote + /// Voting threshold of Yes votes in % required to tip the vote (Approval + /// Quorum) It's the percentage of tokens out of the entire pool of + /// governance tokens eligible to vote Note: If the threshold is below + /// or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always + /// resolved as Defeated In other words a '+1 vote' tie breaker is + /// always required to have a successful vote YesVotePercentage(u8), - /// The minimum number of votes in % out of the entire pool of governance tokens eligible to vote - /// which must be cast for the vote to be valid - /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is required for the vote to succeed - /// Note: Quorum is not implemented in the current version + /// The minimum number of votes in % out of the entire pool of governance + /// tokens eligible to vote which must be cast for the vote to be valid + /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is + /// required for the vote to succeed Note: Quorum is not implemented in + /// the current version QuorumPercentage(u8), - /// Disabled vote threshold indicates the given voting population (community or council) is not allowed to vote - /// on proposals for the given Governance + /// Disabled vote threshold indicates the given voting population (community + /// or council) is not allowed to vote on proposals for the given + /// Governance Disabled, // // Absolute vote threshold expressed in the voting mint units - // It can be implemented once Solana runtime supports accounts resizing to accommodate u64 size extension - // Alternatively we could use the reserved space if it becomes a priority + // It can be implemented once Solana runtime supports accounts resizing to accommodate u64 + // size extension Alternatively we could use the reserved space if it becomes a priority // Absolute(u64) // // Vote threshold which is always accepted @@ -171,8 +187,9 @@ pub enum VoteThreshold { /// Vote tipping means that under some conditions voting will complete early. #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteTipping { - /// Tip when there is no way for another option to win and the vote threshold - /// has been reached. This ignores voters withdrawing their votes. + /// Tip when there is no way for another option to win and the vote + /// threshold has been reached. This ignores voters withdrawing their + /// votes. /// /// Currently only supported for the "yes" option in single choice votes. Strict, @@ -200,33 +217,40 @@ pub enum TransactionExecutionStatus { Error, } -/// Transaction execution flags defining how instructions are executed for a Proposal +/// Transaction execution flags defining how instructions are executed for a +/// Proposal #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum InstructionExecutionFlags { /// No execution flags are specified - /// Instructions can be executed individually, in any order, as soon as they hold_up time expires + /// Instructions can be executed individually, in any order, as soon as they + /// hold_up time expires None, /// Instructions are executed in a specific order /// Note: Ordered execution is not supported in the current version - /// The implementation requires another account type to track deleted instructions + /// The implementation requires another account type to track deleted + /// instructions Ordered, /// Multiple instructions can be executed as a single transaction /// Note: Transactions are not supported in the current version - /// The implementation requires another account type to group instructions within a transaction + /// The implementation requires another account type to group instructions + /// within a transaction UseTransaction, } /// The source of max vote weight used for voting -/// Values below 100% mint supply can be used when the governing token is fully minted but not distributed yet +/// Values below 100% mint supply can be used when the governing token is fully +/// minted but not distributed yet #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum MintMaxVoterWeightSource { - /// Fraction (10^10 precision) of the governing mint supply is used as max vote weight - /// The default is 100% (10^10) to use all available mint supply for voting + /// Fraction (10^10 precision) of the governing mint supply is used as max + /// vote weight The default is 100% (10^10) to use all available mint + /// supply for voting SupplyFraction(u64), - /// Absolute value, irrelevant of the actual mint supply, is used as max voter weight + /// Absolute value, irrelevant of the actual mint supply, is used as max + /// voter weight Absolute(u64), } diff --git a/governance/program/src/state/governance.rs b/governance/program/src/state/governance.rs index e09b2f0f222..1e343462106 100644 --- a/governance/program/src/state/governance.rs +++ b/governance/program/src/state/governance.rs @@ -28,31 +28,37 @@ use { #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceConfig { /// The type of the vote threshold used for community vote - /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported + /// Note: In the current version only YesVotePercentage and Disabled + /// thresholds are supported pub community_vote_threshold: VoteThreshold, - /// Minimum community weight a governance token owner must possess to be able to create a proposal + /// Minimum community weight a governance token owner must possess to be + /// able to create a proposal pub min_community_weight_to_create_proposal: u64, - /// Minimum waiting time in seconds for a transaction to be executed after proposal is voted on + /// Minimum waiting time in seconds for a transaction to be executed after + /// proposal is voted on pub min_transaction_hold_up_time: u32, /// The base voting time in seconds for proposal to be open for voting - /// Voting is unrestricted during the base voting time and any vote types can be cast - /// The base voting time can be extend by optional cool off time when only negative votes (Veto and Deny) are allowed + /// Voting is unrestricted during the base voting time and any vote types + /// can be cast The base voting time can be extend by optional cool off + /// time when only negative votes (Veto and Deny) are allowed pub voting_base_time: u32, /// Conditions under which a Community vote will complete early pub community_vote_tipping: VoteTipping, /// The type of the vote threshold used for council vote - /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported + /// Note: In the current version only YesVotePercentage and Disabled + /// thresholds are supported pub council_vote_threshold: VoteThreshold, /// The threshold for Council Veto votes pub council_veto_vote_threshold: VoteThreshold, - /// Minimum council weight a governance token owner must possess to be able to create a proposal + /// Minimum council weight a governance token owner must possess to be able + /// to create a proposal pub min_council_weight_to_create_proposal: u64, /// Conditions under which a Council vote will complete early @@ -71,28 +77,32 @@ pub struct GovernanceConfig { /// The default number of active proposals exempt from security deposit pub const DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT: u8 = 10; -/// Security deposit is paid when a Proposal is created and can be refunded after voting ends -/// or the Proposals is cancelled +/// Security deposit is paid when a Proposal is created and can be refunded +/// after voting ends or the Proposals is cancelled pub const SECURITY_DEPOSIT_BASE_LAMPORTS: u64 = 100_000_000; // 0.1 SOL /// Governance Account #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceV2 { - /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance + /// Account type. It can be Uninitialized, Governance, ProgramGovernance, + /// TokenGovernance or MintGovernance pub account_type: GovernanceAccountType, /// Governance Realm pub realm: Pubkey, /// Account governed by this Governance and/or PDA identity seed - /// It can be Program account, Mint account, Token account or any other account + /// It can be Program account, Mint account, Token account or any other + /// account /// - /// Note: The account doesn't have to exist. In that case the field is only a PDA seed + /// Note: The account doesn't have to exist. In that case the field is only + /// a PDA seed /// - /// Note: Setting governed_account doesn't give any authority over the governed account - /// The relevant authorities for specific account types must still be transferred to the Governance PDA - /// Ex: mint_authority/freeze_authority for a Mint account - /// or upgrade_authority for a Program account should be transferred to the Governance PDA + /// Note: Setting governed_account doesn't give any authority over the + /// governed account The relevant authorities for specific account types + /// must still be transferred to the Governance PDA Ex: mint_authority/ + /// freeze_authority for a Mint account or upgrade_authority for a + /// Program account should be transferred to the Governance PDA pub governed_account: Pubkey, /// Reserved space for future versions @@ -103,17 +113,21 @@ pub struct GovernanceV2 { /// Reserved space for versions v2 and onwards /// Note 1: V1 accounts must be resized before using this space - /// Note 2: The reserved space should be used from the end to also allow the config to grow if needed + /// Note 2: The reserved space should be used from the end to also allow the + /// config to grow if needed pub reserved_v2: Reserved119, /// The number of required signatories for proposals in the Governance pub required_signatories_count: u8, - /// The number of active proposals where active means Draft, SigningOff or Voting state + /// The number of active proposals where active means Draft, SigningOff or + /// Voting state /// - /// Note: The counter was introduced in program V3 and didn't exist in program V1 & V2 - /// If the program is upgraded from program V1 or V2 while there are any outstanding active proposals - /// the counter won't be accurate until all proposals are transitioned to an inactive final state and the counter reset + /// Note: The counter was introduced in program V3 and didn't exist in + /// program V1 & V2 If the program is upgraded from program V1 or V2 + /// while there are any outstanding active proposals the counter won't + /// be accurate until all proposals are transitioned to an inactive final + /// state and the counter reset pub active_proposal_count: u64, } @@ -154,7 +168,8 @@ pub fn is_governance_v2_account_type(account_type: &GovernanceAccountType) -> bo } } -/// Returns GovernanceV2 type for given GovernanceV1 type or None if the given account type is not GovernanceV1 +/// Returns GovernanceV2 type for given GovernanceV1 type or None if the given +/// account type is not GovernanceV1 pub fn try_get_governance_v2_type_for_v1( account_type: &GovernanceAccountType, ) -> Option { @@ -189,7 +204,8 @@ pub fn try_get_governance_v2_type_for_v1( } } -/// Checks if the given account type is on of the Governance account types of any version +/// Checks if the given account type is on of the Governance account types of +/// any version pub fn is_governance_account_type(account_type: &GovernanceAccountType) -> bool { is_governance_v1_account_type(account_type) || is_governance_v2_account_type(account_type) } @@ -246,15 +262,17 @@ impl GovernanceV2 { if is_governance_v2_account_type(&self.account_type) { borsh::to_writer(writer, &self)? } else if is_governance_v1_account_type(&self.account_type) { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually assessed for GovernanceV1 account backward compatibility impact + // If reserved_v2 is used it must be individually assessed for GovernanceV1 + // account backward compatibility impact if self.reserved_v2 != Reserved119::default() { panic!("Extended data not supported by GovernanceV1") } - // Note: active_proposal_count is not preserved on GovernanceV1 account until it's migrated to GovernanceV2 - // during Proposal creation + // Note: active_proposal_count is not preserved on GovernanceV1 account until + // it's migrated to GovernanceV2 during Proposal creation let governance_data_v1 = GovernanceV1 { account_type: self.account_type, @@ -271,8 +289,10 @@ impl GovernanceV2 { } /// Serializes Governance accounts as GovernanceV2 - /// If the account is GovernanceV1 then it changes its type to GovernanceV2 and resizes account data - /// Note: It supports all the specialized Governance account types (Governance, ProgramGovernance, MintGovernance and TokenGovernance) + /// If the account is GovernanceV1 then it changes its type to GovernanceV2 + /// and resizes account data Note: It supports all the specialized + /// Governance account types (Governance, ProgramGovernance, MintGovernance + /// and TokenGovernance) pub fn serialize_as_governance_v2<'a>( mut self, governance_info: &AccountInfo<'a>, @@ -280,10 +300,12 @@ impl GovernanceV2 { system_info: &AccountInfo<'a>, rent: &Rent, ) -> Result<(), ProgramError> { - // If the Governance account is GovernanceV1 reallocate its size and change type to GovernanceV2 + // If the Governance account is GovernanceV1 reallocate its size and change type + // to GovernanceV2 if let Some(governance_v2_type) = try_get_governance_v2_type_for_v1(&self.account_type) { // Change type to GovernanceV2 - // Note: Only type change is required because the account data was translated to GovernanceV2 during deserialisation + // Note: Only type change is required because the account data was translated to + // GovernanceV2 during deserialisation self.account_type = governance_v2_type; extend_account_size( @@ -298,21 +320,24 @@ impl GovernanceV2 { self.serialize(&mut governance_info.data.borrow_mut()[..]) } - /// Asserts the provided voting population represented by the given governing_token_mint - /// can cast the given vote type on proposals for the Governance + /// Asserts the provided voting population represented by the given + /// governing_token_mint can cast the given vote type on proposals for + /// the Governance pub fn assert_governing_token_mint_can_vote( &self, realm_data: &RealmV2, vote_governing_token_mint: &Pubkey, vote_kind: &VoteKind, ) -> Result<(), ProgramError> { - // resolve_vote_threshold() asserts the vote threshold exists for the given governing_token_mint and is not disabled + // resolve_vote_threshold() asserts the vote threshold exists for the given + // governing_token_mint and is not disabled let _ = self.resolve_vote_threshold(realm_data, vote_governing_token_mint, vote_kind)?; Ok(()) } - /// Resolves VoteThreshold for the given realm, governing token and Vote kind + /// Resolves VoteThreshold for the given realm, governing token and Vote + /// kind pub fn resolve_vote_threshold( &self, realm_data: &RealmV2, @@ -357,14 +382,17 @@ impl GovernanceV2 { Ok(vote_tipping) } - /// Returns the required deposit amount for creating Nth Proposal based on the number of active proposals - /// where N equals to active_proposal_count - deposit_exempt_proposal_count - /// The deposit is not payed unless there are more active Proposal than the exempt amount + /// Returns the required deposit amount for creating Nth Proposal based on + /// the number of active proposals where N equals to + /// active_proposal_count - deposit_exempt_proposal_count The deposit is + /// not payed unless there are more active Proposal than the exempt amount /// - /// Note: The exact deposit payed for Nth Proposal is N*SECURITY_DEPOSIT_BASE_LAMPORTS + min_rent_for(ProposalDeposit) + /// Note: The exact deposit payed for Nth Proposal is + /// N*SECURITY_DEPOSIT_BASE_LAMPORTS + min_rent_for(ProposalDeposit) /// - /// Note: Although the deposit amount payed for Nth proposal is linear the total deposit amount required to create N proposals is sum of arithmetic series - /// Dn = N*r + d*N*(N+1)/2 + /// Note: Although the deposit amount payed for Nth proposal is linear the + /// total deposit amount required to create N proposals is sum of arithmetic + /// series Dn = N*r + d*N*(N+1)/2 // where: // Dn - The total deposit amount required to create N proposals // N = active_proposal_count - deposit_exempt_proposal_count @@ -397,27 +425,36 @@ pub fn get_governance_data( reserved_v2: Reserved119::default(), required_signatories_count: 0, // GovernanceV1 layout doesn't support active_proposal_count - // For any legacy GovernanceV1 account it's not preserved until the account layout is migrated to GovernanceV2 in CreateProposal + // For any legacy GovernanceV1 account it's not preserved until the account layout is + // migrated to GovernanceV2 in CreateProposal active_proposal_count: 0, } } else { get_account_data::(program_id, governance_info)? }; - // In previous versions of spl-gov (< 3) we had config.proposal_cool_off_time:u32 which was unused and always 0 - // In version 3.0.0 proposal_cool_off_time was replaced with council_vote_threshold:VoteThreshold and council_veto_vote_threshold:VoteThreshold - // If we read a legacy account then council_vote_threshold == VoteThreshold::YesVotePercentage(0) + // In previous versions of spl-gov (< 3) we had + // config.proposal_cool_off_time:u32 which was unused and always 0 + // In version 3.0.0 proposal_cool_off_time was replaced with + // council_vote_threshold:VoteThreshold and + // council_veto_vote_threshold:VoteThreshold If we read a legacy account + // then council_vote_threshold == VoteThreshold::YesVotePercentage(0) // - // Note: assert_is_valid_governance_config() prevents setting council_vote_threshold to VoteThreshold::YesVotePercentage(0) - // which gives as guarantee that it is a legacy account layout set with proposal_cool_off_time = 0 + // Note: assert_is_valid_governance_config() prevents setting + // council_vote_threshold to VoteThreshold::YesVotePercentage(0) which gives + // as guarantee that it is a legacy account layout set with + // proposal_cool_off_time = 0 // - // Note: All the settings below are one time config migration from program V1 & V2 account data to V3 + // Note: All the settings below are one time config migration from program V1 & + // V2 account data to V3 if governance_data.config.council_vote_threshold == VoteThreshold::YesVotePercentage(0) { - // Set council_vote_threshold to community_vote_threshold which was used for both council and community thresholds before + // Set council_vote_threshold to community_vote_threshold which was used for + // both council and community thresholds before governance_data.config.council_vote_threshold = governance_data.config.community_vote_threshold.clone(); - // The assumption here is that council should have Veto vote enabled by default and equal to council_vote_threshold + // The assumption here is that council should have Veto vote enabled by default + // and equal to council_vote_threshold governance_data.config.council_veto_vote_threshold = governance_data.config.council_vote_threshold.clone(); @@ -428,7 +465,8 @@ pub fn get_governance_data( // For legacy accounts set the community Veto threshold to Disabled governance_data.config.community_veto_vote_threshold = VoteThreshold::Disabled; - // Reset voting_cool_off_time and deposit_exempt_proposal_count previously used for voting_proposal_count + // Reset voting_cool_off_time and deposit_exempt_proposal_count previously used + // for voting_proposal_count governance_data.config.voting_cool_off_time = 0; governance_data.config.deposit_exempt_proposal_count = DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT; @@ -440,7 +478,8 @@ pub fn get_governance_data( Ok(governance_data) } -/// Deserializes Governance account, checks owner program and asserts governance belongs to the given ream +/// Deserializes Governance account, checks owner program and asserts governance +/// belongs to the given ream pub fn get_governance_data_for_realm( program_id: &Pubkey, governance_info: &AccountInfo, @@ -455,7 +494,8 @@ pub fn get_governance_data_for_realm( Ok(governance_data) } -/// Checks the given account is a governance account and belongs to the given realm +/// Checks the given account is a governance account and belongs to the given +/// realm pub fn assert_governance_for_realm( program_id: &Pubkey, governance_info: &AccountInfo, @@ -471,7 +511,8 @@ pub fn get_program_governance_address_seeds<'a>( governed_program: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'program-governance' prefix ensures uniqueness of the PDA - // Note: Only the current program upgrade authority can create an account with this PDA using CreateProgramGovernance instruction + // Note: Only the current program upgrade authority can create an account with + // this PDA using CreateProgramGovernance instruction [ b"program-governance", realm.as_ref(), @@ -498,7 +539,8 @@ pub fn get_mint_governance_address_seeds<'a>( governed_mint: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'mint-governance' prefix ensures uniqueness of the PDA - // Note: Only the current mint authority can create an account with this PDA using CreateMintGovernance instruction + // Note: Only the current mint authority can create an account with this PDA + // using CreateMintGovernance instruction [b"mint-governance", realm.as_ref(), governed_mint.as_ref()] } @@ -521,7 +563,8 @@ pub fn get_token_governance_address_seeds<'a>( governed_token: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'token-governance' prefix ensures uniqueness of the PDA - // Note: Only the current token account owner can create an account with this PDA using CreateTokenGovernance instruction + // Note: Only the current token account owner can create an account with this + // PDA using CreateTokenGovernance instruction [b"token-governance", realm.as_ref(), governed_token.as_ref()] } @@ -563,7 +606,8 @@ pub fn get_governance_address<'a>( .0 } -/// Checks whether the Governance account exists, is initialized and owned by the Governance program +/// Checks whether the Governance account exists, is initialized and owned by +/// the Governance program pub fn assert_is_valid_governance( program_id: &Pubkey, governance_info: &AccountInfo, @@ -594,15 +638,16 @@ pub fn assert_is_valid_governance_config( assert_is_valid_vote_threshold(&governance_config.council_vote_threshold)?; assert_is_valid_vote_threshold(&governance_config.council_veto_vote_threshold)?; - // Setting both thresholds to Disabled is not allowed, however we might reconsider it as - // a way to disable Governance permanently + // Setting both thresholds to Disabled is not allowed, however we might + // reconsider it as a way to disable Governance permanently if governance_config.community_vote_threshold == VoteThreshold::Disabled && governance_config.council_vote_threshold == VoteThreshold::Disabled { return Err(GovernanceError::AtLeastOneVoteThresholdRequired.into()); } - // Make u8::MAX invalid value in case we would like to use the magic number as Disabled value in the future + // Make u8::MAX invalid value in case we would like to use the magic number as + // Disabled value in the future if governance_config.deposit_exempt_proposal_count == u8::MAX { return Err(GovernanceError::InvalidDepositExemptProposalCount.into()); } @@ -781,7 +826,8 @@ mod test { governance_legacy_data.config.community_vote_threshold = VoteThreshold::YesVotePercentage(60); - // council_vote_threshold == YesVotePercentage(0) indicates legacy account from V1 & V2 program versions + // council_vote_threshold == YesVotePercentage(0) indicates legacy account from + // V1 & V2 program versions governance_legacy_data.config.council_vote_threshold = VoteThreshold::YesVotePercentage(0); governance_legacy_data.config.council_veto_vote_threshold = diff --git a/governance/program/src/state/legacy.rs b/governance/program/src/state/legacy.rs index e38c24d1ebe..d2c65979596 100644 --- a/governance/program/src/state/legacy.rs +++ b/governance/program/src/state/legacy.rs @@ -39,8 +39,9 @@ pub struct RealmV1 { /// and we have preserve it for V1 serialization roundtrip pub voting_proposal_count: u16, - /// Realm authority. The authority must sign transactions which update the realm config - /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals + /// Realm authority. The authority must sign transactions which update the + /// realm config The authority should be transferred to Realm Governance + /// to make the Realm self governed through proposals pub authority: Option, /// Governance Realm name @@ -66,8 +67,8 @@ pub struct TokenOwnerRecordV1 { /// Governing Token Mint the TokenOwnerRecord holds deposit for pub governing_token_mint: Pubkey, - /// The owner (either single or multisig) of the deposited governing SPL Tokens - /// This is who can authorize a withdrawal of the tokens + /// The owner (either single or multisig) of the deposited governing SPL + /// Tokens This is who can authorize a withdrawal of the tokens pub governing_token_owner: Pubkey, /// The amount of governing tokens deposited into the Realm @@ -75,13 +76,15 @@ pub struct TokenOwnerRecordV1 { pub governing_token_deposit_amount: u64, /// The number of votes cast by TokenOwner but not relinquished yet - /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state + /// Every time a vote is cast this number is increased and it's always + /// decreased when relinquishing a vote regardless of the vote state pub unrelinquished_votes_count: u64, /// The number of outstanding proposals the TokenOwner currently owns /// The count is increased when TokenOwner creates a proposal - /// and decreased once it's either voted on (Succeeded or Defeated) or Cancelled - /// By default it's restricted to 10 outstanding Proposal per token owner + /// and decreased once it's either voted on (Succeeded or Defeated) or + /// Cancelled By default it's restricted to 10 outstanding Proposal per + /// token owner pub outstanding_proposal_count: u8, /// Version introduced in program V3 @@ -90,8 +93,9 @@ pub struct TokenOwnerRecordV1 { /// Reserved space for future versions pub reserved: [u8; 6], - /// A single account that is allowed to operate governance with the deposited governing tokens - /// It can be delegated to by the governing_token_owner or current governance_delegate + /// A single account that is allowed to operate governance with the + /// deposited governing tokens It can be delegated to by the + /// governing_token_owner or current governance_delegate pub governance_delegate: Option, } @@ -104,21 +108,25 @@ impl IsInitialized for TokenOwnerRecordV1 { /// Governance Account #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceV1 { - /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance + /// Account type. It can be Uninitialized, Governance, ProgramGovernance, + /// TokenGovernance or MintGovernance pub account_type: GovernanceAccountType, /// Governance Realm pub realm: Pubkey, /// Account governed by this Governance and/or PDA identity seed - /// It can be Program account, Mint account, Token account or any other account + /// It can be Program account, Mint account, Token account or any other + /// account /// - /// Note: The account doesn't have to exist. In that case the field is only a PDA seed + /// Note: The account doesn't have to exist. In that case the field is only + /// a PDA seed /// - /// Note: Setting governed_account doesn't give any authority over the governed account - /// The relevant authorities for specific account types must still be transferred to the Governance PDA - /// Ex: mint_authority/freeze_authority for a Mint account - /// or upgrade_authority for a Program account should be transferred to the Governance PDA + /// Note: Setting governed_account doesn't give any authority over the + /// governed account The relevant authorities for specific account types + /// must still be transferred to the Governance PDA Ex: mint_authority/ + /// freeze_authority for a Mint account or upgrade_authority for a + /// Program account should be transferred to the Governance PDA pub governed_account: Pubkey, /// Running count of proposals @@ -175,13 +183,15 @@ pub struct ProposalV1 { pub governance: Pubkey, /// Indicates which Governing Token is used to vote on the Proposal - /// Whether the general Community token owners or the Council tokens owners vote on this Proposal + /// Whether the general Community token owners or the Council tokens owners + /// vote on this Proposal pub governing_token_mint: Pubkey, /// Current proposal state pub state: ProposalState, - /// The TokenOwnerRecord representing the user who created and owns this Proposal + /// The TokenOwnerRecord representing the user who created and owns this + /// Proposal pub token_owner_record: Pubkey, /// The number of signatories assigned to the Proposal @@ -215,7 +225,8 @@ pub struct ProposalV1 { pub voting_at: Option, /// When the Proposal began voting as Slot - /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights + /// Note: The slot is not currently used but the exact slot is going to be + /// required to support snapshot based vote weights pub voting_at_slot: Option, /// When the Proposal ended voting and entered either Succeeded or Defeated @@ -224,21 +235,24 @@ pub struct ProposalV1 { /// When the Proposal entered Executing state pub executing_at: Option, - /// When the Proposal entered final state Completed or Cancelled and was closed + /// When the Proposal entered final state Completed or Cancelled and was + /// closed pub closed_at: Option, /// Instruction execution flag for ordered and transactional instructions /// Note: This field is not used in the current version pub execution_flags: InstructionExecutionFlags, - /// The max vote weight for the Governing Token mint at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed + /// The max vote weight for the Governing Token mint at the time Proposal + /// was decided It's used to show correct vote results for historical + /// proposals in cases when the mint supply or max weight source changed /// after vote was completed. pub max_vote_weight: Option, /// The vote threshold percentage at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the threshold - /// was changed for governance config after vote was completed. + /// It's used to show correct vote results for historical proposals in cases + /// when the threshold was changed for governance config after vote was + /// completed. pub vote_threshold: Option, /// Proposal name @@ -288,12 +302,14 @@ pub struct ProposalInstructionV1 { /// Unique instruction index within it's parent Proposal pub instruction_index: u16, - /// Minimum waiting time in seconds for the instruction to be executed once proposal is voted on + /// Minimum waiting time in seconds for the instruction to be executed once + /// proposal is voted on pub hold_up_time: u32, /// Instruction to execute /// The instruction will be signed by Governance PDA the Proposal belongs to - // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA + // For example for ProgramGovernance the instruction to upgrade program will be signed by + // ProgramGovernance PDA pub instruction: InstructionData, /// Executed at flag @@ -329,7 +345,8 @@ pub struct VoteRecordV1 { pub proposal: Pubkey, /// The user who casted this vote - /// This is the Governing Token Owner who deposited governing tokens into the Realm + /// This is the Governing Token Owner who deposited governing tokens into + /// the Realm pub governing_token_owner: Pubkey, /// Indicates whether the vote was relinquished by voter diff --git a/governance/program/src/state/native_treasury.rs b/governance/program/src/state/native_treasury.rs index c72ae3b1c1f..45be0e79bc4 100644 --- a/governance/program/src/state/native_treasury.rs +++ b/governance/program/src/state/native_treasury.rs @@ -7,7 +7,8 @@ use { }; /// Treasury account -/// The account has no data and can be used as a payer for instruction signed by Governance PDAs or as a native SOL treasury +/// The account has no data and can be used as a payer for instruction signed by +/// Governance PDAs or as a native SOL treasury #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct NativeTreasury {} diff --git a/governance/program/src/state/program_metadata.rs b/governance/program/src/state/program_metadata.rs index 6906c003690..1034c6544bd 100644 --- a/governance/program/src/state/program_metadata.rs +++ b/governance/program/src/state/program_metadata.rs @@ -10,7 +10,8 @@ use { spl_governance_tools::account::{get_account_data, AccountMaxSize}, }; -/// Program metadata account. It stores information about the particular SPL-Governance program instance +/// Program metadata account. It stores information about the particular +/// SPL-Governance program instance #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProgramMetadata { /// Governance account type diff --git a/governance/program/src/state/proposal.rs b/governance/program/src/state/proposal.rs index e464b9e0eaa..82ca5780ef6 100644 --- a/governance/program/src/state/proposal.rs +++ b/governance/program/src/state/proposal.rs @@ -74,8 +74,9 @@ pub struct ProposalOption { pub enum VoteType { /// Single choice vote with mutually exclusive choices /// In the SingeChoice mode there can ever be a single winner - /// If multiple options score the same highest vote then the Proposal is not resolved and considered as Failed - /// Note: Yes/No vote is a single choice (Yes) vote with the deny option (No) + /// If multiple options score the same highest vote then the Proposal is not + /// resolved and considered as Failed Note: Yes/No vote is a single + /// choice (Yes) vote with the deny option (No) SingleChoice, /// Multiple options can be selected with up to max_voter_options per voter @@ -89,23 +90,26 @@ pub enum VoteType { /// The min number of options a voter must choose /// - /// Note: In the current version the limit is not supported and not enforced - /// and must always be set to 1 + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to 1 #[allow(dead_code)] min_voter_options: u8, /// The max number of options a voter can choose /// - /// Note: In the current version the limit is not supported and not enforced - /// and must always be set to the number of available options + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to the number of available + /// options #[allow(dead_code)] max_voter_options: u8, /// The max number of wining options - /// For executable proposals it limits how many options can be executed for a Proposal + /// For executable proposals it limits how many options can be executed + /// for a Proposal /// - /// Note: In the current version the limit is not supported and not enforced - /// and must always be set to the number of available options + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to the number of available + /// options #[allow(dead_code)] max_winning_options: u8, }, @@ -114,11 +118,13 @@ pub enum VoteType { /// Type of MultiChoice. #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum MultiChoiceType { - /// Multiple options can be approved with full weight allocated to each approved option + /// Multiple options can be approved with full weight allocated to each + /// approved option FullWeight, - /// Multiple options can be approved with weight allocated proportionally to the percentage of the total weight - /// The full weight has to be voted among the approved options, i.e., 100% of the weight has to be allocated + /// Multiple options can be approved with weight allocated proportionally to + /// the percentage of the total weight The full weight has to be voted + /// among the approved options, i.e., 100% of the weight has to be allocated Weighted, } @@ -132,14 +138,16 @@ pub struct ProposalV2 { pub governance: Pubkey, /// Indicates which Governing Token is used to vote on the Proposal - /// Whether the general Community token owners or the Council tokens owners vote on this Proposal + /// Whether the general Community token owners or the Council tokens owners + /// vote on this Proposal pub governing_token_mint: Pubkey, /// Current proposal state pub state: ProposalState, // TODO: add state_at timestamp to have single field to filter recent proposals in the UI - /// The TokenOwnerRecord representing the user who created and owns this Proposal + /// The TokenOwnerRecord representing the user who created and owns this + /// Proposal pub token_owner_record: Pubkey, /// The number of signatories assigned to the Proposal @@ -157,11 +165,12 @@ pub struct ProposalV2 { /// The total weight of the Proposal rejection votes /// If the proposal has no deny option then the weight is None /// - /// Only proposals with the deny option can have executable instructions attached to them - /// Without the deny option a proposal is only non executable survey + /// Only proposals with the deny option can have executable instructions + /// attached to them Without the deny option a proposal is only non + /// executable survey /// - /// The deny options is also used for off-chain and/or manually executable proposal to make them binding - /// as opposed to survey only proposals + /// The deny options is also used for off-chain and/or manually executable + /// proposal to make them binding as opposed to survey only proposals pub deny_vote_weight: Option, /// Reserved space for future versions @@ -172,8 +181,9 @@ pub struct ProposalV2 { /// Note: Abstain is not supported in the current version pub abstain_vote_weight: Option, - /// Optional start time if the Proposal should not enter voting state immediately after being signed off - /// Note: start_at is not supported in the current version + /// Optional start time if the Proposal should not enter voting state + /// immediately after being signed off Note: start_at is not supported + /// in the current version pub start_voting_at: Option, /// When the Proposal was created and entered Draft state @@ -186,7 +196,8 @@ pub struct ProposalV2 { pub voting_at: Option, /// When the Proposal began voting as Slot - /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights + /// Note: The slot is not currently used but the exact slot is going to be + /// required to support snapshot based vote weights pub voting_at_slot: Option, /// When the Proposal ended voting and entered either Succeeded or Defeated @@ -195,26 +206,30 @@ pub struct ProposalV2 { /// When the Proposal entered Executing state pub executing_at: Option, - /// When the Proposal entered final state Completed or Cancelled and was closed + /// When the Proposal entered final state Completed or Cancelled and was + /// closed pub closed_at: Option, /// Instruction execution flag for ordered and transactional instructions /// Note: This field is not used in the current version pub execution_flags: InstructionExecutionFlags, - /// The max vote weight for the Governing Token mint at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed + /// The max vote weight for the Governing Token mint at the time Proposal + /// was decided It's used to show correct vote results for historical + /// proposals in cases when the mint supply or max weight source changed /// after vote was completed. pub max_vote_weight: Option, - /// Max voting time for the proposal if different from parent Governance (only higher value possible) - /// Note: This field is not used in the current version + /// Max voting time for the proposal if different from parent Governance + /// (only higher value possible) Note: This field is not used in the + /// current version pub max_voting_time: Option, /// The vote threshold at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the threshold - /// was changed for governance config after vote was completed. - /// TODO: Use this field to override the threshold from parent Governance (only higher value possible) + /// It's used to show correct vote results for historical proposals in cases + /// when the threshold was changed for governance config after vote was + /// completed. TODO: Use this field to override the threshold from + /// parent Governance (only higher value possible) pub vote_threshold: Option, /// Reserved space for future versions @@ -244,7 +259,8 @@ impl IsInitialized for ProposalV2 { } impl ProposalV2 { - /// Checks if Signatories can be edited (added or removed) for the Proposal in the given state + /// Checks if Signatories can be edited (added or removed) for the Proposal + /// in the given state pub fn assert_can_edit_signatories(&self) -> Result<(), ProgramError> { self.assert_is_draft_state() .map_err(|_| GovernanceError::InvalidStateCannotEditSignatories.into()) @@ -316,8 +332,9 @@ impl ProposalV2 { match vote { Vote::Approve(_) | Vote::Abstain => { - // Once the base voting time passes and we are in the voting cool off time approving votes are no longer accepted - // Abstain is considered as positive vote because when attendance quorum is used it can tip the scales + // Once the base voting time passes and we are in the voting cool off time + // approving votes are no longer accepted Abstain is considered + // as positive vote because when attendance quorum is used it can tip the scales if self.has_voting_base_time_ended(config, current_unix_timestamp) { Err(GovernanceError::VoteNotAllowedInCoolOffTime.into()) } else { @@ -329,7 +346,8 @@ impl ProposalV2 { } } - /// Checks if proposal has concluded so that security deposit is no longer needed + /// Checks if proposal has concluded so that security deposit is no longer + /// needed pub fn assert_can_refund_proposal_deposit(&self) -> Result<(), ProgramError> { match self.state { ProposalState::Succeeded @@ -345,7 +363,8 @@ impl ProposalV2 { } } - /// Expected base vote end time determined by the configured base_voting_time and actual voting start time + /// Expected base vote end time determined by the configured + /// base_voting_time and actual voting start time pub fn voting_base_time_end(&self, config: &GovernanceConfig) -> UnixTimestamp { self.voting_at .unwrap() @@ -363,7 +382,9 @@ impl ProposalV2 { self.voting_base_time_end(config) < current_unix_timestamp } - /// Expected max vote end time determined by the configured base_voting_time, optional voting_cool_off_time and actual voting start time + /// Expected max vote end time determined by the configured + /// base_voting_time, optional voting_cool_off_time and actual voting start + /// time pub fn voting_max_time_end(&self, config: &GovernanceConfig) -> UnixTimestamp { self.voting_base_time_end(config) .checked_add(config.voting_cool_off_time as i64) @@ -389,7 +410,8 @@ impl ProposalV2 { self.assert_is_voting_state() .map_err(|_| GovernanceError::InvalidStateCannotFinalize)?; - // We can only finalize the vote after the configured max_voting_time has expired and vote time ended + // We can only finalize the vote after the configured max_voting_time has + // expired and vote time ended if !self.has_voting_max_time_ended(config, current_unix_timestamp) { return Err(GovernanceError::CannotFinalizeVotingInProgress.into()); } @@ -397,8 +419,9 @@ impl ProposalV2 { Ok(()) } - /// Finalizes vote by moving it to final state Succeeded or Defeated if max_voting_time has passed - /// If Proposal is still within max_voting_time period then error is returned + /// Finalizes vote by moving it to final state Succeeded or Defeated if + /// max_voting_time has passed If Proposal is still within + /// max_voting_time period then error is returned pub fn finalize_vote( &mut self, max_voter_weight: u64, @@ -429,16 +452,19 @@ impl ProposalV2 { let min_vote_threshold_weight = get_min_vote_threshold_weight(vote_threshold, max_vote_weight).unwrap(); - // If the proposal has a reject option then any other option must beat it regardless of the configured min_vote_threshold_weight + // If the proposal has a reject option then any other option must beat it + // regardless of the configured min_vote_threshold_weight let deny_vote_weight = self.deny_vote_weight.unwrap_or(0); let mut best_succeeded_option_weight = 0; let mut best_succeeded_option_count = 0u16; for option in self.options.iter_mut() { - // Any positive vote (Yes) must be equal or above the required min_vote_threshold_weight and higher than the reject option vote (No) - // The same number of positive (Yes) and rejecting (No) votes is a tie and resolved as Defeated - // In other words +1 vote as a tie breaker is required to succeed for the positive option vote + // Any positive vote (Yes) must be equal or above the required + // min_vote_threshold_weight and higher than the reject option vote (No) + // The same number of positive (Yes) and rejecting (No) votes is a tie and + // resolved as Defeated In other words +1 vote as a tie breaker is + // required to succeed for the positive option vote if option.vote_weight >= min_vote_threshold_weight && option.vote_weight > deny_vote_weight { @@ -461,20 +487,23 @@ impl ProposalV2 { } let mut final_state = if best_succeeded_option_count == 0 { - // If none of the individual options succeeded then the proposal as a whole is defeated + // If none of the individual options succeeded then the proposal as a whole is + // defeated ProposalState::Defeated } else { match &self.vote_type { VoteType::SingleChoice => { let proposal_state = if best_succeeded_option_count > 1 { - // If there is more than one winning option then the single choice proposal is considered as defeated + // If there is more than one winning option then the single choice proposal + // is considered as defeated best_succeeded_option_weight = u64::MAX; // no winning option ProposalState::Defeated } else { ProposalState::Succeeded }; - // Coerce options vote results based on the winning score (best_succeeded_vote_weight) + // Coerce options vote results based on the winning score + // (best_succeeded_vote_weight) for option in self.options.iter_mut() { option.vote_result = if option.vote_weight == best_succeeded_option_weight { OptionVoteResult::Succeeded @@ -491,18 +520,23 @@ impl ProposalV2 { max_winning_options: _, min_voter_options: _, } => { - // If any option succeeded for multi choice then the proposal as a whole succeeded as well + // If any option succeeded for multi choice then the proposal as a whole + // succeeded as well ProposalState::Succeeded } } }; - // None executable proposal is just a survey and is considered Completed once the vote ends and no more actions are available - // There is no overall Success or Failure status for the Proposal however individual options still have their own status + // None executable proposal is just a survey and is considered Completed once + // the vote ends and no more actions are available There is no overall + // Success or Failure status for the Proposal however individual options still + // have their own status // - // Note: An off-chain/manually executable Proposal has no instructions but it still must have the deny vote enabled to be binding - // In such a case, if successful, the Proposal vote ends in Succeeded state and it must be manually transitioned to Completed state - // by the Proposal owner once the external actions are executed + // Note: An off-chain/manually executable Proposal has no instructions but it + // still must have the deny vote enabled to be binding In such a case, + // if successful, the Proposal vote ends in Succeeded state and it must be + // manually transitioned to Completed state by the Proposal owner once + // the external actions are executed if self.deny_vote_weight.is_none() { final_state = ProposalState::Completed; } @@ -538,8 +572,9 @@ impl ProposalV2 { MintMaxVoterWeightSource::Absolute(value) => value, }; - // When the fraction or absolute value is used it's possible we can go over the calculated max_vote_weight - // and we have to adjust it in case more votes have been cast + // When the fraction or absolute value is used it's possible we can go over the + // calculated max_vote_weight and we have to adjust it in case more + // votes have been cast Ok(self.coerce_max_voter_weight(max_voter_weight, vote_kind)) } @@ -562,7 +597,8 @@ impl ProposalV2 { max_voter_weight.max(total_vote_weight) } - /// Resolves max voter weight using either 1) voting governing_token_mint supply or 2) max voter weight if configured for the token mint + /// Resolves max voter weight using either 1) voting governing_token_mint + /// supply or 2) max voter weight if configured for the token mint #[allow(clippy::too_many_arguments)] pub fn resolve_max_voter_weight( &mut self, @@ -573,7 +609,8 @@ impl ProposalV2 { vote_governing_token_mint_info: &AccountInfo, vote_kind: &VoteKind, ) -> Result { - // if the Realm is configured to use max voter weight for the given voting governing_token_mint then use the externally provided max_voter_weight + // if the Realm is configured to use max voter weight for the given voting + // governing_token_mint then use the externally provided max_voter_weight // instead of the supply based max if let Some(max_voter_weight_addin) = realm_config_data .get_token_config(realm_data, vote_governing_token_mint_info.key)? @@ -591,8 +628,9 @@ impl ProposalV2 { assert_is_valid_max_voter_weight(&max_voter_weight_record_data)?; - // When the max voter weight addin is used it's possible it can be inaccurate and we can have more votes then the max provided by the addin - // and we have to adjust it to whatever result is higher + // When the max voter weight addin is used it's possible it can be inaccurate + // and we can have more votes then the max provided by the addin and + // we have to adjust it to whatever result is higher return Ok(self.coerce_max_voter_weight( max_voter_weight_record_data.max_voter_weight, vote_kind, @@ -612,8 +650,9 @@ impl ProposalV2 { Ok(max_voter_weight) } - /// Checks if vote can be tipped and automatically transitioned to Succeeded or Defeated state - /// If the conditions are met the state is updated accordingly + /// Checks if vote can be tipped and automatically transitioned to Succeeded + /// or Defeated state If the conditions are met the state is updated + /// accordingly pub fn try_tip_vote( &mut self, max_voter_weight: u64, @@ -642,8 +681,9 @@ impl ProposalV2 { } } - /// Checks if vote can be tipped and automatically transitioned to Succeeded, Defeated or Vetoed state - /// If yes then Some(ProposalState) is returned and None otherwise + /// Checks if vote can be tipped and automatically transitioned to + /// Succeeded, Defeated or Vetoed state If yes then Some(ProposalState) + /// is returned and None otherwise pub fn try_get_tipped_vote_state( &mut self, max_voter_weight: u64, @@ -664,17 +704,20 @@ impl ProposalV2 { } } - /// Checks if Electorate vote can be tipped and automatically transitioned to Succeeded or Defeated state - /// If yes then Some(ProposalState) is returned and None otherwise + /// Checks if Electorate vote can be tipped and automatically transitioned + /// to Succeeded or Defeated state If yes then Some(ProposalState) is + /// returned and None otherwise fn try_get_tipped_electorate_vote_state( &mut self, max_voter_weight: u64, vote_tipping: &VoteTipping, min_vote_threshold_weight: u64, ) -> Option { - // Vote tipping is currently supported for SingleChoice votes with single Yes and No (rejection) options only - // Note: Tipping for multiple options (single choice and multiple choices) should be possible but it requires a great deal of considerations - // and I decided to fight it another day + // Vote tipping is currently supported for SingleChoice votes with single Yes + // and No (rejection) options only Note: Tipping for multiple options + // (single choice and multiple choices) should be possible but it requires a + // great deal of considerations and I decided to fight it another + // day if self.vote_type != VoteType::SingleChoice // Tipping should not be allowed for opinion only proposals (surveys without rejection) to allow everybody's voice to be heard || self.deny_vote_weight.is_none() @@ -730,9 +773,11 @@ impl ProposalV2 { min_vote_threshold_weight: u64, ) -> Option { // Veto vote tips as soon as the required threshold is reached - // It's irrespectively of vote_tipping config because the outcome of the Proposal can't change any longer after being vetoed + // It's irrespectively of vote_tipping config because the outcome of the + // Proposal can't change any longer after being vetoed if self.veto_vote_weight >= min_vote_threshold_weight { - // Note: Since we don't tip multi option votes all options vote_result would remain as None + // Note: Since we don't tip multi option votes all options vote_result would + // remain as None Some(ProposalState::Vetoed) } else { None @@ -748,8 +793,9 @@ impl ProposalV2 { match self.state { ProposalState::Draft | ProposalState::SigningOff => Ok(()), ProposalState::Voting => { - // Note: If there is no tipping point the proposal can be still in Voting state but already past the configured max_voting_time - // In that case we treat the proposal as finalized and it's no longer allowed to be canceled + // Note: If there is no tipping point the proposal can be still in Voting state + // but already past the configured max_voting_time In that case + // we treat the proposal as finalized and it's no longer allowed to be canceled if self.has_voting_max_time_ended(config, current_unix_timestamp) { return Err(GovernanceError::ProposalVotingTimeExpired.into()); } @@ -767,14 +813,16 @@ impl ProposalV2 { } } - /// Checks if Instructions can be edited (inserted or removed) for the Proposal in the given state - /// It also asserts whether the Proposal is executable (has the reject option) + /// Checks if Instructions can be edited (inserted or removed) for the + /// Proposal in the given state It also asserts whether the Proposal is + /// executable (has the reject option) pub fn assert_can_edit_instructions(&self) -> Result<(), ProgramError> { if self.assert_is_draft_state().is_err() { return Err(GovernanceError::InvalidStateCannotEditTransactions.into()); } - // For security purposes only proposals with the reject option can have executable instructions + // For security purposes only proposals with the reject option can have + // executable instructions if self.deny_vote_weight.is_none() { return Err(GovernanceError::ProposalIsNotExecutable.into()); } @@ -782,7 +830,8 @@ impl ProposalV2 { Ok(()) } - /// Checks if Instructions can be executed for the Proposal in the given state + /// Checks if Instructions can be executed for the Proposal in the given + /// state pub fn assert_can_execute_transaction( &self, proposal_transaction_data: &ProposalTransactionV2, @@ -826,7 +875,8 @@ impl ProposalV2 { Ok(()) } - /// Checks if the instruction can be flagged with error for the Proposal in the given state + /// Checks if the instruction can be flagged with error for the Proposal in + /// the given state pub fn assert_can_flag_transaction_error( &self, proposal_transaction_data: &ProposalTransactionV2, @@ -842,7 +892,8 @@ impl ProposalV2 { Ok(()) } - /// Checks if Proposal with off-chain/manual actions can be transitioned to Completed + /// Checks if Proposal with off-chain/manual actions can be transitioned to + /// Completed pub fn assert_can_complete(&self) -> Result<(), ProgramError> { // Proposal vote must be successful if self.state != ProposalState::Succeeded { @@ -883,8 +934,9 @@ impl ProposalV2 { max_voter_options: _, max_winning_options: _, } => { - // Calculate the total percentage for all choices for weighted choice vote - // The total must add up to exactly 100% + // Calculate the total percentage for all choices for weighted + // choice vote The total must add up + // to exactly 100% total_choice_weight_percentage = total_choice_weight_percentage .checked_add(choice.weight_percentage) .ok_or(GovernanceError::TotalVoteWeightMustBe100Percent)?; @@ -950,7 +1002,8 @@ impl ProposalV2 { if self.account_type == GovernanceAccountType::ProposalV2 { borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::ProposalV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format if self.abstain_vote_weight.is_some() { panic!("ProposalV1 doesn't support Abstain vote") @@ -1099,7 +1152,8 @@ pub fn get_proposal_data( get_account_data::(program_id, proposal_info) } -/// Deserializes Proposal and validates it belongs to the given Governance and governing_token_mint +/// Deserializes Proposal and validates it belongs to the given Governance and +/// governing_token_mint pub fn get_proposal_data_for_governance_and_governing_mint( program_id: &Pubkey, proposal_info: &AccountInfo, @@ -2137,7 +2191,8 @@ mod test { // Assert assert_eq!(proposal.state, ProposalState::Succeeded); - assert_eq!(proposal.max_vote_weight, Some(130)); // Deny Vote 10 + Approve Vote 120 + assert_eq!(proposal.max_vote_weight, Some(130)); // Deny Vote 10 + + // Approve Vote 120 } #[test] diff --git a/governance/program/src/state/proposal_deposit.rs b/governance/program/src/state/proposal_deposit.rs index 06d0a9b2e61..76126ff639a 100644 --- a/governance/program/src/state/proposal_deposit.rs +++ b/governance/program/src/state/proposal_deposit.rs @@ -64,7 +64,8 @@ pub fn get_proposal_deposit_address( .0 } -/// Deserializes ProposalDeposit account and checks owner program and account type +/// Deserializes ProposalDeposit account and checks owner program and account +/// type pub fn get_proposal_deposit_data( program_id: &Pubkey, proposal_deposit_info: &AccountInfo, diff --git a/governance/program/src/state/proposal_transaction.rs b/governance/program/src/state/proposal_transaction.rs index c0f049a575b..f2ae26ecb67 100644 --- a/governance/program/src/state/proposal_transaction.rs +++ b/governance/program/src/state/proposal_transaction.rs @@ -22,7 +22,8 @@ use { spl_governance_tools::account::{get_account_data, get_account_type, AccountMaxSize}, }; -/// InstructionData wrapper. It can be removed once Borsh serialization for Instruction is supported in the SDK +/// InstructionData wrapper. It can be removed once Borsh serialization for +/// Instruction is supported in the SDK #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct InstructionData { /// Pubkey of the instruction processor that executes this instruction @@ -38,7 +39,8 @@ pub struct InstructionData { pub struct AccountMetaData { /// An account's public key pub pubkey: Pubkey, - /// True if an Instruction requires a Transaction signature matching `pubkey`. + /// True if an Instruction requires a Transaction signature matching + /// `pubkey`. pub is_signer: bool, /// True if the `pubkey` can be loaded as a read-write account. pub is_writable: bool, @@ -95,13 +97,15 @@ pub struct ProposalTransactionV2 { /// Unique transaction index within it's parent Proposal pub transaction_index: u16, - /// Minimum waiting time in seconds for the instruction to be executed once proposal is voted on + /// Minimum waiting time in seconds for the instruction to be executed once + /// proposal is voted on pub hold_up_time: u32, /// Instructions to execute - /// The instructions will be signed by Governance PDA the Proposal belongs to - // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA - // All instructions will be executed within a single transaction + /// The instructions will be signed by Governance PDA the Proposal belongs + /// to + // For example for ProgramGovernance the instruction to upgrade program will be signed by + // ProgramGovernance PDA All instructions will be executed within a single transaction pub instructions: Vec, /// Executed at flag @@ -143,9 +147,11 @@ impl ProposalTransactionV2 { panic!("Multiple instructions are not supported by ProposalInstructionV1") }; - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by ProposalInstructionV1") } @@ -228,7 +234,8 @@ pub fn get_proposal_transaction_data( get_account_data::(program_id, proposal_transaction_info) } -/// Deserializes and returns ProposalTransaction account and checks it belongs to the given Proposal +/// Deserializes and returns ProposalTransaction account and checks it belongs +/// to the given Proposal pub fn get_proposal_transaction_data_for_proposal( program_id: &Pubkey, proposal_transaction_info: &AccountInfo, diff --git a/governance/program/src/state/realm.rs b/governance/program/src/state/realm.rs index 86f368676e0..a389ae8304e 100644 --- a/governance/program/src/state/realm.rs +++ b/governance/program/src/state/realm.rs @@ -49,12 +49,14 @@ pub struct RealmConfigArgs { /// Realm Config instruction args #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] pub struct GoverningTokenConfigArgs { - /// Indicates whether an external addin program should be used to provide voters weights - /// If yes then the voters weight program account must be passed to the instruction + /// Indicates whether an external addin program should be used to provide + /// voters weights If yes then the voters weight program account must be + /// passed to the instruction pub use_voter_weight_addin: bool, - /// Indicates whether an external addin program should be used to provide max voters weight for the token - /// If yes then the max voter weight program account must be passed to the instruction + /// Indicates whether an external addin program should be used to provide + /// max voters weight for the token If yes then the max voter weight + /// program account must be passed to the instruction pub use_max_voter_weight_addin: bool, /// Governing token type defines how the token is used for governance @@ -64,12 +66,12 @@ pub struct GoverningTokenConfigArgs { /// Realm Config instruction args with account parameters #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] pub struct GoverningTokenConfigAccountArgs { - /// Specifies an external plugin program which should be used to provide voters weights - /// for the given governing token + /// Specifies an external plugin program which should be used to provide + /// voters weights for the given governing token pub voter_weight_addin: Option, - /// Specifies an external an external plugin program should be used to provide max voters weight - /// for the given governing token + /// Specifies an external an external plugin program should be used to + /// provide max voters weight for the given governing token pub max_voter_weight_addin: Option, /// Governing token type defines how the token is used for governance power @@ -80,12 +82,15 @@ pub struct GoverningTokenConfigAccountArgs { #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum SetRealmAuthorityAction { /// Sets realm authority without any checks - /// Uncheck option allows to set the realm authority to non governance accounts + /// Uncheck option allows to set the realm authority to non governance + /// accounts SetUnchecked, - /// Sets realm authority and checks the new new authority is one of the realm's governances - // Note: This is not a security feature because governance creation is only gated with min_community_weight_to_create_governance - // The check is done to prevent scenarios where the authority could be accidentally set to a wrong or none existing account + /// Sets realm authority and checks the new new authority is one of the + /// realm's governances + // Note: This is not a security feature because governance creation is only gated with + // min_community_weight_to_create_governance The check is done to prevent scenarios + // where the authority could be accidentally set to a wrong or none existing account SetChecked, /// Removes realm authority @@ -95,13 +100,15 @@ pub enum SetRealmAuthorityAction { /// Realm Config defining Realm parameters. #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfig { - /// Legacy field introduced and used in V2 as use_community_voter_weight_addin: bool - /// If the field is going to be reused in future version it must be taken under consideration + /// Legacy field introduced and used in V2 as + /// use_community_voter_weight_addin: bool If the field is going to be + /// reused in future version it must be taken under consideration /// that for some Realms it might be already set to 1 pub legacy1: u8, - /// Legacy field introduced and used in V2 as use_max_community_voter_weight_addin: bool - /// If the field is going to be reused in future version it must be taken under consideration + /// Legacy field introduced and used in V2 as + /// use_max_community_voter_weight_addin: bool If the field is going to + /// be reused in future version it must be taken under consideration /// that for some Realms it might be already set to 1 pub legacy2: u8, @@ -135,12 +142,14 @@ pub struct RealmV2 { pub reserved: [u8; 6], /// Legacy field not used since program V3 any longer - /// Note: If the field is going to be reused in future version it must be taken under consideration - /// that for some Realms it might be already set to none zero because it was used as voting_proposal_count before + /// Note: If the field is going to be reused in future version it must be + /// taken under consideration that for some Realms it might be already + /// set to none zero because it was used as voting_proposal_count before pub legacy1: u16, - /// Realm authority. The authority must sign transactions which update the realm config - /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals + /// Realm authority. The authority must sign transactions which update the + /// realm config The authority should be transferred to Realm Governance + /// to make the Realm self governed through proposals pub authority: Option, /// Governance Realm name @@ -163,7 +172,8 @@ impl IsInitialized for RealmV2 { } } -/// Checks if the given account type is on of the Realm account types of any version +/// Checks if the given account type is on of the Realm account types of any +/// version pub fn is_realm_account_type(account_type: &GovernanceAccountType) -> bool { match account_type { GovernanceAccountType::RealmV1 | GovernanceAccountType::RealmV2 => true, @@ -210,12 +220,16 @@ impl RealmV2 { Err(GovernanceError::InvalidGoverningTokenMint.into()) } - /// Returns the governing token mint which is used to vote on a proposal given the provided Vote kind and vote_governing_token_mint + /// Returns the governing token mint which is used to vote on a proposal + /// given the provided Vote kind and vote_governing_token_mint /// - /// Veto vote is cast on a proposal configured for the opposite voting population defined using governing_token_mint - /// Council can veto Community vote and Community can veto Council assuming the veto for the voting population is enabled + /// Veto vote is cast on a proposal configured for the opposite voting + /// population defined using governing_token_mint Council can veto + /// Community vote and Community can veto Council assuming the veto for the + /// voting population is enabled /// - /// For all votes other than Veto (Electorate votes) the vote_governing_token_mint is the same as Proposal governing_token_mint + /// For all votes other than Veto (Electorate votes) the + /// vote_governing_token_mint is the same as Proposal governing_token_mint pub fn get_proposal_governing_token_mint_for_vote( &self, vote_governing_token_mint: &Pubkey, @@ -224,12 +238,14 @@ impl RealmV2 { match vote_kind { VoteKind::Electorate => Ok(*vote_governing_token_mint), VoteKind::Veto => { - // When Community veto Council proposal then return council_token_mint as the Proposal governing_token_mint + // When Community veto Council proposal then return council_token_mint as the + // Proposal governing_token_mint if self.community_mint == *vote_governing_token_mint { return Ok(self.config.council_mint.unwrap()); } - // When Council veto Community proposal then return community_token_mint as the Proposal governing_token_mint + // When Council veto Community proposal then return community_token_mint as the + // Proposal governing_token_mint if self.config.council_mint == Some(*vote_governing_token_mint) { return Ok(self.community_mint); } @@ -239,7 +255,8 @@ impl RealmV2 { } } - /// Asserts the given governing token mint and holding accounts are valid for the realm + /// Asserts the given governing token mint and holding accounts are valid + /// for the realm pub fn assert_is_valid_governing_token_mint_and_holding( &self, program_id: &Pubkey, @@ -268,7 +285,8 @@ impl RealmV2 { create_authority_info: &AccountInfo, account_info_iter: &mut Iter, ) -> Result<(), ProgramError> { - // Check if create_authority_info is realm_authority and if yes then it must signed the transaction + // Check if create_authority_info is realm_authority and if yes then it must + // signed the transaction if self.authority == Some(*create_authority_info.key) { return if !create_authority_info.is_signer { Err(GovernanceError::RealmAuthorityMustSign.into()) @@ -277,7 +295,8 @@ impl RealmV2 { }; } - // If realm_authority hasn't signed then check if TokenOwner or Delegate signed and can crate governance + // If realm_authority hasn't signed then check if TokenOwner or Delegate signed + // and can crate governance let token_owner_record_data = get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm)?; @@ -305,9 +324,11 @@ impl RealmV2 { if self.account_type == GovernanceAccountType::RealmV2 { borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::RealmV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 128] { panic!("Extended data not supported by RealmV1") } @@ -329,7 +350,8 @@ impl RealmV2 { } } -/// Checks whether the Realm account exists, is initialized and owned by Governance program +/// Checks whether the Realm account exists, is initialized and owned by +/// Governance program pub fn assert_is_valid_realm( program_id: &Pubkey, realm_info: &AccountInfo, @@ -383,7 +405,8 @@ pub fn get_realm_data_for_authority( Ok(realm_data) } -/// Deserializes Ream account and asserts the given governing_token_mint is either Community or Council mint of the Realm +/// Deserializes Ream account and asserts the given governing_token_mint is +/// either Community or Council mint of the Realm pub fn get_realm_data_for_governing_token_mint( program_id: &Pubkey, realm_info: &AccountInfo, @@ -490,7 +513,8 @@ mod test { #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfigArgsV1 { /// Indicates whether council_mint should be used - /// If yes then council_mint account must also be passed to the instruction + /// If yes then council_mint account must also be passed to the + /// instruction pub use_council_mint: bool, /// Min number of community tokens required to create a governance @@ -503,7 +527,8 @@ mod test { /// Instructions supported by the Governance program #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum GovernanceInstructionV1 { - /// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint + /// Creates Governance Realm account which aggregates governances for + /// given Community Mint and optional Council Mint CreateRealm { #[allow(dead_code)] /// UTF-8 encoded Governance Realm name @@ -514,7 +539,9 @@ mod test { config_args: RealmConfigArgsV1, }, - /// Deposits governing tokens (Community or Council) to Governance Realm and establishes your voter weight to be used for voting within the Realm + /// Deposits governing tokens (Community or Council) to Governance Realm + /// and establishes your voter weight to be used for voting within the + /// Realm DepositGoverningTokens { /// The amount to deposit into the realm #[allow(dead_code)] diff --git a/governance/program/src/state/realm_config.rs b/governance/program/src/state/realm_config.rs index 1ddd2a8f7e1..6666c7ca1d7 100644 --- a/governance/program/src/state/realm_config.rs +++ b/governance/program/src/state/realm_config.rs @@ -24,31 +24,38 @@ use { /// 2) Which token instructions Deposit, Withdraw and Revoke (burn) are allowed #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum GoverningTokenType { - /// Liquid token is a token which is fully liquid and the token owner retains full authority over it - /// Deposit - Yes + /// Liquid token is a token which is fully liquid and the token owner + /// retains full authority over it Deposit - Yes /// Withdraw - Yes /// Revoke - No, Realm authority cannot revoke liquid tokens Liquid, /// Membership token is a token controlled by Realm authority - /// Deposit - Yes, membership tokens can be deposited to gain governance power - /// The membership tokens are conventionally minted into the holding account to keep them out of members possession - /// Withdraw - No, after membership tokens are deposited they are no longer transferable and can't be withdrawn - /// Revoke - Yes, Realm authority can Revoke (burn) membership tokens + /// Deposit - Yes, membership tokens can be deposited to gain governance + /// power The membership tokens are conventionally minted into + /// the holding account to keep them out of members possession + /// Withdraw - No, after membership tokens are deposited they are no longer + /// transferable and can't be withdrawn Revoke - Yes, Realm authority + /// can Revoke (burn) membership tokens Membership, - /// Dormant token is a token which is only a placeholder and its deposits are not accepted and not used for governance power within the Realm + /// Dormant token is a token which is only a placeholder and its deposits + /// are not accepted and not used for governance power within the Realm /// - /// The Dormant token type is used when only a single voting population is operational. For example a Multisig starter DAO uses Council only - /// and sets Community as Dormant to indicate its not utilized for any governance power. - /// Once the starter DAO decides to decentralise then it can change the Community token to Liquid + /// The Dormant token type is used when only a single voting population is + /// operational. For example a Multisig starter DAO uses Council only + /// and sets Community as Dormant to indicate its not utilized for any + /// governance power. Once the starter DAO decides to decentralise then + /// it can change the Community token to Liquid /// - /// Note: When an external voter weight plugin which takes deposits of the token is used then the type should be set to Dormant - /// to make the intention explicit + /// Note: When an external voter weight plugin which takes deposits of the + /// token is used then the type should be set to Dormant to make the + /// intention explicit /// /// Deposit - No, dormant tokens can't be deposited into the Realm - /// Withdraw - Yes, tokens can still be withdrawn from Realm to support scenario where the config is changed while some tokens are still deposited - /// Revoke - No, Realm authority cannot revoke dormant tokens + /// Withdraw - Yes, tokens can still be withdrawn from Realm to support + /// scenario where the config is changed while some tokens are still + /// deposited Revoke - No, Realm authority cannot revoke dormant tokens Dormant, } @@ -59,7 +66,8 @@ impl Default for GoverningTokenType { } } -/// GoverningTokenConfig specifies configuration for Realm governing token (Community or Council) +/// GoverningTokenConfig specifies configuration for Realm governing token +/// (Community or Council) #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] pub struct GoverningTokenConfig { /// Plugin providing voter weights for the governing token @@ -156,7 +164,8 @@ impl RealmConfigAccount { match governing_token_type { GoverningTokenType::Membership | GoverningTokenType::Liquid => Ok(()), // Note: Preventing deposits of the Dormant type tokens is not a direct security concern - // It only makes the intention of not using deposited tokens as governance power stronger + // It only makes the intention of not using deposited tokens as governance power + // stronger GoverningTokenType::Dormant => Err(GovernanceError::CannotDepositDormantTokens.into()), } } @@ -179,15 +188,18 @@ impl RealmConfigAccount { } } - /// Asserts the given RealmConfigArgs represent a valid Realm configuration change + /// Asserts the given RealmConfigArgs represent a valid Realm configuration + /// change pub fn assert_can_change_config( &self, realm_config_args: &RealmConfigArgs, ) -> Result<(), ProgramError> { // Existing community token type can't be changed to Membership because it would - // give the Realm authority the right to burn members tokens which should not be the case because the tokens belong to the members - // On the other had for the Council token it's acceptable and in fact desired change because council tokens denote membership - // which should be controlled by the Realm + // give the Realm authority the right to burn members tokens which should not be + // the case because the tokens belong to the members On the other had + // for the Council token it's acceptable and in fact desired change because + // council tokens denote membership which should be controlled by the + // Realm if self.community_token_config.token_type != GoverningTokenType::Membership && realm_config_args.community_token_config_args.token_type == GoverningTokenType::Membership @@ -207,8 +219,10 @@ pub fn get_realm_config_data( get_account_data::(program_id, realm_config_info) } -/// If the account exists then deserializes it into RealmConfigAccount struct and checks the owner program and the Realm it belongs to -/// If the account doesn't exist then it checks its address is derived from the given owner program and Realm and returns default RealmConfigAccount +/// If the account exists then deserializes it into RealmConfigAccount struct +/// and checks the owner program and the Realm it belongs to If the account +/// doesn't exist then it checks its address is derived from the given owner +/// program and Realm and returns default RealmConfigAccount pub fn get_realm_config_data_for_realm( program_id: &Pubkey, realm_config_info: &AccountInfo, @@ -216,8 +230,9 @@ pub fn get_realm_config_data_for_realm( ) -> Result { let realm_config_data = if realm_config_info.data_is_empty() { // If RealmConfigAccount doesn't exist yet then validate its PDA - // PDA validation is required because RealmConfigAccount might not exist for legacy Realms - // and then its absence is used as default RealmConfigAccount value with no plugins and Liquid governance tokens + // PDA validation is required because RealmConfigAccount might not exist for + // legacy Realms and then its absence is used as default + // RealmConfigAccount value with no plugins and Liquid governance tokens let realm_config_address = get_realm_config_address(program_id, realm); if realm_config_address != *realm_config_info.key { @@ -253,7 +268,8 @@ pub fn get_realm_config_address_seeds(realm: &Pubkey) -> [&[u8]; 2] { pub fn get_realm_config_address(program_id: &Pubkey, realm: &Pubkey) -> Pubkey { Pubkey::find_program_address(&get_realm_config_address_seeds(realm), program_id).0 } -/// Resolves GoverningTokenConfig from GoverningTokenConfigArgs and instruction accounts +/// Resolves GoverningTokenConfig from GoverningTokenConfigArgs and instruction +/// accounts pub fn resolve_governing_token_config( account_info_iter: &mut Iter, governing_token_config_args: &GoverningTokenConfigArgs, diff --git a/governance/program/src/state/required_signatory.rs b/governance/program/src/state/required_signatory.rs index c1b4d747179..9447b693818 100644 --- a/governance/program/src/state/required_signatory.rs +++ b/governance/program/src/state/required_signatory.rs @@ -33,7 +33,8 @@ impl IsInitialized for RequiredSignatory { } } -/// Deserializes RequiredSignatory account, checks the owner program, and asserts that required signatory belongs to the given governance +/// Deserializes RequiredSignatory account, checks the owner program, and +/// asserts that required signatory belongs to the given governance pub fn get_required_signatory_data_for_governance( program_id: &Pubkey, required_signatory_info: &AccountInfo, diff --git a/governance/program/src/state/signatory_record.rs b/governance/program/src/state/signatory_record.rs index db60c6ccf42..5c3a5a1cfea 100644 --- a/governance/program/src/state/signatory_record.rs +++ b/governance/program/src/state/signatory_record.rs @@ -70,9 +70,11 @@ impl SignatoryRecordV2 { if self.account_type == GovernanceAccountType::SignatoryRecordV2 { borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::SignatoryRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by SignatoryRecordV1") } diff --git a/governance/program/src/state/token_owner_record.rs b/governance/program/src/state/token_owner_record.rs index 2ea3ef5c692..5dbc1509d39 100644 --- a/governance/program/src/state/token_owner_record.rs +++ b/governance/program/src/state/token_owner_record.rs @@ -37,8 +37,8 @@ pub struct TokenOwnerRecordV2 { /// Governing Token Mint the TokenOwnerRecord holds deposit for pub governing_token_mint: Pubkey, - /// The owner (either single or multisig) of the deposited governing SPL Tokens - /// This is who can authorize a withdrawal of the tokens + /// The owner (either single or multisig) of the deposited governing SPL + /// Tokens This is who can authorize a withdrawal of the tokens pub governing_token_owner: Pubkey, /// The amount of governing tokens deposited into the Realm @@ -46,36 +46,52 @@ pub struct TokenOwnerRecordV2 { pub governing_token_deposit_amount: u64, /// The number of votes cast by TokenOwner but not relinquished yet - /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state + /// Every time a vote is cast this number is increased and it's always + /// decreased when relinquishing a vote regardless of the vote state pub unrelinquished_votes_count: u64, /// The number of outstanding proposals the TokenOwner currently owns /// The count is increased when TokenOwner creates a proposal - /// and decreased once it's either voted on (Succeeded or Defeated) or Cancelled - /// By default it's restricted to 1 outstanding Proposal per token owner + /// and decreased once it's either voted on (Succeeded or Defeated) or + /// Cancelled By default it's restricted to 1 outstanding Proposal per + /// token owner pub outstanding_proposal_count: u8, /// Version of the account layout - /// Note: In future versions (>program V3) we should introduce GovernanceAccountType::TokenOwnerRecord(version:u8) as a way to version this account (and all other accounts too) - /// It can't be done in program V3 because it would require to fetch another GovernanceAccountType by the UI and the RPC is already overloaded with all the existing types - /// The new account type and versioning scheme can be introduced once we migrate UI to use indexer to fetch all the accounts - /// Once the new versioning scheme is introduced this field can be migrated and removed + /// Note: In future versions (>program V3) we should introduce + /// GovernanceAccountType::TokenOwnerRecord(version:u8) as a way to version + /// this account (and all other accounts too) It can't be done in + /// program V3 because it would require to fetch another + /// GovernanceAccountType by the UI and the RPC is already overloaded with + /// all the existing types The new account type and versioning scheme + /// can be introduced once we migrate UI to use indexer to fetch all the + /// accounts Once the new versioning scheme is introduced this field can + /// be migrated and removed /// - /// The other issues which need to be addressed before we can cleanup the account versioning code: - /// 1) Remove the specific governance accounts (ProgramGovernance, TokenGovernance, MintGovernance) - /// The only reason they exist is the UI which can't handle the generic use case for those assets - /// 2) For account layout breaking changes all plugins would have to be upgraded - /// 3) For account layout changes the Holaplex indexer would have to be upgraded - /// 4) We should migrate the UI to use the indexer for fetching data and stop using getProgramAccounts - /// 5) The UI would have to be upgraded to support account migration to the latest version - /// 6) The client sdk is already messy because of the different program/account versions and it should be cleaned up before we add even more versions. + /// The other issues which need to be addressed before we can cleanup the + /// account versioning code: + /// 1) Remove the specific governance accounts (ProgramGovernance, + /// TokenGovernance, MintGovernance) The only reason they exist is the UI + /// which can't handle the generic use case for those assets + /// 2) For account layout breaking changes all plugins would have to be + /// upgraded + /// 3) For account layout changes the Holaplex indexer would have to be + /// upgraded + /// 4) We should migrate the UI to use the indexer for fetching data and + /// stop using getProgramAccounts + /// 5) The UI would have to be upgraded to support account migration to the + /// latest version + /// 6) The client sdk is already messy because of the different + /// program/account versions and it should be cleaned up before we add + /// even more versions. pub version: u8, /// Reserved space for future versions pub reserved: [u8; 6], - /// A single account that is allowed to operate governance with the deposited governing tokens - /// It can be delegated to by the governing_token_owner or current governance_delegate + /// A single account that is allowed to operate governance with the + /// deposited governing tokens It can be delegated to by the + /// governing_token_owner or current governance_delegate pub governance_delegate: Option, /// Reserved space for versions v2 and onwards @@ -84,7 +100,8 @@ pub struct TokenOwnerRecordV2 { } /// The current version of TokenOwnerRecord account layout -/// Note: It's the version of the account layout and not the version of the program or the account type +/// Note: It's the version of the account layout and not the version of the +/// program or the account type /// /// program V1,V2 -> account layout version 0 /// program V3 -> account layout version 1 @@ -123,7 +140,8 @@ impl TokenOwnerRecordV2 { Err(GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into()) } - /// Asserts TokenOwner has enough tokens to be allowed to create proposal and doesn't have any outstanding proposals + /// Asserts TokenOwner has enough tokens to be allowed to create proposal + /// and doesn't have any outstanding proposals pub fn assert_can_create_proposal( &self, realm_data: &RealmV2, @@ -139,8 +157,8 @@ impl TokenOwnerRecordV2 { return Err(GovernanceError::InvalidGoverningTokenMint.into()); }; - // If the weight threshold is set to u64::MAX then it indicates explicitly Disabled value - // which should prevent any possibility of using it + // If the weight threshold is set to u64::MAX then it indicates explicitly + // Disabled value which should prevent any possibility of using it if min_weight_to_create_proposal == u64::MAX { return Err(GovernanceError::VoterWeightThresholdDisabled.into()); } @@ -150,7 +168,8 @@ impl TokenOwnerRecordV2 { } // The number of outstanding proposals is currently restricted to 10 - // If there is a need to change it in the future then it should be added to realm or governance config + // If there is a need to change it in the future then it should be added to + // realm or governance config if self.outstanding_proposal_count >= 10 { return Err(GovernanceError::TooManyOutstandingProposals.into()); } @@ -174,8 +193,8 @@ impl TokenOwnerRecordV2 { return Err(GovernanceError::InvalidGoverningTokenMint.into()); }; - // If the weight threshold is set to u64::MAX then it indicates explicitly Disabled value - // which should prevent any possibility of using it + // If the weight threshold is set to u64::MAX then it indicates explicitly + // Disabled value which should prevent any possibility of using it if min_weight_to_create_governance == u64::MAX { return Err(GovernanceError::VoterWeightThresholdDisabled.into()); } @@ -207,14 +226,16 @@ impl TokenOwnerRecordV2 { /// Decreases outstanding_proposal_count pub fn decrease_outstanding_proposal_count(&mut self) { // Previous versions didn't use the count and it can be already 0 - // TODO: Remove this check once all outstanding proposals on mainnet are resolved + // TODO: Remove this check once all outstanding proposals on mainnet are + // resolved if self.outstanding_proposal_count != 0 { self.outstanding_proposal_count = self.outstanding_proposal_count.checked_sub(1).unwrap(); } } - /// Resolves voter's weight using either the amount deposited into the realm or weight provided by voter weight addin (if configured) + /// Resolves voter's weight using either the amount deposited into the realm + /// or weight provided by voter weight addin (if configured) #[allow(clippy::too_many_arguments)] pub fn resolve_voter_weight( &self, @@ -224,7 +245,8 @@ impl TokenOwnerRecordV2 { weight_action: VoterWeightAction, weight_action_target: &Pubkey, ) -> Result { - // if the Realm is configured to use voter weight plugin for our governing_token_mint then use the externally provided voter_weight + // if the Realm is configured to use voter weight plugin for our + // governing_token_mint then use the externally provided voter_weight // instead of governing_token_deposit_amount if let Some(voter_weight_addin) = realm_config_data .get_token_config(realm_data, &self.governing_token_mint)? @@ -255,9 +277,11 @@ impl TokenOwnerRecordV2 { if self.account_type == GovernanceAccountType::TokenOwnerRecordV2 { borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::TokenOwnerRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 128] { panic!("Extended data not supported by TokenOwnerRecordV1") } @@ -343,20 +367,24 @@ pub fn get_token_owner_record_data( get_account_data::(program_id, token_owner_record_info)? }; - // If the deserialized account uses the old account layout indicated by the version value then migrate the data to version 1 + // If the deserialized account uses the old account layout indicated by the + // version value then migrate the data to version 1 if token_owner_record_data.version < 1 { token_owner_record_data.version = 1; - // In previous versions unrelinquished_votes_count was u32 followed by total_votes_count:u32 - // In program V3 unrelinquished_votes_count was changed to u64 by extending it into the space previously used by total_votes_count:u32 - // Since total_votes_count could have some value we have to zero the upper 4 bytes of unrelinquished_votes_count + // In previous versions unrelinquished_votes_count was u32 followed by + // total_votes_count:u32 In program V3 unrelinquished_votes_count was + // changed to u64 by extending it into the space previously used by + // total_votes_count:u32 Since total_votes_count could have some value + // we have to zero the upper 4 bytes of unrelinquished_votes_count token_owner_record_data.unrelinquished_votes_count &= u32::MAX as u64; } Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and checks its PDA against the provided seeds +/// Deserializes TokenOwnerRecord account and checks its PDA against the +/// provided seeds pub fn get_token_owner_record_data_for_seeds( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -372,7 +400,8 @@ pub fn get_token_owner_record_data_for_seeds( get_token_owner_record_data(program_id, token_owner_record_info) } -/// Deserializes TokenOwnerRecord account and asserts it belongs to the given realm +/// Deserializes TokenOwnerRecord account and asserts it belongs to the given +/// realm pub fn get_token_owner_record_data_for_realm( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -387,7 +416,8 @@ pub fn get_token_owner_record_data_for_realm( Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and asserts it belongs to the given realm and is for the given governing mint +/// Deserializes TokenOwnerRecord account and asserts it belongs to the given +/// realm and is for the given governing mint pub fn get_token_owner_record_data_for_realm_and_governing_mint( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -404,7 +434,8 @@ pub fn get_token_owner_record_data_for_realm_and_governing_mint( Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and checks its address is the give proposal_owner +/// Deserializes TokenOwnerRecord account and checks its address is the give +/// proposal_owner pub fn get_token_owner_record_data_for_proposal_owner( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -479,7 +510,8 @@ mod test { assert_eq!(154, size); } - /// Legacy TokenOwnerRecord for program V1 and V2 accounts with outstanding_proposal_count and without version + /// Legacy TokenOwnerRecord for program V1 and V2 accounts with + /// outstanding_proposal_count and without version #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct LegacyTokenOwnerRecord { pub account_type: GovernanceAccountType, diff --git a/governance/program/src/state/vote_record.rs b/governance/program/src/state/vote_record.rs index efa02c797aa..1007cc08a7b 100644 --- a/governance/program/src/state/vote_record.rs +++ b/governance/program/src/state/vote_record.rs @@ -21,8 +21,9 @@ use { }; /// Voter choice for a proposal option -/// In the current version only 1) Single choice, 2) Multiple choices proposals and 3) Weighted voting are supported -/// In the future versions we can add support for 1) Quadratic voting and 2) Ranked choice voting +/// In the current version only 1) Single choice, 2) Multiple choices proposals +/// and 3) Weighted voting are supported In the future versions we can add +/// support for 1) Quadratic voting and 2) Ranked choice voting #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoteChoice { /// The rank given to the choice by voter @@ -39,7 +40,8 @@ impl VoteChoice { Ok(match self.weight_percentage { // Avoid any rounding errors for full weight 100 => voter_weight, - // Note: The total weight for all choices might not equal voter_weight due to rounding errors + // Note: The total weight for all choices might not equal voter_weight due to rounding + // errors 0..=99 => (voter_weight as u128) .checked_mul(self.weight_percentage as u128) .unwrap() @@ -70,11 +72,13 @@ pub enum Vote { /// VoteKind defines the type of the vote being cast #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteKind { - /// Electorate vote is cast by the voting population identified by governing_token_mint - /// Approve, Deny and Abstain votes are Electorate votes + /// Electorate vote is cast by the voting population identified by + /// governing_token_mint Approve, Deny and Abstain votes are Electorate + /// votes Electorate, - /// Vote cast by the opposite voting population to the Electorate identified by governing_token_mint + /// Vote cast by the opposite voting population to the Electorate identified + /// by governing_token_mint Veto, } @@ -96,7 +100,8 @@ pub struct VoteRecordV2 { pub proposal: Pubkey, /// The user who casted this vote - /// This is the Governing Token Owner who deposited governing tokens into the Realm + /// This is the Governing Token Owner who deposited governing tokens into + /// the Realm pub governing_token_owner: Pubkey, /// Indicates whether the vote was relinquished by voter @@ -135,9 +140,11 @@ impl VoteRecordV2 { if self.account_type == GovernanceAccountType::VoteRecordV2 { borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::VoteRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by VoteRecordV1") } @@ -201,7 +208,8 @@ pub fn get_vote_record_data( get_account_data::(program_id, vote_record_info) } -/// Deserializes VoteRecord and checks it belongs to the provided Proposal and TokenOwnerRecord +/// Deserializes VoteRecord and checks it belongs to the provided Proposal and +/// TokenOwnerRecord pub fn get_vote_record_data_for_proposal_and_token_owner_record( program_id: &Pubkey, vote_record_info: &AccountInfo, @@ -220,9 +228,11 @@ pub fn get_vote_record_data_for_proposal_and_token_owner_record( return Err(GovernanceError::InvalidGoverningTokenOwnerForVoteRecord.into()); } - // Assert governing_token_mint between Proposal and TokenOwnerRecord match for the deserialized VoteRecord - // For Approve, Deny and Abstain votes Proposal.governing_token_mint must equal TokenOwnerRecord.governing_token_mint - // For Veto vote it must be the governing_token_mint of the opposite voting population + // Assert governing_token_mint between Proposal and TokenOwnerRecord match for + // the deserialized VoteRecord For Approve, Deny and Abstain votes + // Proposal.governing_token_mint must equal + // TokenOwnerRecord.governing_token_mint For Veto vote it must be the + // governing_token_mint of the opposite voting population let proposal_governing_token_mint = realm_data.get_proposal_governing_token_mint_for_vote( &token_owner_record_data.governing_token_mint, &get_vote_kind(&vote_record_data.vote), diff --git a/governance/program/src/tools/bpf_loader_upgradeable.rs b/governance/program/src/tools/bpf_loader_upgradeable.rs index c3ec4db16c7..9fdf8390de1 100644 --- a/governance/program/src/tools/bpf_loader_upgradeable.rs +++ b/governance/program/src/tools/bpf_loader_upgradeable.rs @@ -57,7 +57,8 @@ pub fn set_program_upgrade_authority<'a>( ) } -/// Asserts the program is upgradable and its upgrade authority is a signer of the transaction +/// Asserts the program is upgradable and its upgrade authority is a signer of +/// the transaction pub fn assert_program_upgrade_authority_is_signer( program_address: &Pubkey, program_data_info: &AccountInfo, diff --git a/governance/program/src/tools/spl_token.rs b/governance/program/src/tools/spl_token.rs index 9b9474a7f3a..141ee7041b2 100644 --- a/governance/program/src/tools/spl_token.rs +++ b/governance/program/src/tools/spl_token.rs @@ -21,7 +21,8 @@ use { }, }; -/// Creates and initializes SPL token account with PDA using the provided PDA seeds +/// Creates and initializes SPL token account with PDA using the provided PDA +/// seeds #[allow(clippy::too_many_arguments)] pub fn create_spl_token_account_signed<'a>( payer_info: &AccountInfo<'a>, @@ -153,7 +154,8 @@ pub fn mint_spl_tokens_to<'a>( Ok(()) } -/// Transfers SPL Tokens from a token account owned by the provided PDA authority with seeds +/// Transfers SPL Tokens from a token account owned by the provided PDA +/// authority with seeds pub fn transfer_spl_tokens_signed<'a>( source_info: &AccountInfo<'a>, destination_info: &AccountInfo<'a>, @@ -202,7 +204,8 @@ pub fn transfer_spl_tokens_signed<'a>( Ok(()) } -/// Burns SPL Tokens from a token account owned by the provided PDA authority with seeds +/// Burns SPL Tokens from a token account owned by the provided PDA authority +/// with seeds pub fn burn_spl_tokens_signed<'a>( token_account_info: &AccountInfo<'a>, token_mint_info: &AccountInfo<'a>, @@ -251,7 +254,8 @@ pub fn burn_spl_tokens_signed<'a>( Ok(()) } -/// Asserts the given account_info represents a valid SPL Token account which is initialized and belongs to spl_token program +/// Asserts the given account_info represents a valid SPL Token account which is +/// initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<(), ProgramError> { if account_info.data_is_empty() { return Err(GovernanceError::SplTokenAccountDoesNotExist.into()); @@ -265,7 +269,8 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<( return Err(GovernanceError::SplTokenInvalidTokenAccountData.into()); } - // TokeAccount layout: mint(32), owner(32), amount(8), delegate(36), state(1), ... + // TokeAccount layout: mint(32), owner(32), amount(8), delegate(36), state(1), + // ... let data = account_info.try_borrow_data()?; let state = array_ref![data, 108, 1]; @@ -281,7 +286,8 @@ pub fn is_spl_token_account(account_info: &AccountInfo) -> bool { assert_is_valid_spl_token_account(account_info).is_ok() } -/// Asserts the given mint_info represents a valid SPL Token Mint account which is initialized and belongs to spl_token program +/// Asserts the given mint_info represents a valid SPL Token Mint account which +/// is initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), ProgramError> { if mint_info.data_is_empty() { return Err(GovernanceError::SplTokenMintDoesNotExist.into()); @@ -333,7 +339,8 @@ pub fn get_spl_token_owner(token_account_info: &AccountInfo) -> Result Result { assert_is_valid_spl_token_mint(mint_info)?; // In token program, 36, 8, 1, 1 is the layout, where the first 8 is supply u64. @@ -344,7 +351,8 @@ pub fn get_spl_token_mint_supply(mint_info: &AccountInfo) -> Result Result, ProgramError> { @@ -356,7 +364,8 @@ pub fn get_spl_token_mint_authority( unpack_coption_pubkey(bytes) } -/// Asserts current mint authority matches the given authority and it's signer of the transaction +/// Asserts current mint authority matches the given authority and it's signer +/// of the transaction pub fn assert_spl_token_mint_authority_is_signer( mint_info: &AccountInfo, mint_authority_info: &AccountInfo, @@ -378,7 +387,8 @@ pub fn assert_spl_token_mint_authority_is_signer( Ok(()) } -/// Asserts current token owner matches the given owner and it's signer of the transaction +/// Asserts current token owner matches the given owner and it's signer of the +/// transaction pub fn assert_spl_token_owner_is_signer( token_info: &AccountInfo, token_owner_info: &AccountInfo, diff --git a/governance/program/tests/process_finalize_vote.rs b/governance/program/tests/process_finalize_vote.rs index 626f0359085..f18de271bb8 100644 --- a/governance/program/tests/process_finalize_vote.rs +++ b/governance/program/tests/process_finalize_vote.rs @@ -344,7 +344,8 @@ async fn test_finalize_council_vote() { .await .unwrap(); - // Cast vote with 47% weight, above 40% quorum but below 50%+1 to tip automatically + // Cast vote with 47% weight, above 40% quorum but below 50%+1 to tip + // automatically governance_test .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) .await diff --git a/governance/program/tests/process_flag_transaction_error.rs b/governance/program/tests/process_flag_transaction_error.rs index 21878317b1e..6eff0c2acfc 100644 --- a/governance/program/tests/process_flag_transaction_error.rs +++ b/governance/program/tests/process_flag_transaction_error.rs @@ -340,7 +340,8 @@ async fn test_flag_transaction_error_with_proposal_transaction_already_executed_ .await .unwrap(); - // Add another transaction to prevent Proposal from transitioning to Competed state + // Add another transaction to prevent Proposal from transitioning to Competed + // state governance_test .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) .await diff --git a/governance/program/tests/process_insert_transaction.rs b/governance/program/tests/process_insert_transaction.rs index 648d773fdfc..0cd72283603 100644 --- a/governance/program/tests/process_insert_transaction.rs +++ b/governance/program/tests/process_insert_transaction.rs @@ -354,7 +354,8 @@ async fn test_insert_transaction_with_invalid_governance_for_proposal_error() { .await .unwrap(); - // Try to maliciously use a different governance account to use with the proposal + // Try to maliciously use a different governance account to use with the + // proposal let governed_account_cookie2 = governance_test.with_governed_account().await; let governance_cookie2 = governance_test diff --git a/governance/program/tests/process_refund_proposal_deposit.rs b/governance/program/tests/process_refund_proposal_deposit.rs index ff367aa345e..042b1e54d7d 100644 --- a/governance/program/tests/process_refund_proposal_deposit.rs +++ b/governance/program/tests/process_refund_proposal_deposit.rs @@ -180,7 +180,8 @@ async fn test_refund_proposal_deposit_with_invalid_proposal_deposit_payer_error( .await .unwrap(); - // Try to refund the deposit to account which is different than Proposal deposit payer + // Try to refund the deposit to account which is different than Proposal deposit + // payer let deposit_payer2 = governance_test.bench.with_wallet().await; // Act @@ -305,17 +306,18 @@ async fn test_refund_proposal_deposit_with_invalid_proposal_deposit_account_erro .unwrap(); // Act - let err = governance_test - .refund_proposal_deposit_using_instruction( - &proposal_cookie, - |i| { - i.accounts[1].pubkey = proposal_cookie.address; // Try to drain the Proposal account - }, - None, - ) - .await - .err() - .unwrap(); + let err = + governance_test + .refund_proposal_deposit_using_instruction( + &proposal_cookie, + |i| { + i.accounts[1].pubkey = proposal_cookie.address; // Try to drain the Proposal account + }, + None, + ) + .await + .err() + .unwrap(); // Assert diff --git a/governance/program/tests/process_set_governance_config.rs b/governance/program/tests/process_set_governance_config.rs index 633d779d157..60d20a3bef2 100644 --- a/governance/program/tests/process_set_governance_config.rs +++ b/governance/program/tests/process_set_governance_config.rs @@ -137,7 +137,8 @@ async fn test_set_governance_config_with_fake_governance_signer_error() { new_governance_config.clone(), ); - // Set Governance signer to fake account we have authority over and can use to sign the transaction + // Set Governance signer to fake account we have authority over and can use to + // sign the transaction let governance_signer = Keypair::new(); set_governance_config_ix.accounts[0].pubkey = governance_signer.pubkey(); @@ -189,7 +190,8 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { .await .unwrap(); - // Try to maliciously use a different governance account to change the given governance config + // Try to maliciously use a different governance account to change the given + // governance config let governed_account_cookie2 = governance_test.with_governed_account().await; let governance_cookie2 = governance_test diff --git a/governance/program/tests/program_test/legacy.rs b/governance/program/tests/program_test/legacy.rs index 2de2e904e68..9a8acd3c561 100644 --- a/governance/program/tests/program_test/legacy.rs +++ b/governance/program/tests/program_test/legacy.rs @@ -32,25 +32,30 @@ pub struct LegacyGovernanceConfigV1 { /// The type of the vote threshold used for voting pub vote_threshold_percentage: VoteThresholdPercentage, - /// Minimum number of community tokens a governance token owner must possess to be able to create a proposal + /// Minimum number of community tokens a governance token owner must possess + /// to be able to create a proposal pub min_community_tokens_to_create_proposal: u64, - /// Minimum waiting time in seconds for an instruction to be executed after proposal is voted on + /// Minimum waiting time in seconds for an instruction to be executed after + /// proposal is voted on pub min_instruction_hold_up_time: u32, /// Time limit in seconds for proposal to be open for voting pub max_voting_time: u32, /// The source of vote weight for voters - /// Note: In the current version only token deposits are accepted as vote weight + /// Note: In the current version only token deposits are accepted as vote + /// weight pub vote_weight_source: VoteWeightSource, - /// The time period in seconds within which a Proposal can be still cancelled after being voted on - /// Once cool off time expires Proposal can't be cancelled any longer and becomes a law - /// Note: This field is not implemented in the current version + /// The time period in seconds within which a Proposal can be still + /// cancelled after being voted on Once cool off time expires Proposal + /// can't be cancelled any longer and becomes a law Note: This field is + /// not implemented in the current version pub proposal_cool_off_time: u32, - /// Minimum number of council tokens a governance token owner must possess to be able to create a proposal + /// Minimum number of council tokens a governance token owner must possess + /// to be able to create a proposal pub min_council_tokens_to_create_proposal: u64, } @@ -59,9 +64,10 @@ pub struct LegacyGovernanceConfigV1 { pub enum VoteWeightSource { /// Governing token deposits into the Realm are used as voter weights Deposit, - /// Governing token account snapshots as of the time a proposal entered voting state are used as voter weights - /// Note: Snapshot source is not supported in the current version - /// Support for account snapshots are required in solana and/or arweave as a prerequisite + /// Governing token account snapshots as of the time a proposal entered + /// voting state are used as voter weights Note: Snapshot source is not + /// supported in the current version Support for account snapshots are + /// required in solana and/or arweave as a prerequisite Snapshot, } @@ -70,15 +76,18 @@ pub enum VoteWeightSource { #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteThresholdPercentage { /// Voting threshold of Yes votes in % required to tip the vote - /// It's the percentage of tokens out of the entire pool of governance tokens eligible to vote - /// Note: If the threshold is below or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as Defeated - /// In other words a '+1 vote' tie breaker is always required to have a successful vote + /// It's the percentage of tokens out of the entire pool of governance + /// tokens eligible to vote Note: If the threshold is below or equal to + /// 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as + /// Defeated In other words a '+1 vote' tie breaker is always required + /// to have a successful vote YesVote(u8), - /// The minimum number of votes in % out of the entire pool of governance tokens eligible to vote - /// which must be cast for the vote to be valid - /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is required for the vote to succeed - /// Note: Quorum is not implemented in the current version + /// The minimum number of votes in % out of the entire pool of governance + /// tokens eligible to vote which must be cast for the vote to be valid + /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is + /// required for the vote to succeed Note: Quorum is not implemented in + /// the current version Quorum(u8), } diff --git a/governance/program/tests/program_test/mod.rs b/governance/program/tests/program_test/mod.rs index 1b3bfad8609..fcd23b31020 100644 --- a/governance/program/tests/program_test/mod.rs +++ b/governance/program/tests/program_test/mod.rs @@ -144,8 +144,9 @@ impl GovernanceProgramTest { ) -> Self { // We only ensure the addin mock program is built but it doesn't detect changes // If the addin is changed then it needs to be manually rebuilt - // Note: The crate of the mock is built when spl-governance is built but we also need spl_governance_addin_mock.so - // And we can't use build.rs script because cargo build-sbf hangs when executed from the script + // Note: The crate of the mock is built when spl-governance is built but we also + // need spl_governance_addin_mock.so And we can't use build.rs + // script because cargo build-sbf hangs when executed from the script ensure_addin_mock_is_built(); Self::start_impl(use_voter_weight_addin, use_max_voter_weight_addin).await @@ -499,7 +500,8 @@ impl GovernanceProgramTest { } } - // Creates TokenOwner which owns 100 community tokens and deposits them into the given Realm + // Creates TokenOwner which owns 100 community tokens and deposits them into the + // given Realm #[allow(dead_code)] pub async fn with_community_token_deposit( &mut self, @@ -2698,7 +2700,8 @@ impl GovernanceProgramTest { index: Option, ) -> Result { // Create NOP instruction as a placeholder - // Note: The actual instruction is irrelevant because we do not execute it in tests + // Note: The actual instruction is irrelevant because we do not execute it in + // tests let mut instruction = Instruction { program_id: Pubkey::new_unique(), accounts: vec![], @@ -2779,7 +2782,8 @@ impl GovernanceProgramTest { .iter() .map(|a| AccountMeta { pubkey: a.pubkey, - is_signer: false, // Remove signer since the Governance account PDA will be signing the instruction for us + is_signer: false, /* Remove signer since the Governance account PDA will be + * signing the instruction for us */ is_writable: a.is_writable, }) .collect(); @@ -3179,7 +3183,8 @@ impl GovernanceProgramTest { let mut n = 1; while clock.unix_timestamp <= unix_timestamp { - // Since the exact time is not deterministic keep wrapping by arbitrary 400 slots until we pass the requested timestamp + // Since the exact time is not deterministic keep wrapping by arbitrary 400 + // slots until we pass the requested timestamp self.bench .context .warp_to_slot(clock.slot + n * 400) diff --git a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs index 1231d758b39..f36ee61ed56 100644 --- a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs +++ b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs @@ -212,7 +212,9 @@ async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_vote .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max + // based on cast + // votes } #[tokio::test] @@ -358,7 +360,9 @@ async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max + // based on cast + // votes } #[tokio::test] diff --git a/governance/program/tests/use_veto_vote.rs b/governance/program/tests/use_veto_vote.rs index 2369f258752..724830cee70 100644 --- a/governance/program/tests/use_veto_vote.rs +++ b/governance/program/tests/use_veto_vote.rs @@ -398,7 +398,8 @@ async fn test_cast_multiple_veto_votes_for_partially_approved_proposal() { .await .unwrap(); - // Mint extra council tokens for total supply of 210 to prevent single vote tipping + // Mint extra council tokens for total supply of 210 to prevent single vote + // tipping governance_test.mint_council_tokens(&realm_cookie, 10).await; let mut governance_cookie = governance_test @@ -415,7 +416,8 @@ async fn test_cast_multiple_veto_votes_for_partially_approved_proposal() { .await .unwrap(); - // Mint extra council tokens for total supply of 200 to prevent single vote tipping + // Mint extra council tokens for total supply of 200 to prevent single vote + // tipping governance_test .mint_community_tokens(&realm_cookie, 100) .await; @@ -621,7 +623,8 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er .await .unwrap(); - // Create Community TokenOwnerRecord for council_token_owner and Cast Community vote + // Create Community TokenOwnerRecord for council_token_owner and Cast Community + // vote let community_token_owner_record_cookie = governance_test .with_community_token_deposit_by_owner( &realm_cookie, @@ -652,7 +655,8 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er &proposal_cookie, &council_token_owner_record_cookie, |i| { - // Try to use a vote_record from community Yes vote to relinquish council Veto vote + // Try to use a vote_record from community Yes vote to relinquish council Veto + // vote i.accounts[4] = AccountMeta::new(community_vote_record_cookie.address, false) }, ) @@ -729,7 +733,8 @@ async fn test_cast_yes_and_veto_votes_with_yes_as_winning_vote() { .await .unwrap(); - // Mint extra council tokens for total supply of 210 to prevent single vote tipping + // Mint extra council tokens for total supply of 210 to prevent single vote + // tipping governance_test .mint_council_tokens(&realm_cookie, 110) .await; diff --git a/governance/test-sdk/src/lib.rs b/governance/test-sdk/src/lib.rs index 76b9ba555ae..b6ab51498bc 100644 --- a/governance/test-sdk/src/lib.rs +++ b/governance/test-sdk/src/lib.rs @@ -25,7 +25,8 @@ pub mod addins; pub mod cookies; pub mod tools; -/// Program's test bench which captures test context, rent and payer and common utility functions +/// Program's test bench which captures test context, rent and payer and common +/// utility functions pub struct ProgramTestBench { pub context: ProgramTestContext, pub rent: Rent, @@ -347,7 +348,8 @@ impl ProgramTestBench { .unwrap_or_else(|| panic!("GET-TEST-ACCOUNT-ERROR: Account {} not found", address)) } - /// Overrides or creates Borsh serialized account with arbitrary account data subverting normal runtime checks + /// Overrides or creates Borsh serialized account with arbitrary account + /// data subverting normal runtime checks pub fn set_borsh_account( &mut self, program_id: &Pubkey, diff --git a/governance/tools/src/account.rs b/governance/tools/src/account.rs index cd29fbf8c9d..347cbb5d07c 100644 --- a/governance/tools/src/account.rs +++ b/governance/tools/src/account.rs @@ -20,13 +20,15 @@ use { /// Trait for accounts to return their max size pub trait AccountMaxSize { - /// Returns max account size or None if max size is not known and actual instance size should be used + /// Returns max account size or None if max size is not known and actual + /// instance size should be used fn get_max_size(&self) -> Option { None } } -/// Creates a new account and serializes data into it using AccountMaxSize to determine the account's size +/// Creates a new account and serializes data into it using AccountMaxSize to +/// determine the account's size pub fn create_and_serialize_account<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, account_info: &AccountInfo<'a>, @@ -78,9 +80,10 @@ pub fn create_and_serialize_account<'a, T: BorshSerialize + AccountMaxSize>( Ok(()) } -/// Creates a new account and serializes data into it using the provided seeds to invoke signed CPI call -/// The owner of the account is set to the PDA program -/// Note: This functions also checks the provided account PDA matches the supplied seeds +/// Creates a new account and serializes data into it using the provided seeds +/// to invoke signed CPI call The owner of the account is set to the PDA program +/// Note: This functions also checks the provided account PDA matches the +/// supplied seeds #[allow(clippy::too_many_arguments)] pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, @@ -105,8 +108,9 @@ pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSiz ) } -/// Creates a new account and serializes data into it using the provided seeds to invoke signed CPI call -/// Note: This functions also checks the provided account PDA matches the supplied seeds +/// Creates a new account and serializes data into it using the provided seeds +/// to invoke signed CPI call Note: This functions also checks the provided +/// account PDA matches the supplied seeds #[allow(clippy::too_many_arguments)] pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, @@ -147,8 +151,9 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac let rent_exempt_lamports = rent.minimum_balance(account_size); let total_lamports = rent_exempt_lamports.checked_add(extra_lamports).unwrap(); - // If the account has some lamports already it can't be created using create_account instruction - // Anybody can send lamports to a PDA and by doing so create the account and perform DoS attack by blocking create_account + // If the account has some lamports already it can't be created using + // create_account instruction Anybody can send lamports to a PDA and by + // doing so create the account and perform DoS attack by blocking create_account if account_info.lamports() > 0 { let top_up_lamports = total_lamports.saturating_sub(account_info.lamports()); @@ -207,7 +212,8 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac Ok(()) } -/// Deserializes account and checks it's initialized and owned by the specified program +/// Deserializes account and checks it's initialized and owned by the specified +/// program pub fn get_account_data( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -227,7 +233,8 @@ pub fn get_account_data( } } -/// Deserializes account type and checks if the given account_info is owned by owner_program_id +/// Deserializes account type and checks if the given account_info is owned by +/// owner_program_id pub fn get_account_type( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -245,8 +252,9 @@ pub fn get_account_type( Ok(account_type) } -/// Asserts the given account is not empty, owned by the given program and of the expected type -/// Note: The function assumes the account type T is stored as the first element in the account data +/// Asserts the given account is not empty, owned by the given program and of +/// the expected type Note: The function assumes the account type T is stored as +/// the first element in the account data pub fn assert_is_valid_account_of_type( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -255,8 +263,10 @@ pub fn assert_is_valid_account_of_type( assert_is_valid_account_of_types(owner_program_id, account_info, |at: &T| *at == account_type) } -/// Asserts the given account is not empty, owned by the given program and one of the types asserted via the provided predicate function -/// Note: The function assumes the account type T is stored as the first element in the account data +/// Asserts the given account is not empty, owned by the given program and one +/// of the types asserted via the provided predicate function Note: The function +/// assumes the account type T is stored as the first element in the account +/// data pub fn assert_is_valid_account_of_types bool>( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -278,8 +288,10 @@ pub fn assert_is_valid_account_of_types ChangeLog { node } - /// Fast forwards the given proof and corresponding leaf by applying an update from - /// the current change log + /// Fast forwards the given proof and corresponding leaf by applying an + /// update from the current change log pub fn update_proof_or_leaf( &self, leaf_index: u32, diff --git a/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs b/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs index 6e619b835af..811e4f25d1c 100644 --- a/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs +++ b/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs @@ -30,22 +30,26 @@ fn check_leaf_index(leaf_index: u32, max_depth: usize) -> Result<(), ConcurrentM /// Conurrent Merkle Tree is a Merkle Tree that allows /// multiple tree operations targeted for the same tree root to succeed. /// -/// In a normal merkle tree, only the first tree operation will succeed because the -/// following operations will have proofs for the unmodified tree state. ConcurrentMerkleTree avoids -/// this by storing a buffer of modified nodes (`change_logs`) which allows it to implement fast-forwarding -/// of concurrent merkle tree operations. +/// In a normal merkle tree, only the first tree operation will succeed because +/// the following operations will have proofs for the unmodified tree state. +/// ConcurrentMerkleTree avoids this by storing a buffer of modified nodes +/// (`change_logs`) which allows it to implement fast-forwarding of concurrent +/// merkle tree operations. /// /// As long as the concurrent merkle tree operations -/// have proofs that are valid for a previous state of the tree that can be found in the stored -/// buffer, that tree operation's proof can be fast-forwarded and the tree operation can be -/// applied. +/// have proofs that are valid for a previous state of the tree that can be +/// found in the stored buffer, that tree operation's proof can be +/// fast-forwarded and the tree operation can be applied. /// /// There are two primitive operations for Concurrent Merkle Trees: -/// [set_leaf](ConcurrentMerkleTree:set_leaf) and [append](ConcurrentMerkleTree::append). Setting a leaf value requires -/// passing a proof to perform that tree operation, but appending does not require a proof. +/// [set_leaf](ConcurrentMerkleTree:set_leaf) and +/// [append](ConcurrentMerkleTree::append). Setting a leaf value requires +/// passing a proof to perform that tree operation, but appending does not +/// require a proof. /// -/// An additional key property of ConcurrentMerkleTree is support for [append](ConcurrentMerkleTree::append) operations, -/// which do not require any proofs to be passed. This is accomplished by keeping track of the +/// An additional key property of ConcurrentMerkleTree is support for +/// [append](ConcurrentMerkleTree::append) operations, which do not require any +/// proofs to be passed. This is accomplished by keeping track of the /// proof to the rightmost leaf in the tree (`rightmost_proof`). #[repr(C)] #[derive(Copy, Clone)] @@ -94,7 +98,8 @@ impl !(self.buffer_size == 0 && self.sequence_number == 0 && self.active_index == 0) } - /// This is the trustless initialization method that should be used in most cases. + /// This is the trustless initialization method that should be used in most + /// cases. pub fn initialize(&mut self) -> Result { check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); if self.is_initialized() { @@ -118,12 +123,13 @@ impl Ok(self.change_logs[0].root) } - /// This is a trustful initialization method that assumes the root contains the expected - /// leaves. + /// This is a trustful initialization method that assumes the root contains + /// the expected leaves. /// - /// At the time of this crate's publishing, there is no supported way to efficiently verify - /// a pre-initialized root on-chain. Using this method before having a method for on-chain verification - /// will prevent other applications from indexing the leaf data stored in this tree. + /// At the time of this crate's publishing, there is no supported way to + /// efficiently verify a pre-initialized root on-chain. Using this + /// method before having a method for on-chain verification will prevent + /// other applications from indexing the leaf data stored in this tree. pub fn initialize_with_root( &mut self, root: Node, @@ -366,8 +372,9 @@ impl } } - /// Returns the Current Seq of the tree, the seq is the monotonic counter of the tree operations - /// that is incremented every time a mutable operation is performed on the tree. + /// Returns the Current Seq of the tree, the seq is the monotonic counter of + /// the tree operations that is incremented every time a mutable + /// operation is performed on the tree. pub fn get_seq(&self) -> u64 { self.sequence_number } @@ -395,7 +402,8 @@ impl log_compute!(); // Modifies proof by iterating through the change log loop { - // If use_full_buffer is false, this loop will terminate if the initial value of changelog_buffer_index is the active index + // If use_full_buffer is false, this loop will terminate if the initial value of + // changelog_buffer_index is the active index if !use_full_buffer && changelog_buffer_index == self.active_index { break; } @@ -485,7 +493,8 @@ impl } /// Note: Enabling `allow_inferred_proof` will fast forward the given proof - /// from the beginning of the buffer in the case that the supplied root is not in the buffer. + /// from the beginning of the buffer in the case that the supplied root is + /// not in the buffer. #[inline(always)] fn try_apply_proof( &mut self, @@ -520,7 +529,8 @@ impl self.sequence_number = self.sequence_number.saturating_add(1); } - /// Creates a new root from a proof that is valid for the root at `self.active_index` + /// Creates a new root from a proof that is valid for the root at + /// `self.active_index` fn update_buffers_from_proof(&mut self, start: Node, proof: &[Node], index: u32) -> Node { let change_log = &mut self.change_logs[self.active_index as usize]; // Also updates change_log's current root diff --git a/libraries/concurrent-merkle-tree/src/error.rs b/libraries/concurrent-merkle-tree/src/error.rs index f834148d867..0c31a9cdaca 100644 --- a/libraries/concurrent-merkle-tree/src/error.rs +++ b/libraries/concurrent-merkle-tree/src/error.rs @@ -31,7 +31,8 @@ pub enum ConcurrentMerkleTreeError { #[error("Root not found in changelog buffer")] RootNotFound, - /// The tree's current leaf value does not match the supplied proof's leaf value + /// The tree's current leaf value does not match the supplied proof's leaf + /// value #[error("This tree's current leaf value does not match the supplied proof's leaf value")] LeafContentsModified, diff --git a/libraries/concurrent-merkle-tree/src/hash.rs b/libraries/concurrent-merkle-tree/src/hash.rs index 887618eb07c..10278c3a662 100644 --- a/libraries/concurrent-merkle-tree/src/hash.rs +++ b/libraries/concurrent-merkle-tree/src/hash.rs @@ -12,7 +12,8 @@ pub fn recompute(leaf: Node, proof: &[Node], index: u32) -> Node { current_node } -/// Computes the parent node of `node` and `sibling` and copies the result into `node` +/// Computes the parent node of `node` and `sibling` and copies the result into +/// `node` #[inline(always)] pub fn hash_to_parent(node: &mut Node, sibling: &Node, is_left: bool) { let parent = if is_left { diff --git a/libraries/concurrent-merkle-tree/src/lib.rs b/libraries/concurrent-merkle-tree/src/lib.rs index cb0c290caf5..fecd503d5d6 100644 --- a/libraries/concurrent-merkle-tree/src/lib.rs +++ b/libraries/concurrent-merkle-tree/src/lib.rs @@ -10,7 +10,8 @@ /// Private macros to enable logging in the Solana runtime #[macro_use] mod log; -/// Changelog implementation to keep track of information necessary to fast forward proofs +/// Changelog implementation to keep track of information necessary to fast +/// forward proofs pub mod changelog; /// Core implementation of the concurrent merkle tree structure pub mod concurrent_merkle_tree; diff --git a/libraries/concurrent-merkle-tree/tests/tests.rs b/libraries/concurrent-merkle-tree/tests/tests.rs index 3138d5bbec0..1c887add5c5 100644 --- a/libraries/concurrent-merkle-tree/tests/tests.rs +++ b/libraries/concurrent-merkle-tree/tests/tests.rs @@ -444,7 +444,8 @@ async fn test_append_bug_repro_2() { } #[tokio::test(flavor = "multi_thread")] -/// Test that empty trees are checked properly by adding & removing leaves one by one +/// Test that empty trees are checked properly by adding & removing leaves one +/// by one async fn test_prove_tree_empty_incremental() { let (mut cmt, mut tree) = setup(); let mut rng = thread_rng(); @@ -452,7 +453,8 @@ async fn test_prove_tree_empty_incremental() { cmt.prove_tree_is_empty().unwrap(); - // Append a random leaf & remove it, and make sure that the tree is empty at the end + // Append a random leaf & remove it, and make sure that the tree is empty at the + // end let tree_size = 64; for i in 0..tree_size { let leaf = rng.gen::<[u8; 32]>(); @@ -486,7 +488,8 @@ async fn test_prove_tree_empty_incremental() { } #[tokio::test(flavor = "multi_thread")] -/// Test that empty trees are checked properly by adding & removing leaves in a batch +/// Test that empty trees are checked properly by adding & removing leaves in a +/// batch async fn test_prove_tree_empty_batched() { let (mut cmt, mut tree) = setup(); let mut rng = thread_rng(); diff --git a/libraries/math/src/checked_ceil_div.rs b/libraries/math/src/checked_ceil_div.rs index 288463e4868..91b53ba8095 100644 --- a/libraries/math/src/checked_ceil_div.rs +++ b/libraries/math/src/checked_ceil_div.rs @@ -11,10 +11,10 @@ use crate::uint::U256; /// calculation. /// /// For example, 400 / 32 = 12, with a remainder cutting off 0.5 of amount. -/// If we simply ceiling the quotient to 13, then we're saying 400 / 32 = 13, which -/// also cuts off value. To improve this result, we calculate the other way -/// around and again check for a remainder: 400 / 13 = 30, with a remainder of -/// 0.77, and we ceiling that value again. This gives us a final calculation +/// If we simply ceiling the quotient to 13, then we're saying 400 / 32 = 13, +/// which also cuts off value. To improve this result, we calculate the other +/// way around and again check for a remainder: 400 / 13 = 30, with a remainder +/// of 0.77, and we ceiling that value again. This gives us a final calculation /// of 400 / 31 = 13, which provides a ceiling calculation without cutting off /// more value than needed. /// diff --git a/libraries/math/src/precise_number.rs b/libraries/math/src/precise_number.rs index c58d248e92c..ac96401bc9b 100644 --- a/libraries/math/src/precise_number.rs +++ b/libraries/math/src/precise_number.rs @@ -9,7 +9,8 @@ type InnerUint = U256; /// The representation of the number one as a precise number as 10^12 pub const ONE: u128 = 1_000_000_000_000; -/// Struct encapsulating a fixed-point number that allows for decimal calculations +/// Struct encapsulating a fixed-point number that allows for decimal +/// calculations #[derive(Clone, Debug, PartialEq)] pub struct PreciseNumber { /// Wrapper over the inner value, which is multiplied by ONE @@ -179,7 +180,8 @@ impl PreciseNumber { Some(Self { value }) } - /// Performs a subtraction, returning the result and whether the result is negative + /// Performs a subtraction, returning the result and whether the result is + /// negative pub fn unsigned_sub(&self, rhs: &Self) -> (Self, bool) { match self.value.checked_sub(rhs.value) { None => { @@ -348,7 +350,8 @@ impl PreciseNumber { } /// Approximate the square root using Newton's method. Based on testing, - /// this provides a precision of 11 digits for inputs between 0 and u128::MAX + /// this provides a precision of 11 digits for inputs between 0 and + /// u128::MAX pub fn sqrt(&self) -> Option { if self.less_than(&Self::minimum_sqrt_base()) || self.greater_than(&Self::maximum_sqrt_base()) diff --git a/libraries/math/tests/instruction_count.rs b/libraries/math/tests/instruction_count.rs index bf97d1e806f..4d414645c72 100644 --- a/libraries/math/tests/instruction_count.rs +++ b/libraries/math/tests/instruction_count.rs @@ -1,4 +1,5 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] use { @@ -45,7 +46,8 @@ async fn test_precise_sqrt_u32_max() { async fn test_sqrt_u64() { let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - // Dial down the BPF compute budget to detect if the operation gets bloated in the future + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future pc.set_compute_max_units(2_500); let (mut banks_client, payer, recent_blockhash) = pc.start().await; @@ -60,7 +62,8 @@ async fn test_sqrt_u64() { async fn test_sqrt_u128() { let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - // Dial down the BPF compute budget to detect if the operation gets bloated in the future + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future pc.set_compute_max_units(4_100); let (mut banks_client, payer, recent_blockhash) = pc.start().await; @@ -183,7 +186,8 @@ async fn test_f32_natural_log() { async fn test_f32_normal_cdf() { let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - // Dial down the BPF compute budget to detect if the operation gets bloated in the future + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future pc.set_compute_max_units(3_100); let (mut banks_client, payer, recent_blockhash) = pc.start().await; diff --git a/libraries/merkle-tree-reference/src/lib.rs b/libraries/merkle-tree-reference/src/lib.rs index 548e9c20cb5..81133b508fd 100644 --- a/libraries/merkle-tree-reference/src/lib.rs +++ b/libraries/merkle-tree-reference/src/lib.rs @@ -7,7 +7,8 @@ use { pub type Node = [u8; 32]; pub const EMPTY: Node = [0; 32]; -/// Max number of concurrent changes to tree supported before having to regenerate proofs +/// Max number of concurrent changes to tree supported before having to +/// regenerate proofs pub const MAX_SIZE: usize = 64; /// Max depth of the Merkle tree diff --git a/libraries/pod/src/bytemuck.rs b/libraries/pod/src/bytemuck.rs index adb12845933..f12cee5da6e 100644 --- a/libraries/pod/src/bytemuck.rs +++ b/libraries/pod/src/bytemuck.rs @@ -19,8 +19,8 @@ pub fn pod_from_bytes(bytes: &[u8]) -> Result<&T, ProgramError> { /// Maybe convert a slice of bytes into a `Pod` (zero copy) /// -/// Returns `None` if the slice is empty, or else `Err` if input length is not equal to -/// `pod_get_packed_len::()`. +/// Returns `None` if the slice is empty, or else `Err` if input length is not +/// equal to `pod_get_packed_len::()`. /// This function exists primarily because `Option` is not a `Pod`. pub fn pod_maybe_from_bytes(bytes: &[u8]) -> Result, ProgramError> { if bytes.is_empty() { diff --git a/libraries/pod/src/optional_keys.rs b/libraries/pod/src/optional_keys.rs index 34bb75e5254..dc71dfb9c1e 100644 --- a/libraries/pod/src/optional_keys.rs +++ b/libraries/pod/src/optional_keys.rs @@ -14,8 +14,8 @@ use { solana_zk_token_sdk::zk_token_elgamal::pod::ElGamalPubkey, }; -/// A Pubkey that encodes `None` as all `0`, meant to be usable as a Pod type, similar to all -/// NonZero* number types from the bytemuck library. +/// A Pubkey that encodes `None` as all `0`, meant to be usable as a Pod type, +/// similar to all NonZero* number types from the bytemuck library. #[cfg_attr( feature = "borsh", derive(BorshDeserialize, BorshSerialize, BorshSchema) @@ -127,13 +127,14 @@ impl<'de> Deserialize<'de> for OptionalNonZeroPubkey { } } -/// An ElGamalPubkey that encodes `None` as all `0`, meant to be usable as a Pod type. +/// An ElGamalPubkey that encodes `None` as all `0`, meant to be usable as a Pod +/// type. #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] #[repr(transparent)] pub struct OptionalNonZeroElGamalPubkey(ElGamalPubkey); impl OptionalNonZeroElGamalPubkey { - /// Checks equality between an OptionalNonZeroElGamalPubkey and an ElGamalPubkey when - /// interpreted as bytes. + /// Checks equality between an OptionalNonZeroElGamalPubkey and an + /// ElGamalPubkey when interpreted as bytes. pub fn equals(&self, other: &ElGamalPubkey) -> bool { &self.0 == other } diff --git a/libraries/pod/src/primitives.rs b/libraries/pod/src/primitives.rs index 9cb8d85206d..2ea7c4bbc60 100644 --- a/libraries/pod/src/primitives.rs +++ b/libraries/pod/src/primitives.rs @@ -36,7 +36,8 @@ impl From for bool { } } -/// Simple macro for implementing conversion functions between Pod* ints and standard ints. +/// Simple macro for implementing conversion functions between Pod* ints and +/// standard ints. /// /// The standard int types can cause alignment issues when placed in a `Pod`, /// so these replacements are usable in all `Pod`s. diff --git a/libraries/tlv-account-resolution/src/account.rs b/libraries/tlv-account-resolution/src/account.rs index 8c9203321a9..28413bdc34e 100644 --- a/libraries/tlv-account-resolution/src/account.rs +++ b/libraries/tlv-account-resolution/src/account.rs @@ -84,8 +84,8 @@ pub struct ExtraAccountMeta { /// Whether the account should be writable pub is_writable: PodBool, } -/// Helper used to to know when the top bit is set, to interpret the discriminator -/// as an index rather than as a type +/// Helper used to to know when the top bit is set, to interpret the +/// discriminator as an index rather than as a type const U8_TOP_BIT: u8 = 1 << 7; impl ExtraAccountMeta { /// Create a `ExtraAccountMeta` from a public key, @@ -118,8 +118,8 @@ impl ExtraAccountMeta { }) } - /// Create a `ExtraAccountMeta` from a list of seed configurations, representing - /// a PDA for an external program + /// Create a `ExtraAccountMeta` from a list of seed configurations, + /// representing a PDA for an external program /// /// This PDA belongs to a program elsewhere in the account list, rather /// than the executing program. For a PDA on the executing program, use diff --git a/libraries/tlv-account-resolution/src/state.rs b/libraries/tlv-account-resolution/src/state.rs index 5a687bfeddc..6aa84b8c903 100644 --- a/libraries/tlv-account-resolution/src/state.rs +++ b/libraries/tlv-account-resolution/src/state.rs @@ -17,7 +17,8 @@ use { /// Type representing the output of an account fetching function, for easy /// chaining between APIs pub type AccountDataResult = Result>, AccountFetchError>; -/// Generic error type that can come out of any client while fetching account data +/// Generic error type that can come out of any client while fetching account +/// data pub type AccountFetchError = Box; /// Helper to convert an `AccountInfo` to an `AccountMeta` diff --git a/memo/program/src/lib.rs b/memo/program/src/lib.rs index 53d80dddd54..93c79713ab9 100644 --- a/memo/program/src/lib.rs +++ b/memo/program/src/lib.rs @@ -1,12 +1,14 @@ #![deny(missing_docs)] -//! A program that accepts a string of encoded characters and verifies that it parses, -//! while verifying and logging signers. Currently handles UTF-8 characters. +//! A program that accepts a string of encoded characters and verifies that it +//! parses, while verifying and logging signers. Currently handles UTF-8 +//! characters. mod entrypoint; pub mod processor; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use solana_program::{ instruction::{AccountMeta, Instruction}, @@ -24,9 +26,9 @@ solana_program::declare_id!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"); /// /// Accounts expected by this instruction: /// -/// 0. ..0+N. `[signer]` Expected signers; if zero provided, instruction will be processed as a +/// 0. ..0+N. `[signer]` Expected signers; if zero provided, instruction will +/// be processed as a /// normal, unsigned spl-memo -/// pub fn build_memo(memo: &[u8], signer_pubkeys: &[&Pubkey]) -> Instruction { Instruction { program_id: id(), diff --git a/memo/program/tests/functional.rs b/memo/program/tests/functional.rs index 763f639ff12..91fef7e12ab 100644 --- a/memo/program/tests/functional.rs +++ b/memo/program/tests/functional.rs @@ -42,7 +42,8 @@ async fn test_memo_signing() { transaction.sign(&[&payer], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); - // Demonstrate success on signature provided, regardless of specific memo AccountMeta + // Demonstrate success on signature provided, regardless of specific memo + // AccountMeta let mut transaction = Transaction::new_with_payer( &[Instruction { program_id: id(), diff --git a/name-service/program/src/instruction.rs b/name-service/program/src/instruction.rs index f047d1cc168..4ed949f1271 100644 --- a/name-service/program/src/instruction.rs +++ b/name-service/program/src/instruction.rs @@ -13,13 +13,14 @@ use { pub enum NameRegistryInstruction { /// Create an empty name record /// - /// The address of the name record (account #1) is a program-derived address with the following - /// seeds to ensure uniqueness: + /// The address of the name record (account #1) is a program-derived address + /// with the following seeds to ensure uniqueness: /// * SHA256(HASH_PREFIX, `Create::name`) /// * Account class (account #3) /// * Parent name record address (account #4) /// - /// If this is a child record, the parent record's owner must approve by signing (account #5) + /// If this is a child record, the parent record's owner must approve by + /// signing (account #5) /// /// Accounts expected by this instruction: /// 0. `[]` System program @@ -27,18 +28,22 @@ pub enum NameRegistryInstruction { /// 2. `[writeable]` Name record to be created (program-derived address) /// 3. `[]` Account owner (written into `NameRecordHeader::owner`) /// 4. `[signer]` Account class (written into `NameRecordHeader::class`). - /// If `Pubkey::default()` then the `signer` bit is not required - /// 5. `[]` Parent name record (written into `NameRecordHeader::parent_name). `Pubkey::default()` is equivalent to no existing parent. - /// 6. `[signer]` Owner of the parent name record. Optional but needed if parent name different than default. - /// + /// If `Pubkey::default()` then the `signer` bit is not required + /// 5. `[]` Parent name record (written into + /// `NameRecordHeader::parent_name). `Pubkey::default()` is equivalent + /// to no existing parent. + /// 6. `[signer]` Owner of the parent name record. Optional but needed if + /// parent name different than default. Create { - /// SHA256 of the (HASH_PREFIX + Name) of the record to create, hashing is done off-chain + /// SHA256 of the (HASH_PREFIX + Name) of the record to create, hashing + /// is done off-chain hashed_name: Vec, /// Number of lamports to fund the name record with lamports: u64, - /// Number of bytes of memory to allocate in addition to the `NameRecordHeader` + /// Number of bytes of memory to allocate in addition to the + /// `NameRecordHeader` space: u32, }, @@ -81,29 +86,30 @@ pub enum NameRegistryInstruction { /// Delete a name record. /// - /// Any lamports remaining in the name record will be transferred to the refund account (#2) + /// Any lamports remaining in the name record will be transferred to the + /// refund account (#2) /// /// Accounts expected by this instruction: /// 0. `[writeable]` Name record to be deleted /// 1. `[signer]` Account owner /// 2. `[writeable]` Refund account - /// Delete, /// Realloc the data of a name record. /// - /// The space change cannot be more than `MAX_PERMITTED_DATA_LENGTH` greater than - /// current `space`. + /// The space change cannot be more than `MAX_PERMITTED_DATA_LENGTH` greater + /// than current `space`. /// /// Accounts expected by this instruction: /// 0. `[]` System program - /// 1. `[writeable, signer]` Payer account (will be refunded if new `space` is less than current `space`) + /// 1. `[writeable, signer]` Payer account (will be refunded if new + /// `space` is less than current `space`) /// 2. `[writeable]` Name record to be reallocated /// 3. `[signer]` Account owner - /// Realloc { /// New total number of bytes in addition to the `NameRecordHeader`. - /// There are no checks on the existing data; it will be truncated if the new space is less than the current space. + /// There are no checks on the existing data; it will be truncated if + /// the new space is less than the current space. space: u32, }, } diff --git a/name-service/program/src/lib.rs b/name-service/program/src/lib.rs index 2b4e21a25f6..bd7e144698c 100644 --- a/name-service/program/src/lib.rs +++ b/name-service/program/src/lib.rs @@ -5,7 +5,8 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"); diff --git a/name-service/program/src/processor.rs b/name-service/program/src/processor.rs index f2533325a58..ca30578c06c 100644 --- a/name-service/program/src/processor.rs +++ b/name-service/program/src/processor.rs @@ -84,7 +84,8 @@ impl Processor { if name_account.data.borrow().len() == 0 { // Issue the name registry account // The creation is done in three steps: transfer, allocate and assign, because - // one cannot `system_instruction::create` an account to which lamports have been transfered before. + // one cannot `system_instruction::create` an account to which lamports have + // been transfered before. invoke( &system_instruction::transfer(payer_account.key, &name_account_key, lamports), &[ diff --git a/name-service/program/src/state.rs b/name-service/program/src/state.rs index 9eb243c8d93..4a6e1eb2f7a 100644 --- a/name-service/program/src/state.rs +++ b/name-service/program/src/state.rs @@ -9,9 +9,11 @@ use { }, }; -/// The data for a Name Registry account is always prefixed a `NameRecordHeader` structure. +/// The data for a Name Registry account is always prefixed a `NameRecordHeader` +/// structure. /// -/// The layout of the remaining bytes in the account data are determined by the record `class` +/// The layout of the remaining bytes in the account data are determined by the +/// record `class` #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)] pub struct NameRecordHeader { // Names are hierarchical. `parent_name` contains the account address of the parent @@ -21,7 +23,8 @@ pub struct NameRecordHeader { // The owner of this name pub owner: Pubkey, - // The class of data this account represents (DNS record, twitter handle, SPL Token name/symbol, etc) + // The class of data this account represents (DNS record, twitter handle, SPL Token + // name/symbol, etc) // // If `Pubkey::default()` the data is unspecified. pub class: Pubkey, @@ -69,7 +72,8 @@ pub fn get_seeds_and_key( name_class_opt: Option<&Pubkey>, parent_name_address_opt: Option<&Pubkey>, ) -> (Pubkey, Vec) { - // let hashed_name: Vec = hashv(&[(HASH_PREFIX.to_owned() + name).as_bytes()]).0.to_vec(); + // let hashed_name: Vec = hashv(&[(HASH_PREFIX.to_owned() + + // name).as_bytes()]).0.to_vec(); let mut seeds_vec: Vec = hashed_name; let name_class = name_class_opt.cloned().unwrap_or_default(); diff --git a/record/program/src/instruction.rs b/record/program/src/instruction.rs index 008af83e2bc..045af3184b0 100644 --- a/record/program/src/instruction.rs +++ b/record/program/src/instruction.rs @@ -42,7 +42,8 @@ pub enum RecordInstruction { /// 2. `[]` New record authority SetAuthority, - /// Close the provided record account, draining lamports to recipient account + /// Close the provided record account, draining lamports to recipient + /// account /// /// Accounts expected by this instruction: /// diff --git a/record/program/src/lib.rs b/record/program/src/lib.rs index 94db665098b..76ff7aca3bc 100644 --- a/record/program/src/lib.rs +++ b/record/program/src/lib.rs @@ -7,7 +7,8 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current SDK types for downstream users building with a different SDK version +// Export current SDK types for downstream users building with a different SDK +// version pub use solana_program; solana_program::declare_id!("ReciQBw6sQKH9TVVJQDnbnJ5W7FP539tPHjZhRF4E9r"); diff --git a/rustfmt.toml b/rustfmt.toml index 1d3d20f519b..2c0e64168cf 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,5 @@ +comment_width = 80 edition = "2021" group_imports = "One" -imports_granularity = "One" \ No newline at end of file +imports_granularity = "One" +wrap_comments = true \ No newline at end of file diff --git a/shared-memory/program/tests/shared-memory.rs b/shared-memory/program/tests/shared-memory.rs index dd5c18b0ac3..c8a327c8c14 100644 --- a/shared-memory/program/tests/shared-memory.rs +++ b/shared-memory/program/tests/shared-memory.rs @@ -1,4 +1,5 @@ -// Program test does not support calling a raw program entrypoint, only `process_instruction` +// Program test does not support calling a raw program entrypoint, only +// `process_instruction` #![cfg(feature = "test-sbf")] use { diff --git a/single-pool/cli/src/cli.rs b/single-pool/cli/src/cli.rs index 4e653562709..244c4777af5 100644 --- a/single-pool/cli/src/cli.rs +++ b/single-pool/cli/src/cli.rs @@ -43,9 +43,9 @@ pub struct Cli { )] pub json_rpc_url: Option, - /// Specify the fee-payer account. This may be a keypair file, the ASK keyword - /// or the pubkey of an offline signer, provided an appropriate --signer argument - /// is also passed. Defaults to the client keypair. + /// Specify the fee-payer account. This may be a keypair file, the ASK + /// keyword or the pubkey of an offline signer, provided an appropriate + /// --signer argument is also passed. Defaults to the client keypair. #[clap( global(true), long, @@ -70,23 +70,25 @@ pub struct Cli { #[derive(Clone, Debug, Subcommand)] pub enum Command { - /// Commands used to initialize or manage existing single-validator stake pools. - /// Other than initializing new pools, most users should never need to use these. + /// Commands used to initialize or manage existing single-validator stake + /// pools. Other than initializing new pools, most users should never + /// need to use these. Manage(ManageCli), - /// Deposit delegated stake into a pool in exchange for pool tokens, closing out - /// the original stake account. Provide either a stake account address, or a - /// pool or vote account address along with the --default-stake-account flag to - /// use an account created with create-stake. + /// Deposit delegated stake into a pool in exchange for pool tokens, closing + /// out the original stake account. Provide either a stake account + /// address, or a pool or vote account address along with the + /// --default-stake-account flag to use an account created with + /// create-stake. Deposit(DepositCli), /// Withdraw stake into a new stake account, burning tokens in exchange. - /// Provide either pool or vote account address, plus either an amount of tokens to burn - /// or the ALL keyword to burn all. + /// Provide either pool or vote account address, plus either an amount of + /// tokens to burn or the ALL keyword to burn all. Withdraw(WithdrawCli), - /// Create and delegate a new stake account to a given validator, using a default address - /// linked to the intended depository pool + /// Create and delegate a new stake account to a given validator, using a + /// default address linked to the intended depository pool CreateDefaultStake(CreateStakeCli), /// Display info for one or all single-validator stake pool(s) @@ -101,22 +103,26 @@ pub struct ManageCli { #[derive(Clone, Debug, Subcommand)] pub enum ManageCommand { - /// Permissionlessly create the single-validator stake pool for a given validator vote account - /// if one does not already exist. The fee payer also pays rent-exemption for accounts, - /// along with the cluster-configured minimum stake delegation + /// Permissionlessly create the single-validator stake pool for a given + /// validator vote account if one does not already exist. The fee payer + /// also pays rent-exemption for accounts, along with the + /// cluster-configured minimum stake delegation Initialize(InitializeCli), - /// Permissionlessly re-stake the pool stake account in the case when it has been deactivated. - /// This may happen if the validator is force-deactivated, and then later reactivated using - /// the same address for its vote account. + /// Permissionlessly re-stake the pool stake account in the case when it has + /// been deactivated. This may happen if the validator is + /// force-deactivated, and then later reactivated using the same address + /// for its vote account. ReactivatePoolStake(ReactivateCli), - /// Permissionlessly create default MPL token metadata for the pool mint. Normally this is done - /// automatically upon initialization, so this does not need to be called. + /// Permissionlessly create default MPL token metadata for the pool mint. + /// Normally this is done automatically upon initialization, so this + /// does not need to be called. CreateTokenMetadata(CreateMetadataCli), - /// Modify the MPL token metadata associated with the pool mint. This action can only be - /// performed by the validator vote account's withdraw authority + /// Modify the MPL token metadata associated with the pool mint. This action + /// can only be performed by the validator vote account's withdraw + /// authority UpdateTokenMetadata(UpdateMetadataCli), } @@ -151,11 +157,13 @@ pub struct ReactivateCli { #[clap(group(ArgGroup::new("stake-source").required(true).args(&["stake-account-address", "default-stake-account"])))] #[clap(group(pool_source_group().required(false)))] pub struct DepositCli { - /// The stake account to deposit from. Must be in the same activation state as the pool's stake account + /// The stake account to deposit from. Must be in the same activation state + /// as the pool's stake account #[clap(value_parser = |p: &str| parse_address(p, "stake_account_address"))] pub stake_account_address: Option, - /// Instead of using a stake account by address, use the user's default account for a specified pool + /// Instead of using a stake account by address, use the user's default + /// account for a specified pool #[clap( short, long, @@ -168,19 +176,23 @@ pub struct DepositCli { #[clap(short, long = "pool", value_parser = |p: &str| parse_address(p, "pool_address"))] pub pool_address: Option, - /// The vote account corresponding to the pool to deposit into. Optional when stake account or pool is provided + /// The vote account corresponding to the pool to deposit into. Optional + /// when stake account or pool is provided #[clap(long = "vote-account", value_parser = |p: &str| parse_address(p, "vote_account_address"))] pub vote_account_address: Option, - /// Signing authority on the stake account to be deposited. Defaults to the client keypair + /// Signing authority on the stake account to be deposited. Defaults to the + /// client keypair #[clap(long = "withdraw-authority", id = "STAKE_WITHDRAW_AUTHORITY_KEYPAIR", validator = |s| is_valid_signer(s))] pub stake_withdraw_authority: Option, - /// The token account to mint to. Defaults to the client keypair's associated token account + /// The token account to mint to. Defaults to the client keypair's + /// associated token account #[clap(long = "token-account", value_parser = |p: &str| parse_address(p, "token_account_address"))] pub token_account_address: Option, - /// The wallet to refund stake account rent to. Defaults to the client keypair's pubkey + /// The wallet to refund stake account rent to. Defaults to the client + /// keypair's pubkey #[clap(long = "recipient", value_parser = |p: &str| parse_address(p, "lamport_recipient_address"))] pub lamport_recipient_address: Option, } @@ -192,7 +204,8 @@ pub struct WithdrawCli { #[clap(value_parser = Amount::parse_decimal_or_all)] pub token_amount: Amount, - /// The token account to withdraw from. Defaults to the associated token account for the pool mint + /// The token account to withdraw from. Defaults to the associated token + /// account for the pool mint #[clap(long = "token-account", value_parser = |p: &str| parse_address(p, "token_account_address"))] pub token_account_address: Option, @@ -208,7 +221,8 @@ pub struct WithdrawCli { #[clap(long = "token-authority", id = "TOKEN_AUTHORITY_KEYPAIR", validator = |s| is_valid_signer(s))] pub token_authority: Option, - /// Authority to assign to the new stake account. Defaults to the pubkey of the client keypair + /// Authority to assign to the new stake account. Defaults to the pubkey of + /// the client keypair #[clap(long = "stake-authority", value_parser = |p: &str| parse_address(p, "stake_authority_address"))] pub stake_authority_address: Option, @@ -240,7 +254,8 @@ pub struct UpdateMetadataCli { #[clap(validator = is_valid_token_symbol)] pub token_symbol: String, - /// Optional external URI for the pool token. Leaving this argument blank will clear any existing value + /// Optional external URI for the pool token. Leaving this argument blank + /// will clear any existing value #[clap(validator = is_valid_token_uri)] pub token_uri: Option, @@ -252,7 +267,8 @@ pub struct UpdateMetadataCli { #[clap(long = "vote-account", value_parser = |p: &str| parse_address(p, "vote_account_address"))] pub vote_account_address: Option, - /// Authorized withdrawer for the vote account, to prove validator ownership. Defaults to the client keypair + /// Authorized withdrawer for the vote account, to prove validator + /// ownership. Defaults to the client keypair #[clap(long, id = "AUTHORIZED_WITHDRAWER_KEYPAIR", validator = |s| is_valid_signer(s))] pub authorized_withdrawer: Option, } @@ -271,7 +287,8 @@ pub struct CreateStakeCli { #[clap(long = "vote-account", value_parser = |p: &str| parse_address(p, "vote_account_address"))] pub vote_account_address: Option, - /// Authority to assign to the new stake account. Defaults to the pubkey of the client keypair + /// Authority to assign to the new stake account. Defaults to the pubkey of + /// the client keypair #[clap(long = "stake-authority", value_parser = |p: &str| parse_address(p, "stake_authority_address"))] pub stake_authority_address: Option, } @@ -302,10 +319,11 @@ pub fn parse_address(path: &str, name: &str) -> Result { if is_valid_pubkey(path).is_ok() { // this all is ugly but safe // wallet_manager doesnt need to be shared, it just saves cycles to cache it - // and the only way argmatches default fails with an unchecked lookup is in the prompt branch - // which seems unlikely to ever be used for pubkeys + // and the only way argmatches default fails with an unchecked lookup is in the + // prompt branch which seems unlikely to ever be used for pubkeys // the usb lookup in signer_from_path_with_config is safe - // and the pubkey lookups are unreachable because pubkey_from_path short circuits that case + // and the pubkey lookups are unreachable because pubkey_from_path short + // circuits that case let mut wallet_manager = None; pubkey_from_path(&ArgMatches::default(), path, name, &mut wallet_manager) .map_err(|_| format!("Failed to load pubkey {} at {}", name, path)) @@ -356,10 +374,11 @@ pub fn pool_address_from_args(maybe_pool: Option, maybe_vote: Option Command let current_epoch = config.rpc_client.get_epoch_info().await?.epoch; // the cli invocation for this is conceptually simple, but a bit tricky - // the user can provide pool or vote and let the cli infer the stake account address - // but they can also provide pool or vote with the stake account, as a safety check - // first we want to get the pool address if they provided a pool or vote address + // the user can provide pool or vote and let the cli infer the stake account + // address but they can also provide pool or vote with the stake account, as + // a safety check first we want to get the pool address if they provided a + // pool or vote address let provided_pool_address = command_config.pool_address.or_else(|| { command_config .vote_account_address @@ -337,7 +339,8 @@ async fn command_deposit(config: &Config, command_config: DepositCli) -> Command payer.clone(), ); - // use token account provided, or get/create the associated account for the client keypair + // use token account provided, or get/create the associated account for the + // client keypair let token_account_address = if let Some(account) = command_config.token_account_address { account } else { @@ -407,8 +410,8 @@ async fn command_withdraw(config: &Config, command_config: WithdrawCli) -> Comma let stake_account = Keypair::new(); let stake_account_address = stake_account.pubkey(); - // since we cant infer pool from token account, the withdraw invocation is rather simpler - // first get the pool address + // since we cant infer pool from token account, the withdraw invocation is + // rather simpler first get the pool address let pool_address = pool_address_from_args( command_config.pool_address, command_config.vote_account_address, @@ -465,7 +468,8 @@ async fn command_withdraw(config: &Config, command_config: WithdrawCli) -> Comma .into()); } - // note a delegate authority is not allowed here because we must authorize the pool authority + // note a delegate authority is not allowed here because we must authorize the + // pool authority if token_account.base.owner != token_authority.pubkey() { return Err(format!( "Invalid token authority: got {}, actual {}", diff --git a/single-pool/cli/src/quarantine.rs b/single-pool/cli/src/quarantine.rs index 1b44a61d490..530f865b8b2 100644 --- a/single-pool/cli/src/quarantine.rs +++ b/single-pool/cli/src/quarantine.rs @@ -1,4 +1,5 @@ -// XXX this file will be deleted and replaced with a stake program client once i write one +// XXX this file will be deleted and replaced with a stake program client once i +// write one use { crate::config::*, diff --git a/single-pool/cli/tests/test.rs b/single-pool/cli/tests/test.rs index bd25bf0d0a9..df34a5811d2 100644 --- a/single-pool/cli/tests/test.rs +++ b/single-pool/cli/tests/test.rs @@ -255,8 +255,9 @@ async fn create_and_delegate_stake_account( async fn reactivate_pool_stake() { let env = setup(true).await; - // setting up a test validator for this to succeed is hell, and success is tested in program tests - // so we just make sure the cli can send a well-formed instruction + // setting up a test validator for this to succeed is hell, and success is + // tested in program tests so we just make sure the cli can send a + // well-formed instruction let output = Command::new(SVSP_CLI) .args([ "manage", diff --git a/single-pool/program/src/error.rs b/single-pool/program/src/error.rs index ef620c7027d..087768492da 100644 --- a/single-pool/program/src/error.rs +++ b/single-pool/program/src/error.rs @@ -13,30 +13,37 @@ use { #[derive(Clone, Debug, Eq, Error, num_derive::FromPrimitive, PartialEq)] pub enum SinglePoolError { // 0. - /// Provided pool account has the wrong address for its vote account, is uninitialized, or otherwise invalid. + /// Provided pool account has the wrong address for its vote account, is + /// uninitialized, or otherwise invalid. #[error("InvalidPoolAccount")] InvalidPoolAccount, - /// Provided pool stake account does not match address derived from the pool account. + /// Provided pool stake account does not match address derived from the pool + /// account. #[error("InvalidPoolStakeAccount")] InvalidPoolStakeAccount, /// Provided pool mint does not match address derived from the pool account. #[error("InvalidPoolMint")] InvalidPoolMint, - /// Provided pool stake authority does not match address derived from the pool account. + /// Provided pool stake authority does not match address derived from the + /// pool account. #[error("InvalidPoolStakeAuthority")] InvalidPoolStakeAuthority, - /// Provided pool mint authority does not match address derived from the pool account. + /// Provided pool mint authority does not match address derived from the + /// pool account. #[error("InvalidPoolMintAuthority")] InvalidPoolMintAuthority, // 5. - /// Provided pool MPL authority does not match address derived from the pool account. + /// Provided pool MPL authority does not match address derived from the pool + /// account. #[error("InvalidPoolMplAuthority")] InvalidPoolMplAuthority, - /// Provided metadata account does not match metadata account derived for pool mint. + /// Provided metadata account does not match metadata account derived for + /// pool mint. #[error("InvalidMetadataAccount")] InvalidMetadataAccount, - /// Authorized withdrawer provided for metadata update does not match the vote account. + /// Authorized withdrawer provided for metadata update does not match the + /// vote account. #[error("InvalidMetadataSigner")] InvalidMetadataSigner, /// Not enough lamports provided for deposit to result in one pool token. @@ -48,7 +55,8 @@ pub enum SinglePoolError { // 10 /// Not enough stake to cover the provided quantity of pool tokens. - /// (Generally this should not happen absent user error, but may if the minimum delegation increases.) + /// (Generally this should not happen absent user error, but may if the + /// minimum delegation increases.) #[error("WithdrawalTooLarge")] WithdrawalTooLarge, /// Required signature is missing. @@ -61,18 +69,21 @@ pub enum SinglePoolError { #[error("ArithmeticOverflow")] ArithmeticOverflow, /// A calculation failed unexpectedly. - /// (This error should never be surfaced; it stands in for failure conditions that should never be reached.) + /// (This error should never be surfaced; it stands in for failure + /// conditions that should never be reached.) #[error("UnexpectedMathError")] UnexpectedMathError, // 15 - /// The V0_23_5 vote account type is unsupported and should be upgraded via `convert_to_current()`. + /// The V0_23_5 vote account type is unsupported and should be upgraded via + /// `convert_to_current()`. #[error("LegacyVoteAccount")] LegacyVoteAccount, /// Failed to parse vote account. #[error("UnparseableVoteAccount")] UnparseableVoteAccount, - /// Incorrect number of lamports provided for rent-exemption when initializing. + /// Incorrect number of lamports provided for rent-exemption when + /// initializing. #[error("WrongRentAmount")] WrongRentAmount, /// Attempted to deposit from or withdraw to pool stake account. diff --git a/single-pool/program/src/instruction.rs b/single-pool/program/src/instruction.rs index d9f440efed4..1c0f7631809 100644 --- a/single-pool/program/src/instruction.rs +++ b/single-pool/program/src/instruction.rs @@ -24,9 +24,10 @@ use { #[repr(C)] #[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)] pub enum SinglePoolInstruction { - /// Initialize the mint and stake account for a new single-validator stake pool. - /// The pool stake account must contain the rent-exempt minimum plus the minimum delegation. - /// No tokens will be minted: to deposit more, use `Deposit` after `InitializeStake`. + /// Initialize the mint and stake account for a new single-validator stake + /// pool. The pool stake account must contain the rent-exempt minimum + /// plus the minimum delegation. No tokens will be minted: to deposit + /// more, use `Deposit` after `InitializeStake`. /// /// 0. `[]` Validator vote account /// 1. `[w]` Pool account @@ -43,8 +44,9 @@ pub enum SinglePoolInstruction { /// 12. `[]` Stake program InitializePool, - /// Restake the pool stake account if it was deactivated. This can happen through the - /// stake program's `DeactivateDelinquent` instruction, or during a cluster restart. + /// Restake the pool stake account if it was deactivated. This can happen + /// through the stake program's `DeactivateDelinquent` instruction, or + /// during a cluster restart. /// /// 0. `[]` Validator vote account /// 1. `[]` Pool account @@ -56,8 +58,9 @@ pub enum SinglePoolInstruction { /// 7. `[]` Stake program ReactivatePoolStake, - /// Deposit stake into the pool. The output is a "pool" token representing fractional - /// ownership of the pool stake. Inputs are converted to the current ratio. + /// Deposit stake into the pool. The output is a "pool" token + /// representing fractional ownership of the pool stake. Inputs are + /// converted to the current ratio. /// /// 0. `[]` Pool account /// 1. `[w]` Pool stake account @@ -92,10 +95,10 @@ pub enum SinglePoolInstruction { token_amount: u64, }, - /// Create token metadata for the stake-pool token in the metaplex-token program. - /// Step three of the permissionless three-stage initialization flow. - /// Note this instruction is not necessary for the pool to operate, to ensure we cannot - /// be broken by upstream. + /// Create token metadata for the stake-pool token in the metaplex-token + /// program. Step three of the permissionless three-stage + /// initialization flow. Note this instruction is not necessary for + /// the pool to operate, to ensure we cannot be broken by upstream. /// /// 0. `[]` Pool account /// 1. `[]` Pool token mint @@ -107,7 +110,8 @@ pub enum SinglePoolInstruction { /// 7. `[]` System program id CreateTokenMetadata, - /// Update token metadata for the stake-pool token in the metaplex-token program. + /// Update token metadata for the stake-pool token in the metaplex-token + /// program. /// /// 0. `[]` Validator vote account /// 1. `[]` Pool account @@ -293,9 +297,11 @@ pub fn deposit_stake( } } -/// Creates all necessary instructions to withdraw stake into a given stake account. -/// If a new stake account is required, the user should first include `system_instruction::create_account` -/// with account size `std::mem::size_of::()` and owner `stake::program::id()`. +/// Creates all necessary instructions to withdraw stake into a given stake +/// account. If a new stake account is required, the user should first include +/// `system_instruction::create_account` with account size +/// `std::mem::size_of::()` and owner +/// `stake::program::id()`. pub fn withdraw( program_id: &Pubkey, pool_address: &Pubkey, @@ -368,9 +374,11 @@ pub fn withdraw_stake( } } -/// Creates necessary instructions to create and delegate a new stake account to a given validator. -/// Uses a fixed address for each wallet and vote account combination to make it easier to find for deposits. -/// This is an optional helper function; deposits can come from any owned stake account without lockup. +/// Creates necessary instructions to create and delegate a new stake account to +/// a given validator. Uses a fixed address for each wallet and vote account +/// combination to make it easier to find for deposits. This is an optional +/// helper function; deposits can come from any owned stake account without +/// lockup. pub fn create_and_delegate_user_stake( program_id: &Pubkey, vote_account_address: &Pubkey, diff --git a/single-pool/program/src/lib.rs b/single-pool/program/src/lib.rs index f34bd52b517..62ed4376647 100644 --- a/single-pool/program/src/lib.rs +++ b/single-pool/program/src/lib.rs @@ -11,7 +11,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] pub mod entrypoint; -// export current sdk types for downstream users building with a different sdk version +// export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use solana_program::{pubkey::Pubkey, stake}; @@ -114,7 +115,8 @@ pub fn find_pool_mpl_authority_address(program_id: &Pubkey, pool_address: &Pubke find_pool_mpl_authority_address_and_bump(program_id, pool_address).0 } -/// Find the address of the default intermediate account that holds activating user stake before deposit. +/// Find the address of the default intermediate account that holds activating +/// user stake before deposit. pub fn find_default_deposit_account_address( pool_address: &Pubkey, user_wallet_address: &Pubkey, diff --git a/single-pool/program/src/processor.rs b/single-pool/program/src/processor.rs index 501c966f061..3ee321c314d 100644 --- a/single-pool/program/src/processor.rs +++ b/single-pool/program/src/processor.rs @@ -40,7 +40,8 @@ use { spl_token::state::Mint, }; -/// Calculate pool tokens to mint, given outstanding token supply, pool active stake, and deposit active stake +/// Calculate pool tokens to mint, given outstanding token supply, pool active +/// stake, and deposit active stake fn calculate_deposit_amount( pre_token_supply: u64, pre_pool_stake: u64, @@ -58,7 +59,8 @@ fn calculate_deposit_amount( } } -/// Calculate pool stake to return, given outstanding token supply, pool active stake, and tokens to redeem +/// Calculate pool stake to return, given outstanding token supply, pool active +/// stake, and tokens to redeem fn calculate_withdraw_amount( pre_token_supply: u64, pre_pool_stake: u64, @@ -317,7 +319,8 @@ fn check_account_owner( } /// Minimum delegation to create a pool -/// We floor at 1sol to avoid over-minting tokens before the relevant feature is active +/// We floor at 1sol to avoid over-minting tokens before the relevant feature is +/// active fn minimum_delegation() -> Result { Ok(std::cmp::max( stake::tools::get_minimum_delegation()?, @@ -650,7 +653,8 @@ impl Processor { mint_authority_signers, )?; - // create the pool stake account. user has already transferred in rent plus at least the minimum + // create the pool stake account. user has already transferred in rent plus at + // least the minimum let minimum_delegation = minimum_delegation()?; let stake_space = std::mem::size_of::(); let stake_rent_plus_initial = rent @@ -814,7 +818,8 @@ impl Processor { .saturating_sub(minimum_delegation); msg!("Available stake pre merge {}", pre_pool_stake); - // user can deposit active stake into an active pool or inactive stake into an activating pool + // user can deposit active stake into an active pool or inactive stake into an + // activating pool let (user_stake_meta, user_stake_state) = get_stake_state(user_stake_info)?; if user_stake_meta.authorized != stake::state::Authorized::auto(pool_stake_authority_info.key) @@ -824,8 +829,9 @@ impl Processor { return Err(SinglePoolError::WrongStakeStake.into()); } - // merge the user stake account, which is preauthed to us, into the pool stake account - // this merge succeeding implicitly validates authority/lockup of the user stake account + // merge the user stake account, which is preauthed to us, into the pool stake + // account this merge succeeding implicitly validates authority/lockup + // of the user stake account Self::stake_merge( pool_info.key, user_stake_info.clone(), @@ -849,7 +855,8 @@ impl Processor { .checked_sub(pre_pool_stake) .ok_or(SinglePoolError::ArithmeticOverflow)?; - // we calculate absolute rather than relative to deposit amount to allow claiming lamports mistakenly transferred in + // we calculate absolute rather than relative to deposit amount to allow + // claiming lamports mistakenly transferred in let excess_lamports = post_pool_lamports .checked_sub(pool_stake_state.delegation.stake) .and_then(|amount| amount.checked_sub(pool_stake_meta.rent_exempt_reserve)) @@ -1120,9 +1127,10 @@ impl Processor { check_mpl_metadata_program(mpl_token_metadata_program_info.key)?; check_mpl_metadata_account_address(metadata_info.key, &pool_mint_address)?; - // we use authorized_withdrawer to authenticate the caller controls the vote account - // this is safer than using an authorized_voter since those keys live hot - // and validator-operators we spoke with indicated this would be their preference as well + // we use authorized_withdrawer to authenticate the caller controls the vote + // account this is safer than using an authorized_voter since those keys + // live hot and validator-operators we spoke with indicated this would + // be their preference as well let vote_account_data = &vote_account_info.try_borrow_data()?; let vote_account_withdrawer = vote_account_data .get(VOTE_STATE_AUTHORIZED_WITHDRAWER_START..VOTE_STATE_AUTHORIZED_WITHDRAWER_END) @@ -1307,7 +1315,8 @@ mod tests { } } - // this deterministically tests basic behavior of calculate_deposit_amount and calculate_withdraw_amount + // this deterministically tests basic behavior of calculate_deposit_amount and + // calculate_withdraw_amount #[test] fn simple_deposit_withdraw() { let mut pool = PoolState::default(); @@ -1327,8 +1336,9 @@ mod tests { assert_eq!(pool.token_supply, 1000); assert_eq!(pool.total_stake, 1000); - // alice controls 25% of the pool and bob controls 75%. rewards should accrue likewise - // use nice even numbers, we can test fiddly stuff in the stochastic cases + // alice controls 25% of the pool and bob controls 75%. rewards should accrue + // likewise use nice even numbers, we can test fiddly stuff in the + // stochastic cases assert_relative_eq!(pool.share(&alice), 0.25); assert_relative_eq!(pool.share(&bob), 0.75); pool.reward(1000); @@ -1337,9 +1347,10 @@ mod tests { assert_relative_eq!(pool.share(&alice), 0.25); assert_relative_eq!(pool.share(&bob), 0.75); - // alice harvests rewards, reducing her share of the *previous* pool size to 12.5% - // but because the pool itself has shrunk to 87.5%, its actually more like 14.3% - // luckily chad deposits immediately after to make our math easier + // alice harvests rewards, reducing her share of the *previous* pool size to + // 12.5% but because the pool itself has shrunk to 87.5%, its actually + // more like 14.3% luckily chad deposits immediately after to make our + // math easier let stake_removed = pool.withdraw(&alice, 125).unwrap(); pool.deposit(&chad, 250).unwrap(); assert_eq!(stake_removed, 250); @@ -1354,9 +1365,11 @@ mod tests { assert_relative_eq!(pool.share(&alice), 1.0); } - // this stochastically tests calculate_deposit_amount and calculate_withdraw_amount - // the objective is specifically to ensure that the math does not fail on any combination of state changes - // the no_minimum case is to account for a future where small deposits are possible through multistake + // this stochastically tests calculate_deposit_amount and + // calculate_withdraw_amount the objective is specifically to ensure that + // the math does not fail on any combination of state changes the no_minimum + // case is to account for a future where small deposits are possible through + // multistake #[test_case(rand::random(), false, false; "no_rewards")] #[test_case(rand::random(), true, false; "with_rewards")] #[test_case(rand::random(), true, true; "no_minimum")] @@ -1387,13 +1400,15 @@ mod tests { // run everything a number of times to get a good sample for _ in 0..100 { // PoolState tracks all outstanding tokens and the total combined stake - // there is no reasonable way to track "deposited stake" because reward accrual makes this concept incoherent - // a token corresponds to a percentage, not a stake value + // there is no reasonable way to track "deposited stake" because reward accrual + // makes this concept incoherent a token corresponds to a + // percentage, not a stake value let mut pool = PoolState::default(); // generate between 1 and 100 users and have ~half of them deposit // note for most of these tests we adhere to the minimum delegation - // one of the thing we want to see is deposit size being many ooms larger than reward size + // one of the thing we want to see is deposit size being many ooms larger than + // reward size let mut users = vec![]; let user_count: usize = prng.gen_range(1..=100); for _ in 0..user_count { @@ -1407,7 +1422,8 @@ mod tests { } // now we do a set of arbitrary operations and confirm invariants hold - // we underweight withdraw a little bit to lessen the chances we random walk to an empty pool + // we underweight withdraw a little bit to lessen the chances we random walk to + // an empty pool for _ in 0..1000 { match op_range.sample(&mut prng) { // deposit a random amount of stake for tokens with a random user @@ -1495,7 +1511,8 @@ mod tests { } // run a single epoch worth of rewards - // check all user shares stay the same and stakes increase by the expected amount + // check all user shares stay the same and stakes increase by the expected + // amount _ => { assert!(with_rewards); @@ -1515,7 +1532,8 @@ mod tests { let stake_share = prev_stake as f64 * INFLATION_BASE_RATE; let stake_diff = (curr_stake - prev_stake) as f64; - // stake increase is within 2 lamps when calculated as a difference or a percentage + // stake increase is within 2 lamps when calculated as a difference or a + // percentage assert!((stake_share - stake_diff).abs() <= 2.0); } } diff --git a/single-pool/program/src/state.rs b/single-pool/program/src/state.rs index 0174263fe63..d13ada20991 100644 --- a/single-pool/program/src/state.rs +++ b/single-pool/program/src/state.rs @@ -45,8 +45,9 @@ impl SinglePool { return Err(SinglePoolError::InvalidPoolAccount.into()); } - // pool vote account address is properly configured. in practice this is irrefutable - // because the pool is initialized from the addresss that derives it, and never modified + // pool vote account address is properly configured. in practice this is + // irrefutable because the pool is initialized from the addresss that + // derives it, and never modified if *account_info.key != find_pool_address(program_id, &pool.vote_account_address) { return Err(SinglePoolError::InvalidPoolAccount.into()); } diff --git a/single-pool/program/tests/accounts.rs b/single-pool/program/tests/accounts.rs index 5d8a928e0bb..1c3cfd44886 100644 --- a/single-pool/program/tests/accounts.rs +++ b/single-pool/program/tests/accounts.rs @@ -27,7 +27,8 @@ enum TestMode { } // build a full transaction for initialize, deposit, and withdraw -// this is used to test knocking out individual accounts, for the sake of confirming the pubkeys are checked +// this is used to test knocking out individual accounts, for the sake of +// confirming the pubkeys are checked async fn build_instructions( context: &mut ProgramTestContext, accounts: &SinglePoolAccounts, @@ -197,7 +198,8 @@ async fn fail_account_checks(test_mode: TestMode) { // make an individual instruction for all program instructions // the match is just so this will error if new instructions are added -// if you are reading this because of that error, add the case to the `consistent_account_order` test!!! +// if you are reading this because of that error, add the case to the +// `consistent_account_order` test!!! fn make_basic_instruction( accounts: &SinglePoolAccounts, instruction_type: SinglePoolInstruction, @@ -246,7 +248,8 @@ where data.windows(2).all(|w| w[0] <= w[1]) } -// check that major accounts always show up in the same order, to spare developer confusion +// check that major accounts always show up in the same order, to spare +// developer confusion #[test] fn consistent_account_order() { let accounts = SinglePoolAccounts::default(); diff --git a/single-pool/program/tests/deposit.rs b/single-pool/program/tests/deposit.rs index e0ae74d05f3..962b77e6cd8 100644 --- a/single-pool/program/tests/deposit.rs +++ b/single-pool/program/tests/deposit.rs @@ -144,7 +144,8 @@ async fn success(activate: bool, extra_lamports: u64, prior_deposit: bool) { ); // alice got her rent back if active, or everything otherwise - // and if someone sent lamports to the stake account, the next depositor gets them + // and if someone sent lamports to the stake account, the next depositor gets + // them assert_eq!( wallet_lamports_after_deposit, USER_STARTING_LAMPORTS - expected_deposit + extra_lamports, diff --git a/single-pool/program/tests/helpers/mod.rs b/single-pool/program/tests/helpers/mod.rs index c35d30a8386..890753d4275 100644 --- a/single-pool/program/tests/helpers/mod.rs +++ b/single-pool/program/tests/helpers/mod.rs @@ -65,8 +65,9 @@ pub struct SinglePoolAccounts { pub token_program_id: Pubkey, } impl SinglePoolAccounts { - // does everything in initialize_for_deposit plus performs the deposit(s) and creates blank account(s) - // optionally advances to activation before the deposit + // does everything in initialize_for_deposit plus performs the deposit(s) and + // creates blank account(s) optionally advances to activation before the + // deposit pub async fn initialize_for_withdraw( &self, context: &mut ProgramTestContext, @@ -147,8 +148,9 @@ impl SinglePoolAccounts { minimum_delegation } - // does everything in initialize plus creates/delegates one or both stake accounts for our users - // note this does not advance time, so everything is in an activating state + // does everything in initialize plus creates/delegates one or both stake + // accounts for our users note this does not advance time, so everything is + // in an activating state pub async fn initialize_for_deposit( &self, context: &mut ProgramTestContext, @@ -206,8 +208,9 @@ impl SinglePoolAccounts { minimum_delegation } - // creates a vote account and stake pool for it. also sets up two users with sol and token accounts - // note this leaves the pool in an activating state. caller can advance to next epoch if they please + // creates a vote account and stake pool for it. also sets up two users with sol + // and token accounts note this leaves the pool in an activating state. + // caller can advance to next epoch if they please pub async fn initialize(&self, context: &mut ProgramTestContext) -> u64 { let slot = context.genesis_config().epoch_schedule.first_normal_slot + 1; context.warp_to_slot(slot).unwrap(); @@ -423,10 +426,10 @@ where }; // this silly thing is because we can guarantee From has a Debug for T - // but TryFrom produces Result and E may not have Debug. so we cant call unwrap - // also we use TryFrom because we have to go `instruction error-> program error` - // because StakeError impls the former but not the latter... - // and that conversion is merely surjective........ + // but TryFrom produces Result and E may not have Debug. so we cant + // call unwrap also we use TryFrom because we have to go `instruction + // error-> program error` because StakeError impls the former but not the + // latter... and that conversion is merely surjective........ // infomercial lady: "if only there were a better way!" let expected_p = match expected.clone().try_into() { Ok(v) => v, diff --git a/single-pool/program/tests/withdraw.rs b/single-pool/program/tests/withdraw.rs index d92c85dfb51..8a1bfa15c24 100644 --- a/single-pool/program/tests/withdraw.rs +++ b/single-pool/program/tests/withdraw.rs @@ -86,7 +86,8 @@ async fn success(activate: bool, extra_lamports: u64, prior_deposit: bool) { get_stake_account(&mut context.banks_client, &accounts.stake_account).await; let pool_stake_after = pool_stake_after.unwrap().delegation.stake; - // when active, the depositor gets their rent back, but when activating, its just added to stake + // when active, the depositor gets their rent back, but when activating, its + // just added to stake let expected_deposit = if activate { TEST_STAKE_AMOUNT } else { diff --git a/stake-pool/cli/src/main.rs b/stake-pool/cli/src/main.rs index bc3b443fd5d..60ab61c6b2e 100644 --- a/stake-pool/cli/src/main.rs +++ b/stake-pool/cli/src/main.rs @@ -1761,7 +1761,8 @@ fn command_set_manager( let new_fee_receiver = match new_fee_receiver { None => stake_pool.manager_fee_account, Some(value) => { - // Check for fee receiver being a valid token account and have to same mint as the stake pool + // Check for fee receiver being a valid token account and have to same mint as + // the stake pool let token_account = get_token_account(&config.rpc_client, value, &stake_pool.pool_mint)?; if token_account.mint != stake_pool.pool_mint { diff --git a/stake-pool/program/src/big_vec.rs b/stake-pool/program/src/big_vec.rs index 0d05f0aee11..f390114602f 100644 --- a/stake-pool/program/src/big_vec.rs +++ b/stake-pool/program/src/big_vec.rs @@ -70,7 +70,8 @@ impl<'data> BigVec<'data> { let gap = removals_found * mem::size_of::(); // In case the compute budget is ever bumped up, allowing us // to use this safe code instead: - //self.data.copy_within(dst_start_index + gap..data_end_index, dst_start_index); + //self.data.copy_within(dst_start_index + gap..data_end_index, + // dst_start_index); unsafe { sol_memmove( self.data[dst_start_index..data_end_index - gap].as_mut_ptr(), diff --git a/stake-pool/program/src/error.rs b/stake-pool/program/src/error.rs index afeaeaf49df..74a7885fe6b 100644 --- a/stake-pool/program/src/error.rs +++ b/stake-pool/program/src/error.rs @@ -13,7 +13,8 @@ pub enum StakePoolError { /// The account cannot be initialized because it is already being used. #[error("AlreadyInUse")] AlreadyInUse, - /// The program address provided doesn't match the value generated by the program. + /// The program address provided doesn't match the value generated by the + /// program. #[error("InvalidProgramAddress")] InvalidProgramAddress, /// The stake pool state is invalid. @@ -67,7 +68,8 @@ pub enum StakePoolError { /// Identify validator stake accounts with old balances and update them. #[error("StakeListOutOfDate")] StakeListOutOfDate, - /// First update old validator stake account balances and then pool stake balance. + /// First update old validator stake account balances and then pool stake + /// balance. #[error("StakeListAndPoolOutOfDate")] StakeListAndPoolOutOfDate, /// Validator stake account is not found in the list storage. @@ -78,7 +80,8 @@ pub enum StakePoolError { WrongMintingAuthority, // 20. - /// The size of the given validator stake list does match the expected amount + /// The size of the given validator stake list does match the expected + /// amount #[error("UnexpectedValidatorListAccountSize")] UnexpectedValidatorListAccountSize, /// Wrong pool staker account. @@ -90,12 +93,14 @@ pub enum StakePoolError { /// The lamports in the validator stake account is not equal to the minimum #[error("StakeLamportsNotEqualToMinimum")] StakeLamportsNotEqualToMinimum, - /// The provided deposit stake account is not delegated to the preferred deposit vote account + /// The provided deposit stake account is not delegated to the preferred + /// deposit vote account #[error("IncorrectDepositVoteAddress")] IncorrectDepositVoteAddress, // 25. - /// The provided withdraw stake account is not the preferred deposit vote account + /// The provided withdraw stake account is not the preferred deposit vote + /// account #[error("IncorrectWithdrawVoteAddress")] IncorrectWithdrawVoteAddress, /// The mint has an invalid freeze authority @@ -121,7 +126,8 @@ pub enum StakePoolError { /// Provided preferred validator is invalid #[error("InvalidPreferredValidator")] InvalidPreferredValidator, - /// Provided validator stake account already has a transient stake account in use + /// Provided validator stake account already has a transient stake account + /// in use #[error("TransientAccountInUse")] TransientAccountInUse, /// Provided sol withdraw authority does not match the program's @@ -132,7 +138,8 @@ pub enum StakePoolError { /// Too much SOL withdrawn from the stake pool's reserve account #[error("SolWithdrawalTooLarge")] SolWithdrawalTooLarge, - /// Provided metadata account does not match metadata account derived for pool mint + /// Provided metadata account does not match metadata account derived for + /// pool mint #[error("InvalidMetadataAccount")] InvalidMetadataAccount, /// The mint has an unsupported extension @@ -149,9 +156,9 @@ pub enum StakePoolError { /// Provided mint does not have 9 decimals to match SOL #[error("IncorrectMintDecimals")] IncorrectMintDecimals, - /// Pool reserve does not have enough lamports to fund rent-exempt reserve in split - /// destination. Deposit more SOL in reserve, or pre-fund split destination with - /// the rent-exempt reserve for a stake account. + /// Pool reserve does not have enough lamports to fund rent-exempt reserve + /// in split destination. Deposit more SOL in reserve, or pre-fund split + /// destination with the rent-exempt reserve for a stake account. #[error("ReserveDepleted")] ReserveDepleted, /// Missing required sysvar account diff --git a/stake-pool/program/src/inline_mpl_token_metadata.rs b/stake-pool/program/src/inline_mpl_token_metadata.rs index 4de593e3721..b7697a29419 100644 --- a/stake-pool/program/src/inline_mpl_token_metadata.rs +++ b/stake-pool/program/src/inline_mpl_token_metadata.rs @@ -1,6 +1,6 @@ -//! Inlined MPL metadata types to avoid a direct dependency on `mpl-token-metadata' -//! NOTE: this file is sym-linked in `spl-single-pool`, so be careful -//! with changes! +//! Inlined MPL metadata types to avoid a direct dependency on +//! `mpl-token-metadata' NOTE: this file is sym-linked in `spl-single-pool`, so +//! be careful with changes! solana_program::declare_id!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"); @@ -127,7 +127,8 @@ pub(crate) mod state { pub symbol: String, /// URI pointing to JSON representing the asset pub uri: String, - /// Royalty basis points that goes to creators in secondary sales (0-10000) + /// Royalty basis points that goes to creators in secondary sales + /// (0-10000) pub seller_fee_basis_points: u16, /// UNUSED Array of creators, optional pub creators: Option, diff --git a/stake-pool/program/src/instruction.rs b/stake-pool/program/src/instruction.rs index fb07373cd5f..ff892f4df6f 100644 --- a/stake-pool/program/src/instruction.rs +++ b/stake-pool/program/src/instruction.rs @@ -56,13 +56,15 @@ pub enum StakePoolInstruction { /// 3. `[]` Stake pool withdraw authority /// 4. `[w]` Uninitialized validator stake list storage account /// 5. `[]` Reserve stake account must be initialized, have zero balance, - /// and staker / withdrawer authority set to pool withdraw authority. - /// 6. `[]` Pool token mint. Must have zero supply, owned by withdraw authority. + /// and staker / withdrawer authority set to pool withdraw authority. + /// 6. `[]` Pool token mint. Must have zero supply, owned by withdraw + /// authority. /// 7. `[]` Pool account to deposit the generated fee for manager. /// 8. `[]` Token program id /// 9. `[]` (Optional) Deposit authority that must sign all deposits. /// Defaults to the program address generated using - /// `find_deposit_authority_program_address`, making deposits permissionless. + /// `find_deposit_authority_program_address`, making deposits + /// permissionless. Initialize { /// Fee assessed as percentage of perceived rewards fee: Fee, @@ -80,7 +82,8 @@ pub enum StakePoolInstruction { /// list of managed validators. /// /// The stake account will have the rent-exempt amount plus - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// It is funded from the stake pool reserve. /// /// 0. `[w]` Stake pool @@ -104,8 +107,9 @@ pub enum StakePoolInstruction { /// (Staker only) Removes validator from the pool, deactivating its stake /// /// Only succeeds if the validator stake account has the minimum of - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. - /// plus the rent-exempt amount. + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. plus the + /// rent-exempt amount. /// /// 0. `[w]` Stake pool /// 1. `[s]` Staker @@ -120,19 +124,22 @@ pub enum StakePoolInstruction { /// NOTE: This instruction has been deprecated since version 0.7.0. Please /// use `DecreaseValidatorStakeWithReserve` instead. /// - /// (Staker only) Decrease active stake on a validator, eventually moving it to the reserve + /// (Staker only) Decrease active stake on a validator, eventually moving it + /// to the reserve /// /// Internally, this instruction splits a validator stake account into its /// corresponding transient stake account and deactivates it. /// /// In order to rebalance the pool without taking custody, the staker needs /// a way of reducing the stake on a stake account. This instruction splits - /// some amount of stake, up to the total activated stake, from the canonical - /// validator stake account, into its "transient" stake account. + /// some amount of stake, up to the total activated stake, from the + /// canonical validator stake account, into its "transient" stake + /// account. /// /// The instruction only succeeds if the transient stake account does not - /// exist. The amount of lamports to move must be at least rent-exemption plus - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// exist. The amount of lamports to move must be at least rent-exemption + /// plus `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[]` Stake pool /// 1. `[s]` Stake pool staker @@ -154,12 +161,14 @@ pub enum StakePoolInstruction { /// (Staker only) Increase stake on a validator from the reserve account /// /// Internally, this instruction splits reserve stake into a transient stake - /// account and delegate to the appropriate validator. `UpdateValidatorListBalance` - /// will do the work of merging once it's ready. + /// account and delegate to the appropriate validator. + /// `UpdateValidatorListBalance` will do the work of merging once it's + /// ready. /// - /// This instruction only succeeds if the transient stake account does not exist. - /// The minimum amount to move is rent-exemption plus - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// This instruction only succeeds if the transient stake account does not + /// exist. The minimum amount to move is rent-exemption plus + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[]` Stake pool /// 1. `[s]` Stake pool staker @@ -178,8 +187,8 @@ pub enum StakePoolInstruction { /// userdata: amount of lamports to increase on the given validator. /// The actual amount split into the transient stake account is: /// `lamports + stake_rent_exemption` - /// The rent-exemption of the stake account is withdrawn back to the reserve - /// after it is merged. + /// The rent-exemption of the stake account is withdrawn back to the + /// reserve after it is merged. IncreaseValidatorStake { /// amount of lamports to increase on the given validator lamports: u64, @@ -187,12 +196,13 @@ pub enum StakePoolInstruction { transient_stake_seed: u64, }, - /// (Staker only) Set the preferred deposit or withdraw stake account for the - /// stake pool + /// (Staker only) Set the preferred deposit or withdraw stake account for + /// the stake pool /// /// In order to avoid users abusing the stake pool as a free conversion /// between SOL staked on different validators, the staker can force all - /// deposits and/or withdraws to go to one chosen account, or unset that account. + /// deposits and/or withdraws to go to one chosen account, or unset that + /// account. /// /// 0. `[w]` Stake pool /// 1. `[s]` Stake pool staker @@ -209,12 +219,12 @@ pub enum StakePoolInstruction { /// Updates balances of validator and transient stake accounts in the pool /// - /// While going through the pairs of validator and transient stake accounts, - /// if the transient stake is inactive, it is merged into the reserve stake - /// account. If the transient stake is active and has matching credits - /// observed, it is merged into the canonical validator stake account. In - /// all other states, nothing is done, and the balance is simply added to - /// the canonical stake account balance. + /// While going through the pairs of validator and transient stake + /// accounts, if the transient stake is inactive, it is merged into the + /// reserve stake account. If the transient stake is active and has + /// matching credits observed, it is merged into the canonical + /// validator stake account. In all other states, nothing is done, and + /// the balance is simply added to the canonical stake account balance. /// /// 0. `[]` Stake pool /// 1. `[]` Stake pool withdraw authority @@ -227,13 +237,15 @@ pub enum StakePoolInstruction { UpdateValidatorListBalance { /// Index to start updating on the validator list start_index: u32, - /// If true, don't try merging transient stake accounts into the reserve or - /// validator stake account. Useful for testing or if a particular stake - /// account is in a bad state, but we still want to update + /// If true, don't try merging transient stake accounts into the reserve + /// or validator stake account. Useful for testing or if a + /// particular stake account is in a bad state, but we still + /// want to update no_merge: bool, }, - /// Updates total pool balance based on balances in the reserve and validator list + /// Updates total pool balance based on balances in the reserve and + /// validator list /// /// 0. `[w]` Stake pool /// 1. `[]` Stake pool withdraw authority @@ -250,19 +262,24 @@ pub enum StakePoolInstruction { /// 1. `[w]` Validator stake list storage account CleanupRemovedValidatorEntries, - /// Deposit some stake into the pool. The output is a "pool" token representing ownership - /// into the pool. Inputs are converted to the current ratio. + /// Deposit some stake into the pool. The output is a "pool" token + /// representing ownership into the pool. Inputs are converted to the + /// current ratio. /// /// 0. `[w]` Stake pool /// 1. `[w]` Validator stake list storage account /// 2. `[s]/[]` Stake pool deposit authority /// 3. `[]` Stake pool withdraw authority - /// 4. `[w]` Stake account to join the pool (withdraw authority for the stake account should be first set to the stake pool deposit authority) - /// 5. `[w]` Validator stake account for the stake account to be merged with + /// 4. `[w]` Stake account to join the pool (withdraw authority for the + /// stake account should be first set to the stake pool deposit + /// authority) + /// 5. `[w]` Validator stake account for the stake account to be merged + /// with /// 6. `[w]` Reserve stake account, to withdraw rent exempt reserve /// 7. `[w]` User account to receive pool tokens /// 8. `[w]` Account to receive pool fee tokens - /// 9. `[w]` Account to receive a portion of pool fee tokens as referral fees + /// 9. `[w]` Account to receive a portion of pool fee tokens as referral + /// fees /// 10. `[w]` Pool token mint account /// 11. '[]' Sysvar clock account /// 12. '[]' Sysvar stake history account @@ -272,10 +289,11 @@ pub enum StakePoolInstruction { /// Withdraw the token from the pool at the current ratio. /// - /// Succeeds if the stake account has enough SOL to cover the desired amount - /// of pool tokens, and if the withdrawal keeps the total staked amount - /// above the minimum of rent-exempt amount + - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// Succeeds if the stake account has enough SOL to cover the desired + /// amount of pool tokens, and if the withdrawal keeps the total + /// staked amount above the minimum of rent-exempt amount + + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// When allowing withdrawals, the order of priority goes: /// @@ -329,8 +347,9 @@ pub enum StakePoolInstruction { /// 2. '[]` New staker pubkey SetStaker, - /// Deposit SOL directly into the pool's reserve account. The output is a "pool" token - /// representing ownership into the pool. Inputs are converted to the current ratio. + /// Deposit SOL directly into the pool's reserve account. The output is a + /// "pool" token representing ownership into the pool. Inputs are + /// converted to the current ratio. /// /// 0. `[w]` Stake pool /// 1. `[]` Stake pool withdraw authority @@ -345,7 +364,8 @@ pub enum StakePoolInstruction { /// 10. `[s]` (Optional) Stake pool sol deposit authority. DepositSol(u64), - /// (Manager only) Update SOL deposit, stake deposit, or SOL withdrawal authority. + /// (Manager only) Update SOL deposit, stake deposit, or SOL withdrawal + /// authority. /// /// 0. `[w]` StakePool /// 1. `[s]` Manager @@ -360,7 +380,8 @@ pub enum StakePoolInstruction { /// 2. `[s]` User transfer authority, for pool token account /// 3. `[w]` User account to burn pool tokens /// 4. `[w]` Reserve stake account, to withdraw SOL - /// 5. `[w]` Account receiving the lamports from the reserve, must be a system account + /// 5. `[w]` Account receiving the lamports from the reserve, must be a + /// system account /// 6. `[w]` Account to receive pool fee tokens /// 7. `[w]` Pool token mint account /// 8. '[]' Clock sysvar @@ -409,13 +430,15 @@ pub enum StakePoolInstruction { /// /// Works regardless if the transient stake account exists. /// - /// Internally, this instruction splits reserve stake into an ephemeral stake - /// account, activates it, then merges or splits it into the transient stake - /// account delegated to the appropriate validator. `UpdateValidatorListBalance` - /// will do the work of merging once it's ready. + /// Internally, this instruction splits reserve stake into an ephemeral + /// stake account, activates it, then merges or splits it into the + /// transient stake account delegated to the appropriate validator. + /// `UpdateValidatorListBalance` will do the work of merging once it's + /// ready. /// /// The minimum amount to move is rent-exemption plus - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[]` Stake pool /// 1. `[s]` Stake pool staker @@ -434,8 +457,8 @@ pub enum StakePoolInstruction { /// userdata: amount of lamports to increase on the given validator. /// The actual amount split into the transient stake account is: /// `lamports + stake_rent_exemption` - /// The rent-exemption of the stake account is withdrawn back to the reserve - /// after it is merged. + /// The rent-exemption of the stake account is withdrawn back to the + /// reserve after it is merged. IncreaseAdditionalValidatorStake { /// amount of lamports to increase on the given validator lamports: u64, @@ -445,19 +468,22 @@ pub enum StakePoolInstruction { ephemeral_stake_seed: u64, }, - /// (Staker only) Decrease active stake again from a validator, eventually moving it to the reserve + /// (Staker only) Decrease active stake again from a validator, eventually + /// moving it to the reserve /// /// Works regardless if the transient stake account already exists. /// /// Internally, this instruction: - /// * withdraws rent-exempt reserve lamports from the reserve into the ephemeral stake + /// * withdraws rent-exempt reserve lamports from the reserve into the + /// ephemeral stake /// * splits a validator stake account into an ephemeral stake account /// * deactivates the ephemeral account - /// * merges or splits the ephemeral account into the transient stake account - /// delegated to the appropriate validator + /// * merges or splits the ephemeral account into the transient stake + /// account delegated to the appropriate validator /// /// The amount of lamports to move must be at least - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[]` Stake pool /// 1. `[s]` Stake pool staker @@ -480,7 +506,8 @@ pub enum StakePoolInstruction { ephemeral_stake_seed: u64, }, - /// (Staker only) Decrease active stake on a validator, eventually moving it to the reserve + /// (Staker only) Decrease active stake on a validator, eventually moving it + /// to the reserve /// /// Internally, this instruction: /// * withdraws enough lamports to make the transient account rent-exempt @@ -489,12 +516,14 @@ pub enum StakePoolInstruction { /// /// In order to rebalance the pool without taking custody, the staker needs /// a way of reducing the stake on a stake account. This instruction splits - /// some amount of stake, up to the total activated stake, from the canonical - /// validator stake account, into its "transient" stake account. + /// some amount of stake, up to the total activated stake, from the + /// canonical validator stake account, into its "transient" stake + /// account. /// /// The instruction only succeeds if the transient stake account does not - /// exist. The amount of lamports to move must be at least rent-exemption plus - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// exist. The amount of lamports to move must be at least rent-exemption + /// plus `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[]` Stake pool /// 1. `[s]` Stake pool staker @@ -514,16 +543,19 @@ pub enum StakePoolInstruction { transient_stake_seed: u64, }, - /// (Staker only) Redelegate active stake on a validator, eventually moving it to another + /// (Staker only) Redelegate active stake on a validator, eventually moving + /// it to another /// /// Internally, this instruction splits a validator stake account into its - /// corresponding transient stake account, redelegates it to an ephemeral stake - /// account, then merges that stake into the destination transient stake account. + /// corresponding transient stake account, redelegates it to an ephemeral + /// stake account, then merges that stake into the destination transient + /// stake account. /// /// In order to rebalance the pool without taking custody, the staker needs /// a way of reducing the stake on a stake account. This instruction splits - /// some amount of stake, up to the total activated stake, from the canonical - /// validator stake account, into its "transient" stake account. + /// some amount of stake, up to the total activated stake, from the + /// canonical validator stake account, into its "transient" stake + /// account. /// /// The instruction only succeeds if the source transient stake account and /// ephemeral stake account do not exist. @@ -548,10 +580,13 @@ pub enum StakePoolInstruction { /// 3. `[w]` Validator list /// 4. `[w]` Reserve stake account, to withdraw rent exempt reserve /// 5. `[w]` Source canonical stake account to split from - /// 6. `[w]` Source transient stake account to receive split and be redelegated + /// 6. `[w]` Source transient stake account to receive split and be + /// redelegated /// 7. `[w]` Uninitialized ephemeral stake account to receive redelegation - /// 8. `[w]` Destination transient stake account to receive ephemeral stake by merge - /// 9. `[]` Destination stake account to receive transient stake after activation + /// 8. `[w]` Destination transient stake account to receive ephemeral stake + /// by merge + /// 9. `[]` Destination stake account to receive transient stake after + /// activation /// 10. `[]` Destination validator vote account /// 11. `[]` Clock sysvar /// 12. `[]` Stake History sysvar @@ -575,20 +610,24 @@ pub enum StakePoolInstruction { destination_transient_stake_seed: u64, }, - /// Deposit some stake into the pool, with a specified slippage constraint. - /// The output is a "pool" token representing ownership into the pool. - /// Inputs are converted at the current ratio. + /// Deposit some stake into the pool, with a specified slippage + /// constraint. The output is a "pool" token representing ownership + /// into the pool. Inputs are converted at the current ratio. /// /// 0. `[w]` Stake pool /// 1. `[w]` Validator stake list storage account /// 2. `[s]/[]` Stake pool deposit authority /// 3. `[]` Stake pool withdraw authority - /// 4. `[w]` Stake account to join the pool (withdraw authority for the stake account should be first set to the stake pool deposit authority) - /// 5. `[w]` Validator stake account for the stake account to be merged with + /// 4. `[w]` Stake account to join the pool (withdraw authority for the + /// stake account should be first set to the stake pool deposit + /// authority) + /// 5. `[w]` Validator stake account for the stake account to be merged + /// with /// 6. `[w]` Reserve stake account, to withdraw rent exempt reserve /// 7. `[w]` User account to receive pool tokens /// 8. `[w]` Account to receive pool fee tokens - /// 9. `[w]` Account to receive a portion of pool fee tokens as referral fees + /// 9. `[w]` Account to receive a portion of pool fee tokens as referral + /// fees /// 10. `[w]` Pool token mint account /// 11. '[]' Sysvar clock account /// 12. '[]' Sysvar stake history account @@ -602,10 +641,11 @@ pub enum StakePoolInstruction { /// Withdraw the token from the pool at the current ratio, specifying a /// minimum expected output lamport amount. /// - /// Succeeds if the stake account has enough SOL to cover the desired amount - /// of pool tokens, and if the withdrawal keeps the total staked amount - /// above the minimum of rent-exempt amount + - /// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`. + /// Succeeds if the stake account has enough SOL to cover the desired + /// amount of pool tokens, and if the withdrawal keeps the total + /// staked amount above the minimum of rent-exempt amount + + /// `max(crate::MINIMUM_ACTIVE_STAKE, + /// solana_program::stake::tools::get_minimum_delegation())`. /// /// 0. `[w]` Stake pool /// 1. `[w]` Validator stake list storage account @@ -629,8 +669,9 @@ pub enum StakePoolInstruction { }, /// Deposit SOL directly into the pool's reserve account, with a specified - /// slippage constraint. The output is a "pool" token representing ownership - /// into the pool. Inputs are converted at the current ratio. + /// slippage constraint. The output is a "pool" token representing + /// ownership into the pool. Inputs are converted at the current + /// ratio. /// /// 0. `[w]` Stake pool /// 1. `[]` Stake pool withdraw authority @@ -659,7 +700,8 @@ pub enum StakePoolInstruction { /// 2. `[s]` User transfer authority, for pool token account /// 3. `[w]` User account to burn pool tokens /// 4. `[w]` Reserve stake account, to withdraw SOL - /// 5. `[w]` Account receiving the lamports from the reserve, must be a system account + /// 5. `[w]` Account receiving the lamports from the reserve, must be a + /// system account /// 6. `[w]` Account to receive pool fee tokens /// 7. `[w]` Pool token mint account /// 8. '[]' Clock sysvar @@ -723,7 +765,8 @@ pub fn initialize( } } -/// Creates `AddValidatorToPool` instruction (add new validator stake account to the pool) +/// Creates `AddValidatorToPool` instruction (add new validator stake account to +/// the pool) pub fn add_validator_to_pool( program_id: &Pubkey, stake_pool: &Pubkey, @@ -761,7 +804,8 @@ pub fn add_validator_to_pool( } } -/// Creates `RemoveValidatorFromPool` instruction (remove validator stake account from the pool) +/// Creates `RemoveValidatorFromPool` instruction (remove validator stake +/// account from the pool) pub fn remove_validator_from_pool( program_id: &Pubkey, stake_pool: &Pubkey, @@ -790,8 +834,8 @@ pub fn remove_validator_from_pool( } } -/// Creates `DecreaseValidatorStake` instruction (rebalance from validator account to -/// transient account) +/// Creates `DecreaseValidatorStake` instruction (rebalance from validator +/// account to transient account) #[deprecated( since = "0.7.0", note = "please use `decrease_validator_stake_with_reserve`" @@ -913,8 +957,8 @@ pub fn decrease_validator_stake_with_reserve( } } -/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to -/// transient account) +/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account +/// to transient account) pub fn increase_validator_stake( program_id: &Pubkey, stake_pool: &Pubkey, @@ -957,8 +1001,8 @@ pub fn increase_validator_stake( } } -/// Creates `IncreaseAdditionalValidatorStake` instruction (rebalance from reserve account to -/// transient account) +/// Creates `IncreaseAdditionalValidatorStake` instruction (rebalance from +/// reserve account to transient account) pub fn increase_additional_validator_stake( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1004,7 +1048,8 @@ pub fn increase_additional_validator_stake( } } -/// Creates `Redelegate` instruction (rebalance from one validator account to another) +/// Creates `Redelegate` instruction (rebalance from one validator account to +/// another) pub fn redelegate( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1107,8 +1152,8 @@ pub fn add_validator_to_pool_with_vote( ) } -/// Create an `RemoveValidatorFromPool` instruction given an existing stake pool and -/// vote account +/// Create an `RemoveValidatorFromPool` instruction given an existing stake pool +/// and vote account pub fn remove_validator_from_pool_with_vote( program_id: &Pubkey, stake_pool: &StakePool, @@ -1142,8 +1187,8 @@ pub fn remove_validator_from_pool_with_vote( ) } -/// Create an `IncreaseValidatorStake` instruction given an existing stake pool and -/// vote account +/// Create an `IncreaseValidatorStake` instruction given an existing stake pool +/// and vote account pub fn increase_validator_stake_with_vote( program_id: &Pubkey, stake_pool: &StakePool, @@ -1229,8 +1274,8 @@ pub fn increase_additional_validator_stake_with_vote( ) } -/// Create a `DecreaseValidatorStake` instruction given an existing stake pool and -/// vote account +/// Create a `DecreaseValidatorStake` instruction given an existing stake pool +/// and vote account pub fn decrease_validator_stake_with_vote( program_id: &Pubkey, stake_pool: &StakePool, @@ -1312,7 +1357,8 @@ pub fn decrease_additional_validator_stake_with_vote( ) } -/// Creates `UpdateValidatorListBalance` instruction (update validator stake account balances) +/// Creates `UpdateValidatorListBalance` instruction (update validator stake +/// account balances) pub fn update_validator_list_balance( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1373,7 +1419,8 @@ pub fn update_validator_list_balance( } } -/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake account list balances) +/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake +/// account list balances) pub fn update_stake_pool_balance( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1402,7 +1449,8 @@ pub fn update_stake_pool_balance( } } -/// Creates `CleanupRemovedValidatorEntries` instruction (removes entries from the validator list) +/// Creates `CleanupRemovedValidatorEntries` instruction (removes entries from +/// the validator list) pub fn cleanup_removed_validator_entries( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1690,9 +1738,10 @@ pub fn deposit_stake_with_authority( ) } -/// Creates instructions required to deposit into a stake pool with slippage, given -/// a stake account owned by the user. The difference with `deposit()` is that a deposit -/// authority must sign this instruction, which is required for private pools. +/// Creates instructions required to deposit into a stake pool with slippage, +/// given a stake account owned by the user. The difference with `deposit()` is +/// that a deposit authority must sign this instruction, which is required for +/// private pools. pub fn deposit_stake_with_authority_and_slippage( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1813,7 +1862,8 @@ pub fn deposit_sol( ) } -/// Creates instruction to deposit SOL directly into a stake pool with slippage constraint. +/// Creates instruction to deposit SOL directly into a stake pool with slippage +/// constraint. pub fn deposit_sol_with_slippage( program_id: &Pubkey, stake_pool: &Pubkey, @@ -1879,7 +1929,8 @@ pub fn deposit_sol_with_authority( ) } -/// Creates instruction to deposit SOL directly into a stake pool with slippage constraint. +/// Creates instruction to deposit SOL directly into a stake pool with slippage +/// constraint. pub fn deposit_sol_with_authority_and_slippage( program_id: &Pubkey, stake_pool: &Pubkey, @@ -2304,8 +2355,8 @@ pub fn set_funding_authority( } } -/// Creates an instruction to update metadata in the mpl token metadata program account for -/// the pool token +/// Creates an instruction to update metadata in the mpl token metadata program +/// account for the pool token pub fn update_token_metadata( program_id: &Pubkey, stake_pool: &Pubkey, @@ -2336,8 +2387,8 @@ pub fn update_token_metadata( } } -/// Creates an instruction to create metadata using the mpl token metadata program for -/// the pool token +/// Creates an instruction to create metadata using the mpl token metadata +/// program for the pool token pub fn create_token_metadata( program_id: &Pubkey, stake_pool: &Pubkey, diff --git a/stake-pool/program/src/lib.rs b/stake-pool/program/src/lib.rs index 8ef0193f968..fe48880be98 100644 --- a/stake-pool/program/src/lib.rs +++ b/stake-pool/program/src/lib.rs @@ -12,7 +12,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] pub mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use { crate::state::Fee, @@ -32,8 +33,8 @@ const TRANSIENT_STAKE_SEED_PREFIX: &[u8] = b"transient"; /// Seed for ephemeral stake account const EPHEMERAL_STAKE_SEED_PREFIX: &[u8] = b"ephemeral"; -/// Minimum amount of staked lamports required in a validator stake account to allow -/// for merges without a mismatch on credits observed +/// Minimum amount of staked lamports required in a validator stake account to +/// allow for merges without a mismatch on credits observed pub const MINIMUM_ACTIVE_STAKE: u64 = 1_000_000; /// Minimum amount of lamports in the reserve diff --git a/stake-pool/program/src/processor.rs b/stake-pool/program/src/processor.rs index b25ec780531..6f5ef75feaf 100644 --- a/stake-pool/program/src/processor.rs +++ b/stake-pool/program/src/processor.rs @@ -279,9 +279,9 @@ fn check_stake_state( Ok(()) } -/// Checks if a validator stake account is valid, which means that it's usable by -/// the pool and delegated to the expected validator. These conditions can be violated -/// if a validator was force destaked during a cluster restart. +/// Checks if a validator stake account is valid, which means that it's usable +/// by the pool and delegated to the expected validator. These conditions can be +/// violated if a validator was force destaked during a cluster restart. fn check_validator_stake_account( stake_account_info: &AccountInfo, program_id: &Pubkey, @@ -308,9 +308,9 @@ fn check_validator_stake_account( Ok(()) } -/// Checks if a transient stake account is valid, which means that it's usable by -/// the pool and delegated to the expected validator. These conditions can be violated -/// if a validator was force destaked during a cluster restart. +/// Checks if a transient stake account is valid, which means that it's usable +/// by the pool and delegated to the expected validator. These conditions can be +/// violated if a validator was force destaked during a cluster restart. fn check_transient_stake_account( stake_account_info: &AccountInfo, program_id: &Pubkey, @@ -467,7 +467,8 @@ impl Processor { ) } - /// Issue stake::instruction::authorize instructions to update both authorities + /// Issue stake::instruction::authorize instructions to update both + /// authorities fn stake_authorize<'a>( stake_account: AccountInfo<'a>, stake_authority: AccountInfo<'a>, @@ -505,7 +506,8 @@ impl Processor { ) } - /// Issue stake::instruction::authorize instructions to update both authorities + /// Issue stake::instruction::authorize instructions to update both + /// authorities #[allow(clippy::too_many_arguments)] fn stake_authorize_signed<'a>( stake_pool: &Pubkey, @@ -551,7 +553,8 @@ impl Processor { ) } - /// Issue stake::instruction::withdraw instruction to move additional lamports + /// Issue stake::instruction::withdraw instruction to move additional + /// lamports #[allow(clippy::too_many_arguments)] fn stake_withdraw<'a>( stake_pool: &Pubkey, @@ -1908,8 +1911,9 @@ impl Processor { // check that we're redelegating enough { - // redelegation requires that the source account maintains rent exemption and that - // the destination account has rent-exemption and minimum delegation + // redelegation requires that the source account maintains rent exemption and + // that the destination account has rent-exemption and minimum + // delegation let minimum_redelegation_lamports = current_minimum_delegation.saturating_add(stake_rent); if lamports < minimum_redelegation_lamports { @@ -2430,7 +2434,8 @@ impl Processor { // Status for validator stake // * active -> do everything - // * any other state / not a stake -> error state, but account for transient stake + // * any other state / not a stake -> error state, but account for transient + // stake let validator_stake_state = try_from_slice_unchecked::( &validator_stake_info.data.borrow(), ) @@ -3159,7 +3164,8 @@ impl Processor { } // To prevent a faulty manager fee account from preventing withdrawals - // if the token program does not own the account, or if the account is not initialized + // if the token program does not own the account, or if the account is not + // initialized let pool_tokens_fee = if stake_pool.manager_fee_account == *burn_from_pool_info.key || stake_pool.check_manager_fee_info(manager_fee_info).is_err() { @@ -3468,7 +3474,8 @@ impl Processor { } // To prevent a faulty manager fee account from preventing withdrawals - // if the token program does not own the account, or if the account is not initialized + // if the token program does not own the account, or if the account is not + // initialized let pool_tokens_fee = if stake_pool.manager_fee_account == *burn_from_pool_info.key || stake_pool.check_manager_fee_info(manager_fee_info).is_err() { diff --git a/stake-pool/program/src/state.rs b/stake-pool/program/src/state.rs index b218cecd40b..f35dd508812 100644 --- a/stake-pool/program/src/state.rs +++ b/stake-pool/program/src/state.rs @@ -46,17 +46,18 @@ pub struct StakePool { /// Account type, must be StakePool currently pub account_type: AccountType, - /// Manager authority, allows for updating the staker, manager, and fee account + /// Manager authority, allows for updating the staker, manager, and fee + /// account pub manager: Pubkey, - /// Staker authority, allows for adding and removing validators, and managing stake - /// distribution + /// Staker authority, allows for adding and removing validators, and + /// managing stake distribution pub staker: Pubkey, /// Stake deposit authority /// - /// If a depositor pubkey is specified on initialization, then deposits must be - /// signed by this authority. If no deposit authority is specified, + /// If a depositor pubkey is specified on initialization, then deposits must + /// be signed by this authority. If no deposit authority is specified, /// then the stake pool will default to the result of: /// `Pubkey::find_program_address( /// &[&stake_pool_address.as_ref(), b"deposit"], @@ -88,7 +89,8 @@ pub struct StakePool { /// this field may not be accurate pub total_lamports: u64, - /// Total supply of pool tokens (should always match the supply in the Pool Mint) + /// Total supply of pool tokens (should always match the supply in the Pool + /// Mint) pub pool_token_supply: u64, /// Last epoch the `total_lamports` field was updated @@ -120,8 +122,9 @@ pub struct StakePool { /// Fees paid out to referrers on referred stake deposits. /// Expressed as a percentage (0 - 100) of deposit fees. - /// i.e. `stake_deposit_fee`% of stake deposited is collected as deposit fees for every deposit - /// and `stake_referral_fee`% of the collected stake deposit fees is paid out to the referrer + /// i.e. `stake_deposit_fee`% of stake deposited is collected as deposit + /// fees for every deposit and `stake_referral_fee`% of the collected + /// stake deposit fees is paid out to the referrer pub stake_referral_fee: u8, /// Toggles whether the `DepositSol` instruction requires a signature from @@ -133,8 +136,9 @@ pub struct StakePool { /// Fees paid out to referrers on referred SOL deposits. /// Expressed as a percentage (0 - 100) of SOL deposit fees. - /// i.e. `sol_deposit_fee`% of SOL deposited is collected as deposit fees for every deposit - /// and `sol_referral_fee`% of the collected SOL deposit fees is paid out to the referrer + /// i.e. `sol_deposit_fee`% of SOL deposited is collected as deposit fees + /// for every deposit and `sol_referral_fee`% of the collected SOL + /// deposit fees is paid out to the referrer pub sol_referral_fee: u8, /// Toggles whether the `WithdrawSol` instruction requires a signature from @@ -154,7 +158,8 @@ pub struct StakePool { pub last_epoch_total_lamports: u64, } impl StakePool { - /// calculate the pool tokens that should be minted for a deposit of `stake_lamports` + /// calculate the pool tokens that should be minted for a deposit of + /// `stake_lamports` #[inline] pub fn calc_pool_tokens_for_deposit(&self, stake_lamports: u64) -> Option { if self.total_lamports == 0 || self.pool_token_supply == 0 { @@ -218,7 +223,8 @@ impl StakePool { u64::try_from(self.sol_deposit_fee.apply(pool_tokens_minted)?).ok() } - /// calculate pool tokens to be deducted from SOL deposit fees as referral fees + /// calculate pool tokens to be deducted from SOL deposit fees as referral + /// fees #[inline] pub fn calc_pool_tokens_sol_referral_fee(&self, sol_deposit_fee: u64) -> Option { u64::try_from( @@ -537,7 +543,8 @@ pub fn is_extension_supported_for_fee_account(extension_type: &ExtensionType) -> #[repr(C)] #[derive(Clone, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ValidatorList { - /// Data outside of the validator list, separated out for cheaper deserializations + /// Data outside of the validator list, separated out for cheaper + /// deserializations pub header: ValidatorListHeader, /// List of stake info for each validator in the pool @@ -606,7 +613,8 @@ impl Default for StakeStatus { )] pub struct PodStakeStatus(u8); impl PodStakeStatus { - /// Downgrade the status towards ready for removal by removing the validator stake + /// Downgrade the status towards ready for removal by removing the validator + /// stake pub fn remove_validator_stake(&mut self) -> Result<(), ProgramError> { let status = StakeStatus::try_from(*self)?; let new_self = match status { @@ -619,7 +627,8 @@ impl PodStakeStatus { *self = new_self.into(); Ok(()) } - /// Downgrade the status towards ready for removal by removing the transient stake + /// Downgrade the status towards ready for removal by removing the transient + /// stake pub fn remove_transient_stake(&mut self) -> Result<(), ProgramError> { let status = StakeStatus::try_from(*self)?; let new_self = match status { @@ -695,7 +704,8 @@ pub struct ValidatorStakeInfo { /// Last epoch the active and transient stake lamports fields were updated pub last_update_epoch: PodU64, - /// Transient account seed suffix, used to derive the transient stake account address + /// Transient account seed suffix, used to derive the transient stake + /// account address pub transient_seed_suffix: PodU64, /// Unused space, initially meant to specify the end of seed suffixes @@ -766,7 +776,8 @@ impl Pack for ValidatorStakeInfo { } impl ValidatorList { - /// Create an empty instance containing space for `max_validators` and preferred validator keys + /// Create an empty instance containing space for `max_validators` and + /// preferred validator keys pub fn new(max_validators: u32) -> Self { Self { header: ValidatorListHeader { @@ -777,7 +788,8 @@ impl ValidatorList { } } - /// Calculate the number of validator entries that fit in the provided length + /// Calculate the number of validator entries that fit in the provided + /// length pub fn calculate_max_validators(buffer_length: usize) -> usize { let header_size = ValidatorListHeader::LEN.saturating_add(4); buffer_length @@ -816,7 +828,8 @@ impl ValidatorList { impl ValidatorListHeader { const LEN: usize = 1 + 4; - /// Check if validator stake list is actually initialized as a validator stake list + /// Check if validator stake list is actually initialized as a validator + /// stake list pub fn is_valid(&self) -> bool { self.account_type == AccountType::ValidatorList } @@ -907,7 +920,8 @@ impl From> for Option { /// Fee rate as a ratio, minted on `UpdateStakePoolBalance` as a proportion of /// the rewards -/// If either the numerator or the denominator is 0, the fee is considered to be 0 +/// If either the numerator or the denominator is 0, the fee is considered to be +/// 0 #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] pub struct Fee { @@ -949,7 +963,8 @@ impl Fee { }; // Check that new_fee / old_fee <= MAX_WITHDRAWAL_FEE_INCREASE - // Program fails if provided numerator or denominator is too large, resulting in overflow + // Program fails if provided numerator or denominator is too large, resulting in + // overflow if (old_num as u128) .checked_mul(self.denominator as u128) .map(|x| x.checked_mul(MAX_WITHDRAWAL_FEE_INCREASE.numerator as u128)) @@ -1018,7 +1033,8 @@ impl FeeType { Ok(()) } - /// Returns if the contained fee can only be updated earliest on the next epoch + /// Returns if the contained fee can only be updated earliest on the next + /// epoch #[inline] pub fn can_only_change_next_epoch(&self) -> bool { matches!( @@ -1250,7 +1266,8 @@ mod test { let fee_lamports = stake_pool .calc_lamports_withdraw_amount(pool_token_fee) .unwrap(); - assert_eq!(fee_lamports, LAMPORTS_PER_SOL - 1); // off-by-one due to truncation + assert_eq!(fee_lamports, LAMPORTS_PER_SOL - 1); // off-by-one due to + // truncation } #[test] diff --git a/stake-pool/program/tests/huge_pool.rs b/stake-pool/program/tests/huge_pool.rs index ccfa5370b62..e87d3339772 100644 --- a/stake-pool/program/tests/huge_pool.rs +++ b/stake-pool/program/tests/huge_pool.rs @@ -21,8 +21,8 @@ use { test_case::test_case, }; -// Note: this is not the real max! The testing framework starts to blow out because -// the test require so many helper accounts. +// Note: this is not the real max! The testing framework starts to blow out +// because the test require so many helper accounts. // 20k is also a very safe number for the current upper bound of the network. const MAX_POOL_SIZE_WITH_REQUESTED_COMPUTE_UNITS: u32 = 20_000; const MAX_POOL_SIZE: u32 = 3_000; diff --git a/stake-pool/program/tests/redelegate.rs b/stake-pool/program/tests/redelegate.rs index 47dc08a438a..a9f12f5fd4f 100644 --- a/stake-pool/program/tests/redelegate.rs +++ b/stake-pool/program/tests/redelegate.rs @@ -572,8 +572,8 @@ async fn success_with_increasing_stake() { .find(&destination_validator_stake.vote.pubkey()) .unwrap(); assert_eq!(u64::from(destination_item.transient_stake_lamports), 0); - // redelegate is smart enough to activate *everything*, so there's no rent-exemption - // worth of inactive stake! + // redelegate is smart enough to activate *everything*, so there's no + // rent-exemption worth of inactive stake! assert_eq!( u64::from(destination_item.active_stake_lamports), pre_validator_stake_account.lamports + redelegate_lamports + current_minimum_delegation diff --git a/stake-pool/program/tests/update_validator_list_balance.rs b/stake-pool/program/tests/update_validator_list_balance.rs index bfc6b7e0ef2..89d6b5f62df 100644 --- a/stake-pool/program/tests/update_validator_list_balance.rs +++ b/stake-pool/program/tests/update_validator_list_balance.rs @@ -509,7 +509,8 @@ async fn merge_into_validator_stake() { } // Check validator stake accounts have the expected balance now: - // validator stake account minimum + deposited lamports + rents + increased lamports + // validator stake account minimum + deposited lamports + rents + increased + // lamports let expected_lamports = current_minimum_delegation + lamports + increase_amount + stake_rent; for stake_account in &stake_accounts { let validator_stake = diff --git a/stake-pool/program/tests/withdraw_edge_cases.rs b/stake-pool/program/tests/withdraw_edge_cases.rs index 4af70cba498..5390bce5ed5 100644 --- a/stake-pool/program/tests/withdraw_edge_cases.rs +++ b/stake-pool/program/tests/withdraw_edge_cases.rs @@ -104,7 +104,8 @@ async fn success_remove_validator(multiple: u64) { _, ) = setup_for_withdraw(spl_token::id(), STAKE_ACCOUNT_RENT_EXEMPTION).await; - // make pool tokens very valuable, so it isn't possible to exactly get down to the minimum + // make pool tokens very valuable, so it isn't possible to exactly get down to + // the minimum transfer( &mut context.banks_client, &context.payer, @@ -130,7 +131,8 @@ async fn success_remove_validator(multiple: u64) { .await; let lamports_per_pool_token = stake_pool.get_lamports_per_pool_token().unwrap(); - // decrease all of stake except for lamports_per_pool_token lamports, must be withdrawable + // decrease all of stake except for lamports_per_pool_token lamports, must be + // withdrawable let error = stake_pool_accounts .decrease_validator_stake_either( &mut context.banks_client, @@ -625,7 +627,8 @@ async fn fail_withdraw_from_transient() { .await; assert!(error.is_none(), "{:?}", error); - // fail withdrawing from transient, still a lamport in the validator stake account + // fail withdrawing from transient, still a lamport in the validator stake + // account let new_user_authority = Pubkey::new_unique(); let error = stake_pool_accounts .withdraw_stake( @@ -750,7 +753,8 @@ async fn success_with_small_preferred_withdraw() { .await .unwrap(); - // make pool tokens very valuable, so it isn't possible to exactly get down to the minimum + // make pool tokens very valuable, so it isn't possible to exactly get down to + // the minimum transfer( &mut context.banks_client, &context.payer, @@ -794,7 +798,8 @@ async fn success_with_small_preferred_withdraw() { .await .unwrap(); - // add a tiny bit of stake, less than lamports per pool token to preferred validator + // add a tiny bit of stake, less than lamports per pool token to preferred + // validator let rent = context.banks_client.get_rent().await.unwrap(); let rent_exempt = rent.minimum_balance(std::mem::size_of::()); let stake_minimum_delegation = diff --git a/stateless-asks/program/src/instruction.rs b/stateless-asks/program/src/instruction.rs index c46f215dba4..71fef665f72 100644 --- a/stateless-asks/program/src/instruction.rs +++ b/stateless-asks/program/src/instruction.rs @@ -16,15 +16,16 @@ pub enum StatelessOfferInstruction { /// Accept a StatelessOffer /// Let's walk through the actions of Alice (maker) and Bob (taker) /// - /// Alice has some amount Token A in mkr_src_account and she creates mkr_dst_account if it doesn't exist - /// Alice calls Approve on mkr_src_account for maker_size to some transfer_authority owned by the Stateless Ask program. - /// This transfer_authority's approval size/mint are expressed in the seeds of the PDA + /// Alice has some amount Token A in mkr_src_account and she creates + /// mkr_dst_account if it doesn't exist Alice calls Approve on + /// mkr_src_account for maker_size to some transfer_authority owned by the + /// Stateless Ask program. This transfer_authority's approval size/mint + /// are expressed in the seeds of the PDA /// /// Some time later: /// - /// Bob initializes tkr_src_account (Token B) and tkr_dst_account (Token A) if they don't exist - /// Bob (or anyone) executes AcceptOffer - /// + /// Bob initializes tkr_src_account (Token B) and tkr_dst_account (Token A) + /// if they don't exist Bob (or anyone) executes AcceptOffer AcceptOffer { #[allow(dead_code)] has_metadata: bool, diff --git a/stateless-asks/program/src/lib.rs b/stateless-asks/program/src/lib.rs index d7261f820f8..e1a49e842f2 100644 --- a/stateless-asks/program/src/lib.rs +++ b/stateless-asks/program/src/lib.rs @@ -6,5 +6,6 @@ pub mod validation_utils; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/stateless-asks/program/src/processor.rs b/stateless-asks/program/src/processor.rs index 2ab98d02fbf..eb9896494ae 100644 --- a/stateless-asks/program/src/processor.rs +++ b/stateless-asks/program/src/processor.rs @@ -46,7 +46,8 @@ pub(crate) mod inline_mpl_token_metadata { pub symbol: String, /// URI pointing to JSON representing the asset pub uri: String, - /// Royalty basis points that goes to creators in secondary sales (0-10000) + /// Royalty basis points that goes to creators in secondary sales + /// (0-10000) pub seller_fee_basis_points: u16, /// Array of creators, optional pub creators: Option>, @@ -203,10 +204,10 @@ fn process_accept_offer( } msg!("Delegate matches"); assert_keys_equal(spl_token::id(), *token_program_info.key)?; - // Both of these transfers will fail if the `transfer_authority` is the delegate of these ATA's - // One consideration is that the taker can get tricked in the case that the maker size is greater than - // the token amount in the maker's ATA, but these stateless offers should just be invalidated in - // the client. + // Both of these transfers will fail if the `transfer_authority` is the delegate + // of these ATA's One consideration is that the taker can get tricked in the + // case that the maker size is greater than the token amount in the maker's + // ATA, but these stateless offers should just be invalidated in the client. assert_is_ata(maker_src_account, maker_wallet.key, maker_src_mint.key)?; assert_is_ata(taker_dst_account, taker_wallet.key, maker_src_mint.key)?; invoke_signed( diff --git a/token-lending/program/src/error.rs b/token-lending/program/src/error.rs index 3503ea98a01..21dc0acf34c 100644 --- a/token-lending/program/src/error.rs +++ b/token-lending/program/src/error.rs @@ -19,7 +19,8 @@ pub enum LendingError { /// Lamport balance below rent-exempt threshold. #[error("Lamport balance below rent-exempt threshold")] NotRentExempt, - /// The program address provided doesn't match the value generated by the program. + /// The program address provided doesn't match the value generated by the + /// program. #[error("Market authority is invalid")] InvalidMarketAuthority, /// Expected a different market owner @@ -27,10 +28,12 @@ pub enum LendingError { InvalidMarketOwner, // 5 - /// The owner of the input isn't set to the program address generated by the program. + /// The owner of the input isn't set to the program address generated by the + /// program. #[error("Input account owner is not the program address")] InvalidAccountOwner, - /// The owner of the account input isn't set to the correct token program id. + /// The owner of the account input isn't set to the correct token program + /// id. #[error("Input token account is not owned by the correct token program id")] InvalidTokenOwner, /// Expected an SPL Token account diff --git a/token-lending/program/src/instruction.rs b/token-lending/program/src/instruction.rs index 8bf938afe94..5455ef92b7e 100644 --- a/token-lending/program/src/instruction.rs +++ b/token-lending/program/src/instruction.rs @@ -31,7 +31,9 @@ pub enum LendingInstruction { /// Owner authority which can add new reserves owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + /// `) or SPL token mint pubkey quote_currency: [u8; 32], }, @@ -52,18 +54,19 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// $authority can transfer $liquidity_amount. + /// 0. `[writable]` Source liquidity token account. $authority can + /// transfer $liquidity_amount. /// 1. `[writable]` Destination collateral token account - uninitialized. /// 2. `[writable]` Reserve account - uninitialized. /// 3. `[]` Reserve liquidity SPL Token mint. - /// 4. `[writable]` Reserve liquidity supply SPL Token account - uninitialized. + /// 4. `[writable]` Reserve liquidity supply SPL Token account - + /// uninitialized. /// 5. `[writable]` Reserve liquidity fee receiver - uninitialized. /// 6. `[writable]` Reserve collateral SPL Token mint - uninitialized. /// 7. `[writable]` Reserve collateral token supply - uninitialized. /// 8. `[]` Pyth product account. - /// 9. `[]` Pyth price account. - /// This will be used as the reserve liquidity oracle account. + /// 9. `[]` Pyth price account. This will be used as the reserve liquidity + /// oracle account. /// 10 `[]` Lending market account. /// 11 `[]` Derived lending market authority. /// 12 `[signer]` Lending market owner. @@ -84,19 +87,19 @@ pub enum LendingInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` Reserve account. - /// 1. `[]` Reserve liquidity oracle account. - /// Must be the Pyth price account specified at InitReserve. + /// 1. `[]` Reserve liquidity oracle account. Must be the Pyth price + /// account specified at InitReserve. /// 2. `[]` Clock sysvar. RefreshReserve, // 4 - /// Deposit liquidity into a reserve in exchange for collateral. Collateral represents a share - /// of the reserve liquidity pool. + /// Deposit liquidity into a reserve in exchange for collateral. Collateral + /// represents a share of the reserve liquidity pool. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// $authority can transfer $liquidity_amount. + /// 0. `[writable]` Source liquidity token account. $authority can + /// transfer $liquidity_amount. /// 1. `[writable]` Destination collateral token account. /// 2. `[writable]` Reserve account. /// 3. `[writable]` Reserve liquidity supply SPL Token account. @@ -116,8 +119,8 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source collateral token account. - /// $authority can transfer $collateral_amount. + /// 0. `[writable]` Source collateral token account. $authority can + /// transfer $collateral_amount. /// 1. `[writable]` Destination liquidity token account. /// 2. `[writable]` Reserve account. /// 3. `[writable]` Reserve collateral SPL Token mint. @@ -146,16 +149,18 @@ pub enum LendingInstruction { InitObligation, // 7 - /// Refresh an obligation's accrued interest and collateral and liquidity prices. Requires - /// refreshed reserves, as all obligation collateral deposit reserves in order, followed by all - /// liquidity borrow reserves in order. + /// Refresh an obligation's accrued interest and collateral and liquidity + /// prices. Requires refreshed reserves, as all obligation collateral + /// deposit reserves in order, followed by all liquidity borrow reserves + /// in order. /// /// Accounts expected by this instruction: /// /// 0. `[writable]` Obligation account. /// 1. `[]` Clock sysvar. - /// .. `[]` Collateral deposit reserve accounts - refreshed, all, in order. - /// .. `[]` Liquidity borrow reserve accounts - refreshed, all, in order. + /// .. `[]` Collateral deposit reserve accounts - refreshed, all, in + /// order. .. `[]` Liquidity borrow reserve accounts - refreshed, all, + /// in order. RefreshObligation, // 8 @@ -163,10 +168,11 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source collateral token account. - /// Minted by deposit reserve collateral mint. - /// $authority can transfer $collateral_amount. - /// 1. `[writable]` Destination deposit reserve collateral supply SPL Token account. + /// 0. `[writable]` Source collateral token account. Minted by deposit + /// reserve collateral mint. $authority can transfer + /// $collateral_amount. + /// 1. `[writable]` Destination deposit reserve collateral supply SPL + /// Token account. /// 2. `[]` Deposit reserve account - refreshed. /// 3. `[writable]` Obligation account. /// 4. `[]` Lending market account. @@ -180,13 +186,15 @@ pub enum LendingInstruction { }, // 9 - /// Withdraw collateral from an obligation. Requires a refreshed obligation and reserve. + /// Withdraw collateral from an obligation. Requires a refreshed obligation + /// and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source withdraw reserve collateral supply SPL Token account. - /// 1. `[writable]` Destination collateral token account. - /// Minted by withdraw reserve collateral mint. + /// 0. `[writable]` Source withdraw reserve collateral supply SPL Token + /// account. + /// 1. `[writable]` Destination collateral token account. Minted by + /// withdraw reserve collateral mint. /// 2. `[]` Withdraw reserve account - refreshed. /// 3. `[writable]` Obligation account - refreshed. /// 4. `[]` Lending market account. @@ -195,22 +203,24 @@ pub enum LendingInstruction { /// 7. `[]` Clock sysvar. /// 8. `[]` Token program id. WithdrawObligationCollateral { - /// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of deposited amount + /// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of + /// deposited amount collateral_amount: u64, }, // 10 - /// Borrow liquidity from a reserve by depositing collateral tokens. Requires a refreshed - /// obligation and reserve. + /// Borrow liquidity from a reserve by depositing collateral tokens. + /// Requires a refreshed obligation and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source borrow reserve liquidity supply SPL Token account. - /// 1. `[writable]` Destination liquidity token account. - /// Minted by borrow reserve liquidity mint. + /// 0. `[writable]` Source borrow reserve liquidity supply SPL Token + /// account. + /// 1. `[writable]` Destination liquidity token account. Minted by borrow + /// reserve liquidity mint. /// 2. `[writable]` Borrow reserve account - refreshed. - /// 3. `[writable]` Borrow reserve liquidity fee receiver account. - /// Must be the fee account specified at InitReserve. + /// 3. `[writable]` Borrow reserve liquidity fee receiver account. Must be + /// the fee account specified at InitReserve. /// 4. `[writable]` Obligation account - refreshed. /// 5. `[]` Lending market account. /// 6. `[]` Derived lending market authority. @@ -221,19 +231,21 @@ pub enum LendingInstruction { BorrowObligationLiquidity { /// Amount of liquidity to borrow - u64::MAX for 100% of borrowing power liquidity_amount: u64, - /// Minimum amount of liquidity to receive, if borrowing 100% of borrowing power + /// Minimum amount of liquidity to receive, if borrowing 100% of + /// borrowing power slippage_limit: u64, }, // 11 - /// Repay borrowed liquidity to a reserve. Requires a refreshed obligation and reserve. + /// Repay borrowed liquidity to a reserve. Requires a refreshed obligation + /// and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by repay reserve liquidity mint. - /// $authority can transfer $liquidity_amount. - /// 1. `[writable]` Destination repay reserve liquidity supply SPL Token account. + /// 0. `[writable]` Source liquidity token account. Minted by repay + /// reserve liquidity mint. $authority can transfer $liquidity_amount. + /// 1. `[writable]` Destination repay reserve liquidity supply SPL Token + /// account. /// 2. `[writable]` Repay reserve account - refreshed. /// 3. `[writable]` Obligation account - refreshed. /// 4. `[]` Lending market account. @@ -246,16 +258,16 @@ pub enum LendingInstruction { }, // 12 - /// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy - /// obligation. Requires a refreshed obligation and reserves. + /// Repay borrowed liquidity to a reserve to receive collateral at a + /// discount from an unhealthy obligation. Requires a refreshed + /// obligation and reserves. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by repay reserve liquidity mint. - /// $authority can transfer $liquidity_amount. - /// 1. `[writable]` Destination collateral token account. - /// Minted by withdraw reserve collateral mint. + /// 0. `[writable]` Source liquidity token account. Minted by repay + /// reserve liquidity mint. $authority can transfer $liquidity_amount. + /// 1. `[writable]` Destination collateral token account. Minted by + /// withdraw reserve collateral mint. /// 2. `[writable]` Repay reserve account - refreshed. /// 3. `[writable]` Repay reserve liquidity supply SPL Token account. /// 4. `[]` Withdraw reserve account - refreshed. @@ -267,7 +279,8 @@ pub enum LendingInstruction { /// 10 `[]` Clock sysvar. /// 11 `[]` Token program id. LiquidateObligation { - /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed amount + /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed + /// amount liquidity_amount: u64, }, @@ -276,44 +289,50 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by reserve liquidity mint. - /// Must match the reserve liquidity supply. - /// 1. `[writable]` Destination liquidity token account. - /// Minted by reserve liquidity mint. + /// 0. `[writable]` Source liquidity token account. Minted by reserve + /// liquidity mint. Must match the reserve liquidity supply. + /// 1. `[writable]` Destination liquidity token account. Minted by reserve + /// liquidity mint. /// 2. `[writable]` Reserve account. - /// 3. `[writable]` Flash loan fee receiver account. - /// Must match the reserve liquidity fee receiver. + /// 3. `[writable]` Flash loan fee receiver account. Must match the + /// reserve liquidity fee receiver. /// 4. `[writable]` Host fee receiver. /// 5. `[]` Lending market account. /// 6. `[]` Derived lending market authority. /// 7. `[]` Token program id. - /// 8. `[]` Flash loan receiver program id. - /// Must implement an instruction that has tag of 0 and a signature of `(amount: u64)` - /// This instruction must return the amount to the source liquidity account. - /// .. `[any]` Additional accounts expected by the receiving program's `ReceiveFlashLoan` instruction. + /// 8. `[]` Flash loan receiver program id. Must implement an instruction + /// that has tag of 0 and a signature of `(amount: u64)` This + /// instruction must return the amount to the source liquidity account. + /// .. `[any]` Additional accounts expected by the receiving program's + /// `ReceiveFlashLoan` instruction. /// - /// The flash loan receiver program that is to be invoked should contain an instruction with - /// tag `0` and accept the total amount (including fee) that needs to be returned back after - /// its execution has completed. + /// The flash loan receiver program that is to be invoked should contain + /// an instruction with tag `0` and accept the total amount (including + /// fee) that needs to be returned back after its execution has + /// completed. /// - /// Flash loan receiver should have an instruction with the following signature: + /// Flash loan receiver should have an instruction with the following + /// signature: /// - /// 0. `[writable]` Source liquidity (matching the destination from above). - /// 1. `[writable]` Destination liquidity (matching the source from above). + /// 0. `[writable]` Source liquidity (matching the destination from + /// above). + /// 1. `[writable]` Destination liquidity (matching the source from + /// above). /// 2. `[]` Token program id - /// .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above. - /// ReceiveFlashLoan { + /// .. `[any]` Additional accounts provided to the lending program's + /// `FlashLoan` instruction above. ReceiveFlashLoan { /// // Amount that must be repaid by the receiver program /// amount: u64 /// } FlashLoan { - /// The amount that is to be borrowed - u64::MAX for up to 100% of available liquidity + /// The amount that is to be borrowed - u64::MAX for up to 100% of + /// available liquidity amount: u64, }, // 14 - /// Modify the ReserveConfig parameters of an already initialized Reserve account + /// Modify the ReserveConfig parameters of an already initialized Reserve + /// account /// /// Accounts expected by this instruction: /// @@ -327,7 +346,8 @@ pub enum LendingInstruction { } impl LendingInstruction { - /// Unpacks a byte buffer into a [LendingInstruction](enum.LendingInstruction.html). + /// Unpacks a byte buffer into a + /// [LendingInstruction](enum.LendingInstruction.html). pub fn unpack(input: &[u8]) -> Result { let (&tag, rest) = input .split_first() @@ -483,7 +503,8 @@ impl LendingInstruction { }) } - /// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte buffer. + /// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); match *self { diff --git a/token-lending/program/src/lib.rs b/token-lending/program/src/lib.rs index 55de39ea7b3..49cb6c6635b 100644 --- a/token-lending/program/src/lib.rs +++ b/token-lending/program/src/lib.rs @@ -11,7 +11,8 @@ pub mod processor; pub mod pyth; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH"); diff --git a/token-lending/program/src/processor.rs b/token-lending/program/src/processor.rs index 61a1710fc51..acae01c8375 100644 --- a/token-lending/program/src/processor.rs +++ b/token-lending/program/src/processor.rs @@ -1572,7 +1572,8 @@ fn process_flash_loan( return Err(LendingError::InvalidAccountInput.into()); } - // @FIXME: if u64::MAX is flash loaned, fees should be inclusive as with ordinary borrows + // @FIXME: if u64::MAX is flash loaned, fees should be inclusive as with + // ordinary borrows let flash_loan_amount = if liquidity_amount == u64::MAX { reserve.liquidity.available_amount } else { @@ -1717,8 +1718,9 @@ fn process_modify_reserve_config( let mut reserve = Reserve::unpack(&reserve_info.data.borrow_mut())?; // Validate that the reserve account corresponds to the correct lending market, - // after validating above that the lending market and lending market owner correspond, - // to prevent one compromised lending market owner from changing configs on other lending markets + // after validating above that the lending market and lending market owner + // correspond, to prevent one compromised lending market owner from changing + // configs on other lending markets if reserve.lending_market != *lending_market_info.key { msg!("Reserve account does not match the lending market"); return Err(LendingError::InvalidAccountInput.into()); diff --git a/token-lending/program/src/state/lending_market.rs b/token-lending/program/src/state/lending_market.rs index 457767d8bd8..326f5297296 100644 --- a/token-lending/program/src/state/lending_market.rs +++ b/token-lending/program/src/state/lending_market.rs @@ -19,7 +19,9 @@ pub struct LendingMarket { /// Owner authority which can add new reserves pub owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or a SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or + /// a SPL token mint pubkey pub quote_currency: [u8; 32], /// Token program id pub token_program_id: Pubkey, @@ -53,7 +55,9 @@ pub struct InitLendingMarketParams { /// Owner authority which can add new reserves pub owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or a SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or + /// a SPL token mint pubkey pub quote_currency: [u8; 32], /// Token program id pub token_program_id: Pubkey, @@ -102,7 +106,8 @@ impl Pack for LendingMarket { oracle_program_id.copy_from_slice(self.oracle_program_id.as_ref()); } - /// Unpacks a byte buffer into a [LendingMarketInfo](struct.LendingMarketInfo.html) + /// Unpacks a byte buffer into a + /// [LendingMarketInfo](struct.LendingMarketInfo.html) fn unpack_from_slice(input: &[u8]) -> Result { let input = array_ref![input, 0, LENDING_MARKET_LEN]; #[allow(clippy::ptr_offset_with_cast)] diff --git a/token-lending/program/src/state/mod.rs b/token-lending/program/src/state/mod.rs index 9f056916bf1..cd62910a17a 100644 --- a/token-lending/program/src/state/mod.rs +++ b/token-lending/program/src/state/mod.rs @@ -15,7 +15,8 @@ use { }; pub use {last_update::*, lending_market::*, obligation::*, reserve::*}; -/// Collateral tokens are initially valued at a ratio of 5:1 (collateral:liquidity) +/// Collateral tokens are initially valued at a ratio of 5:1 +/// (collateral:liquidity) // @FIXME: restore to 5 pub const INITIAL_COLLATERAL_RATIO: u64 = 1; const INITIAL_COLLATERAL_RATE: u64 = INITIAL_COLLATERAL_RATIO * WAD; diff --git a/token-lending/program/src/state/obligation.rs b/token-lending/program/src/state/obligation.rs index 637fd8e31db..a22a1ddd17d 100644 --- a/token-lending/program/src/state/obligation.rs +++ b/token-lending/program/src/state/obligation.rs @@ -19,7 +19,8 @@ use { }, }; -/// Max number of collateral and liquidity reserve accounts combined for an obligation +/// Max number of collateral and liquidity reserve accounts combined for an +/// obligation pub const MAX_OBLIGATION_RESERVES: usize = 10; /// Lending market obligation state @@ -33,7 +34,8 @@ pub struct Obligation { pub lending_market: Pubkey, /// Owner authority which can borrow liquidity pub owner: Pubkey, - /// Deposited collateral for the obligation, unique by deposit reserve address + /// Deposited collateral for the obligation, unique by deposit reserve + /// address pub deposits: Vec, /// Borrowed liquidity for the obligation, unique by borrow reserve address pub borrows: Vec, @@ -217,7 +219,8 @@ pub struct InitObligationParams { pub lending_market: Pubkey, /// Owner authority which can borrow liquidity pub owner: Pubkey, - /// Deposited collateral for the obligation, unique by deposit reserve address + /// Deposited collateral for the obligation, unique by deposit reserve + /// address pub deposits: Vec, /// Borrowed liquidity for the obligation, unique by borrow reserve address pub borrows: Vec, @@ -413,7 +416,8 @@ impl Pack for Obligation { } } - /// Unpacks a byte buffer into an [ObligationInfo](struct.ObligationInfo.html). + /// Unpacks a byte buffer into an + /// [ObligationInfo](struct.ObligationInfo.html). fn unpack_from_slice(src: &[u8]) -> Result { let input = array_ref![src, 0, OBLIGATION_LEN]; #[allow(clippy::ptr_offset_with_cast)] diff --git a/token-lending/program/src/state/reserve.rs b/token-lending/program/src/state/reserve.rs index 21e798a3422..e271f3b76f2 100644 --- a/token-lending/program/src/state/reserve.rs +++ b/token-lending/program/src/state/reserve.rs @@ -60,7 +60,8 @@ impl Reserve { self.config = params.config; } - /// Record deposited liquidity and return amount of collateral tokens to mint + /// Record deposited liquidity and return amount of collateral tokens to + /// mint pub fn deposit_liquidity(&mut self, liquidity_amount: u64) -> Result { let collateral_amount = self .collateral_exchange_rate()? @@ -257,7 +258,8 @@ impl Reserve { } } } else { - // calculate settle_amount and withdraw_amount, repay_amount is settle_amount rounded + // calculate settle_amount and withdraw_amount, repay_amount is settle_amount + // rounded let liquidation_amount = obligation .max_liquidation_amount(liquidity)? .min(max_amount); @@ -429,7 +431,8 @@ impl ReserveLiquidity { Ok(()) } - /// Add repay amount to available liquidity and subtract settle amount from total borrows + /// Add repay amount to available liquidity and subtract settle amount from + /// total borrows pub fn repay(&mut self, repay_amount: u64, settle_amount: Decimal) -> ProgramResult { self.available_amount = self .available_amount @@ -596,9 +599,11 @@ pub struct ReserveConfig { /// Target ratio of the value of borrows to deposits, as a percentage /// 0 if use as collateral is disabled pub loan_to_value_ratio: u8, - /// Bonus a liquidator gets when repaying part of an unhealthy obligation, as a percentage + /// Bonus a liquidator gets when repaying part of an unhealthy obligation, + /// as a percentage pub liquidation_bonus: u8, - /// Loan to value ratio at which an obligation can be liquidated, as a percentage + /// Loan to value ratio at which an obligation can be liquidated, as a + /// percentage pub liquidation_threshold: u8, /// Min borrow APY pub min_borrow_rate: u8, @@ -611,7 +616,8 @@ pub struct ReserveConfig { } impl ReserveConfig { - /// Validate the reserve configs, when initializing or modifying the reserve configs + /// Validate the reserve configs, when initializing or modifying the reserve + /// configs pub fn validate(&self) -> ProgramResult { if self.optimal_utilization_rate > 100 { msg!("Optimal utilization rate must be in range [0, 100]"); @@ -658,9 +664,9 @@ impl ReserveConfig { /// Additional fee information on a reserve /// -/// These exist separately from interest accrual fees, and are specifically for the program owner -/// and frontend host. The fees are paid out as a percentage of liquidity token amounts during -/// repayments and liquidations. +/// These exist separately from interest accrual fees, and are specifically for +/// the program owner and frontend host. The fees are paid out as a percentage +/// of liquidity token amounts during repayments and liquidations. #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct ReserveFees { /// Fee assessed on `BorrowObligationLiquidity`, expressed as a Wad. @@ -764,7 +770,8 @@ impl IsInitialized for Reserve { } } -const RESERVE_LEN: usize = 571; // 1 + 8 + 1 + 32 + 32 + 1 + 32 + 32 + 32 + 8 + 16 + 16 + 16 + 32 + 8 + 32 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 8 + 8 + 1 + 248 +const RESERVE_LEN: usize = 571; // 1 + 8 + 1 + 32 + 32 + 1 + 32 + 32 + 32 + 8 + 16 + 16 + 16 + 32 + 8 + 32 + 1 + + // 1 + 1 + 1 + 1 + 1 + 1 + 8 + 8 + 1 + 248 impl Pack for Reserve { const LEN: usize = RESERVE_LEN; @@ -1004,7 +1011,8 @@ mod test { } } - // Creates rates (threshold, ltv) where 2 <= threshold <= 100 and threshold <= ltv <= 1,000% + // Creates rates (threshold, ltv) where 2 <= threshold <= 100 and threshold <= + // ltv <= 1,000% prop_compose! { fn unhealthy_rates()(threshold in 2..=100u8)( ltv_rate in threshold as u64..=1000u64, diff --git a/token-lending/program/tests/helpers/flash_loan_receiver.rs b/token-lending/program/tests/helpers/flash_loan_receiver.rs index 6c19e6e36af..2c8e50952a6 100644 --- a/token-lending/program/tests/helpers/flash_loan_receiver.rs +++ b/token-lending/program/tests/helpers/flash_loan_receiver.rs @@ -13,14 +13,18 @@ use { }; pub enum FlashLoanReceiverInstruction { - /// Receive a flash loan and perform user-defined operation and finally return the fund back. + /// Receive a flash loan and perform user-defined operation and finally + /// return the fund back. /// /// Accounts expected: /// - /// 0. `[writable]` Source liquidity (matching the destination from above). - /// 1. `[writable]` Destination liquidity (matching the source from above). + /// 0. `[writable]` Source liquidity (matching the destination from + /// above). + /// 1. `[writable]` Destination liquidity (matching the source from + /// above). /// 2. `[]` Token program id - /// .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above. + /// .. `[any]` Additional accounts provided to the lending program's + /// `FlashLoan` instruction above. ReceiveFlashLoan { /// The amount that is loaned amount: u64, diff --git a/token-lending/program/tests/modify_reserve_config.rs b/token-lending/program/tests/modify_reserve_config.rs index 2f1b0bf3fc1..00b9a834205 100644 --- a/token-lending/program/tests/modify_reserve_config.rs +++ b/token-lending/program/tests/modify_reserve_config.rs @@ -304,9 +304,10 @@ async fn owner_of_different_lending_market_cannot_change_reserve_config() { #[tokio::test] // Right owner, wrong lending market async fn correct_owner_providing_wrong_lending_market_fails() { - // When the correct owner of the lending market and reserve provides, perhaps inadvertently, - // a lending market that is different from the given reserve's corresponding lending market, - // then the transaction to modify the current reserve config should fail. + // When the correct owner of the lending market and reserve provides, perhaps + // inadvertently, a lending market that is different from the given + // reserve's corresponding lending market, then the transaction to modify + // the current reserve config should fail. let mut test = ProgramTest::new( "spl_token_lending", spl_token_lending::id(), @@ -366,7 +367,9 @@ async fn correct_owner_providing_wrong_lending_market_fails() { new_config, sol_test_reserve.pubkey, other_lending_market.pubkey, - lending_market.owner.pubkey(), //lending_market.owner == other_lending_market.owner, defined by `add_lending_market` + lending_market.owner.pubkey(), /* lending_market.owner == + * other_lending_market.owner, defined by + * `add_lending_market` */ )], Some(&payer.pubkey()), ); diff --git a/token-metadata/example/src/processor.rs b/token-metadata/example/src/processor.rs index 1ff45bf12e3..073a633d817 100644 --- a/token-metadata/example/src/processor.rs +++ b/token-metadata/example/src/processor.rs @@ -146,7 +146,8 @@ pub fn process_remove_key( Ok(()) } -/// Processes a [UpdateAuthority](enum.TokenMetadataInstruction.html) instruction. +/// Processes a [UpdateAuthority](enum.TokenMetadataInstruction.html) +/// instruction. pub fn process_update_authority( _program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token-metadata/example/tests/emit.rs b/token-metadata/example/tests/emit.rs index 00ef924d527..c34412a070d 100644 --- a/token-metadata/example/tests/emit.rs +++ b/token-metadata/example/tests/emit.rs @@ -91,7 +91,8 @@ async fn success(start: Option, end: Option) { .copy_from_slice(&simulation_return_data.data); assert_eq!(*check_buffer, return_data[..check_buffer.len()]); - // we're sure that we're getting the full data, so also compare the deserialized type + // we're sure that we're getting the full data, so also compare the deserialized + // type if start.is_none() && end.is_none() { let emitted_token_metadata = try_from_slice_unchecked::(&return_data).unwrap(); diff --git a/token-metadata/interface/src/instruction.rs b/token-metadata/interface/src/instruction.rs index 89ad991de73..6be22fc47dc 100644 --- a/token-metadata/interface/src/instruction.rs +++ b/token-metadata/interface/src/instruction.rs @@ -103,7 +103,8 @@ pub enum TokenMetadataInstruction { /// /// By the end of the instruction, the metadata account must be properly /// resized based on the new size of the TLV entry. - /// * If the new size is larger, the program must first reallocate to avoid + /// * If the new size is larger, the program must first reallocate to + /// avoid /// overwriting other TLV entries. /// * If the new size is smaller, the program must reallocate at the end /// so that it's possible to iterate over TLV entries @@ -113,9 +114,9 @@ pub enum TokenMetadataInstruction { /// 0. `[w]` Metadata account /// 1. `[s]` Update authority /// - /// Data: `UpdateField` data, specifying the new field and value. If the field - /// does not exist on the account, it will be created. If the field does exist, - /// it will be overwritten. + /// Data: `UpdateField` data, specifying the new field and value. If the + /// field does not exist on the account, it will be created. If the + /// field does exist, it will be overwritten. UpdateField(UpdateField), /// Removes a key-value pair in a token-metadata account. @@ -161,7 +162,8 @@ pub enum TokenMetadataInstruction { Emit(Emit), } impl TokenMetadataInstruction { - /// Unpacks a byte buffer into a [TokenMetadataInstruction](enum.TokenMetadataInstruction.html). + /// Unpacks a byte buffer into a + /// [TokenMetadataInstruction](enum.TokenMetadataInstruction.html). pub fn unpack(input: &[u8]) -> Result { if input.len() < ArrayDiscriminator::LENGTH { return Err(ProgramError::InvalidInstructionData); @@ -192,7 +194,8 @@ impl TokenMetadataInstruction { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = vec![]; match self { diff --git a/token-metadata/interface/src/lib.rs b/token-metadata/interface/src/lib.rs index 5302765e492..a4329d6ff2b 100644 --- a/token-metadata/interface/src/lib.rs +++ b/token-metadata/interface/src/lib.rs @@ -8,8 +8,8 @@ pub mod error; pub mod instruction; pub mod state; -// Export current sdk types for downstream users building with a different sdk version -// Export borsh for downstream users +// Export current sdk types for downstream users building with a different sdk +// version Export borsh for downstream users pub use {borsh, solana_program}; /// Namespace for all programs implementing token-metadata diff --git a/token-swap/program/src/curve/base.rs b/token-swap/program/src/curve/base.rs index 823c561736a..2014437bae7 100644 --- a/token-swap/program/src/curve/base.rs +++ b/token-swap/program/src/curve/base.rs @@ -27,7 +27,8 @@ use { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum CurveType { - /// Uniswap-style constant product curve, invariant = token_a_amount * token_b_amount + /// Uniswap-style constant product curve, invariant = token_a_amount * + /// token_b_amount ConstantProduct, /// Flat line, always providing 1:1 from one token to another ConstantPrice, @@ -206,8 +207,8 @@ impl PartialEq for SwapCurve { impl Sealed for SwapCurve {} impl Pack for SwapCurve { - /// Size of encoding of all curve parameters, which include fees and any other - /// constants used to calculate swaps, deposits, and withdrawals. + /// Size of encoding of all curve parameters, which include fees and any + /// other constants used to calculate swaps, deposits, and withdrawals. /// This includes 1 byte for the type, and 72 for the calculator to use as /// it needs. Some calculators may be smaller than 72 bytes. const LEN: usize = 33; diff --git a/token-swap/program/src/curve/calculator.rs b/token-swap/program/src/curve/calculator.rs index baa20f0ec8a..36d9de468ea 100644 --- a/token-swap/program/src/curve/calculator.rs +++ b/token-swap/program/src/curve/calculator.rs @@ -114,8 +114,8 @@ pub trait CurveCalculator: Debug + DynPack { /// Get the amount of pool tokens for the deposited amount of token A or B. /// /// This is used for single-sided deposits. It essentially performs a swap - /// followed by a deposit. Because a swap is implicitly performed, this will - /// change the spot price of the pool. + /// followed by a deposit. Because a swap is implicitly performed, this + /// will change the spot price of the pool. /// /// See more background for the calculation at: /// @@ -292,13 +292,13 @@ pub mod test { ); } - /// Test function to check that withdrawing token A is the same as withdrawing - /// both and swapping one side. + /// Test function to check that withdrawing token A is the same as + /// withdrawing both and swapping one side. /// Since calculations use unsigned integers, there will be truncation at /// some point, meaning we can't have perfect equality. /// We guarantee that the relative error between withdrawing one side and - /// performing a withdraw plus a swap will be at most some epsilon provided by - /// the curve. Most curves guarantee accuracy within 0.5%. + /// performing a withdraw plus a swap will be at most some epsilon provided + /// by the curve. Most curves guarantee accuracy within 0.5%. pub fn check_withdraw_token_conversion( curve: &dyn CurveCalculator, pool_token_amount: u128, @@ -515,9 +515,9 @@ pub mod test { let value = curve .normalized_value(swap_token_a_amount, swap_token_b_amount) .unwrap(); - // since we can get rounding issues on the pool value which make it seem that the - // value per token has gone down, we bump it up by an epsilon of 1 to - // cover all cases + // since we can get rounding issues on the pool value which make it seem that + // the value per token has gone down, we bump it up by an epsilon of 1 + // to cover all cases let new_value = curve .normalized_value(new_swap_token_a_amount, new_swap_token_b_amount) .unwrap(); diff --git a/token-swap/program/src/curve/constant_product.rs b/token-swap/program/src/curve/constant_product.rs index 7de5bb3350f..beb78647e68 100644 --- a/token-swap/program/src/curve/constant_product.rs +++ b/token-swap/program/src/curve/constant_product.rs @@ -48,8 +48,8 @@ pub fn swap( /// Get the amount of trading tokens for the given amount of pool tokens, /// provided the total trading tokens and supply of pool tokens. /// -/// The constant product implementation is a simple ratio calculation for how many -/// trading tokens correspond to a certain number of pool tokens +/// The constant product implementation is a simple ratio calculation for how +/// many trading tokens correspond to a certain number of pool tokens pub fn pool_tokens_to_trading_tokens( pool_tokens: u128, pool_token_supply: u128, @@ -159,8 +159,8 @@ pub fn withdraw_single_token_type_exact_out( /// Calculates the total normalized value of the curve given the liquidity /// parameters. /// -/// The constant product implementation for this function gives the square root of -/// the Uniswap invariant. +/// The constant product implementation for this function gives the square root +/// of the Uniswap invariant. pub fn normalized_value( swap_token_a_amount: u128, swap_token_b_amount: u128, @@ -184,8 +184,9 @@ impl CurveCalculator for ConstantProductCurve { swap(source_amount, swap_source_amount, swap_destination_amount) } - /// The constant product implementation is a simple ratio calculation for how many - /// trading tokens correspond to a certain number of pool tokens + /// The constant product implementation is a simple ratio calculation for + /// how many trading tokens correspond to a certain number of pool + /// tokens fn pool_tokens_to_trading_tokens( &self, pool_tokens: u128, @@ -390,15 +391,20 @@ mod tests { let tests: &[(u128, u128, u128, u128, u128)] = &[ (10, 4_000_000, 70_000_000_000, 10, 174_999), // spot: 10 * 70b / ~4m = 174,999.99 - (20, 30_000 - 20, 10_000, 18, 6), // spot: 20 * 1 / 3.000 = 6.6667 (source can be 18 to get 6 dest.) - (19, 30_000 - 20, 10_000, 18, 6), // spot: 19 * 1 / 2.999 = 6.3334 (source can be 18 to get 6 dest.) + (20, 30_000 - 20, 10_000, 18, 6), /* spot: 20 * 1 / 3.000 = 6.6667 + * (source can be 18 + * to get 6 dest.) */ + (19, 30_000 - 20, 10_000, 18, 6), /* spot: 19 * 1 / 2.999 = 6.3334 (source can be 18 + * to get 6 dest.) */ (18, 30_000 - 20, 10_000, 18, 6), // spot: 18 * 1 / 2.999 = 6.0001 (10, 20_000, 30_000, 10, 14), // spot: 10 * 3 / 2.0010 = 14.99 (10, 20_000 - 9, 30_000, 10, 14), // spot: 10 * 3 / 2.0001 = 14.999 (10, 20_000 - 10, 30_000, 10, 15), // spot: 10 * 3 / 2.0000 = 15 - (100, 60_000, 30_000, 99, 49), // spot: 100 * 3 / 6.001 = 49.99 (source can be 99 to get 49 dest.) - (99, 60_000, 30_000, 99, 49), // spot: 99 * 3 / 6.001 = 49.49 - (98, 60_000, 30_000, 97, 48), // spot: 98 * 3 / 6.001 = 48.99 (source can be 97 to get 48 dest.) + (100, 60_000, 30_000, 99, 49), /* spot: 100 * 3 / 6.001 = 49.99 (source can be 99 + * to get 49 dest.) */ + (99, 60_000, 30_000, 99, 49), // spot: 99 * 3 / 6.001 = 49.49 + (98, 60_000, 30_000, 97, 48), /* spot: 98 * 3 / 6.001 = 48.99 (source can be 97 to + * get 48 dest.) */ ]; for ( source_amount, diff --git a/token-swap/program/src/curve/fees.rs b/token-swap/program/src/curve/fees.rs index 9a5abc748cf..b62cecf5cde 100644 --- a/token-swap/program/src/curve/fees.rs +++ b/token-swap/program/src/curve/fees.rs @@ -20,9 +20,9 @@ pub struct Fees { /// Trade fee denominator pub trade_fee_denominator: u64, - /// Owner trading fees are extra token amounts that are held inside the token - /// accounts during a trade, with the equivalent in pool tokens minted to - /// the owner of the program. + /// Owner trading fees are extra token amounts that are held inside the + /// token accounts during a trade, with the equivalent in pool tokens + /// minted to the owner of the program. /// Owner trade fee numerator pub owner_trade_fee_numerator: u64, /// Owner trade fee denominator @@ -124,8 +124,8 @@ impl Fees { ) } - /// Calculate the inverse trading amount, how much input is needed to give the - /// provided output + /// Calculate the inverse trading amount, how much input is needed to give + /// the provided output pub fn pre_trading_fee_amount(&self, post_fee_amount: u128) -> Option { if self.trade_fee_numerator == 0 || self.trade_fee_denominator == 0 { pre_fee_amount( diff --git a/token-swap/program/src/curve/offset.rs b/token-swap/program/src/curve/offset.rs index 7c9e37e4dc1..c1d3f499877 100644 --- a/token-swap/program/src/curve/offset.rs +++ b/token-swap/program/src/curve/offset.rs @@ -34,7 +34,8 @@ impl CurveCalculator for OffsetCurve { /// Constant product swap ensures token a * (token b + offset) = constant /// This is guaranteed to work for all values such that: /// - 1 <= source_amount <= u64::MAX - /// - 1 <= (swap_source_amount * (swap_destination_amount + token_b_offset)) <= u128::MAX + /// - 1 <= (swap_source_amount * (swap_destination_amount + + /// token_b_offset)) <= u128::MAX /// If the offset and token B are both close to u64::MAX, there can be /// overflow errors with the invariant. fn swap_without_fees( @@ -141,8 +142,8 @@ impl CurveCalculator for OffsetCurve { false } - /// The normalized value of the offset curve simply needs to add the offset to - /// the token B side before calculating + /// The normalized value of the offset curve simply needs to add the offset + /// to the token B side before calculating fn normalized_value( &self, swap_token_a_amount: u128, diff --git a/token-swap/program/src/error.rs b/token-swap/program/src/error.rs index f950a6b50ef..1f1ce81ddcd 100644 --- a/token-swap/program/src/error.rs +++ b/token-swap/program/src/error.rs @@ -17,21 +17,26 @@ pub enum SwapError { /// The account cannot be initialized because it is already being used. #[error("Swap account already in use")] AlreadyInUse, - /// The program address provided doesn't match the value generated by the program. + /// The program address provided doesn't match the value generated by the + /// program. #[error("Invalid program address generated from bump seed and key")] InvalidProgramAddress, - /// The owner of the input isn't set to the program address generated by the program. + /// The owner of the input isn't set to the program address generated by the + /// program. #[error("Input account owner is not the program address")] InvalidOwner, - /// The owner of the pool token output is set to the program address generated by the program. + /// The owner of the pool token output is set to the program address + /// generated by the program. #[error("Output pool account owner cannot be the program address")] InvalidOutputOwner, - /// The deserialization of the account returned something besides State::Mint. + /// The deserialization of the account returned something besides + /// State::Mint. #[error("Deserialized account is not an SPL Token mint")] ExpectedMint, // 5. - /// The deserialization of the account returned something besides State::Account. + /// The deserialization of the account returned something besides + /// State::Account. #[error("Deserialized account is not an SPL Token account")] ExpectedAccount, /// The input token account is empty. @@ -94,7 +99,8 @@ pub enum SwapError { /// The provided fee does not match the program owner's constraints #[error("The provided fee does not match the program owner's constraints")] InvalidFee, - /// The provided token program does not match the token program expected by the swap + /// The provided token program does not match the token program expected by + /// the swap #[error("The provided token program does not match the token program expected by the swap")] IncorrectTokenProgramId, diff --git a/token-swap/program/src/instruction.rs b/token-swap/program/src/instruction.rs index 3586b0d8ae2..05fb551d424 100644 --- a/token-swap/program/src/instruction.rs +++ b/token-swap/program/src/instruction.rs @@ -34,9 +34,11 @@ pub struct Initialize { #[repr(C)] #[derive(Clone, Debug, PartialEq)] pub struct Swap { - /// SOURCE amount to transfer, output to DESTINATION is based on the exchange rate + /// SOURCE amount to transfer, output to DESTINATION is based on the + /// exchange rate pub amount_in: u64, - /// Minimum amount of DESTINATION token to output, prevents excessive slippage + /// Minimum amount of DESTINATION token to output, prevents excessive + /// slippage pub minimum_amount_out: u64, } @@ -87,8 +89,8 @@ pub struct DepositSingleTokenTypeExactAmountIn { pub struct WithdrawSingleTokenTypeExactAmountOut { /// Amount of token A or B to receive pub destination_token_amount: u64, - /// Maximum amount of pool tokens to burn. User receives an output of token A - /// or B based on the percentage of the pool tokens that are returned. + /// Maximum amount of pool tokens to burn. User receives an output of token + /// A or B based on the percentage of the pool tokens that are returned. pub maximum_pool_token_amount: u64, } @@ -99,10 +101,12 @@ pub enum SwapInstruction { /// Initializes a new swap /// /// 0. `[writable, signer]` New Token-swap to create. - /// 1. `[]` swap authority derived from `create_program_address(&[Token-swap account])` + /// 1. `[]` swap authority derived from + /// `create_program_address(&[Token-swap account])` /// 2. `[]` token_a Account. Must be non zero, owned by swap authority. /// 3. `[]` token_b Account. Must be non zero, owned by swap authority. - /// 4. `[writable]` Pool Token Mint. Must be empty, owned by swap authority. + /// 4. `[writable]` Pool Token Mint. Must be empty, owned by swap + /// authority. /// 5. `[]` Pool Token Account to deposit trading and withdraw fees. /// Must be empty, not owned by swap authority /// 6. `[writable]` Pool Token Account to deposit the initial pool token @@ -115,10 +119,14 @@ pub enum SwapInstruction { /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority - /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, - /// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token. - /// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token. - /// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner. + /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by + /// user transfer authority, + /// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the + /// SOURCE token. + /// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the + /// DESTINATION token. + /// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as + /// the owner. /// 7. `[writable]` Pool token mint, to generate trading fees /// 8. `[writable]` Fee account, to receive trading fees /// 9. `[]` Token (A|B) SOURCE mint @@ -126,7 +134,8 @@ pub enum SwapInstruction { /// 11. `[]` Token (A|B) SOURCE program id /// 12. `[]` Token (A|B) DESTINATION program id /// 13. `[]` Pool Token program id - /// 14. `[optional, writable]` Host fee account to receive additional trading fees + /// 14. `[optional, writable]` Host fee account to receive additional + /// trading fees Swap(Swap), /// Deposit both types of tokens into the pool. The output is a "pool" @@ -141,7 +150,8 @@ pub enum SwapInstruction { /// 5. `[writable]` token_a Base Account to deposit into. /// 6. `[writable]` token_b Base Account to deposit into. /// 7. `[writable]` Pool MINT account, swap authority is the owner. - /// 8. `[writable]` Pool Account to deposit the generated tokens, user is the owner. + /// 8. `[writable]` Pool Account to deposit the generated tokens, user is + /// the owner. /// 9. `[]` Token A mint /// 10. `[]` Token B mint /// 11. `[]` Token A program id @@ -149,15 +159,16 @@ pub enum SwapInstruction { /// 13. `[]` Pool Token program id DepositAllTokenTypes(DepositAllTokenTypes), - /// Withdraw both types of tokens from the pool at the current ratio, given - /// pool tokens. The pool tokens are burned in exchange for an equivalent - /// amount of token A and B. + /// Withdraw both types of tokens from the pool at the current ratio, + /// given pool tokens. The pool tokens are burned in exchange for an + /// equivalent amount of token A and B. /// /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority /// 3. `[writable]` Pool mint account, swap authority is the owner - /// 4. `[writable]` SOURCE Pool account, amount is transferable by user transfer authority. + /// 4. `[writable]` SOURCE Pool account, amount is transferable by user + /// transfer authority. /// 5. `[writable]` token_a Swap Account to withdraw FROM. /// 6. `[writable]` token_b Swap Account to withdraw FROM. /// 7. `[writable]` token_a user Account to credit. @@ -170,18 +181,20 @@ pub enum SwapInstruction { /// 14. `[]` Token B program id WithdrawAllTokenTypes(WithdrawAllTokenTypes), - /// Deposit one type of tokens into the pool. The output is a "pool" token - /// representing ownership into the pool. Input token is converted as if - /// a swap and deposit all token types were performed. + /// Deposit one type of tokens into the pool. The output is a "pool" + /// token representing ownership into the pool. Input token is + /// converted as if a swap and deposit all token types were performed. /// /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority - /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, + /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by + /// user transfer authority, /// 4. `[writable]` token_a Swap Account, may deposit INTO. /// 5. `[writable]` token_b Swap Account, may deposit INTO. /// 6. `[writable]` Pool MINT account, swap authority is the owner. - /// 7. `[writable]` Pool Account to deposit the generated tokens, user is the owner. + /// 7. `[writable]` Pool Account to deposit the generated tokens, user is + /// the owner. /// 8. `[]` Token (A|B) SOURCE mint /// 9. `[]` Token (A|B) SOURCE program id /// 10. `[]` Pool Token program id @@ -194,7 +207,8 @@ pub enum SwapInstruction { /// 1. `[]` swap authority /// 2. `[]` user transfer authority /// 3. `[writable]` Pool mint account, swap authority is the owner - /// 4. `[writable]` SOURCE Pool account, amount is transferable by user transfer authority. + /// 4. `[writable]` SOURCE Pool account, amount is transferable by user + /// transfer authority. /// 5. `[writable]` token_a Swap Account to potentially withdraw from. /// 6. `[writable]` token_b Swap Account to potentially withdraw from. /// 7. `[writable]` token_(A|B) User Account to credit @@ -206,7 +220,8 @@ pub enum SwapInstruction { } impl SwapInstruction { - /// Unpacks a byte buffer into a [SwapInstruction](enum.SwapInstruction.html). + /// Unpacks a byte buffer into a + /// [SwapInstruction](enum.SwapInstruction.html). pub fn unpack(input: &[u8]) -> Result { let (&tag, rest) = input.split_first().ok_or(SwapError::InvalidInstruction)?; Ok(match tag { diff --git a/token-swap/program/src/lib.rs b/token-swap/program/src/lib.rs index a8d325c9e6d..34fa02092dd 100644 --- a/token-swap/program/src/lib.rs +++ b/token-swap/program/src/lib.rs @@ -13,7 +13,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw"); diff --git a/token-swap/program/src/processor.rs b/token-swap/program/src/processor.rs index de212c31d27..bd60718c8fc 100644 --- a/token-swap/program/src/processor.rs +++ b/token-swap/program/src/processor.rs @@ -1010,7 +1010,8 @@ impl Processor { Ok(()) } - /// Processes a [WithdrawSingleTokenTypeExactAmountOut](enum.Instruction.html). + /// Processes a + /// [WithdrawSingleTokenTypeExactAmountOut](enum.Instruction.html). pub fn process_withdraw_single_token_type_exact_amount_out( program_id: &Pubkey, destination_token_amount: u64, diff --git a/token-upgrade/program/src/instruction.rs b/token-upgrade/program/src/instruction.rs index 69b0e1f7a97..527a263702c 100644 --- a/token-upgrade/program/src/instruction.rs +++ b/token-upgrade/program/src/instruction.rs @@ -13,19 +13,23 @@ use { #[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive)] #[repr(u8)] pub enum TokenUpgradeInstruction { - /// Burns all of the original tokens in the user's account, and transfers the same - /// amount of tokens from an account owned by a PDA into another account. + /// Burns all of the original tokens in the user's account, and transfers + /// the same amount of tokens from an account owned by a PDA into + /// another account. /// /// Accounts expected by this instruction: /// /// 0. `[writeable]` Original token account to burn from /// 1. `[writeable]` Original token mint - /// 2. `[writeable]` Escrow of new tokens held by or delegated to PDA at address: - /// `get_token_upgrade_authority_address(original_mint, new_mint, program_id)` + /// 2. `[writeable]` Escrow of new tokens held by or delegated to PDA at + /// address: `get_token_upgrade_authority_address(original_mint, + /// new_mint, program_id)` /// 3. `[writeable]` New token account to transfer into /// 4. `[]` New token mint - /// 5. `[]` Transfer authority (owner or delegate) of new token escrow held by PDA, must be: - /// `get_token_upgrade_authority_address(original_mint, new_mint, program_id)` + /// 5. `[]` Transfer authority (owner or delegate) of new token escrow + /// held by PDA, must be: + /// `get_token_upgrade_authority_address(original_mint, new_mint, + /// program_id)` /// 6. `[]` SPL Token program for original mint /// 7. `[]` SPL Token program for new mint /// 8. `[]` Original token account transfer authority (owner or delegate) @@ -33,7 +37,6 @@ pub enum TokenUpgradeInstruction { /// /// Data expected by this instruction: /// None - /// Exchange, } diff --git a/token-upgrade/program/src/lib.rs b/token-upgrade/program/src/lib.rs index ecc728ff58c..7944b70b618 100644 --- a/token-upgrade/program/src/lib.rs +++ b/token-upgrade/program/src/lib.rs @@ -7,7 +7,8 @@ pub mod error; pub mod instruction; pub mod processor; -// Export current SDK types for downstream users building with a different SDK version +// Export current SDK types for downstream users building with a different SDK +// version pub use solana_program; use solana_program::pubkey::Pubkey; diff --git a/token-upgrade/program/tests/functional.rs b/token-upgrade/program/tests/functional.rs index bc1c7626195..06f3d0eef3f 100644 --- a/token-upgrade/program/tests/functional.rs +++ b/token-upgrade/program/tests/functional.rs @@ -1,4 +1,5 @@ -// Mark this test as SBF-only due to current `ProgramTest` limitations when CPIing into the system program +// Mark this test as SBF-only due to current `ProgramTest` limitations when +// CPIing into the system program #![cfg(feature = "test-sbf")] use { diff --git a/token-wrap/program/src/instruction.rs b/token-wrap/program/src/instruction.rs index 739e0037e48..fc5975c9dd5 100644 --- a/token-wrap/program/src/instruction.rs +++ b/token-wrap/program/src/instruction.rs @@ -10,18 +10,19 @@ pub enum TokenWrapInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writeable,signer]` Funding account for mint and backpointer (must be a system account) - /// 1. `[writeable]` Unallocated wrapped mint account to create, address must be: - /// `get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id)` + /// 0. `[writeable,signer]` Funding account for mint and backpointer (must + /// be a system account) + /// 1. `[writeable]` Unallocated wrapped mint account to create, address + /// must be: `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` /// 2. `[writeable]` Unallocated wrapped backpointer account to create - /// `get_wrapped_mint_backpointer_address(wrapped_mint_address)` + /// `get_wrapped_mint_backpointer_address(wrapped_mint_address)` /// 3. `[]` Existing unwrapped mint /// 4. `[]` System program /// 5. `[]` SPL Token program for wrapped mint /// /// Data expected by this instruction: /// * bool: true = idempotent creation, false = non-idempotent creation - /// CreateMint, /// Wrap tokens @@ -33,46 +34,48 @@ pub enum TokenWrapInstruction { /// /// 0. `[writeable]` Unwrapped token account to wrap /// 1. `[writeable]` Escrow of unwrapped tokens, must be owned by: - /// `get_wrapped_mint_authority(wrapped_mint_address)` + /// `get_wrapped_mint_authority(wrapped_mint_address)` /// 2. `[]` Unwrapped token mint /// 3. `[writeable]` Wrapped mint, must be initialized, address must be: - /// `get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id)` + /// `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` /// 4. `[writeable]` Recipient wrapped token account /// 5. `[]` Escrow mint authority, address must be: - /// `get_wrapped_mint_authority(wrapped_mint)` + /// `get_wrapped_mint_authority(wrapped_mint)` /// 6. `[]` SPL Token program for unwrapped mint /// 7. `[]` SPL Token program for wrapped mint /// 8. `[signer]` Transfer authority on unwrapped token account - /// 8..8+M. `[signer]` (Optional) M multisig signers on unwrapped token account + /// 8..8+M. `[signer]` (Optional) M multisig signers on unwrapped token + /// account /// /// Data expected by this instruction: /// * little-endian u64 representing the amount to wrap - /// Wrap, /// Unwrap tokens /// - /// Burn user wrapped tokens and transfer the same amount of unwrapped tokens - /// from the escrow account to the provided account. + /// Burn user wrapped tokens and transfer the same amount of unwrapped + /// tokens from the escrow account to the provided account. /// /// Accounts expected by this instruction: /// /// 0. `[writeable]` Wrapped token account to unwrap /// 1. `[writeable]` Wrapped mint, address must be: - /// `get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id)` + /// `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` /// 2. `[writeable]` Escrow of unwrapped tokens, must be owned by: - /// `get_wrapped_mint_authority(wrapped_mint_address)` + /// `get_wrapped_mint_authority(wrapped_mint_address)` /// 3. `[writeable]` Recipient unwrapped tokens /// 4. `[]` Unwrapped token mint /// 5. `[]` Escrow unwrapped token authority - /// `get_wrapped_mint_authority(wrapped_mint)` + /// `get_wrapped_mint_authority(wrapped_mint)` /// 6. `[]` SPL Token program for wrapped mint /// 7. `[]` SPL Token program for unwrapped mint /// 8. `[signer]` Transfer authority on wrapped token account - /// 8..8+M. `[signer]` (Optional) M multisig signers on wrapped token account + /// 8..8+M. `[signer]` (Optional) M multisig signers on wrapped token + /// account /// /// Data expected by this instruction: /// * little-endian u64 representing the amount to unwrap - /// Unwrap, } diff --git a/token-wrap/program/src/lib.rs b/token-wrap/program/src/lib.rs index 9ece3168444..79fda0836c2 100644 --- a/token-wrap/program/src/lib.rs +++ b/token-wrap/program/src/lib.rs @@ -7,7 +7,8 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current SDK types for downstream users building with a different SDK version +// Export current SDK types for downstream users building with a different SDK +// version pub use solana_program; use solana_program::pubkey::Pubkey; diff --git a/token/cli/src/config.rs b/token/cli/src/config.rs index 3059994adbe..f2beb0b2a58 100644 --- a/token/cli/src/config.rs +++ b/token/cli/src/config.rs @@ -352,7 +352,8 @@ impl<'a> Config<'a> { )) } - // Checks if an explicit address was provided, otherwise return the default address if there is one + // Checks if an explicit address was provided, otherwise return the default + // address if there is one pub(crate) fn pubkey_or_default( &self, arg_matches: &ArgMatches<'_>, @@ -368,7 +369,8 @@ impl<'a> Config<'a> { Ok(self.default_signer()?.pubkey()) } - // Checks if an explicit signer was provided, otherwise return the default signer. + // Checks if an explicit signer was provided, otherwise return the default + // signer. pub(crate) fn signer_or_default( &self, arg_matches: &ArgMatches, diff --git a/token/cli/src/main.rs b/token/cli/src/main.rs index f73872fbe33..0feb3b60dae 100644 --- a/token/cli/src/main.rs +++ b/token/cli/src/main.rs @@ -1355,8 +1355,9 @@ async fn command_transfer( ) -> CommandResult { let mint_info = config.get_mint_info(&token_pubkey, mint_decimals).await?; - // if the user got the decimals wrong, they may well have calculated the transfer amount wrong - // we only check in online mode, because in offline, mint_info.decimals is always 9 + // if the user got the decimals wrong, they may well have calculated the + // transfer amount wrong we only check in online mode, because in offline, + // mint_info.decimals is always 9 if !config.sign_only && mint_decimals.is_some() && mint_decimals != Some(mint_info.decimals) { return Err(format!( "Decimals {} was provided, but actual value is {}", @@ -1367,10 +1368,10 @@ async fn command_transfer( } // decimals determines whether transfer_checked is used or not - // in online mode, mint_decimals may be None but mint_info.decimals is always correct - // in offline mode, mint_info.decimals may be wrong, but mint_decimals is always provided - // and in online mode, when mint_decimals is provided, it is verified correct - // hence the fallthrough logic here + // in online mode, mint_decimals may be None but mint_info.decimals is always + // correct in offline mode, mint_info.decimals may be wrong, but + // mint_decimals is always provided and in online mode, when mint_decimals + // is provided, it is verified correct hence the fallthrough logic here let decimals = if use_unchecked_instruction { None } else if mint_decimals.is_some() { @@ -1446,7 +1447,8 @@ async fn command_transfer( // * its a system account, we are happy // * its a non-account for this program, we error helpfully // * its a token account for a different program, we error helpfully - // * otherwise its probabaly a program account owner of an ata, in which case we gate transfer with a flag + // * otherwise its probabaly a program account owner of an ata, in which case we + // gate transfer with a flag if let Some(recipient_account_data) = maybe_recipient_account_data { let recipient_account_owner = recipient_account_data.owner; let maybe_account_state = @@ -1556,7 +1558,8 @@ async fn command_transfer( fund_recipient }; - // and now we determine if we will actually fund it, based on its need and our willingness + // and now we determine if we will actually fund it, based on its need and our + // willingness let fundable_owner = if needs_funding { if confidential_transfer_args.is_some() { return Err( @@ -1596,8 +1599,9 @@ async fn command_transfer( { if !config.sign_only { // we can use the mint data from the start of the function, but will require - // non-trivial amount of refactoring the code due to ownership; for now, we fetch the mint - // a second time. This can potentially be optimized in the future. + // non-trivial amount of refactoring the code due to ownership; for now, we + // fetch the mint a second time. This can potentially be optimized + // in the future. let confidential_transfer_mint = config.get_account_checked(&token_pubkey).await?; let mint_state = StateWithExtensionsOwned::::unpack(confidential_transfer_mint.data) @@ -1610,9 +1614,10 @@ async fn command_transfer( confidential_transfer_mint.auditor_elgamal_pubkey, ); - // if auditor ElGamal pubkey is provided, check consistency with the one in the mint - // if auditor ElGamal pubkey is not provided, then use the expected one from the - // mint, which could also be `None` if auditing is disabled + // if auditor ElGamal pubkey is provided, check consistency with the one in the + // mint if auditor ElGamal pubkey is not provided, then use the + // expected one from the mint, which could also be `None` if + // auditing is disabled if args.auditor_elgamal_pubkey.is_some() && expected_auditor_elgamal_pubkey != args.auditor_elgamal_pubkey { @@ -1934,7 +1939,8 @@ async fn command_freeze( ), ); - // we dont use the decimals from mint_info because its not need and in sign-only its wrong + // we dont use the decimals from mint_info because its not need and in sign-only + // its wrong let token = token_client_from_config(config, &mint_info.address, None)?; let res = token .freeze(&account, &freeze_authority, &bulk_signers) @@ -1969,7 +1975,8 @@ async fn command_thaw( ), ); - // we dont use the decimals from mint_info because its not need and in sign-only its wrong + // we dont use the decimals from mint_info because its not need and in sign-only + // its wrong let token = token_client_from_config(config, &mint_info.address, None)?; let res = token .thaw(&account, &freeze_authority, &bulk_signers) @@ -2025,7 +2032,8 @@ async fn command_wrap( .wrap(&account, &wallet_address, lamports, &bulk_signers) .await? } else { - // this case is hit for a token22 ata, which is always immutable. but it does the right thing anyway + // this case is hit for a token22 ata, which is always immutable. but it does + // the right thing anyway token .wrap_with_mutable_ownership(&account, &wallet_address, lamports, &bulk_signers) .await? @@ -2533,7 +2541,8 @@ async fn command_gc( for (address, (amount, frozen, close_authority)) in accounts { let is_associated = address == associated_token_account; - // only close the associated account if --close-empty-associated-accounts is provided + // only close the associated account if --close-empty-associated-accounts is + // provided if is_associated && !close_empty_associated_accounts { continue; } @@ -3378,8 +3387,8 @@ async fn command_deposit_withdraw_confidential_tokens( // // TODO: expose account balance decryption in token // let aes_key = aes_key.expect("AES key must be provided"); // let current_balance = token - // .confidential_transfer_get_available_balance_with_key(&token_account_address, aes_key) - // .await?; + // .confidential_transfer_get_available_balance_with_key(& + // token_account_address, aes_key) .await?; let withdraw_amount = maybe_amount.expect("ALL keyword is not currently supported for withdraw"); @@ -5685,8 +5694,8 @@ async fn process_command<'a>( // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. // - // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be updated - // once custom ElGamal and AES keys are supported. + // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be + // updated once custom ElGamal and AES keys are supported. let sender_elgamal_keypair = ElGamalKeypair::new_from_signer(&*owner_signer, b"").unwrap(); let sender_aes_key = AeKey::new_from_signer(&*owner_signer, b"").unwrap(); @@ -6274,8 +6283,8 @@ async fn process_command<'a>( // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. // - // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be updated - // once custom ElGamal and AES keys are supported. + // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be + // updated once custom ElGamal and AES keys are supported. let elgamal_keypair = ElGamalKeypair::new_from_signer(&*owner_signer, b"").unwrap(); let aes_key = AeKey::new_from_signer(&*owner_signer, b"").unwrap(); @@ -6364,8 +6373,8 @@ async fn process_command<'a>( // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. // - // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be updated - // once custom ElGamal and AES keys are supported. + // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be + // updated once custom ElGamal and AES keys are supported. let elgamal_keypair = ElGamalKeypair::new_from_signer(&*owner_signer, b"").unwrap(); let aes_key = AeKey::new_from_signer(&*owner_signer, b"").unwrap(); @@ -6408,8 +6417,8 @@ async fn process_command<'a>( // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. // - // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be updated - // once custom ElGamal and AES keys are supported. + // NOTE:: Seed bytes are hardcoded to be empty bytes for now. They will be + // updated once custom ElGamal and AES keys are supported. let elgamal_keypair = ElGamalKeypair::new_from_signer(&*owner_signer, b"").unwrap(); let aes_key = AeKey::new_from_signer(&*owner_signer, b"").unwrap(); diff --git a/token/cli/src/output.rs b/token/cli/src/output.rs index adf928e7192..9b54bbe689e 100644 --- a/token/cli/src/output.rs +++ b/token/cli/src/output.rs @@ -905,7 +905,8 @@ fn display_ui_extension( } Ok(()) } - // ExtensionType::Uninitialized is a hack to ensure a mint/account is never the same length as a multisig + // ExtensionType::Uninitialized is a hack to ensure a mint/account is never the same length + // as a multisig UiExtension::Uninitialized => Ok(()), UiExtension::UnparseableExtension => writeln_name_value( f, diff --git a/token/client/src/client.rs b/token/client/src/client.rs index d926c7de3d6..6e3f8096511 100644 --- a/token/client/src/client.rs +++ b/token/client/src/client.rs @@ -23,8 +23,8 @@ pub trait SimulateTransaction { type SimulationOutput; } -/// Extends basic `SendTransaction` trait with function `send` where client is `&mut BanksClient`. -/// Required for `ProgramBanksClient`. +/// Extends basic `SendTransaction` trait with function `send` where client is +/// `&mut BanksClient`. Required for `ProgramBanksClient`. pub trait SendTransactionBanksClient: SendTransaction { fn send<'a>( &self, @@ -33,8 +33,8 @@ pub trait SendTransactionBanksClient: SendTransaction { ) -> BoxFuture<'a, ProgramClientResult>; } -/// Extends basic `SimulateTransaction` trait with function `simulation` where client is `&mut BanksClient`. -/// Required for `ProgramBanksClient`. +/// Extends basic `SimulateTransaction` trait with function `simulation` where +/// client is `&mut BanksClient`. Required for `ProgramBanksClient`. pub trait SimulateTransactionBanksClient: SimulateTransaction { fn simulate<'a>( &self, @@ -85,8 +85,8 @@ impl SimulateTransactionBanksClient for ProgramBanksClientProcessTransaction { } } -/// Extends basic `SendTransaction` trait with function `send` where client is `&RpcClient`. -/// Required for `ProgramRpcClient`. +/// Extends basic `SendTransaction` trait with function `send` where client is +/// `&RpcClient`. Required for `ProgramRpcClient`. pub trait SendTransactionRpc: SendTransaction { fn send<'a>( &self, @@ -95,8 +95,8 @@ pub trait SendTransactionRpc: SendTransaction { ) -> BoxFuture<'a, ProgramClientResult>; } -/// Extends basic `SimulateTransaction` trait with function `simulate` where client is `&RpcClient`. -/// Required for `ProgramRpcClient`. +/// Extends basic `SimulateTransaction` trait with function `simulate` where +/// client is `&RpcClient`. Required for `ProgramRpcClient`. pub trait SimulateTransactionRpc: SimulateTransaction { fn simulate<'a>( &self, diff --git a/token/client/src/lib.rs b/token/client/src/lib.rs index 850cbbd3f8f..b0d017870bc 100644 --- a/token/client/src/lib.rs +++ b/token/client/src/lib.rs @@ -3,10 +3,11 @@ pub mod client; pub mod output; pub mod token; -/// Helper functions to generate split zero-knowledge proofs for confidential transfers. +/// Helper functions to generate split zero-knowledge proofs for confidential +/// transfers. /// -/// The logic in this submodule should belong to the `solana-zk-token-sdk` and will be removed with -/// an upgrade to the Solana program in the future. +/// The logic in this submodule should belong to the `solana-zk-token-sdk` and +/// will be removed with an upgrade to the Solana program in the future. pub mod proof_generation; pub use spl_token_2022; diff --git a/token/client/src/proof_generation.rs b/token/client/src/proof_generation.rs index 32c90fd73e6..6fff0fae3bf 100644 --- a/token/client/src/proof_generation.rs +++ b/token/client/src/proof_generation.rs @@ -1,8 +1,8 @@ -//! Helper functions to generate split zero-knowledge proofs for confidential transfers in the -//! Confidential Transfer Extension. +//! Helper functions to generate split zero-knowledge proofs for confidential +//! transfers in the Confidential Transfer Extension. //! -//! The logic in this submodule should belong to the `solana-zk-token-sdk` and will be removed with -//! an upgrade to the Solana program. +//! The logic in this submodule should belong to the `solana-zk-token-sdk` and +//! will be removed with an upgrade to the Solana program. use { curve25519_dalek::scalar::Scalar, @@ -131,7 +131,8 @@ pub fn transfer_with_fee_split_proof_data( hi: source_decrypt_handle_hi.into(), }; - // encrypt the transfer amount under the destination and auditor ElGamal public key + // encrypt the transfer amount under the destination and auditor ElGamal public + // key let transfer_amount_destination_auditor_ciphertext_lo = GroupedElGamal::encrypt_with( [destination_elgamal_pubkey, auditor_elgamal_pubkey], transfer_amount_lo, @@ -164,7 +165,8 @@ pub fn transfer_with_fee_split_proof_data( calculate_raw_fee_and_delta(transfer_amount, transfer_fee_basis_points) .ok_or(TokenError::Overflow)?; - // if raw fee is greater than the maximum fee, then use the maximum fee for the fee amount + // if raw fee is greater than the maximum fee, then use the maximum fee for the + // fee amount let fee_amount = std::cmp::min(transfer_fee_maximum_fee, raw_fee_amount); // split and encrypt fee @@ -227,7 +229,8 @@ pub fn transfer_with_fee_split_proof_data( ) .map_err(|_| TokenError::ProofGeneration)?; - // encrypt the fee amount under the destination and withdraw withheld authority ElGamal public key + // encrypt the fee amount under the destination and withdraw withheld authority + // ElGamal public key let fee_destination_withdraw_withheld_authority_ciphertext_lo = GroupedElGamal::encrypt_with( [ destination_elgamal_pubkey, @@ -323,15 +326,17 @@ pub fn transfer_with_fee_split_proof_data( )) } -/// Calculate transfer fee and the "delta" value. The function returns the raw fee, which could be -/// greater than the maximum fee amount of a fee parameter. +/// Calculate transfer fee and the "delta" value. The function returns the raw +/// fee, which could be greater than the maximum fee amount of a fee parameter. /// -/// The "delta" value is a number that captures the round-off value when the fee is computed. The -/// fee is computed according to the formula `fee = transfer_amount * fee_rate_basis_points / -/// 10_000`. If no rounding occurred, then we must have `fee * 10_000 - transfer_amount * -/// fee_rate_basis_points = 0`. If there is rounding involved (`10_000` does not divide cleanly), -/// then the difference `fee * 10_000 - transfer_amount * fee_rate_basis_points` can be a non-zero -/// number between `0` and `9_999` inclusively. We call this number the "delta" value. +/// The "delta" value is a number that captures the round-off value when the fee +/// is computed. The fee is computed according to the formula `fee = +/// transfer_amount * fee_rate_basis_points / 10_000`. If no rounding occurred, +/// then we must have `fee * 10_000 - transfer_amount * fee_rate_basis_points = +/// 0`. If there is rounding involved (`10_000` does not divide cleanly), +/// then the difference `fee * 10_000 - transfer_amount * fee_rate_basis_points` +/// can be a non-zero number between `0` and `9_999` inclusively. We call this +/// number the "delta" value. fn calculate_raw_fee_and_delta( transfer_amount: u64, fee_rate_basis_points: u16, @@ -355,8 +360,8 @@ fn calculate_raw_fee_and_delta( Some((fee as u64, delta_fee as u64)) } -/// Calculate the "delta" commitment-opening pair from a transfer amount and fee commitment-opening -/// pairs. +/// Calculate the "delta" commitment-opening pair from a transfer amount and fee +/// commitment-opening pairs. fn compute_delta_commitment_and_opening( (transfer_amount_commitment, transfer_amount_opening): (&PedersenCommitment, &PedersenOpening), (fee_commitment, fee_opening): (&PedersenCommitment, &PedersenOpening), diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 0198f3a5de1..00465f46613 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -315,7 +315,7 @@ impl TokenMemo { pub struct Token { client: Arc>, - pubkey: Pubkey, /*token mint*/ + pubkey: Pubkey, /* token mint */ decimals: Option, payer: Arc, program_id: Pubkey, @@ -939,7 +939,8 @@ where self.process_ixs(&[instruction], signing_keypairs).await } - /// Transfer tokens to an associated account, creating it if it does not exist + /// Transfer tokens to an associated account, creating it if it does not + /// exist #[allow(clippy::too_many_arguments)] pub async fn create_recipient_associated_account_and_transfer( &self, @@ -1297,7 +1298,8 @@ where self.process_ixs(&instructions, signing_keypairs).await } - /// Wrap lamports into a native account that can always have its ownership changed + /// Wrap lamports into a native account that can always have its ownership + /// changed pub async fn wrap_with_mutable_ownership( &self, account: &Pubkey, @@ -1491,7 +1493,8 @@ where .await } - /// Reallocate a token account to be large enough for a set of ExtensionTypes + /// Reallocate a token account to be large enough for a set of + /// ExtensionTypes pub async fn reallocate( &self, account: &Pubkey, @@ -1721,9 +1724,9 @@ where .await } - /// Configures confidential transfers for a token account. If the maximum pending balance - /// credit counter for the extension is not provided, then it is set to be a default value of - /// `2^16`. + /// Configures confidential transfers for a token account. If the maximum + /// pending balance credit counter for the extension is not provided, + /// then it is set to be a default value of `2^16`. #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_configure_token_account( &self, @@ -1800,7 +1803,8 @@ where .await } - /// Prepare a token account with the confidential transfer extension for closing + /// Prepare a token account with the confidential transfer extension for + /// closing pub async fn confidential_transfer_empty_account( &self, account: &Pubkey, @@ -1852,7 +1856,8 @@ where .await } - /// Deposit SPL Tokens into the pending balance of a confidential token account + /// Deposit SPL Tokens into the pending balance of a confidential token + /// account pub async fn confidential_transfer_deposit( &self, account: &Pubkey, @@ -1879,7 +1884,8 @@ where .await } - /// Withdraw SPL Tokens from the available balance of a confidential token account + /// Withdraw SPL Tokens from the available balance of a confidential token + /// account #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_withdraw( &self, @@ -1943,8 +1949,8 @@ where .await } - /// Create withdraw proof context state account for a confidential transfer withdraw - /// instruction. + /// Create withdraw proof context state account for a confidential transfer + /// withdraw instruction. pub async fn create_withdraw_proof_context_state( &self, context_state_account: &Pubkey, @@ -2059,7 +2065,8 @@ where /// Transfer tokens confidentially using split proofs. /// - /// This function assumes that proof context states have already been created. + /// This function assumes that proof context states have already been + /// created. #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_transfer_with_split_proofs( &self, @@ -2106,8 +2113,8 @@ where /// Transfer tokens confidentially using split proofs in parallel /// - /// This function internally generates the ZK Token proof instructions to create the necessary - /// proof context states. + /// This function internally generates the ZK Token proof instructions to + /// create the necessary proof context states. #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_transfer_with_split_proofs_in_parallel( &self, @@ -2227,7 +2234,8 @@ where .await } - /// Create ciphertext validity proof context state account for a confidential transfer. + /// Create ciphertext validity proof context state account for a + /// confidential transfer. pub async fn create_ciphertext_validity_proof_context_state_for_transfer( &self, context_state_accounts: TransferSplitContextStateAccounts<'_>, @@ -2268,7 +2276,8 @@ where .await } - /// Create equality and ciphertext validity proof context state accounts for a confidential transfer. + /// Create equality and ciphertext validity proof context state accounts for + /// a confidential transfer. #[allow(clippy::too_many_arguments)] pub async fn create_equality_and_ciphertext_validity_proof_context_states_for_transfer< S: Signers, @@ -2289,8 +2298,8 @@ where .await } - /// Create equality and ciphertext validity proof context state accounts with a confidential - /// transfer instruction. + /// Create equality and ciphertext validity proof context state accounts + /// with a confidential transfer instruction. #[allow(clippy::too_many_arguments)] pub async fn create_equality_and_ciphertext_validity_proof_context_states_for_transfer_parallel< S: Signers, @@ -2312,10 +2321,11 @@ where .await } - /// Create equality and ciphertext validity proof context states for a confidential transfer. + /// Create equality and ciphertext validity proof context states for a + /// confidential transfer. /// - /// If an optional transfer instruction is provided, then the transfer instruction is attached - /// to the same transaction. + /// If an optional transfer instruction is provided, then the transfer + /// instruction is attached to the same transaction. #[allow(clippy::too_many_arguments)] async fn create_equality_and_ciphertext_validity_proof_context_state_with_optional_transfer< S: Signers, @@ -2428,7 +2438,8 @@ where .await } - /// Create a range proof context state account with a confidential transfer instruction. + /// Create a range proof context state account with a confidential transfer + /// instruction. pub async fn create_range_proof_context_state_for_transfer_parallel( &self, context_state_accounts: TransferSplitContextStateAccounts<'_>, @@ -2445,7 +2456,8 @@ where .await } - /// Create a range proof context state account and an optional confidential transfer instruction. + /// Create a range proof context state account and an optional confidential + /// transfer instruction. async fn create_range_proof_context_state_with_optional_transfer( &self, context_state_accounts: TransferSplitContextStateAccounts<'_>, @@ -2586,7 +2598,8 @@ where /// Transfer tokens confidentially with fee using split proofs. /// - /// This function assumes that proof context states have already been created. + /// This function assumes that proof context states have already been + /// created. #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_transfer_with_fee_and_split_proofs( &self, @@ -2633,8 +2646,8 @@ where /// Transfer tokens confidentially using split proofs in parallel /// - /// This function internally generates the ZK Token proof instructions to create the necessary - /// proof context states. + /// This function internally generates the ZK Token proof instructions to + /// create the necessary proof context states. #[allow(clippy::too_many_arguments)] pub async fn confidential_transfer_transfer_with_fee_and_split_proofs_in_parallel< S: Signers, @@ -2749,8 +2762,8 @@ where ) } - /// Create equality and transfer amount ciphertext validity proof context state accounts for a - /// confidential transfer with fee. + /// Create equality and transfer amount ciphertext validity proof context + /// state accounts for a confidential transfer with fee. #[allow(clippy::too_many_arguments)] pub async fn create_equality_and_ciphertext_validity_proof_context_states_for_transfer_with_fee< S: Signers, @@ -2771,8 +2784,8 @@ where .await } - /// Create equality and transfer amount ciphertext validity proof context state accounts with a confidential - /// transfer instruction. + /// Create equality and transfer amount ciphertext validity proof context + /// state accounts with a confidential transfer instruction. #[allow(clippy::too_many_arguments)] pub async fn create_equality_and_ciphertext_validity_proof_context_states_for_transfer_with_fee_parallel< S: Signers, @@ -2794,11 +2807,11 @@ where .await } - /// Create equality and ciphertext validity proof context states for a confidential transfer - /// with fee. + /// Create equality and ciphertext validity proof context states for a + /// confidential transfer with fee. /// - /// If an optional transfer instruction is provided, then the transfer instruction is attached - /// to the same transaction. + /// If an optional transfer instruction is provided, then the transfer + /// instruction is attached to the same transaction. #[allow(clippy::too_many_arguments)] async fn create_equality_and_ciphertext_validity_proof_context_states_with_optional_transfer_with_fee< S: Signers, @@ -2871,8 +2884,8 @@ where self.process_ixs(&instructions, signing_keypairs).await } - /// Create fee sigma and fee ciphertext validity proof context state accounts for a - /// confidential transfer with fee. + /// Create fee sigma and fee ciphertext validity proof context state + /// accounts for a confidential transfer with fee. #[allow(clippy::too_many_arguments)] pub async fn create_fee_sigma_and_ciphertext_validity_proof_context_states_for_transfer_with_fee< S: Signers, @@ -2893,8 +2906,8 @@ where .await } - /// Create fee sigma and fee ciphertext validity proof context state accounts with a confidential - /// transfer with fee. + /// Create fee sigma and fee ciphertext validity proof context state + /// accounts with a confidential transfer with fee. #[allow(clippy::too_many_arguments)] pub async fn create_fee_sigma_and_ciphertext_validity_proof_context_states_for_transfer_with_fee_parallel< S: Signers, @@ -2916,11 +2929,11 @@ where .await } - /// Create fee sigma and fee ciphertext validity proof context states for a confidential - /// transfer with fee. + /// Create fee sigma and fee ciphertext validity proof context states for a + /// confidential transfer with fee. /// - /// If an optional transfer instruction is provided, then the transfer instruction is attached - /// to the same transaction. + /// If an optional transfer instruction is provided, then the transfer + /// instruction is attached to the same transaction. #[allow(clippy::too_many_arguments)] async fn create_fee_sigma_and_ciphertext_validity_proof_context_states_with_optional_transfer_with_fee< S: Signers, @@ -2993,7 +3006,8 @@ where self.process_ixs(&instructions, signing_keypairs).await } - /// Create range proof context state account for a confidential transfer with fee. + /// Create range proof context state account for a confidential transfer + /// with fee. #[allow(clippy::too_many_arguments)] pub async fn create_range_proof_context_state_for_transfer_with_fee( &self, @@ -3010,7 +3024,8 @@ where .await } - /// Create range proof context state account for a confidential transfer with fee. + /// Create range proof context state account for a confidential transfer + /// with fee. #[allow(clippy::too_many_arguments)] pub async fn create_range_proof_context_state_for_transfer_with_fee_parallel( &self, @@ -3028,7 +3043,8 @@ where .await } - /// Create a range proof context state account and an optional confidential transfer instruction. + /// Create a range proof context state account and an optional confidential + /// transfer instruction. async fn create_range_proof_context_state_with_optional_transfer_with_fee( &self, context_state_accounts: TransferWithFeeSplitContextStateAccounts<'_>, @@ -3067,7 +3083,8 @@ where self.process_ixs(&instructions, signing_keypairs).await } - /// Applies the confidential transfer pending balance to the available balance + /// Applies the confidential transfer pending balance to the available + /// balance pub async fn confidential_transfer_apply_pending_balance( &self, account: &Pubkey, @@ -3108,7 +3125,8 @@ where .await } - /// Enable confidential transfer `Deposit` and `Transfer` instructions for a token account + /// Enable confidential transfer `Deposit` and `Transfer` instructions for a + /// token account pub async fn confidential_transfer_enable_confidential_credits( &self, account: &Pubkey, @@ -3132,7 +3150,8 @@ where .await } - /// Disable confidential transfer `Deposit` and `Transfer` instructions for a token account + /// Disable confidential transfer `Deposit` and `Transfer` instructions for + /// a token account pub async fn confidential_transfer_disable_confidential_credits( &self, account: &Pubkey, @@ -3156,7 +3175,8 @@ where .await } - /// Enable a confidential extension token account to receive non-confidential payments + /// Enable a confidential extension token account to receive + /// non-confidential payments pub async fn confidential_transfer_enable_non_confidential_credits( &self, account: &Pubkey, @@ -3180,7 +3200,8 @@ where .await } - /// Disable non-confidential payments for a confidential extension token account + /// Disable non-confidential payments for a confidential extension token + /// account pub async fn confidential_transfer_disable_non_confidential_credits( &self, account: &Pubkey, diff --git a/token/program-2022-test/tests/confidential_transfer.rs b/token/program-2022-test/tests/confidential_transfer.rs index f7e16a58a7f..a41d4893c69 100644 --- a/token/program-2022-test/tests/confidential_transfer.rs +++ b/token/program-2022-test/tests/confidential_transfer.rs @@ -530,8 +530,8 @@ async fn confidential_transfer_empty_account() { let mut context = TestContext::new().await; - // newly created confidential transfer account should hold no balance and therefore, - // immediately closable + // newly created confidential transfer account should hold no balance and + // therefore, immediately closable context .init_token_with_mint(vec![ ExtensionInitializationParams::ConfidentialTransferMint { diff --git a/token/program-2022-test/tests/confidential_transfer_fee.rs b/token/program-2022-test/tests/confidential_transfer_fee.rs index 306d5332303..f2eb4086eb7 100644 --- a/token/program-2022-test/tests/confidential_transfer_fee.rs +++ b/token/program-2022-test/tests/confidential_transfer_fee.rs @@ -575,7 +575,8 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_mint() { .unwrap(); assert_eq!(extension.withheld_amount, pod::ElGamalCiphertext::zeroed()); - // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` instruction data + // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` + // instruction data let fee = transfer_fee_parameters.calculate_fee(100).unwrap(); let new_decryptable_available_balance = alice_meta.aes_key.encrypt(fee); @@ -875,7 +876,8 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_mint_with_proof_con ctx.banks_client.process_transaction(tx).await.unwrap(); } - // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` instruction data + // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` + // instruction data let fee = transfer_fee_parameters.calculate_fee(100).unwrap(); let new_decryptable_available_balance = alice_meta.aes_key.encrypt(fee); token @@ -1226,7 +1228,8 @@ async fn confidential_transfer_harvest_withheld_tokens_to_mint() { .unwrap(); assert_eq!(extension.withheld_amount, pod::ElGamalCiphertext::zeroed()); - // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` instruction data + // calculate and encrypt fee to attach to the `WithdrawWithheldTokensFromMint` + // instruction data let fee = transfer_fee_parameters.calculate_fee(100).unwrap(); check_withheld_amount_in_mint(&token, &withdraw_withheld_authority_elgamal_keypair, fee).await; diff --git a/token/program-2022-test/tests/cpi_guard.rs b/token/program-2022-test/tests/cpi_guard.rs index 45aba1424ca..518303aca17 100644 --- a/token/program-2022-test/tests/cpi_guard.rs +++ b/token/program-2022-test/tests/cpi_guard.rs @@ -32,7 +32,8 @@ use { // set up a bank and bank client with spl token 2022 and the instruction padder // also creates a token with no extensions and inits two token accounts async fn make_context() -> TestContext { - // TODO this may be removed when we upgrade to a solana version with a fixed `get_stack_height()` stub + // TODO this may be removed when we upgrade to a solana version with a fixed + // `get_stack_height()` stub if std::env::var("BPF_OUT_DIR").is_err() && std::env::var("SBF_OUT_DIR").is_err() { panic!("CpiGuard tests MUST be invoked with `cargo test-sbf`, NOT `cargo test --feature test-sbf`. \ In a non-BPF context, `get_stack_height()` always returns 0, and all tests WILL fail."); @@ -659,7 +660,8 @@ async fn test_cpi_guard_set_authority() { token, alice, bob, .. } = context.token_context.unwrap(); - // the behavior of cpi guard and close authority is so complicated that its best to test all cases exhaustively + // the behavior of cpi guard and close authority is so complicated that its best + // to test all cases exhaustively let mut states = vec![]; for action in [ SetAuthTest::ChangeOwner, @@ -698,7 +700,8 @@ async fn test_cpi_guard_set_authority() { .unwrap(); } - // if we are changing or removing close auth, we need to have one to change/remove + // if we are changing or removing close auth, we need to have one to + // change/remove if action == SetAuthTest::ChangeCloseAuth || action == SetAuthTest::RemoveCloseAuth { token .set_authority( diff --git a/token/program-2022-test/tests/initialize_mint.rs b/token/program-2022-test/tests/initialize_mint.rs index 709f38d8481..898ecd4ea19 100644 --- a/token/program-2022-test/tests/initialize_mint.rs +++ b/token/program-2022-test/tests/initialize_mint.rs @@ -536,7 +536,8 @@ async fn fail_invalid_extensions_combination() { ) .unwrap(); - // initialize transfer fee and confidential transfers, but no confidential transfer fee + // initialize transfer fee and confidential transfers, but no confidential + // transfer fee let mint_space = ExtensionType::try_calculate_account_len::(&[ ExtensionType::TransferFeeConfig, ExtensionType::ConfidentialTransferMint, @@ -577,7 +578,8 @@ async fn fail_invalid_extensions_combination() { ) ); - // initialize transfer fee and confidential transfer fees, but no confidential transfers + // initialize transfer fee and confidential transfer fees, but no confidential + // transfers let mint_space = ExtensionType::try_calculate_account_len::(&[ ExtensionType::TransferFeeConfig, ExtensionType::ConfidentialTransferFeeConfig, @@ -618,8 +620,8 @@ async fn fail_invalid_extensions_combination() { ) ); - // initialize all of transfer fee, confidential transfers, and confidential transfer fees - // (success case) + // initialize all of transfer fee, confidential transfers, and confidential + // transfer fees (success case) let mint_space = ExtensionType::try_calculate_account_len::(&[ ExtensionType::TransferFeeConfig, ExtensionType::ConfidentialTransferMint, diff --git a/token/program-2022-test/tests/program_test.rs b/token/program-2022-test/tests/program_test.rs index 7c301979fba..1400285a0c0 100644 --- a/token/program-2022-test/tests/program_test.rs +++ b/token/program-2022-test/tests/program_test.rs @@ -146,7 +146,7 @@ impl TestContext { let token_unchecked = Token::new_native(Arc::clone(&client), &id(), Arc::new(payer)); self.token_context = Some(TokenContext { decimals: native_mint::DECIMALS, - mint_authority: Keypair::new(), /*bogus*/ + mint_authority: Keypair::new(), /* bogus */ token, token_unchecked, alice: Keypair::new(), diff --git a/token/program-2022-test/tests/token_metadata_emit.rs b/token/program-2022-test/tests/token_metadata_emit.rs index cf5eb9932af..ccf14c5214b 100644 --- a/token/program-2022-test/tests/token_metadata_emit.rs +++ b/token/program-2022-test/tests/token_metadata_emit.rs @@ -127,7 +127,8 @@ async fn success(start: Option, end: Option) { } assert_eq!(*check_buffer, return_data[..check_buffer.len()]); - // we're sure that we're getting the full data, so also compare the deserialized type + // we're sure that we're getting the full data, so also compare the deserialized + // type if start.is_none() && end.is_none() { let emitted_token_metadata = try_from_slice_unchecked::(&return_data).unwrap(); diff --git a/token/program-2022-test/tests/transfer_fee.rs b/token/program-2022-test/tests/transfer_fee.rs index c0251ec53d2..2249cac0337 100644 --- a/token/program-2022-test/tests/transfer_fee.rs +++ b/token/program-2022-test/tests/transfer_fee.rs @@ -1306,8 +1306,8 @@ async fn max_withdraw_withheld_tokens_from_accounts() { .. } = create_mint_with_accounts(alice_amount).await; - // withdraw from max accounts, which is around 35: 1 mint, 1 destination, 1 authority, - // 32 accounts + // withdraw from max accounts, which is around 35: 1 mint, 1 destination, 1 + // authority, 32 accounts // see https://docs.solana.com/proposals/transactions-v2#problem let destination = Keypair::new(); token diff --git a/token/program-2022-test/tests/transfer_hook.rs b/token/program-2022-test/tests/transfer_hook.rs index eb333536793..4727f97c091 100644 --- a/token/program-2022-test/tests/transfer_hook.rs +++ b/token/program-2022-test/tests/transfer_hook.rs @@ -40,8 +40,8 @@ pub fn process_instruction_fail( Err(ProgramError::InvalidInstructionData) } -/// Test program to check signer / write downgrade for repeated accounts, conforms -/// to transfer-hook-interface +/// Test program to check signer / write downgrade for repeated accounts, +/// conforms to transfer-hook-interface pub fn process_instruction_downgrade( _program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/program-2022/src/error.rs b/token/program-2022/src/error.rs index 6da2fdb2b3d..ff004f0ffb7 100644 --- a/token/program-2022/src/error.rs +++ b/token/program-2022/src/error.rs @@ -119,13 +119,15 @@ pub enum TokenError { /// Transfer fee exceeds maximum of 10,000 basis points #[error("Transfer fee exceeds maximum of 10,000 basis points")] TransferFeeExceedsMaximum, - /// Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee` + /// Mint required for this account to transfer tokens, use + /// `transfer_checked` or `transfer_checked_with_fee` #[error("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`")] MintRequiredForTransfer, /// Calculated fee does not match expected fee #[error("Calculated fee does not match expected fee")] FeeMismatch, - /// Fee parameters associated with confidential transfer zero-knowledge proofs do not match fee parameters in mint + /// Fee parameters associated with confidential transfer zero-knowledge + /// proofs do not match fee parameters in mint #[error( "Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint" )] @@ -135,21 +137,24 @@ pub enum TokenError { ImmutableOwner, // 35 - /// An account can only be closed if its withheld fee balance is zero, harvest fees to the - /// mint and try again + /// An account can only be closed if its withheld fee balance is zero, + /// harvest fees to the mint and try again #[error("An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again")] AccountHasWithheldTransferFees, - /// No memo in previous instruction; required for recipient to receive a transfer + /// No memo in previous instruction; required for recipient to receive a + /// transfer #[error("No memo in previous instruction; required for recipient to receive a transfer")] NoMemo, /// Transfer is disabled for this mint #[error("Transfer is disabled for this mint")] NonTransferable, - /// Non-transferable tokens can't be minted to an account without immutable ownership + /// Non-transferable tokens can't be minted to an account without immutable + /// ownership #[error("Non-transferable tokens can't be minted to an account without immutable ownership")] NonTransferableNeedsImmutableOwnership, - /// The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the - /// associated `maximum_pending_balance_credit_counter` + /// The total number of `Deposit` and `Transfer` instructions to an account + /// cannot exceed the associated + /// `maximum_pending_balance_credit_counter` #[error( "The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the associated `maximum_pending_balance_credit_counter`" @@ -157,21 +162,25 @@ pub enum TokenError { MaximumPendingBalanceCreditCounterExceeded, // 40 - /// The deposit amount for the confidential extension exceeds the maximum limit + /// The deposit amount for the confidential extension exceeds the maximum + /// limit #[error("Deposit amount exceeds maximum limit")] MaximumDepositAmountExceeded, /// CPI Guard cannot be enabled or disabled in CPI #[error("CPI Guard cannot be enabled or disabled in CPI")] CpiGuardSettingsLocked, - /// CPI Guard is enabled, and a program attempted to transfer user funds without using a delegate + /// CPI Guard is enabled, and a program attempted to transfer user funds + /// without using a delegate #[error("CPI Guard is enabled, and a program attempted to transfer user funds via CPI without using a delegate")] CpiGuardTransferBlocked, - /// CPI Guard is enabled, and a program attempted to burn user funds without using a delegate + /// CPI Guard is enabled, and a program attempted to burn user funds without + /// using a delegate #[error( "CPI Guard is enabled, and a program attempted to burn user funds via CPI without using a delegate" )] CpiGuardBurnBlocked, - /// CPI Guard is enabled, and a program attempted to close an account without returning lamports to owner + /// CPI Guard is enabled, and a program attempted to close an account + /// without returning lamports to owner #[error("CPI Guard is enabled, and a program attempted to close an account via CPI without returning lamports to owner")] CpiGuardCloseAccountBlocked, @@ -179,7 +188,8 @@ pub enum TokenError { /// CPI Guard is enabled, and a program attempted to approve a delegate #[error("CPI Guard is enabled, and a program attempted to approve a delegate via CPI")] CpiGuardApproveBlocked, - /// CPI Guard is enabled, and a program attempted to add or replace an authority + /// CPI Guard is enabled, and a program attempted to add or replace an + /// authority #[error( "CPI Guard is enabled, and a program attempted to add or replace an authority via CPI" )] @@ -198,7 +208,8 @@ pub enum TokenError { /// An account can only be closed if the confidential withheld fee is zero #[error("An account can only be closed if the confidential withheld fee is zero")] ConfidentialTransferFeeAccountHasWithheldFee, - /// A mint or an account is initialized to an invalid combination of extensions + /// A mint or an account is initialized to an invalid combination of + /// extensions #[error("A mint or an account is initialized to an invalid combination of extensions")] InvalidExtensionCombination, /// Extension allocation with overwrite must use the same length diff --git a/token/program-2022/src/extension/confidential_transfer/account_info.rs b/token/program-2022/src/extension/confidential_transfer/account_info.rs index 741321a8438..bfa88b73b3e 100644 --- a/token/program-2022/src/extension/confidential_transfer/account_info.rs +++ b/token/program-2022/src/extension/confidential_transfer/account_info.rs @@ -24,7 +24,8 @@ use { spl_pod::primitives::PodU64, }; -/// Confidential transfer extension information needed to construct an `EmptyAccount` instruction. +/// Confidential transfer extension information needed to construct an +/// `EmptyAccount` instruction. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct EmptyAccountAccountInfo { @@ -32,7 +33,8 @@ pub struct EmptyAccountAccountInfo { pub(crate) available_balance: EncryptedBalance, } impl EmptyAccountAccountInfo { - /// Create the `EmptyAccount` instruction account information from `ConfidentialTransferAccount`. + /// Create the `EmptyAccount` instruction account information from + /// `ConfidentialTransferAccount`. pub fn new(account: &ConfidentialTransferAccount) -> Self { Self { available_balance: account.available_balance, @@ -54,13 +56,13 @@ impl EmptyAccountAccountInfo { } } -/// Confidential Transfer extension information needed to construct an `ApplyPendingBalance` -/// instruction. +/// Confidential Transfer extension information needed to construct an +/// `ApplyPendingBalance` instruction. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct ApplyPendingBalanceAccountInfo { - /// The total number of `Deposit` and `Transfer` instructions that have credited - /// `pending_balance` + /// The total number of `Deposit` and `Transfer` instructions that have + /// credited `pending_balance` pub(crate) pending_balance_credit_counter: PodU64, /// The low 16 bits of the pending balance (encrypted by `elgamal_pubkey`) pub(crate) pending_balance_lo: EncryptedBalance, @@ -142,7 +144,8 @@ impl ApplyPendingBalanceAccountInfo { } } -/// Confidential Transfer extension information needed to construct a `Withdraw` instruction. +/// Confidential Transfer extension information needed to construct a `Withdraw` +/// instruction. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct WithdrawAccountInfo { @@ -208,7 +211,8 @@ impl WithdrawAccountInfo { } } -/// Confidential Transfer extension information needed to construct a `Transfer` instruction. +/// Confidential Transfer extension information needed to construct a `Transfer` +/// instruction. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct TransferAccountInfo { @@ -218,7 +222,8 @@ pub struct TransferAccountInfo { pub decryptable_available_balance: DecryptableBalance, } impl TransferAccountInfo { - /// Create the `Transfer` instruction account information from `ConfidentialTransferAccount`. + /// Create the `Transfer` instruction account information from + /// `ConfidentialTransferAccount`. pub fn new(account: &ConfidentialTransferAccount) -> Self { Self { available_balance: account.available_balance, @@ -267,8 +272,8 @@ impl TransferAccountInfo { .map_err(|_| TokenError::ProofGeneration) } - /// Create a transfer proof data that is split into equality, ciphertext validity, and range - /// proofs. + /// Create a transfer proof data that is split into equality, ciphertext + /// validity, and range proofs. pub fn generate_split_transfer_proof_data( &self, transfer_amount: u64, diff --git a/token/program-2022/src/extension/confidential_transfer/ciphertext_extraction.rs b/token/program-2022/src/extension/confidential_transfer/ciphertext_extraction.rs index 63fbd0888a5..527668e293b 100644 --- a/token/program-2022/src/extension/confidential_transfer/ciphertext_extraction.rs +++ b/token/program-2022/src/extension/confidential_transfer/ciphertext_extraction.rs @@ -32,11 +32,13 @@ use { /// Extract the commitment component from a grouped ciphertext with 2 handles. /// -/// A grouped ciphertext with 2 handles consists of the following 32-bytes components that are -/// serialized in order: +/// A grouped ciphertext with 2 handles consists of the following 32-bytes +/// components that are serialized in order: /// 1. The `commitment` component that encodes the fee amount. -/// 3. The `decryption handle` component with respect to the destination public key. -/// 4. The `decryption handle` component with respect to the withdraw withheld authority public key. +/// 3. The `decryption handle` component with respect to the destination +/// public key. +/// 4. The `decryption handle` component with respect to the withdraw withheld +/// authority public key. /// /// The fee commitment component consists of the first 32-byte. pub(crate) fn extract_commitment_from_grouped_ciphertext( @@ -48,17 +50,21 @@ pub(crate) fn extract_commitment_from_grouped_ciphertext( PedersenCommitment(transfer_amount_commitment_bytes) } -/// Extract the transfer amount ciphertext encrypted under the source ElGamal public key. +/// Extract the transfer amount ciphertext encrypted under the source ElGamal +/// public key. /// -/// A transfer amount ciphertext consists of the following 32-byte components that are serialized -/// in order: +/// A transfer amount ciphertext consists of the following 32-byte components +/// that are serialized in order: /// 1. The `commitment` component that encodes the transfer amount. -/// 2. The `decryption handle` component with respect to the source public key. -/// 3. The `decryption handle` component with respect to the destination public key. -/// 4. The `decryption handle` component with respect to the auditor public key. +/// 2. The `decryption handle` component with respect to the source public +/// key. +/// 3. The `decryption handle` component with respect to the destination +/// public key. +/// 4. The `decryption handle` component with respect to the auditor public +/// key. /// -/// An ElGamal ciphertext for the source consists of the `commitment` component and the `decryption -/// handle` component with respect to the source. +/// An ElGamal ciphertext for the source consists of the `commitment` component +/// and the `decryption handle` component with respect to the source. pub fn transfer_amount_source_ciphertext( transfer_amount_ciphertext: &TransferAmountCiphertext, ) -> ElGamalCiphertext { @@ -71,17 +77,22 @@ pub fn transfer_amount_source_ciphertext( ElGamalCiphertext(source_ciphertext_bytes) } -/// Extract the transfer amount ciphertext encrypted under the destination ElGamal public key. +/// Extract the transfer amount ciphertext encrypted under the destination +/// ElGamal public key. /// -/// A transfer amount ciphertext consists of the following 32-byte components that are serialized -/// in order: +/// A transfer amount ciphertext consists of the following 32-byte components +/// that are serialized in order: /// 1. The `commitment` component that encodes the transfer amount. -/// 2. The `decryption handle` component with respect to the source public key. -/// 3. The `decryption handle` component with respect to the destination public key. -/// 4. The `decryption handle` component with respect to the auditor public key. +/// 2. The `decryption handle` component with respect to the source public +/// key. +/// 3. The `decryption handle` component with respect to the destination +/// public key. +/// 4. The `decryption handle` component with respect to the auditor public +/// key. /// -/// An ElGamal ciphertext for the destination consists of the `commitment` component and the -/// `decryption handle` component with respect to the destination public key. +/// An ElGamal ciphertext for the destination consists of the `commitment` +/// component and the `decryption handle` component with respect to the +/// destination public key. #[cfg(feature = "zk-ops")] pub(crate) fn transfer_amount_destination_ciphertext( transfer_amount_ciphertext: &TransferAmountCiphertext, @@ -95,17 +106,20 @@ pub(crate) fn transfer_amount_destination_ciphertext( ElGamalCiphertext(destination_ciphertext_bytes) } -/// Extract the fee amount ciphertext encrypted under the destination ElGamal public key. +/// Extract the fee amount ciphertext encrypted under the destination ElGamal +/// public key. /// -/// A fee encryption amount consists of the following 32-byte components that are serialized in -/// order: +/// A fee encryption amount consists of the following 32-byte components that +/// are serialized in order: /// 1. The `commitment` component that encodes the fee amount. -/// 2. The `decryption handle` component with respect to the destination public key. -/// 3. The `decryption handle` component with respect to the withdraw withheld authority public -/// key. +/// 2. The `decryption handle` component with respect to the destination +/// public key. +/// 3. The `decryption handle` component with respect to the withdraw withheld +/// authority public key. /// -/// An ElGamal ciphertext for the destination consists of the `commitment` component and the -/// `decryption handle` component with respect to the destination public key. +/// An ElGamal ciphertext for the destination consists of the `commitment` +/// component and the `decryption handle` component with respect to the +/// destination public key. #[cfg(feature = "zk-ops")] pub(crate) fn fee_amount_destination_ciphertext( transfer_amount_ciphertext: &EncryptedFee, @@ -119,18 +133,20 @@ pub(crate) fn fee_amount_destination_ciphertext( ElGamalCiphertext(source_ciphertext_bytes) } -/// Extract the transfer amount ciphertext encrypted under the withdraw withheld authority ElGamal -/// public key. +/// Extract the transfer amount ciphertext encrypted under the withdraw withheld +/// authority ElGamal public key. /// -/// A fee encryption amount consists of the following 32-byte components that are serialized in -/// order: +/// A fee encryption amount consists of the following 32-byte components that +/// are serialized in order: /// 1. The `commitment` component that encodes the fee amount. -/// 2. The `decryption handle` component with respect to the destination public key. -/// 3. The `decryption handle` component with respect to the withdraw withheld authority public -/// key. +/// 2. The `decryption handle` component with respect to the destination +/// public key. +/// 3. The `decryption handle` component with respect to the withdraw withheld +/// authority public key. /// -/// An ElGamal ciphertext for the destination consists of the `commitment` component and the -/// `decryption handle` component with respect to the withdraw withheld authority public key. +/// An ElGamal ciphertext for the destination consists of the `commitment` +/// component and the `decryption handle` component with respect to the withdraw +/// withheld authority public key. #[cfg(feature = "zk-ops")] pub(crate) fn fee_amount_withdraw_withheld_authority_ciphertext( transfer_amount_ciphertext: &EncryptedFee, @@ -206,28 +222,31 @@ impl From for TransferProofContextInfo { #[cfg(feature = "zk-ops")] impl TransferProofContextInfo { - /// Create a transfer proof context information needed to process a [Transfer] instruction from - /// split proof contexts after verifying their consistency. + /// Create a transfer proof context information needed to process a + /// [Transfer] instruction from split proof contexts after verifying + /// their consistency. pub fn verify_and_extract( equality_proof_context: &CiphertextCommitmentEqualityProofContext, ciphertext_validity_proof_context: &BatchedGroupedCiphertext2HandlesValidityProofContext, range_proof_context: &BatchedRangeProofContext, source_decrypt_handles: &SourceDecryptHandles, ) -> Result { - // The equality proof context consists of the source ElGamal public key, the new source - // available balance ciphertext, and the new source available commitment. The public key - // and ciphertext should be returned as parts of `TransferProofContextInfo` and the - // commitment should be checked with range proof for consistency. + // The equality proof context consists of the source ElGamal public key, the new + // source available balance ciphertext, and the new source available + // commitment. The public key and ciphertext should be returned as parts + // of `TransferProofContextInfo` and the commitment should be checked + // with range proof for consistency. let CiphertextCommitmentEqualityProofContext { pubkey: source_pubkey, ciphertext: new_source_ciphertext, commitment: new_source_commitment, } = equality_proof_context; - // The ciphertext validity proof context consists of the destination ElGamal public key, - // auditor ElGamal public key, and the transfer amount ciphertexts. All of these fields - // should be returned as part of `TransferProofContextInfo`. In addition, the commitments - // pertaining to the transfer amount ciphertexts should be checked with range proof for + // The ciphertext validity proof context consists of the destination ElGamal + // public key, auditor ElGamal public key, and the transfer amount + // ciphertexts. All of these fields should be returned as part of + // `TransferProofContextInfo`. In addition, the commitments pertaining + // to the transfer amount ciphertexts should be checked with range proof for // consistency. let BatchedGroupedCiphertext2HandlesValidityProofContext { destination_pubkey, @@ -236,17 +255,19 @@ impl TransferProofContextInfo { grouped_ciphertext_hi: transfer_amount_ciphertext_hi, } = ciphertext_validity_proof_context; - // The range proof context consists of the Pedersen commitments and bit-lengths for which - // the range proof is proved. The commitments must consist of three commitments pertaining - // to the new source available balance, the low bits of the transfer amount, and high bits - // of the transfer amount. These commitments must be checked for bit lengths `64`, `16`, + // The range proof context consists of the Pedersen commitments and bit-lengths + // for which the range proof is proved. The commitments must consist of + // three commitments pertaining to the new source available balance, the + // low bits of the transfer amount, and high bits of the transfer + // amount. These commitments must be checked for bit lengths `64`, `16`, // and `32`. let BatchedRangeProofContext { commitments: range_proof_commitments, bit_lengths: range_proof_bit_lengths, } = range_proof_context; - // check that the range proof was created for the correct set of Pedersen commitments + // check that the range proof was created for the correct set of Pedersen + // commitments let transfer_amount_commitment_lo = extract_commitment_from_grouped_ciphertext(transfer_amount_ciphertext_lo); let transfer_amount_commitment_hi = @@ -326,18 +347,21 @@ pub struct TransferWithFeePubkeysInfo { pub withdraw_withheld_authority: ElGamalPubkey, } -/// The proof context information needed to process a [Transfer] instruction with fee. +/// The proof context information needed to process a [Transfer] instruction +/// with fee. #[cfg(feature = "zk-ops")] pub struct TransferWithFeeProofContextInfo { /// Group encryption of the low 16 bits of the transfer amount pub ciphertext_lo: TransferAmountCiphertext, /// Group encryption of the high 48 bits of the transfer amount pub ciphertext_hi: TransferAmountCiphertext, - /// The public encryption keys associated with the transfer: source, dest, auditor, and withdraw withheld authority + /// The public encryption keys associated with the transfer: source, dest, + /// auditor, and withdraw withheld authority pub transfer_with_fee_pubkeys: TransferWithFeePubkeysInfo, /// The final spendable ciphertext after the transfer, pub new_source_ciphertext: ElGamalCiphertext, - /// The transfer fee encryption of the low 16 bits of the transfer fee amount + /// The transfer fee encryption of the low 16 bits of the transfer fee + /// amount pub fee_ciphertext_lo: EncryptedFee, /// The transfer fee encryption of the hi 32 bits of the transfer fee amount pub fee_ciphertext_hi: EncryptedFee, @@ -368,8 +392,9 @@ impl From for TransferWithFeeProofContextInfo { #[cfg(feature = "zk-ops")] impl TransferWithFeeProofContextInfo { - /// Create a transfer proof context information needed to process a [Transfer] instruction from - /// split proof contexts after verifying their consistency. + /// Create a transfer proof context information needed to process a + /// [Transfer] instruction from split proof contexts after verifying + /// their consistency. pub fn verify_and_extract( equality_proof_context: &CiphertextCommitmentEqualityProofContext, transfer_amount_ciphertext_validity_proof_context: &BatchedGroupedCiphertext2HandlesValidityProofContext, @@ -379,20 +404,22 @@ impl TransferWithFeeProofContextInfo { source_decrypt_handles: &SourceDecryptHandles, fee_parameters: &TransferFee, ) -> Result { - // The equality proof context consists of the source ElGamal public key, the new source - // available balance ciphertext, and the new source available commitment. The public key - // and ciphertext should be returned as part of `TransferWithFeeProofContextInfo` and the - // commitment should be checked with range proof for consistency. + // The equality proof context consists of the source ElGamal public key, the new + // source available balance ciphertext, and the new source available + // commitment. The public key and ciphertext should be returned as part + // of `TransferWithFeeProofContextInfo` and the commitment should be + // checked with range proof for consistency. let CiphertextCommitmentEqualityProofContext { pubkey: source_pubkey, ciphertext: new_source_ciphertext, commitment: new_source_commitment, } = equality_proof_context; - // The transfer amount ciphertext validity proof context consists of the destination - // ElGamal public key, auditor ElGamal public key, and the transfer amount ciphertexts. All - // of these fields should be returned as part of `TransferWithFeeProofContextInfo`. In - // addition, the commitments pertaining to the transfer amount ciphertexts should be + // The transfer amount ciphertext validity proof context consists of the + // destination ElGamal public key, auditor ElGamal public key, and the + // transfer amount ciphertexts. All of these fields should be returned + // as part of `TransferWithFeeProofContextInfo`. In addition, the + // commitments pertaining to the transfer amount ciphertexts should be // checked with range proof for consistency. let BatchedGroupedCiphertext2HandlesValidityProofContext { destination_pubkey, @@ -401,10 +428,11 @@ impl TransferWithFeeProofContextInfo { grouped_ciphertext_hi: transfer_amount_ciphertext_hi, } = transfer_amount_ciphertext_validity_proof_context; - // The fee sigma proof context consists of the fee commitment, delta commitment, claimed - // commitment, and max fee. The fee and claimed commitment should be checked with range - // proof for consistency. The delta commitment should be checked whether it is properly - // generated with respect to the fee parameters. The max fee should be checked for + // The fee sigma proof context consists of the fee commitment, delta commitment, + // claimed commitment, and max fee. The fee and claimed commitment + // should be checked with range proof for consistency. The delta + // commitment should be checked whether it is properly generated with + // respect to the fee parameters. The max fee should be checked for // consistency with the fee parameters. let FeeSigmaProofContext { fee_commitment, @@ -419,13 +447,15 @@ impl TransferWithFeeProofContextInfo { return Err(ProgramError::InvalidInstructionData); } - // The transfer fee ciphertext validity proof context consists of the destination ElGamal - // public key, withdraw withheld authority ElGamal public key, and the transfer fee - // ciphertexts. The rest of the fields should be return as part of - // `TransferWithFeeProofContextInfo`. In addition, the destination public key should be - // checked for consistency with the destination public key contained in the transfer amount - // ciphertext validity proof, and the commitments pertaining to the transfer fee amount - // ciphertexts should be checked with range proof for consistency. + // The transfer fee ciphertext validity proof context consists of the + // destination ElGamal public key, withdraw withheld authority ElGamal + // public key, and the transfer fee ciphertexts. The rest of the fields + // should be return as part of `TransferWithFeeProofContextInfo`. In + // addition, the destination public key should be checked for + // consistency with the destination public key contained in the transfer amount + // ciphertext validity proof, and the commitments pertaining to the transfer fee + // amount ciphertexts should be checked with range proof for + // consistency. let BatchedGroupedCiphertext2HandlesValidityProofContext { destination_pubkey: destination_pubkey_from_transfer_fee_validity_proof, auditor_pubkey: withdraw_withheld_authority_pubkey, @@ -437,9 +467,9 @@ impl TransferWithFeeProofContextInfo { return Err(ProgramError::InvalidInstructionData); } - // The range proof context consists of the Pedersen commitments and bit-lengths for which - // the range proof is proved. The commitments must consist of seven commitments pertaining - // to + // The range proof context consists of the Pedersen commitments and bit-lengths + // for which the range proof is proved. The commitments must consist of + // seven commitments pertaining to // - the new source available balance (64 bits) // - the low bits of the transfer amount (16 bits) // - the high bits of the transfer amount (32 bits) @@ -452,7 +482,8 @@ impl TransferWithFeeProofContextInfo { bit_lengths: range_proof_bit_lengths, } = range_proof_context; - // check that the range proof was created for the correct set of Pedersen commitments + // check that the range proof was created for the correct set of Pedersen + // commitments let transfer_amount_commitment_lo = extract_commitment_from_grouped_ciphertext(transfer_amount_ciphertext_lo); let transfer_amount_commitment_hi = @@ -563,23 +594,26 @@ impl TransferWithFeeProofContextInfo { } } -/// The ElGamal ciphertext decryption handle pertaining to the low and high bits of the transfer -/// amount under the source public key of the transfer. +/// The ElGamal ciphertext decryption handle pertaining to the low and high bits +/// of the transfer amount under the source public key of the transfer. /// -/// The `TransferProofContext` contains decryption handles for the low and high bits of the -/// transfer amount. Howver, these decryption handles were (mistakenly) removed from the split -/// proof contexts as a form of optimization. These components should be added back into these -/// split proofs in `zk-token-sdk`. Until this modifications is made, include `SourceDecryptHandle` -/// in the transfer instruction data. +/// The `TransferProofContext` contains decryption handles for the low and high +/// bits of the transfer amount. Howver, these decryption handles were +/// (mistakenly) removed from the split proof contexts as a form of +/// optimization. These components should be added back into these split proofs +/// in `zk-token-sdk`. Until this modifications is made, include +/// `SourceDecryptHandle` in the transfer instruction data. #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct SourceDecryptHandles { - /// The ElGamal decryption handle pertaining to the low 16 bits of the transfer amount. + /// The ElGamal decryption handle pertaining to the low 16 bits of the + /// transfer amount. #[cfg_attr(feature = "serde-traits", serde(with = "decrypthandle_fromstr"))] pub lo: DecryptHandle, - /// The ElGamal decryption handle pertaining to the low 32 bits of the transfer amount. + /// The ElGamal decryption handle pertaining to the low 32 bits of the + /// transfer amount. #[cfg_attr(feature = "serde-traits", serde(with = "decrypthandle_fromstr"))] pub hi: DecryptHandle, } diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs index c235f40fffd..b4c995fb377 100644 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer/instruction.rs @@ -33,12 +33,13 @@ use { pub enum ConfidentialTransferInstruction { /// Initializes confidential transfers for a mint. /// - /// The `ConfidentialTransferInstruction::InitializeMint` instruction requires no signers - /// and MUST be included within the same Transaction as `TokenInstruction::InitializeMint`. - /// Otherwise another party can initialize the configuration. + /// The `ConfidentialTransferInstruction::InitializeMint` instruction + /// requires no signers and MUST be included within the same Transaction + /// as `TokenInstruction::InitializeMint`. Otherwise another party can + /// initialize the configuration. /// - /// The instruction fails if the `TokenInstruction::InitializeMint` instruction has already - /// executed for the mint. + /// The instruction fails if the `TokenInstruction::InitializeMint` + /// instruction has already executed for the mint. /// /// Accounts expected by this instruction: /// @@ -46,12 +47,12 @@ pub enum ConfidentialTransferInstruction { /// /// Data expected by this instruction: /// `InitializeMintData` - /// InitializeMint, /// Updates the confidential transfer mint configuration for a mint. /// - /// Use `TokenInstruction::SetAuthority` to update the confidential transfer mint authority. + /// Use `TokenInstruction::SetAuthority` to update the confidential transfer + /// mint authority. /// /// Accounts expected by this instruction: /// @@ -60,52 +61,57 @@ pub enum ConfidentialTransferInstruction { /// /// Data expected by this instruction: /// `UpdateMintData` - /// UpdateMint, /// Configures confidential transfers for a token account. /// - /// The instruction fails if the confidential transfers are already configured, or if the mint - /// was not initialized with confidential transfer support. + /// The instruction fails if the confidential transfers are already + /// configured, or if the mint was not initialized with confidential + /// transfer support. /// - /// The instruction fails if the `TokenInstruction::InitializeAccount` instruction has not yet - /// successfully executed for the token account. + /// The instruction fails if the `TokenInstruction::InitializeAccount` + /// instruction has not yet successfully executed for the token account. /// - /// Upon success, confidential and non-confidential deposits and transfers are enabled. Use the - /// `DisableConfidentialCredits` and `DisableNonConfidentialCredits` instructions to disable. + /// Upon success, confidential and non-confidential deposits and transfers + /// are enabled. Use the `DisableConfidentialCredits` and + /// `DisableNonConfidentialCredits` instructions to disable. /// - /// In order for this instruction to be successfully processed, it must be accompanied by the - /// `VerifyPubkeyValidityProof` instruction of the `zk_token_proof` program in the same - /// transaction or the address of a context state account for the proof must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by the `VerifyPubkeyValidityProof` instruction of the + /// `zk_token_proof` program in the same transaction or the address of a + /// context state account for the proof must be provided. /// /// Accounts expected by this instruction: /// /// * Single owner/delegate /// 0. `[writeable]` The SPL Token account. /// 1. `[]` The corresponding SPL Token mint. - /// 2. `[]` Instructions sysvar if `VerifyPubkeyValidityProof` is included in the same - /// transaction or context state account if `VerifyPubkeyValidityProof` is pre-verified - /// into a context state account. + /// 2. `[]` Instructions sysvar if `VerifyPubkeyValidityProof` is included + /// in the same transaction or context state account if + /// `VerifyPubkeyValidityProof` is pre-verified into a context state + /// account. /// 3. `[signer]` The single source account owner. /// /// * Multisignature owner/delegate /// 0. `[writeable]` The SPL Token account. /// 1. `[]` The corresponding SPL Token mint. - /// 2. `[]` Instructions sysvar if `VerifyPubkeyValidityProof` is included in the same - /// transaction or context state account if `VerifyPubkeyValidityProof` is pre-verified - /// into a context state account. + /// 2. `[]` Instructions sysvar if `VerifyPubkeyValidityProof` is included + /// in the same transaction or context state account if + /// `VerifyPubkeyValidityProof` is pre-verified into a context state + /// account. /// 3. `[]` The multisig source account owner. - /// 4.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 4.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `ConfigureAccountInstructionData` - /// ConfigureAccount, /// Approves a token account for confidential transfers. /// - /// Approval is only required when the `ConfidentialTransferMint::approve_new_accounts` - /// field is set in the SPL Token mint. This instruction must be executed after the account + /// Approval is only required when the + /// `ConfidentialTransferMint::approve_new_accounts` field is set in the + /// SPL Token mint. This instruction must be executed after the account /// owner configures their account for confidential transfers with /// `ConfidentialTransferInstruction::ConfigureAccount`. /// @@ -117,49 +123,56 @@ pub enum ConfidentialTransferInstruction { /// /// Data expected by this instruction: /// None - /// ApproveAccount, /// Empty the available balance in a confidential token account. /// - /// A token account that is extended for confidential transfers can only be closed if the - /// pending and available balance ciphertexts are emptied. The pending balance can be emptied - /// via the `ConfidentialTransferInstruction::ApplyPendingBalance` instruction. Use the - /// `ConfidentialTransferInstruction::EmptyAccount` instruction to empty the available balance - /// ciphertext. + /// A token account that is extended for confidential transfers can only be + /// closed if the pending and available balance ciphertexts are emptied. + /// The pending balance can be emptied + /// via the `ConfidentialTransferInstruction::ApplyPendingBalance` + /// instruction. Use the `ConfidentialTransferInstruction::EmptyAccount` + /// instruction to empty the available balance ciphertext. /// - /// Note that a newly configured account is always empty, so this instruction is not required - /// prior to account closing if no instructions beyond - /// `ConfidentialTransferInstruction::ConfigureAccount` have affected the token account. + /// Note that a newly configured account is always empty, so this + /// instruction is not required prior to account closing if no + /// instructions beyond + /// `ConfidentialTransferInstruction::ConfigureAccount` have affected the + /// token account. /// - /// In order for this instruction to be successfully processed, it must be accompanied by the - /// `VerifyZeroBalanceProof` instruction of the `zk_token_proof` program in the same - /// transaction or the address of a context state account for the proof must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by the `VerifyZeroBalanceProof` instruction of the + /// `zk_token_proof` program in the same transaction or the address of a + /// context state account for the proof must be provided. /// /// * Single owner/delegate /// 0. `[writable]` The SPL Token account. - /// 1. `[]` Instructions sysvar if `VerifyZeroBalanceProof` is included in the same - /// transaction or context state account if `VerifyZeroBalanceProof` is pre-verified into - /// a context state account. + /// 1. `[]` Instructions sysvar if `VerifyZeroBalanceProof` is included in + /// the same transaction or context state account if + /// `VerifyZeroBalanceProof` is pre-verified into a context state + /// account. /// 2. `[signer]` The single account owner. /// /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. - /// 1. `[]` Instructions sysvar if `VerifyZeroBalanceProof` is included in the same - /// transaction or context state account if `VerifyZeroBalanceProof` is pre-verified into - /// a context state account. + /// 1. `[]` Instructions sysvar if `VerifyZeroBalanceProof` is included in + /// the same transaction or context state account if + /// `VerifyZeroBalanceProof` is pre-verified into a context state + /// account. /// 2. `[]` The multisig account owner. - /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `EmptyAccountInstructionData` - /// EmptyAccount, - /// Deposit SPL Tokens into the pending balance of a confidential token account. + /// Deposit SPL Tokens into the pending balance of a confidential token + /// account. /// - /// The account owner can then invoke the `ApplyPendingBalance` instruction to roll the deposit - /// into their available balance at a time of their choosing. + /// The account owner can then invoke the `ApplyPendingBalance` instruction + /// to roll the deposit into their available balance at a time of their + /// choosing. /// /// Fails if the source or destination accounts are frozen. /// Fails if the associated mint is extended as `NonTransferable`. @@ -175,52 +188,55 @@ pub enum ConfidentialTransferInstruction { /// 0. `[writable]` The SPL Token account. /// 1. `[]` The token mint. /// 2. `[]` The multisig account owner or delegate. - /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `DepositInstructionData` - /// Deposit, - /// Withdraw SPL Tokens from the available balance of a confidential token account. + /// Withdraw SPL Tokens from the available balance of a confidential token + /// account. /// /// Fails if the source or destination accounts are frozen. /// Fails if the associated mint is extended as `NonTransferable`. /// - /// In order for this instruction to be successfully processed, it must be accompanied by the - /// `VerifyWithdraw` instruction of the `zk_token_proof` program in the same transaction or the - /// address of a context state account for the proof must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by the `VerifyWithdraw` instruction of the + /// `zk_token_proof` program in the same transaction or the address of a + /// context state account for the proof must be provided. /// /// Accounts expected by this instruction: /// /// * Single owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The token mint. - /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the same transaction or - /// context state account if `VerifyWithdraw` is pre-verified into a context state - /// account. + /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the + /// same transaction or context state account if `VerifyWithdraw` is + /// pre-verified into a context state account. /// 3. `[signer]` The single source account owner. /// /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The token mint. - /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the same transaction or - /// context state account if `VerifyWithdraw` is pre-verified into a context state - /// account. + /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the + /// same transaction or context state account if `VerifyWithdraw` is + /// pre-verified into a context state account. /// 3. `[]` The multisig source account owner. - /// 4.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 4.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `WithdrawInstructionData` - /// Withdraw, /// Transfer tokens confidentially. /// - /// In order for this instruction to be successfully processed, it must be accompanied by - /// either the `VerifyTransfer` or `VerifyTransferWithFee` instruction of the `zk_token_proof` - /// program in the same transaction or the address of a context state account for the proof - /// must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by either the `VerifyTransfer` or + /// `VerifyTransferWithFee` instruction of the `zk_token_proof` + /// program in the same transaction or the address of a context state + /// account for the proof must be provided. /// /// Fails if the associated mint is extended as `NonTransferable`. /// @@ -228,8 +244,9 @@ pub enum ConfidentialTransferInstruction { /// 1. `[writable]` The source SPL Token account. /// 2. `[]` The token mint. /// 3. `[writable]` The destination SPL Token account. - /// 4. `[]` Instructions sysvar if `VerifyTransfer` or `VerifyTransferWithFee` is included in - /// the same transaction or context state account if these proofs are pre-verified into a + /// 4. `[]` Instructions sysvar if `VerifyTransfer` or + /// `VerifyTransferWithFee` is included in the same transaction or + /// context state account if these proofs are pre-verified into a /// context state account. /// 5. `[signer]` The single source account owner. /// @@ -237,26 +254,29 @@ pub enum ConfidentialTransferInstruction { /// 1. `[writable]` The source SPL Token account. /// 2. `[]` The token mint. /// 3. `[writable]` The destination SPL Token account. - /// 4. `[]` Instructions sysvar if `VerifyTransfer` or `VerifyTransferWithFee` is included in - /// the same transaction or context state account if these proofs are pre-verified into a + /// 4. `[]` Instructions sysvar if `VerifyTransfer` or + /// `VerifyTransferWithFee` is included in the same transaction or + /// context state account if these proofs are pre-verified into a /// context state account. /// 5. `[]` The multisig source account owner. - /// 6.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 6.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `TransferInstructionData` - /// Transfer, - /// Applies the pending balance to the available balance, based on the history of `Deposit` - /// and/or `Transfer` instructions. + /// Applies the pending balance to the available balance, based on the + /// history of `Deposit` and/or `Transfer` instructions. /// /// After submitting `ApplyPendingBalance`, the client should compare - /// `ConfidentialTransferAccount::expected_pending_balance_credit_counter` with + /// `ConfidentialTransferAccount::expected_pending_balance_credit_counter` + /// with /// `ConfidentialTransferAccount::actual_applied_pending_balance_instructions`. If they are - /// equal then the `ConfidentialTransferAccount::decryptable_available_balance` is consistent - /// with `ConfidentialTransferAccount::available_balance`. If they differ then there is more - /// pending balance to be applied. + /// equal then the + /// `ConfidentialTransferAccount::decryptable_available_balance` is + /// consistent with `ConfidentialTransferAccount::available_balance`. If + /// they differ then there is more pending balance to be applied. /// /// Account expected by this instruction: /// @@ -267,14 +287,15 @@ pub enum ConfidentialTransferInstruction { /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// `ApplyPendingBalanceData` - /// ApplyPendingBalance, - /// Configure a confidential extension account to accept incoming confidential transfers. + /// Configure a confidential extension account to accept incoming + /// confidential transfers. /// /// Accounts expected by this instruction: /// @@ -285,20 +306,21 @@ pub enum ConfidentialTransferInstruction { /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` Multisig authority. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None - /// EnableConfidentialCredits, - /// Configure a confidential extension account to reject any incoming confidential transfers. + /// Configure a confidential extension account to reject any incoming + /// confidential transfers. /// - /// If the `allow_non_confidential_credits` field is `true`, then the base account can still - /// receive non-confidential transfers. + /// If the `allow_non_confidential_credits` field is `true`, then the base + /// account can still receive non-confidential transfers. /// - /// This instruction can be used to disable confidential payments after a token account has - /// already been extended for confidential transfers. + /// This instruction can be used to disable confidential payments after a + /// token account has already been extended for confidential transfers. /// /// Accounts expected by this instruction: /// @@ -309,15 +331,15 @@ pub enum ConfidentialTransferInstruction { /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None - /// DisableConfidentialCredits, - /// Configure an account with the confidential extension to accept incoming non-confidential - /// transfers. + /// Configure an account with the confidential extension to accept incoming + /// non-confidential transfers. /// /// Accounts expected by this instruction: /// @@ -328,18 +350,18 @@ pub enum ConfidentialTransferInstruction { /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None - /// EnableNonConfidentialCredits, - /// Configure an account with the confidential extension to reject any incoming - /// non-confidential transfers. + /// Configure an account with the confidential extension to reject any + /// incoming non-confidential transfers. /// - /// This instruction can be used to configure a confidential extension account to exclusively - /// receive confidential payments. + /// This instruction can be used to configure a confidential extension + /// account to exclusively receive confidential payments. /// /// Accounts expected by this instruction: /// @@ -350,33 +372,39 @@ pub enum ConfidentialTransferInstruction { /// * Multisignature owner/delegate /// 0. `[writable]` The SPL Token account. /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None - /// DisableNonConfidentialCredits, - /// Transfer tokens confidentially with zero-knowledge proofs that are split into smaller - /// components. + /// Transfer tokens confidentially with zero-knowledge proofs that are split + /// into smaller components. /// - /// In order for this instruction to be successfully processed, it must be accompanied by - /// suitable zero-knowledge proof context accounts listed below. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by suitable zero-knowledge proof context accounts listed + /// below. /// - /// The same restrictions for the `Transfer` applies to `TransferWithSplitProofs`. Namely, the - /// instruction fails if the associated mint is extended as `NonTransferable`. + /// The same restrictions for the `Transfer` applies to + /// `TransferWithSplitProofs`. Namely, the instruction fails if the + /// associated mint is extended as `NonTransferable`. /// /// * Transfer without fee /// 1. `[writable]` The source SPL Token account. /// 2. `[]` The token mint. /// 3. `[writable]` The destination SPL Token account. - /// 4. `[]` Context state account for `VerifyCiphertextCommitmentEqualityProof`. - /// 5. `[]` Context state account for `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. + /// 4. `[]` Context state account for + /// `VerifyCiphertextCommitmentEqualityProof`. + /// 5. `[]` Context state account for + /// `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. /// 6. `[]` Context state account for `VerifyBatchedRangeProofU128`. /// 7. `[signer]` The source account owner. - /// If `close_split_context_state_on_execution` is set, all context state accounts must be - /// `writable` and the following additional sequence of accounts are needed: - /// 8. `[]` The destination account for lamports from the context state accounts. + /// If `close_split_context_state_on_execution` is set, all context state + /// accounts must be `writable` and the following additional sequence + /// of accounts are needed: + /// 8. `[]` The destination account for lamports from the context state + /// accounts. /// 9. `[signer]` The context state account owner. /// 10. `[]` The zk token proof program. /// @@ -384,21 +412,25 @@ pub enum ConfidentialTransferInstruction { /// 1. `[writable]` The source SPL Token account. /// 2. `[]` The token mint. /// 3. `[writable]` The destination SPL Token account. - /// 4. `[]` Context state account for `VerifyCiphertextCommitmentEqualityProof`. - /// 5. `[]` Context state account for `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. + /// 4. `[]` Context state account for + /// `VerifyCiphertextCommitmentEqualityProof`. + /// 5. `[]` Context state account for + /// `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. /// 6. `[]` Context state account for `VerifyFeeSigmaProof`. - /// 7. `[]` Context state account for `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. + /// 7. `[]` Context state account for + /// `VerifyBatchedGroupedCiphertext2HandlesValidityProof`. /// 8. `[]` Context state account for `VerifyBatchedRangeProofU256`. /// 9. `[signer]` The source account owner. - /// If `close_split_context_state_on_execution` is set, all context state accounts must be - /// `writable` and the following additional sequence of accounts are needed: - /// 10. `[]` The destination account for lamports from the context state accounts. + /// If `close_split_context_state_on_execution` is set, all context state + /// accounts must be `writable` and the following additional sequence + /// of accounts are needed: + /// 10. `[]` The destination account for lamports from the context state + /// accounts. /// 11. `[signer]` The context state account owner. /// 12. `[]` The zk token proof program. /// /// Data expected by this instruction: /// `TransferWithSplitProofsInstructionData` - /// TransferWithSplitProofs, } @@ -408,11 +440,11 @@ pub enum ConfidentialTransferInstruction { #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct InitializeMintData { - /// Authority to modify the `ConfidentialTransferMint` configuration and to approve new - /// accounts. + /// Authority to modify the `ConfidentialTransferMint` configuration and to + /// approve new accounts. pub authority: OptionalNonZeroPubkey, - /// Determines if newly configured accounts must be approved by the `authority` before they may - /// be used by the user. + /// Determines if newly configured accounts must be approved by the + /// `authority` before they may be used by the user. pub auto_approve_new_accounts: PodBool, /// New authority to decode any transfer amount in a confidential transfer. pub auditor_elgamal_pubkey: OptionalNonZeroElGamalPubkey, @@ -424,8 +456,8 @@ pub struct InitializeMintData { #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct UpdateMintData { - /// Determines if newly configured accounts must be approved by the `authority` before they may - /// be used by the user. + /// Determines if newly configured accounts must be approved by the + /// `authority` before they may be used by the user. pub auto_approve_new_accounts: PodBool, /// New authority to decode any transfer amount in a confidential transfer. pub auditor_elgamal_pubkey: OptionalNonZeroElGamalPubkey, @@ -440,12 +472,13 @@ pub struct ConfigureAccountInstructionData { /// The decryptable balance (always 0) once the configure account succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub decryptable_zero_balance: DecryptableBalance, - /// The maximum number of despots and transfers that an account can receiver before the - /// `ApplyPendingBalance` is executed + /// The maximum number of despots and transfers that an account can receiver + /// before the `ApplyPendingBalance` is executed pub maximum_pending_balance_credit_counter: PodU64, - /// Relative location of the `ProofInstruction::ZeroBalanceProof` instruction to the - /// `ConfigureAccount` instruction in the transaction. If the offset is `0`, then use a context - /// state account for the proof. + /// Relative location of the `ProofInstruction::ZeroBalanceProof` + /// instruction to the `ConfigureAccount` instruction in the + /// transaction. If the offset is `0`, then use a context state account + /// for the proof. pub proof_instruction_offset: i8, } @@ -455,9 +488,9 @@ pub struct ConfigureAccountInstructionData { #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct EmptyAccountInstructionData { - /// Relative location of the `ProofInstruction::VerifyCloseAccount` instruction to the - /// `EmptyAccount` instruction in the transaction. If the offset is `0`, then use a context - /// state account for the proof. + /// Relative location of the `ProofInstruction::VerifyCloseAccount` + /// instruction to the `EmptyAccount` instruction in the transaction. If + /// the offset is `0`, then use a context state account for the proof. pub proof_instruction_offset: i8, } @@ -486,9 +519,9 @@ pub struct WithdrawInstructionData { /// The new decryptable balance if the withdrawal succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_decryptable_available_balance: DecryptableBalance, - /// Relative location of the `ProofInstruction::VerifyWithdraw` instruction to the `Withdraw` - /// instruction in the transaction. If the offset is `0`, then use a context state account for - /// the proof. + /// Relative location of the `ProofInstruction::VerifyWithdraw` instruction + /// to the `Withdraw` instruction in the transaction. If the offset is + /// `0`, then use a context state account for the proof. pub proof_instruction_offset: i8, } @@ -501,9 +534,9 @@ pub struct TransferInstructionData { /// The new source decryptable balance if the transfer succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_source_decryptable_available_balance: DecryptableBalance, - /// Relative location of the `ProofInstruction::VerifyTransfer` instruction to the - /// `Transfer` instruction in the transaction. If the offset is `0`, then use a context state - /// account for the proof. + /// Relative location of the `ProofInstruction::VerifyTransfer` instruction + /// to the `Transfer` instruction in the transaction. If the offset is + /// `0`, then use a context state account for the proof. pub proof_instruction_offset: i8, } @@ -516,7 +549,8 @@ pub struct ApplyPendingBalanceData { /// The expected number of pending balance credits since the last successful /// `ApplyPendingBalance` instruction pub expected_pending_balance_credit_counter: PodU64, - /// The new decryptable balance if the pending balance is applied successfully + /// The new decryptable balance if the pending balance is applied + /// successfully #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_decryptable_available_balance: DecryptableBalance, } @@ -529,61 +563,75 @@ pub struct TransferWithSplitProofsInstructionData { /// The new source decryptable balance if the transfer succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_source_decryptable_available_balance: DecryptableBalance, - /// If true, execute no op when an associated context state account is not initialized. - /// Otherwise, fail on an uninitialized context state account. + /// If true, execute no op when an associated context state account is not + /// initialized. Otherwise, fail on an uninitialized context state + /// account. pub no_op_on_uninitialized_split_context_state: PodBool, - /// Close associated context states after a complete execution of the transfer instruction. + /// Close associated context states after a complete execution of the + /// transfer instruction. pub close_split_context_state_on_execution: PodBool, - /// The ElGamal decryption handle pertaining to the low and high bits of the transfer amount. - /// This field is used when the transfer proofs are split and verified as smaller components. + /// The ElGamal decryption handle pertaining to the low and high bits of the + /// transfer amount. This field is used when the transfer proofs are + /// split and verified as smaller components. /// /// NOTE: This field is to be removed in the next Solana upgrade. pub source_decrypt_handles: SourceDecryptHandles, } -/// Type for split transfer (without fee) instruction proof context state account addresses -/// intended to be used as parameters to functions. +/// Type for split transfer (without fee) instruction proof context state +/// account addresses intended to be used as parameters to functions. #[derive(Clone, Copy)] pub struct TransferSplitContextStateAccounts<'a> { - /// The context state account address for an equality proof needed for a transfer. + /// The context state account address for an equality proof needed for a + /// transfer. pub equality_proof: &'a Pubkey, - /// The context state account address for a ciphertext validity proof needed for a transfer. + /// The context state account address for a ciphertext validity proof needed + /// for a transfer. pub ciphertext_validity_proof: &'a Pubkey, - /// The context state account address for a range proof needed for a transfer. + /// The context state account address for a range proof needed for a + /// transfer. pub range_proof: &'a Pubkey, /// The context state accounts authority pub authority: &'a Pubkey, - /// No op if an associated split proof context state account is not initialized. + /// No op if an associated split proof context state account is not + /// initialized. pub no_op_on_uninitialized_split_context_state: bool, - /// Accounts needed if `close_split_context_state_on_execution` flag is enabled. + /// Accounts needed if `close_split_context_state_on_execution` flag is + /// enabled. pub close_split_context_state_accounts: Option>, } -/// Type for split transfer (with fee) instruction proof context state account addresses intended -/// to be used as parameters to functions. +/// Type for split transfer (with fee) instruction proof context state account +/// addresses intended to be used as parameters to functions. #[derive(Clone, Copy)] pub struct TransferWithFeeSplitContextStateAccounts<'a> { - /// The context state account address for an equality proof needed for a transfer with fee. + /// The context state account address for an equality proof needed for a + /// transfer with fee. pub equality_proof: &'a Pubkey, - /// The context state account address for a transfer amount ciphertext validity proof needed - /// for a transfer with fee. + /// The context state account address for a transfer amount ciphertext + /// validity proof needed for a transfer with fee. pub transfer_amount_ciphertext_validity_proof: &'a Pubkey, - /// The context state account address for a fee sigma proof needed for a transfer with fee. + /// The context state account address for a fee sigma proof needed for a + /// transfer with fee. pub fee_sigma_proof: &'a Pubkey, - /// The context state account address for a fee ciphertext validity proof needed for a transfer - /// with fee. + /// The context state account address for a fee ciphertext validity proof + /// needed for a transfer with fee. pub fee_ciphertext_validity_proof: &'a Pubkey, - /// The context state account address for a range proof needed for a transfer with fee. + /// The context state account address for a range proof needed for a + /// transfer with fee. pub range_proof: &'a Pubkey, /// The context state accounts authority pub authority: &'a Pubkey, - /// No op if an associated split proof context state account is not initialized. + /// No op if an associated split proof context state account is not + /// initialized. pub no_op_on_uninitialized_split_context_state: bool, - /// Accounts needed if `close_split_context_state_on_execution` flag is enabled. + /// Accounts needed if `close_split_context_state_on_execution` flag is + /// enabled. pub close_split_context_state_accounts: Option>, } -/// Accounts needed if `close_split_context_state_on_execution` flag is enabled on a transfer. +/// Accounts needed if `close_split_context_state_on_execution` flag is enabled +/// on a transfer. #[derive(Clone, Copy)] pub struct CloseSplitContextStateAccounts<'a> { /// The lamport destination account. @@ -729,10 +777,10 @@ pub fn configure_account( if let ProofLocation::InstructionOffset(proof_instruction_offset, proof_data) = proof_data_location { - // This constructor appends the proof instruction right after the `ConfigureAccount` - // instruction. This means that the proof instruction offset must be always be 1. To - // use an arbitrary proof instruction offset, use the `inner_configure_account` - // constructor. + // This constructor appends the proof instruction right after the + // `ConfigureAccount` instruction. This means that the proof instruction + // offset must be always be 1. To use an arbitrary proof instruction + // offset, use the `inner_configure_account` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { return Err(TokenError::InvalidProofInstructionOffset.into()); @@ -833,8 +881,9 @@ pub fn empty_account( proof_data_location { // This constructor appends the proof instruction right after the `EmptyAccount` - // instruction. This means that the proof instruction offset must be always be 1. To use an - // arbitrary proof instruction offset, use the `inner_empty_account` constructor. + // instruction. This means that the proof instruction offset must be always be + // 1. To use an arbitrary proof instruction offset, use the + // `inner_empty_account` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { return Err(TokenError::InvalidProofInstructionOffset.into()); @@ -963,9 +1012,10 @@ pub fn withdraw( if let ProofLocation::InstructionOffset(proof_instruction_offset, proof_data) = proof_data_location { - // This constructor appends the proof instruction right after the `Withdraw` instruction. - // This means that the proof instruction offset must be always be 1. To use an arbitrary - // proof instruction offset, use the `inner_withdraw` constructor. + // This constructor appends the proof instruction right after the `Withdraw` + // instruction. This means that the proof instruction offset must be + // always be 1. To use an arbitrary proof instruction offset, use the + // `inner_withdraw` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { return Err(TokenError::InvalidProofInstructionOffset.into()); @@ -1056,9 +1106,10 @@ pub fn transfer( if let ProofLocation::InstructionOffset(proof_instruction_offset, proof_data) = proof_data_location { - // This constructor appends the proof instruction right after the `Transfer` instruction. - // This means that the proof instruction offset must be always be 1. To use an arbitrary - // proof instruction offset, use the `inner_transfer` constructor. + // This constructor appends the proof instruction right after the `Transfer` + // instruction. This means that the proof instruction offset must be + // always be 1. To use an arbitrary proof instruction offset, use the + // `inner_transfer` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { return Err(TokenError::InvalidProofInstructionOffset.into()); @@ -1149,10 +1200,10 @@ pub fn transfer_with_fee( if let ProofLocation::InstructionOffset(proof_instruction_offset, proof_data) = proof_data_location { - // This constructor appends the proof instruction right after the `TransferWithFee` - // instruction. This means that the proof instruction offset must be always be 1. To - // use an arbitrary proof instruction offset, use the `inner_transfer_with_fee` - // constructor. + // This constructor appends the proof instruction right after the + // `TransferWithFee` instruction. This means that the proof instruction + // offset must be always be 1. To use an arbitrary proof instruction + // offset, use the `inner_transfer_with_fee` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { return Err(TokenError::InvalidProofInstructionOffset.into()); @@ -1330,8 +1381,8 @@ pub fn transfer_with_split_proofs( if let Some(close_split_context_state_on_execution_accounts) = context_accounts.close_split_context_state_accounts { - // If `close_split_context_state_accounts` is set, then all context state accounts must - // be `writable`. + // If `close_split_context_state_accounts` is set, then all context state + // accounts must be `writable`. accounts.push(AccountMeta::new(*context_accounts.equality_proof, false)); accounts.push(AccountMeta::new( *context_accounts.ciphertext_validity_proof, @@ -1350,8 +1401,8 @@ pub fn transfer_with_split_proofs( )); true } else { - // If `close_split_context_state_accounts` is not set, then context state accounts can - // be read-only. + // If `close_split_context_state_accounts` is not set, then context state + // accounts can be read-only. accounts.push(AccountMeta::new_readonly( *context_accounts.equality_proof, false, @@ -1409,8 +1460,8 @@ pub fn transfer_with_fee_and_split_proofs( if let Some(close_split_context_state_on_execution_accounts) = context_accounts.close_split_context_state_accounts { - // If `close_split_context_state_accounts` is set, then all context state accounts must - // be `writable`. + // If `close_split_context_state_accounts` is set, then all context state + // accounts must be `writable`. accounts.push(AccountMeta::new(*context_accounts.equality_proof, false)); accounts.push(AccountMeta::new( *context_accounts.transfer_amount_ciphertext_validity_proof, @@ -1434,8 +1485,8 @@ pub fn transfer_with_fee_and_split_proofs( )); true } else { - // If `close_split_context_state_accounts` is not set, then context state accounts can - // be read-only. + // If `close_split_context_state_accounts` is not set, then context state + // accounts can be read-only. accounts.push(AccountMeta::new_readonly( *context_accounts.equality_proof, false, diff --git a/token/program-2022/src/extension/confidential_transfer/mod.rs b/token/program-2022/src/extension/confidential_transfer/mod.rs index a55102656e6..c2f177d1acf 100644 --- a/token/program-2022/src/extension/confidential_transfer/mod.rs +++ b/token/program-2022/src/extension/confidential_transfer/mod.rs @@ -27,14 +27,15 @@ pub mod instruction; /// Confidential Transfer Extension processor pub mod processor; -/// Helper functions to verify zero-knowledge proofs in the Confidential Transfer Extension +/// Helper functions to verify zero-knowledge proofs in the Confidential +/// Transfer Extension pub mod verify_proof; -/// Helper functions to generate split zero-knowledge proofs for confidential transfers in the -/// Confidential Transfer Extension. +/// Helper functions to generate split zero-knowledge proofs for confidential +/// transfers in the Confidential Transfer Extension. /// -/// The logic in this submodule should belong to the `solana-zk-token-sdk` and will be removed with -/// the next upgrade to the Solana program. +/// The logic in this submodule should belong to the `solana-zk-token-sdk` and +/// will be removed with the next upgrade to the Solana program. #[cfg(not(target_os = "solana"))] pub mod split_proof_generation; @@ -56,18 +57,19 @@ pub type DecryptableBalance = AeCiphertext; #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct ConfidentialTransferMint { - /// Authority to modify the `ConfidentialTransferMint` configuration and to approve new - /// accounts (if `auto_approve_new_accounts` is true) + /// Authority to modify the `ConfidentialTransferMint` configuration and to + /// approve new accounts (if `auto_approve_new_accounts` is true) /// /// The legacy Token Multisig account is not supported as the authority pub authority: OptionalNonZeroPubkey, - /// Indicate if newly configured accounts must be approved by the `authority` before they may be - /// used by the user. + /// Indicate if newly configured accounts must be approved by the + /// `authority` before they may be used by the user. /// - /// * If `true`, no approval is required and new accounts may be used immediately + /// * If `true`, no approval is required and new accounts may be used + /// immediately /// * If `false`, the authority must approve newly configured accounts (see - /// `ConfidentialTransferInstruction::ConfigureAccount`) + /// `ConfidentialTransferInstruction::ConfigureAccount`) pub auto_approve_new_accounts: PodBool, /// Authority to decode any transfer amount in a confidential transafer. @@ -82,8 +84,9 @@ impl Extension for ConfidentialTransferMint { #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct ConfidentialTransferAccount { - /// `true` if this account has been approved for use. All confidential transfer operations for - /// the account will fail until approval is granted. + /// `true` if this account has been approved for use. All confidential + /// transfer operations for the account will fail until approval is + /// granted. pub approved: PodBool, /// The public key associated with ElGamal encryption @@ -101,26 +104,28 @@ pub struct ConfidentialTransferAccount { /// The decryptable available balance pub decryptable_available_balance: DecryptableBalance, - /// If `false`, the extended account rejects any incoming confidential transfers + /// If `false`, the extended account rejects any incoming confidential + /// transfers pub allow_confidential_credits: PodBool, /// If `false`, the base account rejects any incoming transfers pub allow_non_confidential_credits: PodBool, - /// The total number of `Deposit` and `Transfer` instructions that have credited - /// `pending_balance` + /// The total number of `Deposit` and `Transfer` instructions that have + /// credited `pending_balance` pub pending_balance_credit_counter: PodU64, - /// The maximum number of `Deposit` and `Transfer` instructions that can credit - /// `pending_balance` before the `ApplyPendingBalance` instruction is executed + /// The maximum number of `Deposit` and `Transfer` instructions that can + /// credit `pending_balance` before the `ApplyPendingBalance` + /// instruction is executed pub maximum_pending_balance_credit_counter: PodU64, - /// The `expected_pending_balance_credit_counter` value that was included in the last - /// `ApplyPendingBalance` instruction + /// The `expected_pending_balance_credit_counter` value that was included in + /// the last `ApplyPendingBalance` instruction pub expected_pending_balance_credit_counter: PodU64, - /// The actual `pending_balance_credit_counter` when the last `ApplyPendingBalance` instruction - /// was executed + /// The actual `pending_balance_credit_counter` when the last + /// `ApplyPendingBalance` instruction was executed pub actual_pending_balance_credit_counter: PodU64, } @@ -150,8 +155,8 @@ impl ConfidentialTransferAccount { } } - /// Check if a base account of a `ConfidentialTransferAccount` accepts non-confidential - /// transfers. + /// Check if a base account of a `ConfidentialTransferAccount` accepts + /// non-confidential transfers. pub fn non_confidential_transfer_allowed(&self) -> ProgramResult { if bool::from(&self.allow_non_confidential_credits) { Ok(()) @@ -167,10 +172,12 @@ impl ConfidentialTransferAccount { /// Checks if a confidential extension is configured to receive funds. /// - /// A destination account can receive funds if the following conditions are satisfied: + /// A destination account can receive funds if the following conditions are + /// satisfied: /// 1. The account is approved by the confidential transfer mint authority /// 2. The account is not disabled by the account owner - /// 3. The number of credits into the account has not reached the maximum credit counter + /// 3. The number of credits into the account has not reached the maximum + /// credit counter pub fn valid_as_destination(&self) -> ProgramResult { self.approved()?; diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index 58c2f3a9413..58a3140adb5 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -127,8 +127,9 @@ fn process_configure_account( let mint = StateWithExtensions::::unpack(mint_data)?; let confidential_transfer_mint = mint.get_extension::()?; - // Note: The caller is expected to use the `Reallocate` instruction to ensure there is - // sufficient room in their token account for the new `ConfidentialTransferAccount` extension + // Note: The caller is expected to use the `Reallocate` instruction to ensure + // there is sufficient room in their token account for the new + // `ConfidentialTransferAccount` extension let confidential_transfer_account = token_account.init_extension::(false)?; confidential_transfer_account.approved = confidential_transfer_mint.auto_approve_new_accounts; @@ -148,7 +149,8 @@ fn process_configure_account( confidential_transfer_account.actual_pending_balance_credit_counter = 0.into(); confidential_transfer_account.allow_non_confidential_credits = true.into(); - // if the mint is extended for fees, then initialize account for confidential transfer fees + // if the mint is extended for fees, then initialize account for confidential + // transfer fees if mint.get_extension::().is_ok() { let confidential_transfer_fee_amount = token_account.init_extension::(false)?; @@ -197,7 +199,8 @@ fn process_empty_account( let account_info_iter = &mut accounts.iter(); let token_account_info = next_account_info(account_info_iter)?; - // zero-knowledge proof certifies that the available balance ciphertext holds the balance of 0. + // zero-knowledge proof certifies that the available balance ciphertext holds + // the balance of 0. let proof_context = verify_empty_account_proof(account_info_iter, proof_instruction_offset)?; let authority_info = next_account_info(account_info_iter)?; @@ -218,8 +221,9 @@ fn process_empty_account( let confidential_transfer_account = token_account.get_extension_mut::()?; - // Check that the encryption public key and ciphertext associated with the confidential - // extension account are consistent with those that were actually used to generate the zkp. + // Check that the encryption public key and ciphertext associated with the + // confidential extension account are consistent with those that were + // actually used to generate the zkp. if confidential_transfer_account.elgamal_pubkey != proof_context.pubkey { msg!("Encryption public-key mismatch"); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); @@ -299,7 +303,8 @@ fn process_deposit( // A deposit amount must be a 48-bit number let (amount_lo, amount_hi) = verify_and_split_deposit_amount(amount)?; - // Prevent unnecessary ciphertext arithmetic syscalls if `amount_lo` or `amount_hi` is zero + // Prevent unnecessary ciphertext arithmetic syscalls if `amount_lo` or + // `amount_hi` is zero if amount_lo > 0 { confidential_transfer_account.pending_balance_lo = syscall::add_to(&confidential_transfer_account.pending_balance_lo, amount_lo) @@ -316,8 +321,8 @@ fn process_deposit( Ok(()) } -/// Verifies that a deposit amount is a 48-bit number and returns the least significant 16 bits and -/// most significant 32 bits of the amount. +/// Verifies that a deposit amount is a 48-bit number and returns the least +/// significant 16 bits and most significant 32 bits of the amount. #[cfg(feature = "zk-ops")] pub fn verify_and_split_deposit_amount(amount: u64) -> Result<(u64, u64), TokenError> { if amount > MAXIMUM_DEPOSIT_TRANSFER_AMOUNT { @@ -342,8 +347,8 @@ fn process_withdraw( let token_account_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?; - // zero-knowledge proof certifies that the account has enough available balance to withdraw the - // amount. + // zero-knowledge proof certifies that the account has enough available balance + // to withdraw the amount. let proof_context = verify_withdraw_proof(account_info_iter, proof_instruction_offset)?; let authority_info = next_account_info(account_info_iter)?; @@ -381,27 +386,30 @@ fn process_withdraw( return Err(TokenError::MintMismatch.into()); } - // Wrapped SOL withdrawals are not supported because lamports cannot be apparated. + // Wrapped SOL withdrawals are not supported because lamports cannot be + // apparated. assert!(!token_account.base.is_native()); let confidential_transfer_account = token_account.get_extension_mut::()?; confidential_transfer_account.valid_as_source()?; - // Check that the encryption public key associated with the confidential extension is - // consistent with the public key that was actually used to generate the zkp. + // Check that the encryption public key associated with the confidential + // extension is consistent with the public key that was actually used to + // generate the zkp. if confidential_transfer_account.elgamal_pubkey != proof_context.pubkey { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } - // Prevent unnecessary ciphertext arithmetic syscalls if the withdraw amount is zero + // Prevent unnecessary ciphertext arithmetic syscalls if the withdraw amount is + // zero if amount > 0 { confidential_transfer_account.available_balance = syscall::subtract_from(&confidential_transfer_account.available_balance, amount) .ok_or(TokenError::CiphertextArithmeticFailed)?; } - // Check that the final available balance ciphertext is consistent with the actual ciphertext - // for which the zero-knowledge proof was generated for. + // Check that the final available balance ciphertext is consistent with the + // actual ciphertext for which the zero-knowledge proof was generated for. if confidential_transfer_account.available_balance != proof_context.final_ciphertext { return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); } @@ -444,15 +452,19 @@ fn process_transfer( } let confidential_transfer_mint = mint.get_extension::()?; - // A `Transfer` instruction must be accompanied by a zero-knowledge proof instruction that - // certify the validity of the transfer amounts. The kind of zero-knowledge proof instruction - // depends on whether a transfer incurs a fee or not. - // - If the mint is not extended for fees or the instruction is for a self-transfer, then + // A `Transfer` instruction must be accompanied by a zero-knowledge proof + // instruction that certify the validity of the transfer amounts. The kind + // of zero-knowledge proof instruction depends on whether a transfer incurs + // a fee or not. + // - If the mint is not extended for fees or the instruction is for a + // self-transfer, then // transfer fee is not required. - // - If the mint is extended for fees and the instruction is not a self-transfer, then + // - If the mint is extended for fees and the instruction is not a + // self-transfer, then // transfer fee is required. if mint.get_extension::().is_err() { - // Transfer fee is not required. Decode the zero-knowledge proof as `TransferData`. + // Transfer fee is not required. Decode the zero-knowledge proof as + // `TransferData`. // // The zero-knowledge proof certifies that: // 1. the transfer amount is encrypted in the correct form @@ -466,14 +478,15 @@ fn process_transfer( source_decrypt_handles, )?; // If `maybe_proof_context` is `None`, then this means that - // `no_op_on_uninitialized_split_context_state` is true and a required context state - // account is not yet initialized. Even if this is the case, we follow through with the - // rest of the transfer logic to perform all the necessary checks for a transfer to be - // safe. - - // If `close_split_context_state_on_execution` is `true`, then the source account authority - // info is located after the lamport destination, context state authority, and zk token - // proof program account infos. Flush out these account infos. + // `no_op_on_uninitialized_split_context_state` is true and a required context + // state account is not yet initialized. Even if this is the case, we + // follow through with the rest of the transfer logic to perform all the + // necessary checks for a transfer to be safe. + + // If `close_split_context_state_on_execution` is `true`, then the source + // account authority info is located after the lamport destination, + // context state authority, and zk token proof program account infos. + // Flush out these account infos. if close_split_context_state_on_execution && maybe_proof_context.is_none() { let _lamport_destination_account_info = next_account_info(account_info_iter)?; let _context_state_authority_info = next_account_info(account_info_iter)?; @@ -482,8 +495,8 @@ fn process_transfer( let authority_info = next_account_info(account_info_iter)?; - // Check that the auditor encryption public key associated wth the confidential mint is - // consistent with what was actually used to generate the zkp. + // Check that the auditor encryption public key associated wth the confidential + // mint is consistent with what was actually used to generate the zkp. if let Some(ref proof_context) = maybe_proof_context { if !confidential_transfer_mint .auditor_elgamal_pubkey @@ -537,13 +550,15 @@ fn process_transfer( )?; // If `maybe_proof_context` is `None`, then this means that - // `no_op_on_uninitialized_split_context_state` is true and a required context state - // account is not yet initialized. Even if this is the case, we follow through with the - // rest of the transfer with fee logic to perform all the necessary checks to be safe. - - // If `close_split_context_state_on_execution` is `true`, then the source account authority - // info is located after the lamport destination, context state authority, and zk token - // proof program account infos. Flush out these account infos. + // `no_op_on_uninitialized_split_context_state` is true and a required context + // state account is not yet initialized. Even if this is the case, we + // follow through with the rest of the transfer with fee logic to + // perform all the necessary checks to be safe. + + // If `close_split_context_state_on_execution` is `true`, then the source + // account authority info is located after the lamport destination, + // context state authority, and zk token proof program account infos. + // Flush out these account infos. if close_split_context_state_on_execution && maybe_proof_context.is_none() { let _lamport_destination_account_info = next_account_info(account_info_iter)?; let _context_state_authority_info = next_account_info(account_info_iter)?; @@ -552,9 +567,9 @@ fn process_transfer( let authority_info = next_account_info(account_info_iter)?; - // Check that the encryption public keys associated with the mint confidential transfer and - // confidential transfer fee extensions are consistent with the keys that were used to - // generate the zkp. + // Check that the encryption public keys associated with the mint confidential + // transfer and confidential transfer fee extensions are consistent with + // the keys that were used to generate the zkp. if let Some(ref proof_context) = maybe_proof_context { if !confidential_transfer_mint .auditor_elgamal_pubkey @@ -643,8 +658,8 @@ fn process_source_for_transfer( confidential_transfer_account.valid_as_source()?; if let Some(proof_context) = maybe_proof_context { - // Check that the source encryption public key is consistent with what was actually used to - // generate the zkp. + // Check that the source encryption public key is consistent with what was + // actually used to generate the zkp. if proof_context.transfer_pubkeys.source != confidential_transfer_account.elgamal_pubkey { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } @@ -661,8 +676,8 @@ fn process_source_for_transfer( ) .ok_or(TokenError::CiphertextArithmeticFailed)?; - // Check that the computed available balance is consistent with what was actually used to - // generate the zkp on the client side. + // Check that the computed available balance is consistent with what was + // actually used to generate the zkp on the client side. if new_source_available_balance != proof_context.new_source_ciphertext { return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); } @@ -769,8 +784,8 @@ fn process_source_for_transfer_with_fee( confidential_transfer_account.valid_as_source()?; if let Some(proof_context) = maybe_proof_context { - // Check that the source encryption public key is consistent with what was actually used to - // generate the zkp. + // Check that the source encryption public key is consistent with what was + // actually used to generate the zkp. if proof_context.transfer_with_fee_pubkeys.source != confidential_transfer_account.elgamal_pubkey { @@ -789,8 +804,8 @@ fn process_source_for_transfer_with_fee( ) .ok_or(TokenError::CiphertextArithmeticFailed)?; - // Check that the computed available balance is consistent with what was actually used to - // generate the zkp on the client side. + // Check that the computed available balance is consistent with what was + // actually used to generate the zkp on the client side. if new_source_available_balance != proof_context.new_source_ciphertext { return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); } @@ -859,7 +874,8 @@ fn process_destination_for_transfer_with_fee( // process transfer fee if !is_self_transfer { - // Decode lo and hi fee amounts encrypted under the destination encryption public key + // Decode lo and hi fee amounts encrypted under the destination encryption + // public key let destination_fee_lo = fee_amount_destination_ciphertext(&proof_context.fee_ciphertext_lo); let destination_fee_hi = @@ -877,8 +893,8 @@ fn process_destination_for_transfer_with_fee( ) .ok_or(TokenError::CiphertextArithmeticFailed)?; - // Decode lo and hi fee amounts encrypted under the withdraw authority encryption public - // key + // Decode lo and hi fee amounts encrypted under the withdraw authority + // encryption public key let withdraw_withheld_authority_fee_lo = fee_amount_withdraw_withheld_authority_ciphertext(&proof_context.fee_ciphertext_lo); let withdraw_withheld_authority_fee_hi = @@ -950,7 +966,8 @@ fn process_apply_pending_balance( Ok(()) } -/// Processes a [DisableConfidentialCredits] or [EnableConfidentialCredits] instruction. +/// Processes a [DisableConfidentialCredits] or [EnableConfidentialCredits] +/// instruction. fn process_allow_confidential_credits( program_id: &Pubkey, accounts: &[AccountInfo], @@ -980,7 +997,8 @@ fn process_allow_confidential_credits( Ok(()) } -/// Processes an [DisableNonConfidentialCredits] or [EnableNonConfidentialCredits] instruction. +/// Processes an [DisableNonConfidentialCredits] or +/// [EnableNonConfidentialCredits] instruction. fn process_allow_non_confidential_credits( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/program-2022/src/extension/confidential_transfer/split_proof_generation.rs b/token/program-2022/src/extension/confidential_transfer/split_proof_generation.rs index 1e1955646e9..9d376bb0883 100644 --- a/token/program-2022/src/extension/confidential_transfer/split_proof_generation.rs +++ b/token/program-2022/src/extension/confidential_transfer/split_proof_generation.rs @@ -1,8 +1,8 @@ -//! Helper functions to generate split zero-knowledge proofs for confidential transfers in the -//! Confidential Transfer Extension. +//! Helper functions to generate split zero-knowledge proofs for confidential +//! transfers in the Confidential Transfer Extension. //! -//! The logic in this submodule should belong to the `solana-zk-token-sdk` and will be removed with -//! the next upgrade to the Solana program. +//! The logic in this submodule should belong to the `solana-zk-token-sdk` and +//! will be removed with the next upgrade to the Solana program. use crate::{ extension::confidential_transfer::{ @@ -119,7 +119,8 @@ pub fn transfer_split_proof_data( hi: source_decrypt_handle_hi.into(), }; - // encrypt the transfer amount under the destination and auditor ElGamal public key + // encrypt the transfer amount under the destination and auditor ElGamal public + // key let transfer_amount_destination_auditor_ciphertext_lo = GroupedElGamal::encrypt_with( [destination_elgamal_pubkey, auditor_elgamal_pubkey], transfer_amount_lo, diff --git a/token/program-2022/src/extension/confidential_transfer/verify_proof.rs b/token/program-2022/src/extension/confidential_transfer/verify_proof.rs index 67c3ed09a8b..5f5e10025c2 100644 --- a/token/program-2022/src/extension/confidential_transfer/verify_proof.rs +++ b/token/program-2022/src/extension/confidential_transfer/verify_proof.rs @@ -18,8 +18,8 @@ use { std::slice::Iter, }; -/// Verify zero-knowledge proof needed for a [ConfigureAccount] instruction and return the -/// corresponding proof context. +/// Verify zero-knowledge proof needed for a [ConfigureAccount] instruction and +/// return the corresponding proof context. pub fn verify_configure_account_proof( account_info_iter: &mut Iter<'_, AccountInfo<'_>>, proof_instruction_offset: i64, @@ -52,8 +52,8 @@ pub fn verify_configure_account_proof( } } -/// Verify zero-knowledge proof needed for a [EmptyAccount] instruction and return the -/// corresponding proof context. +/// Verify zero-knowledge proof needed for a [EmptyAccount] instruction and +/// return the corresponding proof context. pub fn verify_empty_account_proof( account_info_iter: &mut Iter<'_, AccountInfo<'_>>, proof_instruction_offset: i64, @@ -86,8 +86,8 @@ pub fn verify_empty_account_proof( } } -/// Verify zero-knowledge proof needed for a [Withdraw] instruction and return the -/// corresponding proof context. +/// Verify zero-knowledge proof needed for a [Withdraw] instruction and return +/// the corresponding proof context. pub fn verify_withdraw_proof( account_info_iter: &mut Iter<'_, AccountInfo<'_>>, proof_instruction_offset: i64, @@ -119,14 +119,16 @@ pub fn verify_withdraw_proof( } } -/// Verify zero-knowledge proof needed for a [Transfer] instruction without fee and return the -/// corresponding proof context. +/// Verify zero-knowledge proof needed for a [Transfer] instruction without fee +/// and return the corresponding proof context. /// -/// This returns a `Result` type for an `Option` type. If the proof -/// verification fails, then the function returns a suitable error variant. If the proof succeeds -/// to verify, then the function returns a `TransferProofContextInfo` that is wrapped inside -/// `Ok(Some(TransferProofContextInfo))`. If `no_op_on_split_proof_context_state` is `true` and -/// some a split context state account is not initialized, then it returns `Ok(None)`. +/// This returns a `Result` type for an `Option` type. +/// If the proof verification fails, then the function returns a suitable error +/// variant. If the proof succeeds to verify, then the function returns a +/// `TransferProofContextInfo` that is wrapped inside +/// `Ok(Some(TransferProofContextInfo))`. If +/// `no_op_on_split_proof_context_state` is `true` and some a split context +/// state account is not initialized, then it returns `Ok(None)`. #[cfg(feature = "zk-ops")] pub fn verify_transfer_proof( account_info_iter: &mut Iter<'_, AccountInfo<'_>>, @@ -174,8 +176,8 @@ pub fn verify_transfer_proof( verify_transfer_range_proof(range_proof_context_state_account_info)?; // The `TransferProofContextInfo` constructor verifies the consistency of the - // individual proof context and generates a `TransferWithFeeProofInfo` struct that is used - // to process the rest of the token-2022 logic. + // individual proof context and generates a `TransferWithFeeProofInfo` struct + // that is used to process the rest of the token-2022 logic. let transfer_proof_context = TransferProofContextInfo::verify_and_extract( &equality_proof_context, &ciphertext_validity_proof_context, @@ -266,8 +268,8 @@ pub fn verify_transfer_proof( } } -/// Verify zero-knowledge proof needed for a [Transfer] instruction with fee and return the -/// corresponding proof context. +/// Verify zero-knowledge proof needed for a [Transfer] instruction with fee and +/// return the corresponding proof context. #[cfg(feature = "zk-ops")] pub fn verify_transfer_with_fee_proof( account_info_iter: &mut Iter<'_, AccountInfo<'_>>, @@ -342,11 +344,12 @@ pub fn verify_transfer_with_fee_proof( let range_proof_context = verify_transfer_with_fee_range_proof(range_proof_context_state_account_info)?; - // The `TransferWithFeeProofContextInfo` constructor verifies the consistency of the - // individual proof context and generates a `TransferWithFeeProofInfo` struct that is used - // to process the rest of the token-2022 logic. The consistency check includes verifying - // whether the fee-related zkps were generated with respect to the correct fee parameter - // that is stored in the mint extension. + // The `TransferWithFeeProofContextInfo` constructor verifies the consistency of + // the individual proof context and generates a + // `TransferWithFeeProofInfo` struct that is used to process the rest of + // the token-2022 logic. The consistency check includes verifying + // whether the fee-related zkps were generated with respect to the correct fee + // parameter that is stored in the mint extension. let transfer_with_fee_proof_context = TransferWithFeeProofContextInfo::verify_and_extract( &equality_proof_context, &transfer_amount_ciphertext_validity_proof_context, @@ -469,8 +472,8 @@ pub fn verify_transfer_with_fee_proof( .maximum_fee .into(); - // check consistency of the transfer fee parameters in the mint extension with what were - // used to generate the zkp, which is not checked in the + // check consistency of the transfer fee parameters in the mint extension with + // what were used to generate the zkp, which is not checked in the // `From` implementation for // `TransferWithFeeProofContextInfo`. if u16::from(fee_parameters.transfer_fee_basis_points) != proof_tranfer_fee_basis_points @@ -494,8 +497,8 @@ pub fn verify_transfer_with_fee_proof( proof_context.fee_parameters.fee_rate_basis_points.into(); let proof_maximum_fee: u64 = proof_context.fee_parameters.maximum_fee.into(); - // check consistency of the transfer fee parameters in the mint extension with what were - // used to generate the zkp, which is not checked in the + // check consistency of the transfer fee parameters in the mint extension with + // what were used to generate the zkp, which is not checked in the // `From` implementation for // `TransferWithFeeProofContextInfo`. if u16::from(fee_parameters.transfer_fee_basis_points) != proof_tranfer_fee_basis_points @@ -508,7 +511,8 @@ pub fn verify_transfer_with_fee_proof( } } -/// Verify and process equality proof for [Transfer] and [TransferWithFee] instructions. +/// Verify and process equality proof for [Transfer] and [TransferWithFee] +/// instructions. fn verify_equality_proof( account_info: &AccountInfo<'_>, ) -> Result { @@ -525,7 +529,8 @@ fn verify_equality_proof( Ok(equality_proof_context_state.proof_context) } -/// Verify and process ciphertext validity proof for [Transfer] and [TransferWithFee] instructions. +/// Verify and process ciphertext validity proof for [Transfer] and +/// [TransferWithFee] instructions. fn verify_ciphertext_validity_proof( account_info: &AccountInfo<'_>, ) -> Result { diff --git a/token/program-2022/src/extension/confidential_transfer_fee/account_info.rs b/token/program-2022/src/extension/confidential_transfer_fee/account_info.rs index 720b3081838..40a8919ae9c 100644 --- a/token/program-2022/src/extension/confidential_transfer_fee/account_info.rs +++ b/token/program-2022/src/extension/confidential_transfer_fee/account_info.rs @@ -11,7 +11,8 @@ use { }; /// Confidential transfer fee extension information needed to construct a -/// `WithdrawWithheldTokensFromMint` or `WithdrawWithheldTokensFromAccounts` instruction. +/// `WithdrawWithheldTokensFromMint` or `WithdrawWithheldTokensFromAccounts` +/// instruction. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct WithheldTokensInfo { diff --git a/token/program-2022/src/extension/confidential_transfer_fee/instruction.rs b/token/program-2022/src/extension/confidential_transfer_fee/instruction.rs index 9d79b7bbe4e..ba5df33d890 100644 --- a/token/program-2022/src/extension/confidential_transfer_fee/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer_fee/instruction.rs @@ -38,12 +38,12 @@ pub enum ConfidentialTransferFeeInstruction { /// Initializes confidential transfer fees for a mint. /// /// The `ConfidentialTransferFeeInstruction::InitializeConfidentialTransferFeeConfig` - /// instruction requires no signers and MUST be included within the same Transaction as - /// `TokenInstruction::InitializeMint`. Otherwise another party can initialize the - /// configuration. + /// instruction requires no signers and MUST be included within the same + /// Transaction as `TokenInstruction::InitializeMint`. Otherwise another + /// party can initialize the configuration. /// - /// The instruction fails if the `TokenInstruction::InitializeMint` instruction has already - /// executed for the mint. + /// The instruction fails if the `TokenInstruction::InitializeMint` + /// instruction has already executed for the mint. /// /// Accounts expected by this instruction: /// @@ -51,100 +51,113 @@ pub enum ConfidentialTransferFeeInstruction { /// /// Data expected by this instruction: /// `InitializeConfidentialTransferFeeConfigData` - /// InitializeConfidentialTransferFeeConfig, - /// Transfer all withheld confidential tokens in the mint to an account. Signed by the mint's - /// withdraw withheld tokens authority. + /// Transfer all withheld confidential tokens in the mint to an account. + /// Signed by the mint's withdraw withheld tokens authority. /// - /// The withheld confidential tokens are aggregated directly into the destination available - /// balance. + /// The withheld confidential tokens are aggregated directly into the + /// destination available balance. /// - /// In order for this instruction to be successfully processed, it must be accompanied by the - /// `VerifyCiphertextCiphertextEquality` instruction of the `zk_token_proof` program in the - /// same transaction or the address of a context state account for the proof must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by the `VerifyCiphertextCiphertextEquality` instruction + /// of the `zk_token_proof` program in the same transaction or the + /// address of a context state account for the proof must be provided. /// /// Accounts expected by this instruction: /// /// * Single owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is included in the same - /// transaction or context state account if `VerifyCiphertextCiphertextEquality` is - /// pre-verified into a context state account. + /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` and `ConfidentialTransferAccount` extensions. + /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is + /// included in the same transaction or context state account if + /// `VerifyCiphertextCiphertextEquality` is pre-verified into a context + /// state account. /// 3. `[signer]` The mint's `withdraw_withheld_authority`. /// /// * Multisignature owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is included in the same - /// transaction or context state account if `VerifyCiphertextCiphertextEquality` is - /// pre-verified into a context state account. + /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` and `ConfidentialTransferAccount` extensions. + /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is + /// included in the same transaction or context state account if + /// `VerifyCiphertextCiphertextEquality` is pre-verified into a context + /// state account. /// 3. `[]` The mint's multisig `withdraw_withheld_authority`. /// 4. ..3+M `[signer]` M signer accounts. /// /// Data expected by this instruction: /// WithdrawWithheldTokensFromMintData - /// WithdrawWithheldTokensFromMint, - /// Transfer all withheld tokens to an account. Signed by the mint's withdraw withheld tokens - /// authority. This instruction is susceptible to front-running. Use - /// `HarvestWithheldTokensToMint` and `WithdrawWithheldTokensFromMint` as an alternative. - /// - /// The withheld confidential tokens are aggregated directly into the destination available - /// balance. - /// - /// Note on front-running: This instruction requires a zero-knowledge proof verification - /// instruction that is checked with respect to the account state (the currently withheld - /// fees). Suppose that a withdraw withheld authority generates the - /// `WithdrawWithheldTokensFromAccounts` instruction along with a corresponding zero-knowledge - /// proof for a specified set of accounts, and submits it on chain. If the withheld fees at any - /// of the specified accounts change before the `WithdrawWithheldTokensFromAccounts` is - /// executed on chain, the zero-knowledge proof will not verify with respect to the new state, + /// Transfer all withheld tokens to an account. Signed by the mint's + /// withdraw withheld tokens authority. This instruction is susceptible + /// to front-running. Use `HarvestWithheldTokensToMint` and + /// `WithdrawWithheldTokensFromMint` as an alternative. + /// + /// The withheld confidential tokens are aggregated directly into the + /// destination available balance. + /// + /// Note on front-running: This instruction requires a zero-knowledge proof + /// verification instruction that is checked with respect to the account + /// state (the currently withheld fees). Suppose that a withdraw + /// withheld authority generates the + /// `WithdrawWithheldTokensFromAccounts` instruction along with a + /// corresponding zero-knowledge proof for a specified set of accounts, + /// and submits it on chain. If the withheld fees at any + /// of the specified accounts change before the + /// `WithdrawWithheldTokensFromAccounts` is executed on chain, the + /// zero-knowledge proof will not verify with respect to the new state, /// forcing the transaction to fail. /// - /// If front-running occurs, then users can look up the updated states of the accounts, - /// generate a new zero-knowledge proof and try again. Alternatively, withdraw withheld - /// authority can first move the withheld amount to the mint using - /// `HarvestWithheldTokensToMint` and then move the withheld fees from mint to a specified - /// destination account using `WithdrawWithheldTokensFromMint`. + /// If front-running occurs, then users can look up the updated states of + /// the accounts, generate a new zero-knowledge proof and try again. + /// Alternatively, withdraw withheld authority can first move the + /// withheld amount to the mint using `HarvestWithheldTokensToMint` and + /// then move the withheld fees from mint to a specified destination + /// account using `WithdrawWithheldTokensFromMint`. /// - /// In order for this instruction to be successfully processed, it must be accompanied by the - /// `VerifyWithdrawWithheldTokens` instruction of the `zk_token_proof` program in the same - /// transaction or the address of a context state account for the proof must be provided. + /// In order for this instruction to be successfully processed, it must be + /// accompanied by the `VerifyWithdrawWithheldTokens` instruction of the + /// `zk_token_proof` program in the same transaction or the address of a + /// context state account for the proof must be provided. /// /// Accounts expected by this instruction: /// /// * Single owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is included in the - /// same transaction or context state account if `VerifyCiphertextCiphertextEquality` is - /// pre-verified into a context state account. + /// 0. `[]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` and `ConfidentialTransferAccount` extensions. + /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is + /// included in the same transaction or context state account if + /// `VerifyCiphertextCiphertextEquality` is pre-verified into a context + /// state account. /// 3. `[signer]` The mint's `withdraw_withheld_authority`. /// 4. ..3+N `[writable]` The source accounts to withdraw from. /// /// * Multisignature owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is included in the - /// same transaction or context state account if `VerifyCiphertextCiphertextEquality` is - /// pre-verified into a context state account. + /// 0. `[]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` and `ConfidentialTransferAccount` extensions. + /// 2. `[]` Instructions sysvar if `VerifyCiphertextCiphertextEquality` is + /// included in the same transaction or context state account if + /// `VerifyCiphertextCiphertextEquality` is pre-verified into a context + /// state account. /// 3. `[]` The mint's multisig `withdraw_withheld_authority`. /// 4. ..4+M `[signer]` M signer accounts. /// 4+M+1. ..4+M+N `[writable]` The source accounts to withdraw from. /// /// Data expected by this instruction: /// WithdrawWithheldTokensFromAccountsData - /// WithdrawWithheldTokensFromAccounts, - /// Permissionless instruction to transfer all withheld confidential tokens to the mint. + /// Permissionless instruction to transfer all withheld confidential tokens + /// to the mint. /// /// Succeeds for frozen accounts. /// @@ -158,10 +171,10 @@ pub enum ConfidentialTransferFeeInstruction { /// /// Data expected by this instruction: /// None - /// HarvestWithheldTokensToMint, - /// Configure a confidential transfer fee mint to accept harvested confidential fees. + /// Configure a confidential transfer fee mint to accept harvested + /// confidential fees. /// /// Accounts expected by this instruction: /// @@ -172,13 +185,15 @@ pub enum ConfidentialTransferFeeInstruction { /// *Multisignature owner/delegate /// 0. `[writable]` The token mint. /// 1. `[]` The confidential transfer fee multisig authority, - /// 2. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None EnableHarvestToMint, - /// Configure a confidential transfer fee mint to reject any harvested confidential fees. + /// Configure a confidential transfer fee mint to reject any harvested + /// confidential fees. /// /// Accounts expected by this instruction: /// @@ -189,7 +204,8 @@ pub enum ConfidentialTransferFeeInstruction { /// *Multisignature owner/delegate /// 0. `[writable]` The token mint. /// 1. `[]` The confidential transfer fee multisig authority, - /// 2. `[signer]` Required M signer accounts for the SPL Token Multisig account. + /// 2. `[signer]` Required M signer accounts for the SPL Token Multisig + /// account. /// /// Data expected by this instruction: /// None @@ -210,22 +226,25 @@ pub struct InitializeConfidentialTransferFeeConfigData { pub withdraw_withheld_authority_elgamal_pubkey: ElGamalPubkey, } -/// Data expected by `ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromMint` +/// Data expected by +/// `ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromMint` #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct WithdrawWithheldTokensFromMintData { - /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` instruction to the - /// `WithdrawWithheldTokensFromMint` instruction in the transaction. If the offset is `0`, then - /// use a context state account for the proof. + /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` + /// instruction to the `WithdrawWithheldTokensFromMint` instruction in + /// the transaction. If the offset is `0`, then use a context state + /// account for the proof. pub proof_instruction_offset: i8, /// The new decryptable balance in the destination token account. #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_decryptable_available_balance: DecryptableBalance, } -/// Data expected by `ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromAccounts` +/// Data expected by +/// `ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromAccounts` #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] @@ -233,9 +252,10 @@ pub struct WithdrawWithheldTokensFromMintData { pub struct WithdrawWithheldTokensFromAccountsData { /// Number of token accounts harvested pub num_token_accounts: u8, - /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` instruction to the - /// `VerifyWithdrawWithheldTokensFromAccounts` instruction in the transaction. If the offset is - /// `0`, then use a context state account for the proof. + /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` + /// instruction to the `VerifyWithdrawWithheldTokensFromAccounts` + /// instruction in the transaction. If the offset is `0`, then use a + /// context state account for the proof. pub proof_instruction_offset: i8, /// The new decryptable balance in the destination token account. #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] @@ -338,8 +358,9 @@ pub fn withdraw_withheld_tokens_from_mint( proof_data_location { // This constructor appends the proof instruction right after the - // `WithdrawWithheldTokensFromMint` instruction. This means that the proof instruction - // offset must be always be 1. To use an arbitrary proof instruction offset, use the + // `WithdrawWithheldTokensFromMint` instruction. This means that the proof + // instruction offset must be always be 1. To use an arbitrary proof + // instruction offset, use the // `inner_withdraw_withheld_tokens_from_mint` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { @@ -437,8 +458,9 @@ pub fn withdraw_withheld_tokens_from_accounts( proof_data_location { // This constructor appends the proof instruction right after the - // `WithdrawWithheldTokensFromAccounts` instruction. This means that the proof instruction - // offset must always be 1. To use an arbitrary proof instruction offset, use the + // `WithdrawWithheldTokensFromAccounts` instruction. This means that the proof + // instruction offset must always be 1. To use an arbitrary proof + // instruction offset, use the // `inner_withdraw_withheld_tokens_from_accounts` constructor. let proof_instruction_offset: i8 = proof_instruction_offset.into(); if proof_instruction_offset != 1 { diff --git a/token/program-2022/src/extension/confidential_transfer_fee/mod.rs b/token/program-2022/src/extension/confidential_transfer_fee/mod.rs index df6204dfa88..64576b9a720 100644 --- a/token/program-2022/src/extension/confidential_transfer_fee/mod.rs +++ b/token/program-2022/src/extension/confidential_transfer_fee/mod.rs @@ -15,7 +15,8 @@ pub mod instruction; /// Confidential transfer fee extension processor pub mod processor; -/// Confidential Transfer Fee extension account information needed for instructions +/// Confidential Transfer Fee extension account information needed for +/// instructions #[cfg(not(target_os = "solana"))] pub mod account_info; @@ -33,15 +34,17 @@ pub struct ConfidentialTransferFeeConfig { /// Withheld fees from accounts must be encrypted with this ElGamal key. /// - /// Note that whoever holds the ElGamal private key for this ElGamal public key has the ability - /// to decode any withheld fee amount that are associated with accounts. When combined with the - /// fee parameters, the withheld fee amounts can reveal information about transfer amounts. + /// Note that whoever holds the ElGamal private key for this ElGamal public + /// key has the ability to decode any withheld fee amount that are + /// associated with accounts. When combined with the fee parameters, the + /// withheld fee amounts can reveal information about transfer amounts. pub withdraw_withheld_authority_elgamal_pubkey: ElGamalPubkey, /// If `false`, the harvest of withheld tokens to mint is rejected. pub harvest_to_mint_enabled: PodBool, - /// Withheld confidential transfer fee tokens that have been moved to the mint for withdrawal. + /// Withheld confidential transfer fee tokens that have been moved to the + /// mint for withdrawal. pub withheld_amount: EncryptedWithheldAmount, } diff --git a/token/program-2022/src/extension/confidential_transfer_fee/processor.rs b/token/program-2022/src/extension/confidential_transfer_fee/processor.rs index 2e1743afd47..d3b2ba78eef 100644 --- a/token/program-2022/src/extension/confidential_transfer_fee/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer_fee/processor.rs @@ -77,8 +77,8 @@ fn process_withdraw_withheld_tokens_from_mint( let mint_account_info = next_account_info(account_info_iter)?; let destination_account_info = next_account_info(account_info_iter)?; - // zero-knowledge proof certifies that the exact withheld amount is credited to the destination - // account. + // zero-knowledge proof certifies that the exact withheld amount is credited to + // the destination account. let proof_context = verify_ciphertext_ciphertext_equality_proof( next_account_info(account_info_iter)?, proof_instruction_offset, @@ -105,15 +105,18 @@ fn process_withdraw_withheld_tokens_from_mint( authority_info_data_len, account_info_iter.as_slice(), )?; - } // free `transfer_fee_config` to borrow `confidential_transfer_fee_config` as mutable + } // free `transfer_fee_config` to borrow `confidential_transfer_fee_config` as + // mutable - // mint must also be extended for confidential transfers, but forgo an explicit check since it - // is not possible to initialize a confidential transfer mint without it + // mint must also be extended for confidential transfers, but forgo an explicit + // check since it is not possible to initialize a confidential transfer mint + // without it let confidential_transfer_fee_config = mint.get_extension_mut::()?; - // basic checks for the destination account - must be extended for confidential transfers + // basic checks for the destination account - must be extended for confidential + // transfers let mut destination_account_data = destination_account_info.data.borrow_mut(); let mut destination_account = StateWithExtensionsMut::::unpack(&mut destination_account_data)?; @@ -128,30 +131,31 @@ fn process_withdraw_withheld_tokens_from_mint( destination_account.get_extension_mut::()?; destination_confidential_transfer_account.valid_as_destination()?; - // The funds are moved from the mint to a destination account. Here, the `source` equates to - // the withdraw withheld authority associated in the mint. + // The funds are moved from the mint to a destination account. Here, the + // `source` equates to the withdraw withheld authority associated in the + // mint. - // Check that the withdraw authority ElGamal public key associated with the mint is - // consistent with what was actually used to generate the zkp. + // Check that the withdraw authority ElGamal public key associated with the mint + // is consistent with what was actually used to generate the zkp. if proof_context.source_pubkey != confidential_transfer_fee_config.withdraw_withheld_authority_elgamal_pubkey { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } - // Check that the ElGamal public key associated with the destination account is consistent - // with what was actually used to generate the zkp. + // Check that the ElGamal public key associated with the destination account is + // consistent with what was actually used to generate the zkp. if proof_context.destination_pubkey != destination_confidential_transfer_account.elgamal_pubkey { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } - // Check that the withheld amount ciphertext is consistent with the ciphertext data that was - // actually used to generate the zkp. + // Check that the withheld amount ciphertext is consistent with the ciphertext + // data that was actually used to generate the zkp. if proof_context.source_ciphertext != confidential_transfer_fee_config.withheld_amount { return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); } - // The proof data contains the mint withheld amount encrypted under the destination ElGamal pubkey. - // Add this amount to the available balance. + // The proof data contains the mint withheld amount encrypted under the + // destination ElGamal pubkey. Add this amount to the available balance. destination_confidential_transfer_account.available_balance = syscall::add( &destination_confidential_transfer_account.available_balance, &proof_context.destination_ciphertext, @@ -167,8 +171,9 @@ fn process_withdraw_withheld_tokens_from_mint( Ok(()) } -/// Verify zero-knowledge proof needed for a [WithdrawWithheldTokensFromMint] instruction or a -/// `[WithdrawWithheldTokensFromAccounts]` and return the corresponding proof context. +/// Verify zero-knowledge proof needed for a [WithdrawWithheldTokensFromMint] +/// instruction or a `[WithdrawWithheldTokensFromAccounts]` and return the +/// corresponding proof context. fn verify_ciphertext_ciphertext_equality_proof( account_info: &AccountInfo<'_>, proof_instruction_offset: i64, @@ -212,8 +217,8 @@ fn process_withdraw_withheld_tokens_from_accounts( let mint_account_info = next_account_info(account_info_iter)?; let destination_account_info = next_account_info(account_info_iter)?; - // zero-knowledge proof certifies that the exact aggregate withheld amount is credited to the - // destination account. + // zero-knowledge proof certifies that the exact aggregate withheld amount is + // credited to the destination account. let proof_context = verify_ciphertext_ciphertext_equality_proof( next_account_info(account_info_iter)?, proof_instruction_offset, @@ -289,11 +294,12 @@ fn process_withdraw_withheld_tokens_from_accounts( destination_account.get_extension_mut::()?; destination_confidential_transfer_account.valid_as_destination()?; - // The funds are moved from the accounts to a destination account. Here, the `source` equates - // to the withdraw withheld authority associated in the mint. + // The funds are moved from the accounts to a destination account. Here, the + // `source` equates to the withdraw withheld authority associated in the + // mint. - // Checks that the withdraw authority ElGamal public key associated with the mint is - // consistent with what was actually used to generate the zkp. + // Checks that the withdraw authority ElGamal public key associated with the + // mint is consistent with what was actually used to generate the zkp. let confidential_transfer_fee_config = mint.get_extension_mut::()?; if proof_context.source_pubkey @@ -301,20 +307,21 @@ fn process_withdraw_withheld_tokens_from_accounts( { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } - // Checks that the ElGamal public key associated with the destination account is consistent - // with what was actually used to generate the zkp. + // Checks that the ElGamal public key associated with the destination account is + // consistent with what was actually used to generate the zkp. if proof_context.destination_pubkey != destination_confidential_transfer_account.elgamal_pubkey { return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } - // Checks that the withheld amount ciphertext is consistent with the ciphertext data that was - // actually used to generate the zkp. + // Checks that the withheld amount ciphertext is consistent with the ciphertext + // data that was actually used to generate the zkp. if proof_context.source_ciphertext != aggregate_withheld_amount { return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); } - // The proof data contains the mint withheld amount encrypted under the destination ElGamal pubkey. - // This amount is added to the destination available balance. + // The proof data contains the mint withheld amount encrypted under the + // destination ElGamal pubkey. This amount is added to the destination + // available balance. destination_confidential_transfer_account.available_balance = syscall::add( &destination_confidential_transfer_account.available_balance, &proof_context.destination_ciphertext, diff --git a/token/program-2022/src/extension/cpi_guard/instruction.rs b/token/program-2022/src/extension/cpi_guard/instruction.rs index fa3ae346d41..4474ae91122 100644 --- a/token/program-2022/src/extension/cpi_guard/instruction.rs +++ b/token/program-2022/src/extension/cpi_guard/instruction.rs @@ -19,7 +19,8 @@ use { #[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] #[repr(u8)] pub enum CpiGuardInstruction { - /// Lock certain token operations from taking place within CPI for this Account, namely: + /// Lock certain token operations from taking place within CPI for this + /// Account, namely: /// * Transfer and Burn must go through a delegate. /// * CloseAccount can only return lamports to owner. /// * SetAuthority can only be used to remove an existing close authority. @@ -36,11 +37,11 @@ pub enum CpiGuardInstruction { /// 0. `[writable]` The account to update. /// 1. `[]` The account's multisignature owner. /// 2. ..2+M `[signer]` M signer accounts. - /// Enable, /// Allow all token operations to happen via CPI as normal. /// - /// Implicitly initializes the extension in the case where it is not present. + /// Implicitly initializes the extension in the case where it is not + /// present. /// /// Accounts expected by this instruction: /// @@ -51,7 +52,6 @@ pub enum CpiGuardInstruction { /// 0. `[writable]` The account to update. /// 1. `[]` The account's multisignature owner. /// 2. ..2+M `[signer]` M signer accounts. - /// Disable, } diff --git a/token/program-2022/src/extension/cpi_guard/processor.rs b/token/program-2022/src/extension/cpi_guard/processor.rs index 2fdc4d15799..3419a27358b 100644 --- a/token/program-2022/src/extension/cpi_guard/processor.rs +++ b/token/program-2022/src/extension/cpi_guard/processor.rs @@ -18,7 +18,8 @@ use { }, }; -/// Toggle the CpiGuard extension, initializing the extension if not already present. +/// Toggle the CpiGuard extension, initializing the extension if not already +/// present. fn process_toggle_cpi_guard( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/program-2022/src/extension/default_account_state/instruction.rs b/token/program-2022/src/extension/default_account_state/instruction.rs index 5d49357a24f..e7d72039a1a 100644 --- a/token/program-2022/src/extension/default_account_state/instruction.rs +++ b/token/program-2022/src/extension/default_account_state/instruction.rs @@ -35,10 +35,9 @@ pub enum DefaultAccountStateInstruction { /// /// Data expected by this instruction: /// `crate::state::AccountState` - /// Initialize, - /// Update the default state for new Accounts. Only supported for mints that include the - /// `DefaultAccountState` extension. + /// Update the default state for new Accounts. Only supported for mints that + /// include the `DefaultAccountState` extension. /// /// Accounts expected by this instruction: /// @@ -53,7 +52,6 @@ pub enum DefaultAccountStateInstruction { /// /// Data expected by this instruction: /// `crate::state::AccountState` - /// Update, } diff --git a/token/program-2022/src/extension/group_pointer/instruction.rs b/token/program-2022/src/extension/group_pointer/instruction.rs index dc630c71cd1..5fccbd9ad89 100644 --- a/token/program-2022/src/extension/group_pointer/instruction.rs +++ b/token/program-2022/src/extension/group_pointer/instruction.rs @@ -37,7 +37,6 @@ pub enum GroupPointerInstruction { /// /// Data expected by this instruction: /// `crate::extension::group_pointer::instruction::InitializeInstructionData` - /// Initialize, /// Update the group pointer address. Only supported for mints that /// include the `GroupPointer` extension. @@ -55,7 +54,6 @@ pub enum GroupPointerInstruction { /// /// Data expected by this instruction: /// `crate::extension::group_pointer::instruction::UpdateInstructionData` - /// Update, } diff --git a/token/program-2022/src/extension/interest_bearing_mint/instruction.rs b/token/program-2022/src/extension/interest_bearing_mint/instruction.rs index 2221f934ee2..f98ec592c27 100644 --- a/token/program-2022/src/extension/interest_bearing_mint/instruction.rs +++ b/token/program-2022/src/extension/interest_bearing_mint/instruction.rs @@ -38,7 +38,6 @@ pub enum InterestBearingMintInstruction { /// /// Data expected by this instruction: /// `crate::extension::interest_bearing::instruction::InitializeInstructionData` - /// Initialize, /// Update the interest rate. Only supported for mints that include the /// `InterestBearingConfig` extension. @@ -56,7 +55,6 @@ pub enum InterestBearingMintInstruction { /// /// Data expected by this instruction: /// `crate::extension::interest_bearing::BasisPoints` - /// UpdateRate, } diff --git a/token/program-2022/src/extension/interest_bearing_mint/mod.rs b/token/program-2022/src/extension/interest_bearing_mint/mod.rs index 5bdf05a3dd9..914ff24833b 100644 --- a/token/program-2022/src/extension/interest_bearing_mint/mod.rs +++ b/token/program-2022/src/extension/interest_bearing_mint/mod.rs @@ -31,8 +31,8 @@ pub type UnixTimestamp = PodI64; /// compounded continuously, so APY will be higher than the published interest /// rate. /// -/// To support changing the rate, the config also maintains state for the previous -/// rate. +/// To support changing the rate, the config also maintains state for the +/// previous rate. #[repr(C)] #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] @@ -80,8 +80,8 @@ impl InterestBearingConfig { ) } - /// Convert a raw amount to its UI representation using the given decimals field - /// Excess zeroes or unneeded decimal point are trimmed. + /// Convert a raw amount to its UI representation using the given decimals + /// field Excess zeroes or unneeded decimal point are trimmed. pub fn amount_to_ui_amount( &self, amount: u64, @@ -93,8 +93,8 @@ impl InterestBearingConfig { Some(scaled_amount_with_interest.to_string()) } - /// Try to convert a UI representation of a token amount to its raw amount using the given decimals - /// field + /// Try to convert a UI representation of a token amount to its raw amount + /// using the given decimals field pub fn try_ui_amount_into_amount( &self, ui_amount: &str, @@ -111,12 +111,13 @@ impl InterestBearingConfig { if amount > (u64::MAX as f64) || amount < (u64::MIN as f64) || amount.is_nan() { Err(ProgramError::InvalidArgument) } else { - Ok(amount.round() as u64) // this is important, if you round earlier, you'll get wrong "inf" answers + Ok(amount.round() as u64) // this is important, if you round + // earlier, you'll get wrong "inf" answers } } - /// The new average rate is the time-weighted average of the current rate and average rate, - /// solving for r such that: + /// The new average rate is the time-weighted average of the current rate + /// and average rate, solving for r such that: /// /// exp(r_1 * t_1) * exp(r_2 * t_2) = exp(r * (t_1 + t_2)) /// diff --git a/token/program-2022/src/extension/memo_transfer/instruction.rs b/token/program-2022/src/extension/memo_transfer/instruction.rs index 2c276b5c75f..0a619a1400b 100644 --- a/token/program-2022/src/extension/memo_transfer/instruction.rs +++ b/token/program-2022/src/extension/memo_transfer/instruction.rs @@ -19,8 +19,8 @@ use { #[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] #[repr(u8)] pub enum RequiredMemoTransfersInstruction { - /// Require memos for transfers into this Account. Adds the MemoTransfer extension to the - /// Account, if it doesn't already exist. + /// Require memos for transfers into this Account. Adds the MemoTransfer + /// extension to the Account, if it doesn't already exist. /// /// Accounts expected by this instruction: /// @@ -31,11 +31,11 @@ pub enum RequiredMemoTransfersInstruction { /// 0. `[writable]` The account to update. /// 1. `[]` The account's multisignature owner. /// 2. ..2+M `[signer]` M signer accounts. - /// Enable, /// Stop requiring memos for transfers into this Account. /// - /// Implicitly initializes the extension in the case where it is not present. + /// Implicitly initializes the extension in the case where it is not + /// present. /// /// Accounts expected by this instruction: /// @@ -46,7 +46,6 @@ pub enum RequiredMemoTransfersInstruction { /// 0. `[writable]` The account to update. /// 1. `[]` The account's multisignature owner. /// 2. ..2+M `[signer]` M signer accounts. - /// Disable, } diff --git a/token/program-2022/src/extension/memo_transfer/processor.rs b/token/program-2022/src/extension/memo_transfer/processor.rs index a2d406230c1..e699e0d1a5c 100644 --- a/token/program-2022/src/extension/memo_transfer/processor.rs +++ b/token/program-2022/src/extension/memo_transfer/processor.rs @@ -17,7 +17,8 @@ use { }, }; -/// Toggle the RequiredMemoTransfers extension, initializing the extension if not already present. +/// Toggle the RequiredMemoTransfers extension, initializing the extension if +/// not already present. fn process_toggle_required_memo_transfers( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/program-2022/src/extension/metadata_pointer/instruction.rs b/token/program-2022/src/extension/metadata_pointer/instruction.rs index 2c34ffbf2f5..778c7dddb38 100644 --- a/token/program-2022/src/extension/metadata_pointer/instruction.rs +++ b/token/program-2022/src/extension/metadata_pointer/instruction.rs @@ -37,7 +37,6 @@ pub enum MetadataPointerInstruction { /// /// Data expected by this instruction: /// `crate::extension::metadata_pointer::instruction::InitializeInstructionData` - /// Initialize, /// Update the metadata pointer address. Only supported for mints that /// include the `MetadataPointer` extension. @@ -55,7 +54,6 @@ pub enum MetadataPointerInstruction { /// /// Data expected by this instruction: /// `crate::extension::metadata_pointer::instruction::UpdateInstructionData` - /// Update, } diff --git a/token/program-2022/src/extension/mod.rs b/token/program-2022/src/extension/mod.rs index bb08b07d90a..d0bd1f75f49 100644 --- a/token/program-2022/src/extension/mod.rs +++ b/token/program-2022/src/extension/mod.rs @@ -170,7 +170,8 @@ fn get_extension_indices( Err(ProgramError::InvalidAccountData) } -/// Basic information about the TLV buffer, collected from iterating through all entries +/// Basic information about the TLV buffer, collected from iterating through all +/// entries #[derive(Debug, PartialEq)] struct TlvDataInfo { /// The extension types written in the TLV buffer @@ -272,8 +273,9 @@ fn check_account_type(account_type: AccountType) -> Result<(), Pro /// ^ ^ ^ ^ /// acct type extension length data... /// -/// Mint: 82 bytes... + 83 bytes of other extension data + [2, 0, 3, 0, 100, ....] -/// ^ data in extension just happens to look like this +/// Mint: 82 bytes... + 83 bytes of other extension data + [2, 0, 3, 0, 100, +/// ....] ^ data in +/// extension just happens to look like this /// /// With this approach, we only start writing the TLV data after Account::LEN, /// which means we always know that the account type is going to be right after @@ -304,7 +306,8 @@ fn type_and_tlv_indices( } } -/// Checks a base buffer to verify if it is an Account without having to completely deserialize it +/// Checks a base buffer to verify if it is an Account without having to +/// completely deserialize it fn is_initialized_account(input: &[u8]) -> Result { const ACCOUNT_INITIALIZED_INDEX: usize = 108; // See state.rs#L99 @@ -323,7 +326,8 @@ fn get_extension_bytes(tlv_data: &[u8]) -> Result<&[ length_start, value_start, } = get_extension_indices::(tlv_data, false)?; - // get_extension_indices has checked that tlv_data is long enough to include these indices + // get_extension_indices has checked that tlv_data is long enough to include + // these indices let length = pod_from_bytes::(&tlv_data[length_start..value_start])?; let value_end = value_start.saturating_add(usize::from(*length)); if tlv_data.len() < value_end { @@ -343,7 +347,8 @@ fn get_extension_bytes_mut( length_start, value_start, } = get_extension_indices::(tlv_data, false)?; - // get_extension_indices has checked that tlv_data is long enough to include these indices + // get_extension_indices has checked that tlv_data is long enough to include + // these indices let length = pod_from_bytes::(&tlv_data[length_start..value_start])?; let value_end = value_start.saturating_add(usize::from(*length)); if tlv_data.len() < value_end { @@ -401,8 +406,8 @@ pub trait BaseStateWithExtensions { /// Calculate the new expected size if the state allocates the given number /// of bytes for the given extension type. /// - /// Provides the correct answer regardless if the extension is already present - /// in the TLV data. + /// Provides the correct answer regardless if the extension is already + /// present in the TLV data. fn try_get_new_account_len( &self, new_extension: &V, @@ -431,7 +436,8 @@ pub trait BaseStateWithExtensions { } } -/// Encapsulates owned immutable base state data (mint or account) with possible extensions +/// Encapsulates owned immutable base state data (mint or account) with possible +/// extensions #[derive(Clone, Debug, PartialEq)] pub struct StateWithExtensionsOwned { /// Unpacked base data @@ -469,7 +475,8 @@ impl BaseStateWithExtensions for StateWithExtensionsOwned { } } -/// Encapsulates immutable base state data (mint or account) with possible extensions +/// Encapsulates immutable base state data (mint or account) with possible +/// extensions #[derive(Debug, PartialEq)] pub struct StateWithExtensions<'data, S: BaseState> { /// Unpacked base data @@ -508,7 +515,8 @@ impl<'a, S: BaseState> BaseStateWithExtensions for StateWithExtensions<'a, S> } } -/// Encapsulates mutable base state data (mint or account) with possible extensions +/// Encapsulates mutable base state data (mint or account) with possible +/// extensions #[derive(Debug, PartialEq)] pub struct StateWithExtensionsMut<'data, S: BaseState> { /// Unpacked base data @@ -550,7 +558,8 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { } } - /// Unpack an uninitialized base state, leaving the extension data as a mutable slice + /// Unpack an uninitialized base state, leaving the extension data as a + /// mutable slice /// /// Fails if the base state has already been initialized. pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result { @@ -596,13 +605,14 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { get_extension_bytes_mut::(self.tlv_data) } - /// Unpack a portion of the TLV data as the desired type that allows modifying the type + /// Unpack a portion of the TLV data as the desired type that allows + /// modifying the type pub fn get_extension_mut(&mut self) -> Result<&mut V, ProgramError> { pod_from_bytes_mut::(self.get_extension_bytes_mut::()?) } - /// Packs a variable-length extension into its appropriate data segment. Fails - /// if space hasn't already been allocated for the given extension + /// Packs a variable-length extension into its appropriate data segment. + /// Fails if space hasn't already been allocated for the given extension pub fn pack_variable_len_extension( &mut self, extension: &V, @@ -618,10 +628,11 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { S::pack_into_slice(&self.base, self.base_data); } - /// Packs the default extension data into an open slot if not already found in the - /// data buffer. If extension is already found in the buffer, it overwrites the existing - /// extension with the default state if `overwrite` is set. If extension found, but - /// `overwrite` is not set, it returns error. + /// Packs the default extension data into an open slot if not already found + /// in the data buffer. If extension is already found in the buffer, it + /// overwrites the existing extension with the default state if + /// `overwrite` is set. If extension found, but `overwrite` is not set, + /// it returns error. pub fn init_extension( &mut self, overwrite: bool, @@ -636,8 +647,8 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { /// Reallocate and overwite the TLV entry for the given variable-length /// extension. /// - /// Returns an error if the extension is not present, or if there is not enough - /// space in the buffer. + /// Returns an error if the extension is not present, or if there is not + /// enough space in the buffer. pub fn realloc_variable_len_extension( &mut self, new_extension: &V, @@ -646,14 +657,15 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { new_extension.pack_into_slice(data) } - /// Reallocate the TLV entry for the given extension to the given number of bytes. + /// Reallocate the TLV entry for the given extension to the given number of + /// bytes. /// - /// If the new length is smaller, it will compact the rest of the buffer and zero out - /// the difference at the end. If it's larger, it will move the rest of - /// the buffer data and zero out the new data. + /// If the new length is smaller, it will compact the rest of the buffer and + /// zero out the difference at the end. If it's larger, it will move the + /// rest of the buffer data and zero out the new data. /// - /// Returns an error if the extension is not present, or if this is not enough - /// space in the buffer. + /// Returns an error if the extension is not present, or if this is not + /// enough space in the buffer. fn realloc( &mut self, length: usize, @@ -702,11 +714,11 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { Ok(&mut self.tlv_data[value_start..new_value_end]) } - /// Allocate the given number of bytes for the given variable-length extension - /// and write its contents into the TLV buffer. + /// Allocate the given number of bytes for the given variable-length + /// extension and write its contents into the TLV buffer. /// - /// This can only be used for variable-sized types, such as `String` or `Vec`. - /// `Pod` types must use `init_extension` + /// This can only be used for variable-sized types, such as `String` or + /// `Vec`. `Pod` types must use `init_extension` pub fn init_variable_len_extension( &mut self, extension: &V, @@ -760,10 +772,12 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { } } - /// If `extension_type` is an Account-associated ExtensionType that requires initialization on - /// InitializeAccount, this method packs the default relevant Extension of an ExtensionType - /// into an open slot if not already found in the data buffer, otherwise overwrites the - /// existing extension with the default state. For all other ExtensionTypes, this is a no-op. + /// If `extension_type` is an Account-associated ExtensionType that requires + /// initialization on InitializeAccount, this method packs the default + /// relevant Extension of an ExtensionType into an open slot if not + /// already found in the data buffer, otherwise overwrites the + /// existing extension with the default state. For all other ExtensionTypes, + /// this is a no-op. pub fn init_account_extension_from_type( &mut self, extension_type: ExtensionType, @@ -817,7 +831,8 @@ impl<'a, S: BaseState> BaseStateWithExtensions for StateWithExtensionsMut<'a, /// If AccountType is uninitialized, set it to the BaseState's ACCOUNT_TYPE; /// if AccountType is already set, check is set correctly for BaseState -/// This method assumes that the `base_data` has already been packed with data of the desired type. +/// This method assumes that the `base_data` has already been packed with data +/// of the desired type. pub fn set_account_type(input: &mut [u8]) -> Result<(), ProgramError> { check_min_len_and_not_multisig(input, S::LEN)?; let (base_data, rest) = input.split_at_mut(S::LEN); @@ -838,10 +853,10 @@ pub fn set_account_type(input: &mut [u8]) -> Result<(), ProgramErr } } -/// Different kinds of accounts. Note that `Mint`, `Account`, and `Multisig` types -/// are determined exclusively by the size of the account, and are not included in -/// the account data. `AccountType` is only included if extensions have been -/// initialized. +/// Different kinds of accounts. Note that `Mint`, `Account`, and `Multisig` +/// types are determined exclusively by the size of the account, and are not +/// included in the account data. `AccountType` is only included if extensions +/// have been initialized. #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] pub enum AccountType { @@ -858,17 +873,19 @@ impl Default for AccountType { } } -/// Extensions that can be applied to mints or accounts. Mint extensions must only be -/// applied to mint accounts, and account extensions must only be applied to token holding -/// accounts. +/// Extensions that can be applied to mints or accounts. Mint extensions must +/// only be applied to mint accounts, and account extensions must only be +/// applied to token holding accounts. #[repr(u16)] #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] pub enum ExtensionType { - /// Used as padding if the account size would otherwise be 355, same as a multisig + /// Used as padding if the account size would otherwise be 355, same as a + /// multisig Uninitialized, - /// Includes transfer fee rate info and accompanying authorities to withdraw and set the fee + /// Includes transfer fee rate info and accompanying authorities to withdraw + /// and set the fee TransferFeeConfig, /// Includes withheld transfer fees TransferFeeAmount, @@ -892,30 +909,37 @@ pub enum ExtensionType { CpiGuard, /// Includes an optional permanent delegate PermanentDelegate, - /// Indicates that the tokens in this account belong to a non-transferable mint + /// Indicates that the tokens in this account belong to a non-transferable + /// mint NonTransferableAccount, - /// Mint requires a CPI to a program implementing the "transfer hook" interface + /// Mint requires a CPI to a program implementing the "transfer hook" + /// interface TransferHook, - /// Indicates that the tokens in this account belong to a mint with a transfer hook + /// Indicates that the tokens in this account belong to a mint with a + /// transfer hook TransferHookAccount, - /// Includes encrypted withheld fees and the encryption public that they are encrypted under + /// Includes encrypted withheld fees and the encryption public that they are + /// encrypted under ConfidentialTransferFeeConfig, /// Includes confidential withheld transfer fees ConfidentialTransferFeeAmount, - /// Mint contains a pointer to another account (or the same account) that holds metadata + /// Mint contains a pointer to another account (or the same account) that + /// holds metadata MetadataPointer, /// Mint contains token-metadata TokenMetadata, /// Test variable-length mint extension - /// Mint contains a pointer to another account (or the same account) that holds group - /// configurations + /// Mint contains a pointer to another account (or the same account) that + /// holds group configurations GroupPointer, #[cfg(test)] VariableLenMintTest = u16::MAX - 2, - /// Padding extension used to make an account exactly Multisig::LEN, used for testing + /// Padding extension used to make an account exactly Multisig::LEN, used + /// for testing #[cfg(test)] AccountPaddingTest, - /// Padding extension used to make a mint exactly Multisig::LEN, used for testing + /// Padding extension used to make a mint exactly Multisig::LEN, used for + /// testing #[cfg(test)] MintPaddingTest, } @@ -1062,8 +1086,8 @@ impl ExtensionType { } } - /// Based on a set of AccountType::Mint ExtensionTypes, get the list of AccountType::Account - /// ExtensionTypes required on InitializeAccount + /// Based on a set of AccountType::Mint ExtensionTypes, get the list of + /// AccountType::Account ExtensionTypes required on InitializeAccount pub fn get_required_init_account_extensions(mint_extension_types: &[Self]) -> Vec { let mut account_extension_types = vec![]; for extension_type in mint_extension_types { @@ -1204,7 +1228,8 @@ pub fn alloc_and_serialize( } if previous_account_len < new_account_len { - // account size increased, so realloc the account, then the TLV entry, then write data + // account size increased, so realloc the account, then the TLV entry, then + // write data account_info.realloc(new_account_len, false)?; let mut buffer = account_info.try_borrow_mut_data()?; if extension_already_exists { diff --git a/token/program-2022/src/extension/non_transferable.rs b/token/program-2022/src/extension/non_transferable.rs index c8b6a61cf86..ebcc9a8a176 100644 --- a/token/program-2022/src/extension/non_transferable.rs +++ b/token/program-2022/src/extension/non_transferable.rs @@ -12,7 +12,8 @@ use { #[repr(transparent)] pub struct NonTransferable; -/// Indicates that the tokens from this account belong to a non-transferable mint +/// Indicates that the tokens from this account belong to a non-transferable +/// mint #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] diff --git a/token/program-2022/src/extension/reallocate.rs b/token/program-2022/src/extension/reallocate.rs index df2a8f12482..c21ada497d4 100644 --- a/token/program-2022/src/extension/reallocate.rs +++ b/token/program-2022/src/extension/reallocate.rs @@ -55,7 +55,8 @@ pub fn process_reallocate( { return Err(TokenError::InvalidState.into()); } - // ExtensionType::try_calculate_account_len() dedupes types, so just a dumb concatenation is fine here + // ExtensionType::try_calculate_account_len() dedupes types, so just a dumb + // concatenation is fine here current_extension_types.extend_from_slice(&new_extension_types); let needed_account_len = ExtensionType::try_calculate_account_len::(¤t_extension_types)?; diff --git a/token/program-2022/src/extension/token_metadata/processor.rs b/token/program-2022/src/extension/token_metadata/processor.rs index 88f58d8a9ec..4c13ee8c654 100644 --- a/token/program-2022/src/extension/token_metadata/processor.rs +++ b/token/program-2022/src/extension/token_metadata/processor.rs @@ -158,7 +158,8 @@ pub fn process_remove_key( Ok(()) } -/// Processes a [UpdateAuthority](enum.TokenMetadataInstruction.html) instruction. +/// Processes a [UpdateAuthority](enum.TokenMetadataInstruction.html) +/// instruction. pub fn process_update_authority( _program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/program-2022/src/extension/transfer_fee/instruction.rs b/token/program-2022/src/extension/transfer_fee/instruction.rs index 8ccd7f93a55..308724af7fa 100644 --- a/token/program-2022/src/extension/transfer_fee/instruction.rs +++ b/token/program-2022/src/extension/transfer_fee/instruction.rs @@ -42,8 +42,8 @@ pub enum TransferFeeInstruction { /// Withdraw instructions must be signed by this key #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] withdraw_withheld_authority: COption, - /// Amount of transfer collected as fees, expressed as basis points of the - /// transfer amount + /// Amount of transfer collected as fees, expressed as basis points of + /// the transfer amount transfer_fee_basis_points: u16, /// Maximum fee assessed on transfers maximum_fee: u64, @@ -53,9 +53,12 @@ pub enum TransferFeeInstruction { /// Accounts expected by this instruction: /// /// * Single owner/delegate - /// 0. `[writable]` The source account. Must include the `TransferFeeAmount` extension. - /// 1. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 2. `[writable]` The destination account. Must include the `TransferFeeAmount` extension. + /// 0. `[writable]` The source account. Must include the + /// `TransferFeeAmount` extension. + /// 1. `[]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 2. `[writable]` The destination account. Must include the + /// `TransferFeeAmount` extension. /// 3. `[signer]` The source account's owner/delegate. /// /// * Multisignature owner/delegate @@ -69,19 +72,21 @@ pub enum TransferFeeInstruction { amount: u64, /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, - /// Expected fee assessed on this transfer, calculated off-chain based on - /// the transfer_fee_basis_points and maximum_fee of the mint. + /// Expected fee assessed on this transfer, calculated off-chain based + /// on the transfer_fee_basis_points and maximum_fee of the + /// mint. fee: u64, }, - /// Transfer all withheld tokens in the mint to an account. Signed by the mint's - /// withdraw withheld tokens authority. + /// Transfer all withheld tokens in the mint to an account. Signed by the + /// mint's withdraw withheld tokens authority. /// /// Accounts expected by this instruction: /// /// * Single owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` extension - /// associated with the provided mint. + /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` extension associated with the provided mint. /// 2. `[signer]` The mint's `withdraw_withheld_authority`. /// /// * Multisignature owner/delegate @@ -96,9 +101,11 @@ pub enum TransferFeeInstruction { /// Accounts expected by this instruction: /// /// * Single owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` - /// extension and be associated with the provided mint. + /// 0. `[]` The token mint. Must include the `TransferFeeConfig` + /// extension. + /// 1. `[writable]` The fee receiver account. Must include the + /// `TransferFeeAmount` extension and be associated with the provided + /// mint. /// 2. `[signer]` The mint's `withdraw_withheld_authority`. /// 3. ..3+N `[writable]` The source accounts to withdraw from. /// @@ -116,15 +123,16 @@ pub enum TransferFeeInstruction { /// /// Succeeds for frozen accounts. /// - /// Accounts provided should include the `TransferFeeAmount` extension. If not, - /// the account is skipped. + /// Accounts provided should include the `TransferFeeAmount` extension. If + /// not, the account is skipped. /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint. /// 1. ..1+N `[writable]` The source accounts to harvest from. HarvestWithheldTokensToMint, - /// Set transfer fee. Only supported for mints that include the `TransferFeeConfig` extension. + /// Set transfer fee. Only supported for mints that include the + /// `TransferFeeConfig` extension. /// /// Accounts expected by this instruction: /// @@ -137,8 +145,8 @@ pub enum TransferFeeInstruction { /// 1. `[]` The mint's multisignature fee account owner. /// 2. ..2+M `[signer]` M signer accounts. SetTransferFee { - /// Amount of transfer collected as fees, expressed as basis points of the - /// transfer amount + /// Amount of transfer collected as fees, expressed as basis points of + /// the transfer amount transfer_fee_basis_points: u16, /// Maximum fee assessed on transfers maximum_fee: u64, diff --git a/token/program-2022/src/extension/transfer_fee/mod.rs b/token/program-2022/src/extension/transfer_fee/mod.rs index d31c78f48ae..153bc61b3e3 100644 --- a/token/program-2022/src/extension/transfer_fee/mod.rs +++ b/token/program-2022/src/extension/transfer_fee/mod.rs @@ -44,8 +44,9 @@ pub struct TransferFee { impl TransferFee { /// Calculate ceiling-division /// - /// Ceiling-division `ceil[ numerator / denominator ]` can be represented as a floor-division - /// `floor[ (numerator + denominator - 1) / denominator ]` + /// Ceiling-division `ceil[ numerator / denominator ]` can be represented as + /// a floor-division `floor[ (numerator + denominator - 1) / denominator + /// ]` fn ceil_div(numerator: u128, denominator: u128) -> Option { numerator .checked_add(denominator)? @@ -73,16 +74,17 @@ impl TransferFee { pre_fee_amount.checked_sub(self.calculate_fee(pre_fee_amount)?) } - /// Calculate the transfer amount that will result in a specified net transfer amount. + /// Calculate the transfer amount that will result in a specified net + /// transfer amount. /// - /// The original transfer amount may not always be unique due to rounding. In this case, the - /// smaller amount will be chosen. - /// e.g. Both transfer amount 10, 11 with 10% fee rate results in net transfer amount of 9. In - /// this case, 10 will be chosen. + /// The original transfer amount may not always be unique due to rounding. + /// In this case, the smaller amount will be chosen. + /// e.g. Both transfer amount 10, 11 with 10% fee rate results in net + /// transfer amount of 9. In this case, 10 will be chosen. /// e.g. Fee rate is 100%. In this case, 0 will be chosen. /// - /// The original transfer amount may not always exist on large net transfer amounts due to - /// overflow. In this case, `None` is returned. + /// The original transfer amount may not always exist on large net transfer + /// amounts due to overflow. In this case, `None` is returned. /// e.g. The net fee amount is `u64::MAX` with a positive fee rate. pub fn calculate_pre_fee_amount(&self, post_fee_amount: u64) -> Option { let maximum_fee = u64::from(self.maximum_fee); @@ -122,7 +124,8 @@ pub struct TransferFeeConfig { pub transfer_fee_config_authority: OptionalNonZeroPubkey, /// Withdraw from mint instructions must be signed by this key pub withdraw_withheld_authority: OptionalNonZeroPubkey, - /// Withheld transfer fee tokens that have been moved to the mint for withdrawal + /// Withheld transfer fee tokens that have been moved to the mint for + /// withdrawal pub withheld_amount: PodU64, /// Older transfer fee, used if the current epoch < new_transfer_fee.epoch pub older_transfer_fee: TransferFee, diff --git a/token/program-2022/src/extension/transfer_fee/processor.rs b/token/program-2022/src/extension/transfer_fee/processor.rs index 10e396b0bbf..ce4e1d1731b 100644 --- a/token/program-2022/src/extension/transfer_fee/processor.rs +++ b/token/program-2022/src/extension/transfer_fee/processor.rs @@ -89,10 +89,11 @@ fn process_set_transfer_fee( } // When setting the transfer fee, we have two situations: - // * newer transfer fee epoch <= current epoch: - // newer transfer fee is the active one, so overwrite older transfer fee with newer, then overwrite newer transfer fee - // * newer transfer fee epoch >= next epoch: - // it was never used, so just overwrite next transfer fee + // * newer transfer fee epoch <= current epoch: newer transfer fee is the active + // one, so overwrite older transfer fee with newer, then overwrite newer + // transfer fee + // * newer transfer fee epoch >= next epoch: it was never used, so just + // overwrite next transfer fee let epoch = Clock::get()?.epoch; if u64::from(extension.newer_transfer_fee.epoch) <= epoch { extension.older_transfer_fee = extension.newer_transfer_fee; diff --git a/token/program-2022/src/extension/transfer_hook/instruction.rs b/token/program-2022/src/extension/transfer_hook/instruction.rs index 449d25081c7..735b2866899 100644 --- a/token/program-2022/src/extension/transfer_hook/instruction.rs +++ b/token/program-2022/src/extension/transfer_hook/instruction.rs @@ -37,7 +37,6 @@ pub enum TransferHookInstruction { /// /// Data expected by this instruction: /// `crate::extension::transfer_hook::instruction::InitializeInstructionData` - /// Initialize, /// Update the transfer hook program id. Only supported for mints that /// include the `TransferHook` extension. @@ -55,7 +54,6 @@ pub enum TransferHookInstruction { /// /// Data expected by this instruction: /// `crate::extension::transfer_hook::UpdateInstructionData` - /// Update, } diff --git a/token/program-2022/src/extension/transfer_hook/mod.rs b/token/program-2022/src/extension/transfer_hook/mod.rs index c7a43f69be2..518aa207cd8 100644 --- a/token/program-2022/src/extension/transfer_hook/mod.rs +++ b/token/program-2022/src/extension/transfer_hook/mod.rs @@ -29,7 +29,8 @@ pub struct TransferHook { pub program_id: OptionalNonZeroPubkey, } -/// Indicates that the tokens from this account belong to a mint with a transfer hook +/// Indicates that the tokens from this account belong to a mint with a transfer +/// hook #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] @@ -58,7 +59,8 @@ pub fn get_program_id>( .and_then(|e| Option::::from(e.program_id)) } -/// Helper function to set the transferring flag before calling into transfer hook +/// Helper function to set the transferring flag before calling into transfer +/// hook pub fn set_transferring(account: &mut StateWithExtensionsMut) -> Result<(), ProgramError> { let account_extension = account.get_extension_mut::()?; account_extension.transferring = true.into(); diff --git a/token/program-2022/src/generic_token_account.rs b/token/program-2022/src/generic_token_account.rs index 1123ba6fe8e..69496c95e83 100644 --- a/token/program-2022/src/generic_token_account.rs +++ b/token/program-2022/src/generic_token_account.rs @@ -8,24 +8,27 @@ use { const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; -/// A trait for token Account structs to enable efficiently unpacking various fields -/// without unpacking the complete state. +/// A trait for token Account structs to enable efficiently unpacking various +/// fields without unpacking the complete state. pub trait GenericTokenAccount { /// Check if the account data is a valid token account fn valid_account_data(account_data: &[u8]) -> bool; - /// Call after account length has already been verified to unpack the account owner + /// Call after account length has already been verified to unpack the + /// account owner fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) } - /// Call after account length has already been verified to unpack the account mint + /// Call after account length has already been verified to unpack the + /// account mint fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) } - /// Call after account length has already been verified to unpack a Pubkey at - /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` + /// Call after account length has already been verified to unpack a Pubkey + /// at the specified offset. Panics if `account_data.len()` is less than + /// `PUBKEY_BYTES` fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) } diff --git a/token/program-2022/src/instruction.rs b/token/program-2022/src/instruction.rs index d0636314be9..4e1f4a3f665 100644 --- a/token/program-2022/src/instruction.rs +++ b/token/program-2022/src/instruction.rs @@ -1,6 +1,7 @@ //! Instruction types -#![allow(deprecated)] // needed to avoid deprecation warning when generating serde implementation for TokenInstruction +#![allow(deprecated)] // needed to avoid deprecation warning when generating serde implementation for + // TokenInstruction #[cfg(feature = "serde-traits")] use { @@ -62,7 +63,6 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The mint to initialize. /// 1. `[]` Rent sysvar - /// InitializeMint { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -124,8 +124,9 @@ pub enum TokenInstruction<'a> { /// amounts of SOL and Tokens will be transferred to the destination /// account. /// - /// If either account contains an `TransferFeeAmount` extension, this will fail. - /// Mints with the `TransferFeeConfig` extension are required in order to assess the fee. + /// If either account contains an `TransferFeeAmount` extension, this will + /// fail. Mints with the `TransferFeeConfig` extension are required in + /// order to assess the fee. /// /// Accounts expected by this instruction: /// @@ -239,20 +240,22 @@ pub enum TokenInstruction<'a> { /// Close an account by transferring all its SOL to the destination account. /// Non-native accounts may only be closed if its token amount is zero. /// - /// Accounts with the `TransferFeeAmount` extension may only be closed if the withheld - /// amount is zero. + /// Accounts with the `TransferFeeAmount` extension may only be closed if + /// the withheld amount is zero. /// - /// Accounts with the `ConfidentialTransfer` extension may only be closed if the pending and - /// available balance ciphertexts are empty. Use + /// Accounts with the `ConfidentialTransfer` extension may only be closed if + /// the pending and available balance ciphertexts are empty. Use /// `ConfidentialTransferInstruction::ApplyPendingBalance` and - /// `ConfidentialTransferInstruction::EmptyAccount` to empty these ciphertexts. + /// `ConfidentialTransferInstruction::EmptyAccount` to empty these + /// ciphertexts. /// - /// Accounts with the `ConfidentialTransferFee` extension may only be closed if the withheld - /// amount ciphertext is empty. Use - /// `ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint` to empty this ciphertext. + /// Accounts with the `ConfidentialTransferFee` extension may only be closed + /// if the withheld amount ciphertext is empty. Use + /// `ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint` to + /// empty this ciphertext. /// - /// Mints may be closed if they have the `MintCloseAuthority` extension and their token - /// supply is zero + /// Mints may be closed if they have the `MintCloseAuthority` extension and + /// their token supply is zero /// /// Accounts /// @@ -411,10 +414,10 @@ pub enum TokenInstruction<'a> { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction data - /// rather than the accounts list. This variant may be preferable when using - /// Cross Program Invocation from an instruction that does not need the owner's - /// `AccountInfo` otherwise. + /// Like InitializeAccount, but the owner pubkey is passed via instruction + /// data rather than the accounts list. This variant may be preferable + /// when using Cross Program Invocation from an instruction that does + /// not need the owner's `AccountInfo` otherwise. /// /// Accounts expected by this instruction: /// @@ -428,15 +431,17 @@ pub enum TokenInstruction<'a> { }, /// Given a wrapped / native token account (a token account containing SOL) /// updates its amount field based on the account's underlying `lamports`. - /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - /// to move lamports to a wrapped token account, and needs to have its token - /// `amount` field updated. + /// This is useful if a non-wrapped SOL account uses + /// `system_instruction::transfer` to move lamports to a wrapped token + /// account, and needs to have its token `amount` field updated. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` The native token account to sync with its underlying lamports. + /// 0. `[writable]` The native token account to sync with its underlying + /// lamports. SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be provided + /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -447,7 +452,8 @@ pub enum TokenInstruction<'a> { #[cfg_attr(feature = "serde-traits", serde(with = "As::"))] owner: Pubkey, }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be provided + /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -464,7 +470,6 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. - /// InitializeMint2 { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -475,8 +480,8 @@ pub enum TokenInstruction<'a> { #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] freeze_authority: COption, }, - /// Gets the required size of an account for the given mint as a little-endian - /// `u64`. + /// Gets the required size of an account for the given mint as a + /// little-endian `u64`. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -490,8 +495,8 @@ pub enum TokenInstruction<'a> { }, /// Initialize the Immutable Owner extension for the given token account /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeAccount`. + /// Fails if the account has already been initialized, so must be called + /// before `InitializeAccount`. /// /// Accounts expected by this instruction: /// @@ -499,14 +504,14 @@ pub enum TokenInstruction<'a> { /// /// Data expected by this instruction: /// None - /// InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. + /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// mint. /// /// Fails on an invalid mint. /// - /// Return data can be fetched using `sol_get_return_data` and deserialized with - /// `String::from_utf8`. + /// Return data can be fetched using `sol_get_return_data` and deserialized + /// with `String::from_utf8`. /// /// Accounts expected by this instruction: /// @@ -515,7 +520,8 @@ pub enum TokenInstruction<'a> { /// The amount of tokens to convert. amount: u64, }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. + /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using + /// the given mint. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -547,20 +553,26 @@ pub enum TokenInstruction<'a> { /// The common instruction prefix for Transfer Fee extension instructions. /// /// See `extension::transfer_fee::instruction::TransferFeeInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix TransferFeeExtension(TransferFeeInstruction), - /// The common instruction prefix for Confidential Transfer extension instructions. + /// The common instruction prefix for Confidential Transfer extension + /// instructions. /// /// See `extension::confidential_transfer::instruction::ConfidentialTransferInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix ConfidentialTransferExtension, - /// The common instruction prefix for Default Account State extension instructions. + /// The common instruction prefix for Default Account State extension + /// instructions. /// /// See `extension::default_account_state::instruction::DefaultAccountStateInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix DefaultAccountStateExtension, - /// Check to see if a token account is large enough for a list of ExtensionTypes, and if not, - /// use reallocation to increase the data size. + /// Check to see if a token account is large enough for a list of + /// ExtensionTypes, and if not, use reallocation to increase the data + /// size. /// /// Accounts expected by this instruction: /// @@ -576,33 +588,33 @@ pub enum TokenInstruction<'a> { /// 2. `[]` System program for reallocation funding /// 3. `[]` The account's multisignature owner/delegate. /// 4. ..4+M `[signer]` M signer accounts. - /// Reallocate { /// New extension types to include in the reallocated account extension_types: Vec, }, - /// The common instruction prefix for Memo Transfer account extension instructions. + /// The common instruction prefix for Memo Transfer account extension + /// instructions. /// /// See `extension::memo_transfer::instruction::RequiredMemoTransfersInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix MemoTransferExtension, /// Creates the native mint. /// - /// This instruction only needs to be invoked once after deployment and is permissionless, - /// Wrapped SOL (`native_mint::id()`) will not be available until this instruction is - /// successfully executed. + /// This instruction only needs to be invoked once after deployment and is + /// permissionless, Wrapped SOL (`native_mint::id()`) will not be + /// available until this instruction is successfully executed. /// /// Accounts expected by this instruction: /// /// 0. `[writeable,signer]` Funding account (must be a system account) /// 1. `[writable]` The native mint address /// 2. `[]` System program for mint account funding - /// CreateNativeMint, /// Initialize the non transferable extension for the given mint account /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeMint`. + /// Fails if the account has already been initialized, so must be called + /// before `InitializeMint`. /// /// Accounts expected by this instruction: /// @@ -610,17 +622,20 @@ pub enum TokenInstruction<'a> { /// /// Data expected by this instruction: /// None - /// InitializeNonTransferableMint, - /// The common instruction prefix for Interest Bearing extension instructions. + /// The common instruction prefix for Interest Bearing extension + /// instructions. /// /// See `extension::interest_bearing_mint::instruction::InterestBearingMintInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix InterestBearingMintExtension, - /// The common instruction prefix for CPI Guard account extension instructions. + /// The common instruction prefix for CPI Guard account extension + /// instructions. /// /// See `extension::cpi_guard::instruction::CpiGuardInstruction` for - /// further details about the extended instructions that share this instruction prefix + /// further details about the extended instructions that share this + /// instruction prefix CpiGuardExtension, /// Initialize the permanent delegate on a new mint. /// @@ -637,7 +652,6 @@ pub enum TokenInstruction<'a> { /// /// Data expected by this instruction: /// Pubkey for the permanent delegate - /// InitializePermanentDelegate { /// Authority that may sign for `Transfer`s and `Burn`s on any account #[cfg_attr(feature = "serde-traits", serde(with = "As::"))] @@ -646,13 +660,15 @@ pub enum TokenInstruction<'a> { /// The common instruction prefix for transfer hook extension instructions. /// /// See `extension::transfer_hook::instruction::TransferHookInstruction` - /// for further details about the extended instructions that share this instruction - /// prefix + /// for further details about the extended instructions that share this + /// instruction prefix TransferHookExtension, - /// The common instruction prefix for the confidential transfer fee extension instructions. + /// The common instruction prefix for the confidential transfer fee + /// extension instructions. /// /// See `extension::confidential_transfer_fee::instruction::ConfidentialTransferFeeInstruction` - /// for further details about the extended instructions that share this instruction prefix + /// for further details about the extended instructions that share this + /// instruction prefix ConfidentialTransferFeeExtension, /// This instruction is to be used to rescue SOLs sent to any TokenProgram /// owned account by sending them to any other account, leaving behind only @@ -663,21 +679,23 @@ pub enum TokenInstruction<'a> { /// 2. `[signer]` Authority /// 3. ..2+M `[signer]` M signer accounts. WithdrawExcessLamports, - /// The common instruction prefix for metadata pointer extension instructions. + /// The common instruction prefix for metadata pointer extension + /// instructions. /// /// See `extension::metadata_pointer::instruction::MetadataPointerInstruction` - /// for further details about the extended instructions that share this instruction - /// prefix + /// for further details about the extended instructions that share this + /// instruction prefix MetadataPointerExtension, /// The common instruction prefix for group pointer extension instructions. /// /// See `extension::group_pointer::instruction::GroupPointerInstruction` - /// for further details about the extended instructions that share this instruction - /// prefix + /// for further details about the extended instructions that share this + /// instruction prefix GroupPointerExtension, } impl<'a> TokenInstruction<'a> { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). + /// Unpacks a byte buffer into a + /// [TokenInstruction](enum.TokenInstruction.html). pub fn unpack(input: &'a [u8]) -> Result { use TokenError::InvalidInstruction; @@ -819,7 +837,8 @@ impl<'a> TokenInstruction<'a> { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); match self { @@ -1067,8 +1086,8 @@ pub enum AuthorityType { InterestRate, /// Authority to transfer or burn any tokens for a mint PermanentDelegate, - /// Authority to update confidential transfer mint and aprove accounts for confidential - /// transfers + /// Authority to update confidential transfer mint and aprove accounts for + /// confidential transfers ConfidentialTransferMint, /// Authority to set the transfer hook program id TransferHookProgramId, diff --git a/token/program-2022/src/lib.rs b/token/program-2022/src/lib.rs index eef7f9b0786..925c95c8f78 100644 --- a/token/program-2022/src/lib.rs +++ b/token/program-2022/src/lib.rs @@ -20,7 +20,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version use solana_program::{ entrypoint::ProgramResult, program_error::ProgramError, @@ -30,18 +31,20 @@ use solana_program::{ }; pub use {solana_program, solana_zk_token_sdk}; -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount +/// Convert the UI representation of a token amount (using the decimals field +/// defined in its mint) to the raw amount pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { let decimals = decimals as usize; if decimals > 0 { @@ -66,12 +69,13 @@ pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { s } -/// Try to convert a UI representation of a token amount to its raw amount using the given decimals -/// field +/// Try to convert a UI representation of a token amount to its raw amount using +/// the given decimals field pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least length == 1 + let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at + // least length == 1 let after_decimal = parts.next().unwrap_or(""); let after_decimal = after_decimal.trim_end_matches('0'); if (amount_str.is_empty() && after_decimal.is_empty()) @@ -100,7 +104,8 @@ pub fn check_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { Ok(()) } -/// Checks that the supplied program ID is corect for spl-token or spl-token-2022 +/// Checks that the supplied program ID is corect for spl-token or +/// spl-token-2022 pub fn check_spl_token_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { if spl_token_program_id != &id() && spl_token_program_id != &spl_token::id() { return Err(ProgramError::IncorrectProgramId); @@ -108,7 +113,8 @@ pub fn check_spl_token_program_account(spl_token_program_id: &Pubkey) -> Program Ok(()) } -/// Checks that the supplied program ID is correct for the ZK Token proof program +/// Checks that the supplied program ID is correct for the ZK Token proof +/// program pub fn check_zk_token_proof_program_account(zk_token_proof_program_id: &Pubkey) -> ProgramResult { if zk_token_proof_program_id != &solana_zk_token_sdk::zk_token_proof_program::id() { return Err(ProgramError::IncorrectProgramId); diff --git a/token/program-2022/src/offchain.rs b/token/program-2022/src/offchain.rs index 94ca6c5590a..e0e6fbf82c0 100644 --- a/token/program-2022/src/offchain.rs +++ b/token/program-2022/src/offchain.rs @@ -11,7 +11,8 @@ use { std::future::Future, }; -/// Offchain helper to get all additional required account metas for a checked transfer +/// Offchain helper to get all additional required account metas for a checked +/// transfer /// /// To be client-agnostic and to avoid pulling in the full solana-sdk, this /// simply takes a function that will return its data as `Future>` for diff --git a/token/program-2022/src/onchain.rs b/token/program-2022/src/onchain.rs index c28e23b8c2b..a174b499aa8 100644 --- a/token/program-2022/src/onchain.rs +++ b/token/program-2022/src/onchain.rs @@ -14,8 +14,8 @@ use { spl_transfer_hook_interface::onchain::add_cpi_accounts_for_execute, }; -/// Helper to CPI into token-2022 on-chain, looking through the additional account -/// infos to create the proper instruction with the proper account infos +/// Helper to CPI into token-2022 on-chain, looking through the additional +/// account infos to create the proper instruction with the proper account infos #[allow(clippy::too_many_arguments)] pub fn invoke_transfer_checked<'a>( token_program_id: &Pubkey, diff --git a/token/program-2022/src/processor.rs b/token/program-2022/src/processor.rs index 4bcfb09b10c..dcef1eae4a3 100644 --- a/token/program-2022/src/processor.rs +++ b/token/program-2022/src/processor.rs @@ -198,17 +198,20 @@ impl Processor { Ok(()) } - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { Self::_process_initialize_account(accounts, None, true) } - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { Self::_process_initialize_account(accounts, Some(&owner), true) } - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount3](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account3(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { Self::_process_initialize_account(accounts, Some(&owner), false) } @@ -255,12 +258,14 @@ impl Processor { Ok(()) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, true) } - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, false) } @@ -1239,7 +1244,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeMintCloseAuthority](enum.TokenInstruction.html) instruction + /// Processes an [InitializeMintCloseAuthority](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_mint_close_authority( accounts: &[AccountInfo], close_authority: COption, @@ -1271,8 +1277,8 @@ impl Processor { let mint_account_info = next_account_info(account_info_iter)?; let mut account_extensions = Self::get_required_account_extensions(mint_account_info)?; - // ExtensionType::try_calculate_account_len() dedupes types, so just a dumb concatenation is fine - // here + // ExtensionType::try_calculate_account_len() dedupes types, so just a dumb + // concatenation is fine here account_extensions.extend_from_slice(&new_extension_types); let account_len = ExtensionType::try_calculate_account_len::(&account_extensions)?; @@ -1281,7 +1287,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction + /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let token_account_info = next_account_info(account_info_iter)?; @@ -1380,7 +1387,8 @@ impl Processor { ) } - /// Processes an [InitializeNonTransferableMint](enum.TokenInstruction.html) instruction + /// Processes an [InitializeNonTransferableMint](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_non_transferable_mint(accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_account_info = next_account_info(account_info_iter)?; @@ -1392,7 +1400,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializePermanentDelegate](enum.TokenInstruction.html) instruction + /// Processes an [InitializePermanentDelegate](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_permanent_delegate( accounts: &[AccountInfo], delegate: Pubkey, @@ -1408,8 +1417,8 @@ impl Processor { Ok(()) } - /// Withdraw Excess Lamports is used to recover Lamports transfered to any TokenProgram owned account - /// by moving them to another account + /// Withdraw Excess Lamports is used to recover Lamports transfered to any + /// TokenProgram owned account by moving them to another account /// of the source account. pub fn process_withdraw_excess_lamports( program_id: &Pubkey, @@ -5891,7 +5900,8 @@ mod tests { Epoch::default(), ); - // no multisig, but the account is its own authority, and data is mutably borrowed + // no multisig, but the account is its own authority, and data is mutably + // borrowed { let mut lamports = 0; let mut data = vec![0; Account::get_packed_len()]; @@ -7517,7 +7527,8 @@ mod tests { get_account_data_size( &program_id, &mint_key, - &[ExtensionType::TransferFeeAmount], // User extension that's also added by the mint ignored... + &[ExtensionType::TransferFeeAmount], /* User extension that's also added by the + * mint ignored... */ ) .unwrap(), vec![&mut extended_mint_account], diff --git a/token/program-2022/src/proof.rs b/token/program-2022/src/proof.rs index ac72c5020ec..fbb9b525a10 100644 --- a/token/program-2022/src/proof.rs +++ b/token/program-2022/src/proof.rs @@ -10,7 +10,8 @@ use { std::num::NonZeroI8, }; -/// Decodes the proof context data associated with a zero-knowledge proof instruction. +/// Decodes the proof context data associated with a zero-knowledge proof +/// instruction. pub fn decode_proof_instruction_context, U: Pod>( expected: ProofInstruction, instruction: &Instruction, @@ -27,10 +28,12 @@ pub fn decode_proof_instruction_context, U: Pod>( .ok_or(ProgramError::InvalidInstructionData) } -/// A proof location type meant to be used for arguments to instruction constructors. +/// A proof location type meant to be used for arguments to instruction +/// constructors. #[derive(Clone, Copy)] pub enum ProofLocation<'a, T> { - /// The proof is included in the same transaction of a corresponding token-2022 instruction. + /// The proof is included in the same transaction of a corresponding + /// token-2022 instruction. InstructionOffset(NonZeroI8, &'a T), /// The proof is pre-verified into a context state account. ContextStateAccount(&'a Pubkey), @@ -39,9 +42,11 @@ pub enum ProofLocation<'a, T> { /// Instruction options for when using split context state accounts #[derive(Clone, Copy)] pub struct SplitContextStateAccountsConfig { - /// If true, execute no op when an associated split proof context state account is not - /// initialized. Otherwise, fail on an uninitialized context state account. + /// If true, execute no op when an associated split proof context state + /// account is not initialized. Otherwise, fail on an uninitialized + /// context state account. pub no_op_on_uninitialized_split_context_state: bool, - /// Close associated context states after a complete execution of the transfer instruction. + /// Close associated context states after a complete execution of the + /// transfer instruction. pub close_split_context_state_on_execution: bool, } diff --git a/token/program-2022/src/serialization.rs b/token/program-2022/src/serialization.rs index 850ec1cb8c1..9287caacab8 100644 --- a/token/program-2022/src/serialization.rs +++ b/token/program-2022/src/serialization.rs @@ -1,4 +1,5 @@ -//! serialization module - contains helpers for serde types from other crates, deserialization visitors +//! serialization module - contains helpers for serde types from other crates, +//! deserialization visitors use { base64::{prelude::BASE64_STANDARD, Engine}, diff --git a/token/program-2022/src/state.rs b/token/program-2022/src/state.rs index 94bd76980ea..6dcdd41ac9a 100644 --- a/token/program-2022/src/state.rs +++ b/token/program-2022/src/state.rs @@ -20,9 +20,10 @@ use { #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Mint { - /// Optional authority used to mint new tokens. The mint authority may only be provided during - /// mint creation. If no mint authority is present then the mint has a fixed supply and no - /// further tokens may be minted. + /// Optional authority used to mint new tokens. The mint authority may only + /// be provided during mint creation. If no mint authority is present + /// then the mint has a fixed supply and no further tokens may be + /// minted. pub mint_authority: COption, /// Total supply of tokens. pub supply: u64, @@ -101,9 +102,10 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - /// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - /// SOL accounts do not drop below this threshold. + /// If is_some, this is a native token, and the value logs the rent-exempt + /// reserve. An Account is required to be rent-exempt, so the value is + /// used by the Processor to ensure that wrapped SOL accounts do not + /// drop below this threshold. pub is_native: COption, /// The amount delegated pub delegated_amount: u64, @@ -119,7 +121,8 @@ impl Account { pub fn is_native(&self) -> bool { self.is_native.is_some() } - /// Checks if a token Account's owner is the system_program or the incinerator + /// Checks if a token Account's owner is the system_program or the + /// incinerator pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { solana_program::system_program::check_id(&self.owner) || solana_program::incinerator::check_id(&self.owner) @@ -189,11 +192,12 @@ pub enum AccountState { /// Account is not yet initialized #[default] Uninitialized, - /// Account is initialized; the account owner and/or delegate may perform permitted operations - /// on this account + /// Account is initialized; the account owner and/or delegate may perform + /// permitted operations on this account Initialized, - /// Account has been frozen by the mint freeze authority. Neither the account owner nor - /// the delegate are able to perform operations on this account. + /// Account has been frozen by the mint freeze authority. Neither the + /// account owner nor the delegate are able to perform operations on + /// this account. Frozen, } @@ -448,22 +452,22 @@ pub(crate) mod test { let result = Account::unpack_account_owner(&src); assert_eq!(result, Option::None); - // Account data length > account data size with a valid extension and initialized, - // expect some key returned + // Account data length > account data size with a valid extension and + // initialized, expect some key returned let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; src[Account::LEN] = AccountType::Account as u8; src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; let result = Account::unpack_account_owner(&src); assert!(result.is_some()); - // Account data length > account data size with a valid extension but uninitialized, - // expect None + // Account data length > account data size with a valid extension but + // uninitialized, expect None src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; let result = Account::unpack_account_owner(&src); assert!(result.is_none()); - // Account data length is multi-sig data size with a valid extension and initialized, - // expect none + // Account data length is multi-sig data size with a valid extension and + // initialized, expect none let mut src: [u8; Multisig::LEN] = [0; Multisig::LEN]; src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; src[Account::LEN] = AccountType::Account as u8; @@ -496,22 +500,22 @@ pub(crate) mod test { let result = Account::unpack_account_mint(&src); assert_eq!(result, Option::None); - // Account data length > account data size with a valid extension and initialized, - // expect some key returned + // Account data length > account data size with a valid extension and + // initialized, expect some key returned let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; src[Account::LEN] = AccountType::Account as u8; let result = Account::unpack_account_mint(&src); assert!(result.is_some()); - // Account data length > account data size with a valid extension but uninitialized, - // expect none + // Account data length > account data size with a valid extension but + // uninitialized, expect none src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; let result = Account::unpack_account_mint(&src); assert!(result.is_none()); - // Account data length is multi-sig data size with a valid extension and initialized, - // expect none + // Account data length is multi-sig data size with a valid extension and + // initialized, expect none let mut src: [u8; Multisig::LEN] = [0; Multisig::LEN]; src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; src[Account::LEN] = AccountType::Account as u8; diff --git a/token/program-2022/tests/serialization.rs b/token/program-2022/tests/serialization.rs index da192afc97e..9645daadb83 100644 --- a/token/program-2022/tests/serialization.rs +++ b/token/program-2022/tests/serialization.rs @@ -45,7 +45,8 @@ fn serde_instruction_coption_pubkey_with_none() { #[test] fn serde_instruction_optional_nonzero_pubkeys_podbool() { - // tests serde of ix containing OptionalNonZeroPubkey, PodBool and OptionalNonZeroElGamalPubkey + // tests serde of ix containing OptionalNonZeroPubkey, PodBool and + // OptionalNonZeroElGamalPubkey let authority_option: Option = Some(Pubkey::from_str("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM").unwrap()); let authority: OptionalNonZeroPubkey = authority_option.try_into().unwrap(); @@ -75,8 +76,8 @@ fn serde_instruction_optional_nonzero_pubkeys_podbool() { #[test] fn serde_instruction_optional_nonzero_pubkeys_podbool_with_none() { - // tests serde of ix containing OptionalNonZeroPubkey, PodBool and OptionalNonZeroElGamalPubkey - // with null values + // tests serde of ix containing OptionalNonZeroPubkey, PodBool and + // OptionalNonZeroElGamalPubkey with null values let authority: OptionalNonZeroPubkey = None.try_into().unwrap(); let auditor_elgamal_pubkey: OptionalNonZeroElGamalPubkey = diff --git a/token/program/src/instruction.rs b/token/program/src/instruction.rs index 067fde5f332..ede7308e34a 100644 --- a/token/program/src/instruction.rs +++ b/token/program/src/instruction.rs @@ -36,7 +36,6 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The mint to initialize. /// 1. `[]` Rent sysvar - /// InitializeMint { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -352,10 +351,10 @@ pub enum TokenInstruction<'a> { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction data - /// rather than the accounts list. This variant may be preferable when using - /// Cross Program Invocation from an instruction that does not need the owner's - /// `AccountInfo` otherwise. + /// Like InitializeAccount, but the owner pubkey is passed via instruction + /// data rather than the accounts list. This variant may be preferable + /// when using Cross Program Invocation from an instruction that does + /// not need the owner's `AccountInfo` otherwise. /// /// Accounts expected by this instruction: /// @@ -368,15 +367,17 @@ pub enum TokenInstruction<'a> { }, /// Given a wrapped / native token account (a token account containing SOL) /// updates its amount field based on the account's underlying `lamports`. - /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - /// to move lamports to a wrapped token account, and needs to have its token - /// `amount` field updated. + /// This is useful if a non-wrapped SOL account uses + /// `system_instruction::transfer` to move lamports to a wrapped token + /// account, and needs to have its token `amount` field updated. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` The native token account to sync with its underlying lamports. + /// 0. `[writable]` The native token account to sync with its underlying + /// lamports. SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be provided + /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -386,7 +387,8 @@ pub enum TokenInstruction<'a> { /// The new account's owner/multisignature. owner: Pubkey, }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be provided + /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -398,12 +400,12 @@ pub enum TokenInstruction<'a> { /// account. m: u8, }, - /// Like [`InitializeMint`], but does not require the Rent sysvar to be provided + /// Like [`InitializeMint`], but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. - /// InitializeMint2 { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -412,8 +414,8 @@ pub enum TokenInstruction<'a> { /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, - /// Gets the required size of an account for the given mint as a little-endian - /// `u64`. + /// Gets the required size of an account for the given mint as a + /// little-endian `u64`. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -424,8 +426,8 @@ pub enum TokenInstruction<'a> { GetAccountDataSize, // typically, there's also data, but this program ignores it /// Initialize the Immutable Owner extension for the given token account /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeAccount`. + /// Fails if the account has already been initialized, so must be called + /// before `InitializeAccount`. /// /// No-ops in this version of the program, but is included for compatibility /// with the Associated Token Account program. @@ -437,13 +439,14 @@ pub enum TokenInstruction<'a> { /// Data expected by this instruction: /// None InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. + /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// mint. In this version of the program, the mint can only specify the + /// number of decimals. /// /// Fails on an invalid mint. /// - /// Return data can be fetched using `sol_get_return_data` and deserialized with - /// `String::from_utf8`. + /// Return data can be fetched using `sol_get_return_data` and deserialized + /// with `String::from_utf8`. /// /// Accounts expected by this instruction: /// @@ -452,8 +455,9 @@ pub enum TokenInstruction<'a> { /// The amount of tokens to reformat. amount: u64, }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. + /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using + /// the given mint. In this version of the program, the mint can only + /// specify the number of decimals. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -470,7 +474,8 @@ pub enum TokenInstruction<'a> { // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility } impl<'a> TokenInstruction<'a> { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). + /// Unpacks a byte buffer into a + /// [TokenInstruction](enum.TokenInstruction.html). pub fn unpack(input: &'a [u8]) -> Result { use TokenError::InvalidInstruction; @@ -574,7 +579,8 @@ impl<'a> TokenInstruction<'a> { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); match self { diff --git a/token/program/src/lib.rs b/token/program/src/lib.rs index 1eb3855df90..6506dd6cd42 100644 --- a/token/program/src/lib.rs +++ b/token/program/src/lib.rs @@ -13,22 +13,25 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}; -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount +/// Convert the UI representation of a token amount (using the decimals field +/// defined in its mint) to the raw amount pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { let decimals = decimals as usize; if decimals > 0 { @@ -53,12 +56,13 @@ pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { s } -/// Try to convert a UI representation of a token amount to its raw amount using the given decimals -/// field +/// Try to convert a UI representation of a token amount to its raw amount using +/// the given decimals field pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least length == 1 + let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at + // least length == 1 let after_decimal = parts.next().unwrap_or(""); let after_decimal = after_decimal.trim_end_matches('0'); if (amount_str.is_empty() && after_decimal.is_empty()) diff --git a/token/program/src/processor.rs b/token/program/src/processor.rs index a849382edff..550df44320e 100644 --- a/token/program/src/processor.rs +++ b/token/program/src/processor.rs @@ -141,7 +141,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account( program_id: &Pubkey, accounts: &[AccountInfo], @@ -149,7 +150,8 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, None, true) } - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account2( program_id: &Pubkey, accounts: &[AccountInfo], @@ -158,7 +160,8 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, Some(&owner), true) } - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount3](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account3( program_id: &Pubkey, accounts: &[AccountInfo], @@ -209,12 +212,14 @@ impl Processor { Ok(()) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, true) } - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, false) } @@ -789,7 +794,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction + /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let token_account_info = next_account_info(account_info_iter)?; diff --git a/token/program/src/state.rs b/token/program/src/state.rs index 062daab6bd6..fe23fbaafc4 100644 --- a/token/program/src/state.rs +++ b/token/program/src/state.rs @@ -16,9 +16,10 @@ use { #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Mint { - /// Optional authority used to mint new tokens. The mint authority may only be provided during - /// mint creation. If no mint authority is present then the mint has a fixed supply and no - /// further tokens may be minted. + /// Optional authority used to mint new tokens. The mint authority may only + /// be provided during mint creation. If no mint authority is present + /// then the mint has a fixed supply and no further tokens may be + /// minted. pub mint_authority: COption, /// Total supply of tokens. pub supply: u64, @@ -97,9 +98,10 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An - /// Account is required to be rent-exempt, so the value is used by the Processor to ensure that - /// wrapped SOL accounts do not drop below this threshold. + /// If is_native.is_some, this is a native token, and the value logs the + /// rent-exempt reserve. An Account is required to be rent-exempt, so + /// the value is used by the Processor to ensure that wrapped SOL + /// accounts do not drop below this threshold. pub is_native: COption, /// The amount delegated pub delegated_amount: u64, @@ -115,7 +117,8 @@ impl Account { pub fn is_native(&self) -> bool { self.is_native.is_some() } - /// Checks if a token Account's owner is the system_program or the incinerator + /// Checks if a token Account's owner is the system_program or the + /// incinerator pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { solana_program::system_program::check_id(&self.owner) || solana_program::incinerator::check_id(&self.owner) @@ -185,11 +188,12 @@ pub enum AccountState { /// Account is not yet initialized #[default] Uninitialized, - /// Account is initialized; the account owner and/or delegate may perform permitted operations - /// on this account + /// Account is initialized; the account owner and/or delegate may perform + /// permitted operations on this account Initialized, - /// Account has been frozen by the mint freeze authority. Neither the account owner nor - /// the delegate are able to perform operations on this account. + /// Account has been frozen by the mint freeze authority. Neither the + /// account owner nor the delegate are able to perform operations on + /// this account. Frozen, } @@ -292,24 +296,27 @@ fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; -/// A trait for token Account structs to enable efficiently unpacking various fields -/// without unpacking the complete state. +/// A trait for token Account structs to enable efficiently unpacking various +/// fields without unpacking the complete state. pub trait GenericTokenAccount { /// Check if the account data is a valid token account fn valid_account_data(account_data: &[u8]) -> bool; - /// Call after account length has already been verified to unpack the account owner + /// Call after account length has already been verified to unpack the + /// account owner fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) } - /// Call after account length has already been verified to unpack the account mint + /// Call after account length has already been verified to unpack the + /// account mint fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) } - /// Call after account length has already been verified to unpack a Pubkey at - /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` + /// Call after account length has already been verified to unpack a Pubkey + /// at the specified offset. Panics if `account_data.len()` is less than + /// `PUBKEY_BYTES` fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) } diff --git a/token/transfer-hook/example/src/processor.rs b/token/transfer-hook/example/src/processor.rs index fccd0ba0bae..16b2d1f11a7 100644 --- a/token/transfer-hook/example/src/processor.rs +++ b/token/transfer-hook/example/src/processor.rs @@ -73,7 +73,9 @@ pub fn process_execute( Ok(()) } -/// Processes a [InitializeExtraAccountMetaList](enum.TransferHookInstruction.html) instruction. +/// Processes a +/// [InitializeExtraAccountMetaList](enum.TransferHookInstruction.html) +/// instruction. pub fn process_initialize_extra_account_meta_list( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token/transfer-hook/interface/src/instruction.rs b/token/transfer-hook/interface/src/instruction.rs index a1fdcfea519..b0326efbe4c 100644 --- a/token/transfer-hook/interface/src/instruction.rs +++ b/token/transfer-hook/interface/src/instruction.rs @@ -26,8 +26,8 @@ pub enum TransferHookInstruction { /// 2. `[]` Destination account /// 3. `[]` Source account's owner/delegate /// 4. `[]` Validation account - /// 5..5+M `[]` `M` additional accounts, written in validation account data - /// + /// 5..5+M `[]` `M` additional accounts, written in validation account + /// data Execute { /// Amount of tokens to transfer amount: u64, @@ -41,15 +41,14 @@ pub enum TransferHookInstruction { /// 1. `[]` Mint /// 2. `[s]` Mint authority /// 3. `[]` System program - /// InitializeExtraAccountMetaList { /// List of `ExtraAccountMeta`s to write into the account extra_account_metas: Vec, }, } /// TLV instruction type only used to define the discriminator. The actual data -/// is entirely managed by `ExtraAccountMetaList`, and it is the only data contained -/// by this type. +/// is entirely managed by `ExtraAccountMetaList`, and it is the only data +/// contained by this type. #[derive(SplDiscriminate)] #[discriminator_hash_input("spl-transfer-hook-interface:execute")] pub struct ExecuteInstruction; @@ -61,7 +60,8 @@ pub struct ExecuteInstruction; pub struct InitializeExtraAccountMetaListInstruction; impl TransferHookInstruction { - /// Unpacks a byte buffer into a [TransferHookInstruction](enum.TransferHookInstruction.html). + /// Unpacks a byte buffer into a + /// [TransferHookInstruction](enum.TransferHookInstruction.html). pub fn unpack(input: &[u8]) -> Result { if input.len() < ArrayDiscriminator::LENGTH { return Err(ProgramError::InvalidInstructionData); @@ -87,7 +87,8 @@ impl TransferHookInstruction { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = vec![]; match self { diff --git a/token/transfer-hook/interface/src/lib.rs b/token/transfer-hook/interface/src/lib.rs index 20af3abe1ed..d22b7f89f18 100644 --- a/token/transfer-hook/interface/src/lib.rs +++ b/token/transfer-hook/interface/src/lib.rs @@ -12,7 +12,8 @@ pub mod instruction; pub mod offchain; pub mod onchain; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use solana_program::pubkey::Pubkey; diff --git a/token/transfer-hook/interface/src/onchain.rs b/token/transfer-hook/interface/src/onchain.rs index 1c0e0fb76ef..7eb52e3752a 100644 --- a/token/transfer-hook/interface/src/onchain.rs +++ b/token/transfer-hook/interface/src/onchain.rs @@ -1,4 +1,5 @@ -//! On-chain program invoke helper to perform on-chain `execute` with correct accounts +//! On-chain program invoke helper to perform on-chain `execute` with correct +//! accounts use { crate::{error::TransferHookError, get_extra_account_metas_address, instruction}, @@ -53,8 +54,8 @@ pub fn invoke_execute<'a>( invoke(&cpi_instruction, &cpi_account_infos) } -/// Helper to add accounts required for the transfer-hook program on-chain, looking -/// through the additional account infos to add the proper accounts +/// Helper to add accounts required for the transfer-hook program on-chain, +/// looking through the additional account infos to add the proper accounts pub fn add_cpi_accounts_for_execute<'a>( cpi_instruction: &mut Instruction, cpi_account_infos: &mut Vec>,