diff --git a/Cargo.lock b/Cargo.lock index 263f1f209bc..ece475e14eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3674,13 +3674,14 @@ dependencies = [ [[package]] name = "spl-governance" -version = "2.1.1" +version = "2.1.2" dependencies = [ "arrayref", "assert_matches", "base64 0.13.0", "bincode", "borsh", + "lazy_static", "num-derive", "num-traits", "proptest", @@ -3691,6 +3692,7 @@ dependencies = [ "solana-sdk", "spl-governance 1.1.1", "spl-governance-test-sdk", + "spl-governance-tools", "spl-token 3.2.0", "thiserror", ] @@ -3712,8 +3714,9 @@ dependencies = [ "solana-program", "solana-program-test", "solana-sdk", - "spl-governance 2.1.1", + "spl-governance 2.1.2", "spl-governance-test-sdk", + "spl-governance-tools", "spl-token 3.2.0", "thiserror", ] @@ -3736,6 +3739,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-governance-tools" +version = "0.1.0" +dependencies = [ + "arrayref", + "bincode", + "borsh", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-token 3.2.0", + "thiserror", +] + [[package]] name = "spl-governance-voter-weight-addin" version = "0.1.0" @@ -3753,9 +3772,9 @@ dependencies = [ "solana-program", "solana-program-test", "solana-sdk", - "spl-governance 2.1.1", - "spl-governance-chat", + "spl-governance 2.1.2", "spl-governance-test-sdk", + "spl-governance-tools", "spl-token 3.2.0", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index ad852ae1198..4b12838ec8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "governance/voter-weight-addin/program", "governance/program", "governance/test-sdk", + "governance/tools", "governance/chat/program", "libraries/math", "memo/program", diff --git a/governance/chat/program/Cargo.toml b/governance/chat/program/Cargo.toml index 705dcb7dd57..a26957dbb12 100644 --- a/governance/chat/program/Cargo.toml +++ b/governance/chat/program/Cargo.toml @@ -21,7 +21,8 @@ serde = "1.0.127" serde_derive = "1.0.103" solana-program = "1.8.0" spl-token = { version = "3.2", path = "../../../token/program", features = [ "no-entrypoint" ] } -spl-governance= { version = "2.1.0", path ="../../program", features = [ "no-entrypoint" ]} +spl-governance= { version = "2.1.2", path ="../../program", features = [ "no-entrypoint" ]} +spl-governance-tools= { version = "0.1.0", path ="../../tools"} thiserror = "1.0" diff --git a/governance/chat/program/src/lib.rs b/governance/chat/program/src/lib.rs index 04eaac9c5b7..3e314df865f 100644 --- a/governance/chat/program/src/lib.rs +++ b/governance/chat/program/src/lib.rs @@ -6,7 +6,6 @@ pub mod error; pub mod instruction; pub mod processor; pub mod state; -pub mod tools; // 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 e7099ed6283..90c7a1f3959 100644 --- a/governance/chat/program/src/processor.rs +++ b/governance/chat/program/src/processor.rs @@ -4,7 +4,6 @@ use crate::{ error::GovernanceChatError, instruction::GovernanceChatInstruction, state::{assert_is_valid_chat_message, ChatMessage, GovernanceChatAccountType, MessageBody}, - tools::account::create_and_serialize_account, }; use borsh::BorshDeserialize; @@ -21,6 +20,7 @@ use spl_governance::state::{ governance::get_governance_data, proposal::get_proposal_data_for_governance, token_owner_record::get_token_owner_record_data_for_realm, }; +use spl_governance_tools::account::create_and_serialize_account; /// Processes an instruction pub fn process_instruction( diff --git a/governance/chat/program/src/state.rs b/governance/chat/program/src/state.rs index f67623df8fc..fe0d816914f 100644 --- a/governance/chat/program/src/state.rs +++ b/governance/chat/program/src/state.rs @@ -4,7 +4,8 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use solana_program::{ account_info::AccountInfo, clock::UnixTimestamp, program_error::ProgramError, pubkey::Pubkey, }; -use spl_governance::tools::account::{assert_is_valid_account, AccountMaxSize}; + +use spl_governance_tools::account::{assert_is_valid_account, AccountMaxSize}; /// Defines all GovernanceChat accounts types #[repr(C)] diff --git a/governance/chat/program/src/tools/account.rs b/governance/chat/program/src/tools/account.rs deleted file mode 100644 index 48bf5a186ac..00000000000 --- a/governance/chat/program/src/tools/account.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! General purpose account utility functions - -use borsh::BorshSerialize; -use solana_program::{ - account_info::AccountInfo, program::invoke, program_error::ProgramError, pubkey::Pubkey, - rent::Rent, system_instruction::create_account, system_program, sysvar::Sysvar, -}; -use spl_governance::tools::account::AccountMaxSize; - -use crate::error::GovernanceChatError; - -/// 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>, - account_data: &T, - program_id: &Pubkey, - system_info: &AccountInfo<'a>, -) -> Result<(), ProgramError> { - // Assert the account is not initialized yet - if !(account_info.data_is_empty() && *account_info.owner == system_program::id()) { - return Err(GovernanceChatError::AccountAlreadyInitialized.into()); - } - - let (serialized_data, account_size) = if let Some(max_size) = account_data.get_max_size() { - (None, max_size) - } else { - let serialized_data = account_data.try_to_vec()?; - let account_size = serialized_data.len(); - (Some(serialized_data), account_size) - }; - - let rent = Rent::get()?; - - let create_account_instruction = create_account( - payer_info.key, - account_info.key, - rent.minimum_balance(account_size), - account_size as u64, - program_id, - ); - - invoke( - &create_account_instruction, - &[ - payer_info.clone(), - account_info.clone(), - system_info.clone(), - ], - )?; - - if let Some(serialized_data) = serialized_data { - account_info - .data - .borrow_mut() - .copy_from_slice(&serialized_data); - } else { - account_data.serialize(&mut *account_info.data.borrow_mut())?; - } - - Ok(()) -} diff --git a/governance/chat/program/src/tools/mod.rs b/governance/chat/program/src/tools/mod.rs deleted file mode 100644 index 5cb1ab5f753..00000000000 --- a/governance/chat/program/src/tools/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Utility functions - -pub mod account; diff --git a/governance/program/Cargo.toml b/governance/program/Cargo.toml index 1fc8c17bb85..af1a411025b 100644 --- a/governance/program/Cargo.toml +++ b/governance/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-governance" -version = "2.1.1" +version = "2.1.2" description = "Solana Program Library Governance Program" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" @@ -21,17 +21,18 @@ serde = "1.0.130" serde_derive = "1.0.103" solana-program = "1.8.0" spl-token = { version = "3.2", path = "../../token/program", features = [ "no-entrypoint" ] } +spl-governance-tools= { version = "0.1.0", path ="../tools"} thiserror = "1.0" [dev-dependencies] assert_matches = "1.5.0" base64 = "0.13" +lazy_static = "1.4.0" proptest = "1.0" solana-program-test = "1.8.0" solana-sdk = "1.8.0" spl-governance-test-sdk = { version = "0.1.0", path ="../test-sdk"} spl-governance-v1 = {package="spl-governance", version = "1.1.1", features = [ "no-entrypoint" ] } - [lib] crate-type = ["cdylib", "lib"] diff --git a/governance/program/src/addins/voter_weight.rs b/governance/program/src/addins/voter_weight.rs index 2ef864b37ee..e8ee8813f24 100644 --- a/governance/program/src/addins/voter_weight.rs +++ b/governance/program/src/addins/voter_weight.rs @@ -9,12 +9,9 @@ use solana_program::{ pubkey::Pubkey, sysvar::Sysvar, }; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; -use crate::{ - error::GovernanceError, - state::token_owner_record::TokenOwnerRecord, - tools::account::{get_account_data, AccountMaxSize}, -}; +use crate::{error::GovernanceError, state::token_owner_record::TokenOwnerRecord}; /// VoterWeight account type #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] @@ -82,7 +79,7 @@ pub fn get_voter_weight_record_data( program_id: &Pubkey, voter_weight_record_info: &AccountInfo, ) -> Result { - get_account_data::(voter_weight_record_info, program_id) + 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 diff --git a/governance/program/src/error.rs b/governance/program/src/error.rs index 75b04b1654f..06a84c5c291 100644 --- a/governance/program/src/error.rs +++ b/governance/program/src/error.rs @@ -162,20 +162,6 @@ pub enum GovernanceError { #[error("Invalid Signatory Mint")] InvalidSignatoryMint, - /// ---- Account Tools Errors ---- - - /// Invalid account owner - #[error("Invalid account owner")] - InvalidAccountOwner, - - /// Account doesn't exist - #[error("Account doesn't exist")] - AccountDoesNotExist, - - /// Invalid Account type - #[error("Invalid Account type")] - InvalidAccountType, - /// Proposal does not belong to the given Governance #[error("Proposal does not belong to the given Governance")] InvalidGovernanceForProposal, diff --git a/governance/program/src/processor/process_add_signatory.rs b/governance/program/src/processor/process_add_signatory.rs index 2e44cc32099..f443b4983ee 100644 --- a/governance/program/src/processor/process_add_signatory.rs +++ b/governance/program/src/processor/process_add_signatory.rs @@ -8,15 +8,13 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; -use crate::{ - state::{ - enums::GovernanceAccountType, - proposal::get_proposal_data, - signatory_record::{get_signatory_record_address_seeds, SignatoryRecord}, - token_owner_record::get_token_owner_record_data_for_proposal_owner, - }, - tools::account::create_and_serialize_account_signed, +use crate::state::{ + enums::GovernanceAccountType, + proposal::get_proposal_data, + signatory_record::{get_signatory_record_address_seeds, SignatoryRecord}, + token_owner_record::get_token_owner_record_data_for_proposal_owner, }; /// Processes AddSignatory instruction diff --git a/governance/program/src/processor/process_cast_vote.rs b/governance/program/src/processor/process_cast_vote.rs index 13a130f450c..49b0b846ff8 100644 --- a/governance/program/src/processor/process_cast_vote.rs +++ b/governance/program/src/processor/process_cast_vote.rs @@ -8,6 +8,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -23,7 +24,7 @@ use crate::{ }, vote_record::{get_vote_record_address_seeds, VoteRecord}, }, - tools::{account::create_and_serialize_account_signed, spl_token::get_spl_token_mint_supply}, + tools::spl_token::get_spl_token_mint_supply, }; use borsh::BorshSerialize; diff --git a/governance/program/src/processor/process_create_account_governance.rs b/governance/program/src/processor/process_create_account_governance.rs index 52e1560723e..116dfc416de 100644 --- a/governance/program/src/processor/process_create_account_governance.rs +++ b/governance/program/src/processor/process_create_account_governance.rs @@ -1,16 +1,13 @@ //! Program state processor -use crate::{ - state::{ - enums::GovernanceAccountType, - governance::{ - assert_valid_create_governance_args, get_account_governance_address_seeds, Governance, - GovernanceConfig, - }, - realm::get_realm_data, - token_owner_record::get_token_owner_record_data_for_realm, +use crate::state::{ + enums::GovernanceAccountType, + governance::{ + assert_valid_create_governance_args, get_account_governance_address_seeds, Governance, + GovernanceConfig, }, - tools::account::create_and_serialize_account_signed, + realm::get_realm_data, + token_owner_record::get_token_owner_record_data_for_realm, }; use solana_program::{ account_info::{next_account_info, AccountInfo}, @@ -19,6 +16,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; /// Processes CreateAccountGovernance instruction pub fn process_create_account_governance( diff --git a/governance/program/src/processor/process_create_mint_governance.rs b/governance/program/src/processor/process_create_mint_governance.rs index 9ecd2b34049..2a235bdf419 100644 --- a/governance/program/src/processor/process_create_mint_governance.rs +++ b/governance/program/src/processor/process_create_mint_governance.rs @@ -10,10 +10,7 @@ use crate::{ realm::get_realm_data, token_owner_record::get_token_owner_record_data_for_realm, }, - tools::{ - account::create_and_serialize_account_signed, - spl_token::{assert_spl_token_mint_authority_is_signer, set_spl_token_mint_authority}, - }, + tools::spl_token::{assert_spl_token_mint_authority_is_signer, set_spl_token_mint_authority}, }; use solana_program::{ account_info::{next_account_info, AccountInfo}, @@ -22,6 +19,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; /// Processes CreateMintGovernance instruction pub fn process_create_mint_governance( diff --git a/governance/program/src/processor/process_create_program_governance.rs b/governance/program/src/processor/process_create_program_governance.rs index b7359ed70e6..15ce01f38ae 100644 --- a/governance/program/src/processor/process_create_program_governance.rs +++ b/governance/program/src/processor/process_create_program_governance.rs @@ -11,11 +11,8 @@ use crate::{ realm::get_realm_data, token_owner_record::get_token_owner_record_data_for_realm, }, - tools::{ - account::create_and_serialize_account_signed, - bpf_loader_upgradeable::{ - assert_program_upgrade_authority_is_signer, set_program_upgrade_authority, - }, + tools::bpf_loader_upgradeable::{ + assert_program_upgrade_authority_is_signer, set_program_upgrade_authority, }, }; use solana_program::{ @@ -25,6 +22,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; /// Processes CreateProgramGovernance instruction pub fn process_create_program_governance( diff --git a/governance/program/src/processor/process_create_proposal.rs b/governance/program/src/processor/process_create_proposal.rs index 4a094a6409d..52d6197cd24 100644 --- a/governance/program/src/processor/process_create_proposal.rs +++ b/governance/program/src/processor/process_create_proposal.rs @@ -9,6 +9,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -19,7 +20,6 @@ use crate::{ realm::get_realm_data_for_governing_token_mint, token_owner_record::get_token_owner_record_data_for_realm, }, - tools::account::create_and_serialize_account_signed, }; /// Processes CreateProposal instruction diff --git a/governance/program/src/processor/process_create_realm.rs b/governance/program/src/processor/process_create_realm.rs index 0e425efdfea..a4f62572256 100644 --- a/governance/program/src/processor/process_create_realm.rs +++ b/governance/program/src/processor/process_create_realm.rs @@ -7,6 +7,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -18,9 +19,7 @@ use crate::{ }, realm_config::{get_realm_config_address_seeds, RealmConfigAccount}, }, - tools::{ - account::create_and_serialize_account_signed, spl_token::create_spl_token_account_signed, - }, + tools::spl_token::create_spl_token_account_signed, }; /// Processes CreateRealm instruction @@ -92,9 +91,9 @@ pub fn process_create_realm( account_type: GovernanceAccountType::RealmConfig, realm: *realm_info.key, community_voter_weight_addin: Some(*community_voter_weight_addin_info.key), - reserved_1: None, - reserved_2: None, - reserved_3: None, + community_max_vote_weight_addin: None, + council_voter_weight_addin: None, + council_max_vote_weight_addin: None, reserved: [0; 128], }; diff --git a/governance/program/src/processor/process_create_token_governance.rs b/governance/program/src/processor/process_create_token_governance.rs index a1dde948154..f7f2c32eba5 100644 --- a/governance/program/src/processor/process_create_token_governance.rs +++ b/governance/program/src/processor/process_create_token_governance.rs @@ -10,10 +10,7 @@ use crate::{ realm::get_realm_data, token_owner_record::get_token_owner_record_data_for_realm, }, - tools::{ - account::create_and_serialize_account_signed, - spl_token::{assert_spl_token_owner_is_signer, set_spl_token_owner}, - }, + tools::spl_token::{assert_spl_token_owner_is_signer, set_spl_token_owner}, }; use solana_program::{ account_info::{next_account_info, AccountInfo}, @@ -22,6 +19,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; /// Processes CreateTokenGovernance instruction pub fn process_create_token_governance( diff --git a/governance/program/src/processor/process_create_token_owner_record.rs b/governance/program/src/processor/process_create_token_owner_record.rs index d643592fdc0..20bc544750c 100644 --- a/governance/program/src/processor/process_create_token_owner_record.rs +++ b/governance/program/src/processor/process_create_token_owner_record.rs @@ -7,6 +7,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -15,7 +16,6 @@ use crate::{ realm::get_realm_data, token_owner_record::{get_token_owner_record_address_seeds, TokenOwnerRecord}, }, - tools::account::create_and_serialize_account_signed, }; /// Processes CreateTokenOwnerRecord instruction diff --git a/governance/program/src/processor/process_deposit_governing_tokens.rs b/governance/program/src/processor/process_deposit_governing_tokens.rs index c5588bd9f69..b09b0a4630e 100644 --- a/governance/program/src/processor/process_deposit_governing_tokens.rs +++ b/governance/program/src/processor/process_deposit_governing_tokens.rs @@ -8,6 +8,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -19,10 +20,7 @@ use crate::{ TokenOwnerRecord, }, }, - tools::{ - account::create_and_serialize_account_signed, - spl_token::{get_spl_token_mint, get_spl_token_owner, transfer_spl_tokens}, - }, + tools::spl_token::{get_spl_token_mint, get_spl_token_owner, transfer_spl_tokens}, }; /// Processes DepositGoverningTokens instruction diff --git a/governance/program/src/processor/process_insert_instruction.rs b/governance/program/src/processor/process_insert_instruction.rs index a4e8196efb6..5a072863a63 100644 --- a/governance/program/src/processor/process_insert_instruction.rs +++ b/governance/program/src/processor/process_insert_instruction.rs @@ -10,6 +10,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -22,7 +23,6 @@ use crate::{ }, token_owner_record::get_token_owner_record_data_for_proposal_owner, }, - tools::account::create_and_serialize_account_signed, }; /// Processes InsertInstruction instruction diff --git a/governance/program/src/processor/process_relinquish_vote.rs b/governance/program/src/processor/process_relinquish_vote.rs index 0e0d6c74357..ab81363e209 100644 --- a/governance/program/src/processor/process_relinquish_vote.rs +++ b/governance/program/src/processor/process_relinquish_vote.rs @@ -5,16 +5,14 @@ use solana_program::{ entrypoint::ProgramResult, pubkey::Pubkey, }; - -use crate::{ - state::{ - enums::{ProposalState, VoteWeight}, - governance::get_governance_data, - proposal::get_proposal_data_for_governance_and_governing_mint, - token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, - vote_record::get_vote_record_data_for_proposal_and_token_owner, - }, - tools::account::dispose_account, +use spl_governance_tools::account::dispose_account; + +use crate::state::{ + enums::{ProposalState, VoteWeight}, + governance::get_governance_data, + proposal::get_proposal_data_for_governance_and_governing_mint, + token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, + vote_record::get_vote_record_data_for_proposal_and_token_owner, }; use borsh::BorshSerialize; diff --git a/governance/program/src/processor/process_remove_instruction.rs b/governance/program/src/processor/process_remove_instruction.rs index 8e9ffb6d6fd..3387766a472 100644 --- a/governance/program/src/processor/process_remove_instruction.rs +++ b/governance/program/src/processor/process_remove_instruction.rs @@ -6,14 +6,11 @@ use solana_program::{ entrypoint::ProgramResult, pubkey::Pubkey, }; +use spl_governance_tools::account::dispose_account; -use crate::{ - state::{ - proposal::get_proposal_data, - proposal_instruction::assert_proposal_instruction_for_proposal, - token_owner_record::get_token_owner_record_data_for_proposal_owner, - }, - tools::account::dispose_account, +use crate::state::{ + proposal::get_proposal_data, proposal_instruction::assert_proposal_instruction_for_proposal, + token_owner_record::get_token_owner_record_data_for_proposal_owner, }; /// Processes RemoveInstruction instruction diff --git a/governance/program/src/processor/process_remove_signatory.rs b/governance/program/src/processor/process_remove_signatory.rs index 01dbed95200..7f40b7aa970 100644 --- a/governance/program/src/processor/process_remove_signatory.rs +++ b/governance/program/src/processor/process_remove_signatory.rs @@ -6,13 +6,11 @@ use solana_program::{ entrypoint::ProgramResult, pubkey::Pubkey, }; +use spl_governance_tools::account::dispose_account; -use crate::{ - state::{ - proposal::get_proposal_data, signatory_record::get_signatory_record_data_for_seeds, - token_owner_record::get_token_owner_record_data_for_proposal_owner, - }, - tools::account::dispose_account, +use crate::state::{ + proposal::get_proposal_data, signatory_record::get_signatory_record_data_for_seeds, + token_owner_record::get_token_owner_record_data_for_proposal_owner, }; /// Processes RemoveSignatory instruction diff --git a/governance/program/src/processor/process_set_realm_config.rs b/governance/program/src/processor/process_set_realm_config.rs index a9093a76d6f..dd597af9644 100644 --- a/governance/program/src/processor/process_set_realm_config.rs +++ b/governance/program/src/processor/process_set_realm_config.rs @@ -8,6 +8,7 @@ use solana_program::{ rent::Rent, sysvar::Sysvar, }; +use spl_governance_tools::account::create_and_serialize_account_signed; use crate::{ error::GovernanceError, @@ -18,7 +19,6 @@ use crate::{ get_realm_config_address_seeds, get_realm_config_data_for_realm, RealmConfigAccount, }, }, - tools::account::create_and_serialize_account_signed, }; /// Processes SetRealmConfig instruction @@ -77,9 +77,9 @@ pub fn process_set_realm_config( account_type: GovernanceAccountType::RealmConfig, realm: *realm_info.key, community_voter_weight_addin: Some(*community_voter_weight_addin_info.key), - reserved_1: None, - reserved_2: None, - reserved_3: None, + community_max_vote_weight_addin: None, + council_voter_weight_addin: None, + council_max_vote_weight_addin: None, reserved: [0; 128], }; diff --git a/governance/program/src/state/governance.rs b/governance/program/src/state/governance.rs index e21c2aae0d2..875da18e8b9 100644 --- a/governance/program/src/state/governance.rs +++ b/governance/program/src/state/governance.rs @@ -6,13 +6,16 @@ use crate::{ enums::{GovernanceAccountType, VoteThresholdPercentage, VoteWeightSource}, realm::assert_is_valid_realm, }, - tools::account::{get_account_data, AccountMaxSize}, }; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use solana_program::{ account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::{ + account::{get_account_data, AccountMaxSize}, + error::GovernanceToolsError, +}; /// Governance config #[repr(C)] @@ -94,7 +97,7 @@ impl Governance { GovernanceAccountType::TokenGovernance => { get_token_governance_address_seeds(&self.realm, &self.governed_account) } - _ => return Err(GovernanceError::InvalidAccountType.into()), + _ => return Err(GovernanceToolsError::InvalidAccountType.into()), }; Ok(seeds) @@ -106,7 +109,7 @@ pub fn get_governance_data( program_id: &Pubkey, governance_info: &AccountInfo, ) -> Result { - get_account_data::(governance_info, program_id) + get_account_data::(program_id, governance_info) } /// Deserializes Governance account, checks owner program and asserts governance belongs to the given ream diff --git a/governance/program/src/state/proposal.rs b/governance/program/src/state/proposal.rs index d48c8673ff3..48a20b271cf 100644 --- a/governance/program/src/state/proposal.rs +++ b/governance/program/src/state/proposal.rs @@ -6,6 +6,7 @@ use solana_program::{ account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; use crate::{ error::GovernanceError, @@ -18,7 +19,6 @@ use crate::{ proposal_instruction::ProposalInstruction, realm::Realm, }, - tools::account::{get_account_data, AccountMaxSize}, PROGRAM_AUTHORITY_SEED, }; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -450,7 +450,7 @@ pub fn get_proposal_data( program_id: &Pubkey, proposal_info: &AccountInfo, ) -> Result { - get_account_data::(proposal_info, program_id) + get_account_data::(program_id, proposal_info) } /// Deserializes Proposal and validates it belongs to the given Governance and Governing Mint diff --git a/governance/program/src/state/proposal_instruction.rs b/governance/program/src/state/proposal_instruction.rs index e6b706f8073..e3ffb4925ca 100644 --- a/governance/program/src/state/proposal_instruction.rs +++ b/governance/program/src/state/proposal_instruction.rs @@ -3,7 +3,6 @@ use crate::{ error::GovernanceError, state::enums::{GovernanceAccountType, InstructionExecutionStatus}, - tools::account::{get_account_data, AccountMaxSize}, PROGRAM_AUTHORITY_SEED, }; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -15,6 +14,7 @@ use solana_program::{ program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; /// InstructionData wrapper. It can be removed once Borsh serialization for Instruction is supported in the SDK #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] @@ -146,7 +146,7 @@ pub fn get_proposal_instruction_data( program_id: &Pubkey, proposal_instruction_info: &AccountInfo, ) -> Result { - get_account_data::(proposal_instruction_info, program_id) + get_account_data::(program_id, proposal_instruction_info) } /// Deserializes and returns ProposalInstruction account and checks it belongs to the given Proposal diff --git a/governance/program/src/state/realm.rs b/governance/program/src/state/realm.rs index 6e04188df72..9f81b0fc79f 100644 --- a/governance/program/src/state/realm.rs +++ b/governance/program/src/state/realm.rs @@ -5,11 +5,11 @@ use solana_program::{ account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::account::{assert_is_valid_account, get_account_data, AccountMaxSize}; use crate::{ error::GovernanceError, state::enums::{GovernanceAccountType, MintMaxVoteWeightSource}, - tools::account::{assert_is_valid_account, get_account_data, AccountMaxSize}, PROGRAM_AUTHORITY_SEED, }; @@ -155,7 +155,7 @@ pub fn get_realm_data( program_id: &Pubkey, realm_info: &AccountInfo, ) -> Result { - get_account_data::(realm_info, program_id) + get_account_data::(program_id, realm_info) } /// Deserializes account and checks the given authority is Realm's authority @@ -164,7 +164,7 @@ pub fn get_realm_data_for_authority( realm_info: &AccountInfo, realm_authority: &Pubkey, ) -> Result { - let realm_data = get_account_data::(realm_info, program_id)?; + let realm_data = get_account_data::(program_id, realm_info)?; if realm_data.authority.is_none() { return Err(GovernanceError::RealmHasNoAuthority.into()); diff --git a/governance/program/src/state/realm_config.rs b/governance/program/src/state/realm_config.rs index 4b131d77579..9f0f05326cd 100644 --- a/governance/program/src/state/realm_config.rs +++ b/governance/program/src/state/realm_config.rs @@ -6,12 +6,9 @@ use solana_program::{ }; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; -use crate::{ - error::GovernanceError, - state::enums::GovernanceAccountType, - tools::account::{get_account_data, AccountMaxSize}, -}; +use crate::{error::GovernanceError, state::enums::GovernanceAccountType}; /// RealmConfig account /// The account is an optional extension to RealmConfig stored on Realm account @@ -26,14 +23,17 @@ pub struct RealmConfigAccount { /// Addin providing voter weights for community token pub community_voter_weight_addin: Option, - /// Reserved for community max vote weight addin - pub reserved_1: Option, + /// Addin providing max vote weight for community token + /// Note: This field is not implemented in the current version + pub community_max_vote_weight_addin: Option, - /// Reserved for council voter weight addin - pub reserved_2: Option, + /// Addin providing voter weights for council token + /// Note: This field is not implemented in the current version + pub council_voter_weight_addin: Option, - /// Reserved for council max vote weight addin - pub reserved_3: Option, + /// Addin providing max vote weight for council token + /// Note: This field is not implemented in the current version + pub council_max_vote_weight_addin: Option, /// Reserved pub reserved: [u8; 128], @@ -56,7 +56,7 @@ pub fn get_realm_config_data( program_id: &Pubkey, realm_config_info: &AccountInfo, ) -> Result { - get_account_data::(realm_config_info, program_id) + get_account_data::(program_id, realm_config_info) } /// Deserializes RealmConfig account and checks the owner program and the Realm it belongs to @@ -95,9 +95,9 @@ mod test { account_type: GovernanceAccountType::Realm, realm: Pubkey::new_unique(), community_voter_weight_addin: Some(Pubkey::new_unique()), - reserved_1: Some(Pubkey::new_unique()), - reserved_2: Some(Pubkey::new_unique()), - reserved_3: Some(Pubkey::new_unique()), + community_max_vote_weight_addin: Some(Pubkey::new_unique()), + council_voter_weight_addin: Some(Pubkey::new_unique()), + council_max_vote_weight_addin: Some(Pubkey::new_unique()), reserved: [0; 128], }; diff --git a/governance/program/src/state/signatory_record.rs b/governance/program/src/state/signatory_record.rs index d9e6d058a0e..337b1efe2ae 100644 --- a/governance/program/src/state/signatory_record.rs +++ b/governance/program/src/state/signatory_record.rs @@ -5,12 +5,9 @@ use solana_program::{ account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; -use crate::{ - error::GovernanceError, - tools::account::{get_account_data, AccountMaxSize}, - PROGRAM_AUTHORITY_SEED, -}; +use crate::{error::GovernanceError, PROGRAM_AUTHORITY_SEED}; use crate::state::enums::GovernanceAccountType; @@ -93,7 +90,7 @@ pub fn get_signatory_record_data( program_id: &Pubkey, signatory_record_info: &AccountInfo, ) -> Result { - get_account_data::(signatory_record_info, program_id) + get_account_data::(program_id, signatory_record_info) } /// Deserializes SignatoryRecord and validates its PDA diff --git a/governance/program/src/state/token_owner_record.rs b/governance/program/src/state/token_owner_record.rs index 3aeed227729..79081f2f3f7 100644 --- a/governance/program/src/state/token_owner_record.rs +++ b/governance/program/src/state/token_owner_record.rs @@ -9,7 +9,6 @@ use crate::{ enums::GovernanceAccountType, governance::GovernanceConfig, realm::Realm, realm_config::get_realm_config_data_for_realm, }, - tools::account::{get_account_data, AccountMaxSize}, PROGRAM_AUTHORITY_SEED, }; @@ -20,6 +19,7 @@ use solana_program::{ program_pack::IsInitialized, pubkey::Pubkey, }; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; /// Governance Token Owner Record /// Account PDA seeds: ['governance', realm, token_mint, token_owner ] @@ -241,7 +241,7 @@ pub fn get_token_owner_record_data( program_id: &Pubkey, token_owner_record_info: &AccountInfo, ) -> Result { - get_account_data::(token_owner_record_info, program_id) + get_account_data::(program_id, token_owner_record_info) } /// Deserializes TokenOwnerRecord account and checks its PDA against the provided seeds diff --git a/governance/program/src/state/vote_record.rs b/governance/program/src/state/vote_record.rs index a946e090cc4..29dd6ebc936 100644 --- a/governance/program/src/state/vote_record.rs +++ b/governance/program/src/state/vote_record.rs @@ -4,10 +4,11 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use solana_program::account_info::AccountInfo; use solana_program::program_error::ProgramError; use solana_program::{program_pack::IsInitialized, pubkey::Pubkey}; +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; use crate::error::GovernanceError; -use crate::tools::account::get_account_data; -use crate::{tools::account::AccountMaxSize, PROGRAM_AUTHORITY_SEED}; + +use crate::PROGRAM_AUTHORITY_SEED; use crate::state::enums::{GovernanceAccountType, VoteWeight}; @@ -55,7 +56,7 @@ pub fn get_vote_record_data( program_id: &Pubkey, vote_record_info: &AccountInfo, ) -> Result { - get_account_data::(vote_record_info, program_id) + get_account_data::(program_id, vote_record_info) } /// Deserializes VoteRecord and checks it belongs to the provided Proposal and Governing Token Owner diff --git a/governance/program/src/tools/mod.rs b/governance/program/src/tools/mod.rs index 6d895ce73ee..92d42769369 100644 --- a/governance/program/src/tools/mod.rs +++ b/governance/program/src/tools/mod.rs @@ -1,7 +1,5 @@ //! Utility functions -pub mod account; - pub mod spl_token; pub mod bpf_loader_upgradeable; diff --git a/governance/program/tests/fixtures/spl_governance_voter_weight_addin.so b/governance/program/tests/fixtures/spl_governance_voter_weight_addin.so deleted file mode 100755 index ef99326389d..00000000000 Binary files a/governance/program/tests/fixtures/spl_governance_voter_weight_addin.so and /dev/null differ diff --git a/governance/program/tests/process_create_account_governance.rs b/governance/program/tests/process_create_account_governance.rs index 827c3ce770f..6f71e5e8747 100644 --- a/governance/program/tests/process_create_account_governance.rs +++ b/governance/program/tests/process_create_account_governance.rs @@ -5,6 +5,7 @@ use solana_program_test::*; use program_test::*; use spl_governance::{error::GovernanceError, state::enums::VoteThresholdPercentage}; +use spl_governance_tools::error::GovernanceToolsError; #[tokio::test] async fn test_create_account_governance() { @@ -77,7 +78,7 @@ async fn test_create_account_governance_with_invalid_realm_error() { // Assert - assert_eq!(err, GovernanceError::InvalidAccountType.into()); + assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); } #[tokio::test] diff --git a/governance/program/tests/process_create_mint_governance.rs b/governance/program/tests/process_create_mint_governance.rs index 279fcb80040..0d9e2bd0375 100644 --- a/governance/program/tests/process_create_mint_governance.rs +++ b/governance/program/tests/process_create_mint_governance.rs @@ -6,6 +6,7 @@ use solana_program_test::*; use program_test::*; use solana_sdk::{signature::Keypair, signer::Signer}; use spl_governance::error::GovernanceError; +use spl_governance_tools::error::GovernanceToolsError; use spl_token::error::TokenError; #[tokio::test] @@ -223,5 +224,5 @@ async fn test_create_mint_governance_with_invalid_realm_error() { .unwrap(); // Assert - assert_eq!(err, GovernanceError::InvalidAccountType.into()); + assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); } diff --git a/governance/program/tests/process_create_program_governance.rs b/governance/program/tests/process_create_program_governance.rs index 3b9782b27c8..e8dd1414bee 100644 --- a/governance/program/tests/process_create_program_governance.rs +++ b/governance/program/tests/process_create_program_governance.rs @@ -9,6 +9,7 @@ use spl_governance::{ error::GovernanceError, tools::bpf_loader_upgradeable::get_program_upgrade_authority, }; use spl_governance_test_sdk::tools::ProgramInstructionError; +use spl_governance_tools::error::GovernanceToolsError; #[tokio::test] async fn test_create_program_governance() { @@ -232,5 +233,5 @@ async fn test_create_program_governance_with_invalid_realm_error() { .unwrap(); // Assert - assert_eq!(err, GovernanceError::InvalidAccountType.into()); + assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); } diff --git a/governance/program/tests/process_create_token_governance.rs b/governance/program/tests/process_create_token_governance.rs index eaac98dcfca..8c48c242fc5 100644 --- a/governance/program/tests/process_create_token_governance.rs +++ b/governance/program/tests/process_create_token_governance.rs @@ -6,6 +6,8 @@ use solana_program_test::*; use program_test::*; use solana_sdk::{signature::Keypair, signer::Signer}; use spl_governance::error::GovernanceError; +use spl_governance_tools::error::GovernanceToolsError; + use spl_token::error::TokenError; #[tokio::test] @@ -221,5 +223,5 @@ async fn test_create_token_governance_with_invalid_realm_error() { .unwrap(); // Assert - assert_eq!(err, GovernanceError::InvalidAccountType.into()); + assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); } diff --git a/governance/program/tests/process_set_governance_config.rs b/governance/program/tests/process_set_governance_config.rs index 95a5b04f027..976766161c7 100644 --- a/governance/program/tests/process_set_governance_config.rs +++ b/governance/program/tests/process_set_governance_config.rs @@ -12,6 +12,8 @@ use spl_governance::{ }; use spl_governance_test_sdk::tools::ProgramInstructionError; +use spl_governance_tools::error::GovernanceToolsError; + #[tokio::test] async fn test_set_governance_config() { // Arrange @@ -145,7 +147,7 @@ async fn test_set_governance_config_with_fake_governance_signer_error() { .unwrap(); // Assert - assert_eq!(err, GovernanceError::AccountDoesNotExist.into()); + assert_eq!(err, GovernanceToolsError::AccountDoesNotExist.into()); } #[tokio::test] diff --git a/governance/program/tests/program_test/addins.rs b/governance/program/tests/program_test/addins.rs new file mode 100644 index 00000000000..f3aafed9d0e --- /dev/null +++ b/governance/program/tests/program_test/addins.rs @@ -0,0 +1,24 @@ +use lazy_static::lazy_static; +use solana_program_test::find_file; +use std::{process::Command, sync::Mutex}; + +lazy_static! { + pub static ref VOTER_WEIGHT_ADDIN_BUILD_GUARD: Mutex:: = Mutex::new(0); +} + +pub fn ensure_voter_weight_addin_is_built() { + if find_file("spl_governance_voter_weight_addin.so").is_none() { + let _guard = VOTER_WEIGHT_ADDIN_BUILD_GUARD.lock().unwrap(); + if find_file("spl_governance_voter_weight_addin.so").is_none() { + assert!(Command::new("cargo") + .args(&[ + "build-bpf", + "--manifest-path", + "../voter-weight-addin/program/Cargo.toml", + ]) + .status() + .expect("Failed to build voter-weight-addin program") + .success()); + } + } +} diff --git a/governance/program/tests/program_test/mod.rs b/governance/program/tests/program_test/mod.rs index 5c62a795009..88296b23680 100644 --- a/governance/program/tests/program_test/mod.rs +++ b/governance/program/tests/program_test/mod.rs @@ -52,6 +52,7 @@ use spl_governance::{ tools::bpf_loader_upgradeable::get_program_data_address, }; +pub mod addins; pub mod cookies; use crate::program_test::cookies::{ @@ -63,10 +64,13 @@ use spl_governance_test_sdk::{ ProgramTestBench, TestBenchProgram, }; -use self::cookies::{ - GovernanceCookie, GovernedAccountCookie, GovernedMintCookie, GovernedProgramCookie, - GovernedTokenCookie, ProposalCookie, ProposalInstructionCookie, RealmCookie, - TokenOwnerRecordCookie, VoteRecordCookie, +use self::{ + addins::ensure_voter_weight_addin_is_built, + cookies::{ + GovernanceCookie, GovernedAccountCookie, GovernedMintCookie, GovernedProgramCookie, + GovernedTokenCookie, ProposalCookie, ProposalInstructionCookie, RealmCookie, + TokenOwnerRecordCookie, VoteRecordCookie, + }, }; pub struct GovernanceProgramTest { @@ -84,6 +88,8 @@ impl GovernanceProgramTest { #[allow(dead_code)] pub async fn start_with_voter_weight_addin() -> Self { + ensure_voter_weight_addin_is_built(); + Self::start_impl(true).await } @@ -251,9 +257,9 @@ impl GovernanceProgramTest { account_type: GovernanceAccountType::RealmConfig, realm: realm_address, community_voter_weight_addin: self.voter_weight_addin_id, - reserved_1: None, - reserved_2: None, - reserved_3: None, + community_max_vote_weight_addin: None, + council_voter_weight_addin: None, + council_max_vote_weight_addin: None, reserved: [0; 128], }, }) @@ -815,9 +821,9 @@ impl GovernanceProgramTest { community_voter_weight_addin: Some( set_realm_config_ix.accounts[community_voter_weight_addin_index].pubkey, ), - reserved_1: None, - reserved_2: None, - reserved_3: None, + community_max_vote_weight_addin: None, + council_voter_weight_addin: None, + council_max_vote_weight_addin: None, reserved: [0; 128], }, }) @@ -2194,8 +2200,6 @@ impl GovernanceProgramTest { // Governance program has no dependency on the voter-weight-addin program and hence we can't use its instruction creator here // and the instruction has to be created manually - // TODO: Currently the addin spl_governance_voter_weight_addin.so must be manually copied to tests/fixtures to work on CI - // We should automate this step as part of the build to build the addin before governance let accounts = vec![ AccountMeta::new_readonly(self.program_id, false), AccountMeta::new_readonly(token_owner_record_cookie.account.realm, false), diff --git a/governance/test-sdk/README.md b/governance/test-sdk/README.md new file mode 100644 index 00000000000..6783b5109fd --- /dev/null +++ b/governance/test-sdk/README.md @@ -0,0 +1,3 @@ +# Governance Test SDK + +Governance test SDK is a set of test utility functions used across the governance programs ecosystem diff --git a/governance/tools/Cargo.toml b/governance/tools/Cargo.toml new file mode 100644 index 00000000000..766999595df --- /dev/null +++ b/governance/tools/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "spl-governance-tools" +version = "0.1.0" +description = "Solana Program Library Governance Tools" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2018" + +[dependencies] +arrayref = "0.3.6" +bincode = "1.3.2" +borsh = "0.9.1" +num-derive = "0.3" +num-traits = "0.2" +serde = "1.0.127" +serde_derive = "1.0.103" +solana-program = "1.8.0" +spl-token = { version = "3.2", path = "../../token/program", features = [ "no-entrypoint" ] } +thiserror = "1.0" diff --git a/governance/tools/README.md b/governance/tools/README.md new file mode 100644 index 00000000000..070f802463d --- /dev/null +++ b/governance/tools/README.md @@ -0,0 +1,3 @@ +# Governance Tool + +Governance tools is a set of general purpose utility functions used across the governance programs ecosystem diff --git a/governance/program/src/tools/account.rs b/governance/tools/src/account.rs similarity index 66% rename from governance/program/src/tools/account.rs rename to governance/tools/src/account.rs index 07c7059bd13..526d67041f6 100644 --- a/governance/program/src/tools/account.rs +++ b/governance/tools/src/account.rs @@ -2,12 +2,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::{ - account_info::AccountInfo, borsh::try_from_slice_unchecked, msg, program::invoke_signed, - program_error::ProgramError, program_pack::IsInitialized, pubkey::Pubkey, rent::Rent, - system_instruction::create_account, + account_info::AccountInfo, borsh::try_from_slice_unchecked, msg, program::invoke, + program::invoke_signed, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, rent::Rent, system_instruction::create_account, system_program, sysvar::Sysvar, }; -use crate::error::GovernanceError; +use crate::error::GovernanceToolsError; /// Trait for accounts to return their max size pub trait AccountMaxSize { @@ -17,6 +17,58 @@ pub trait AccountMaxSize { } } +/// 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>, + account_data: &T, + program_id: &Pubkey, + system_info: &AccountInfo<'a>, +) -> Result<(), ProgramError> { + // Assert the account is not initialized yet + if !(account_info.data_is_empty() && *account_info.owner == system_program::id()) { + return Err(GovernanceToolsError::AccountAlreadyInitialized.into()); + } + + let (serialized_data, account_size) = if let Some(max_size) = account_data.get_max_size() { + (None, max_size) + } else { + let serialized_data = account_data.try_to_vec()?; + let account_size = serialized_data.len(); + (Some(serialized_data), account_size) + }; + + let rent = Rent::get()?; + + let create_account_instruction = create_account( + payer_info.key, + account_info.key, + rent.minimum_balance(account_size), + account_size as u64, + program_id, + ); + + invoke( + &create_account_instruction, + &[ + payer_info.clone(), + account_info.clone(), + system_info.clone(), + ], + )?; + + if let Some(serialized_data) = serialized_data { + account_info + .data + .borrow_mut() + .copy_from_slice(&serialized_data); + } else { + account_data.serialize(&mut *account_info.data.borrow_mut())?; + } + + Ok(()) +} + /// 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 pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSize>( @@ -85,14 +137,14 @@ pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSiz /// Deserializes account and checks it's initialized and owned by the specified program pub fn get_account_data( - account_info: &AccountInfo, owner_program_id: &Pubkey, + account_info: &AccountInfo, ) -> Result { if account_info.data_is_empty() { - return Err(GovernanceError::AccountDoesNotExist.into()); + return Err(GovernanceToolsError::AccountDoesNotExist.into()); } if account_info.owner != owner_program_id { - return Err(GovernanceError::InvalidAccountOwner.into()); + return Err(GovernanceToolsError::InvalidAccountOwner.into()); } let account: T = try_from_slice_unchecked(&account_info.data.borrow())?; @@ -111,17 +163,17 @@ pub fn assert_is_valid_account( owner_program_id: &Pubkey, ) -> Result<(), ProgramError> { if account_info.owner != owner_program_id { - return Err(GovernanceError::InvalidAccountOwner.into()); + return Err(GovernanceToolsError::InvalidAccountOwner.into()); } if account_info.data_is_empty() { - return Err(GovernanceError::AccountDoesNotExist.into()); + return Err(GovernanceToolsError::AccountDoesNotExist.into()); } let account_type: T = try_from_slice_unchecked(&account_info.data.borrow())?; if account_type != expected_account_type { - return Err(GovernanceError::InvalidAccountType.into()); + return Err(GovernanceToolsError::InvalidAccountType.into()); }; Ok(()) diff --git a/governance/tools/src/error.rs b/governance/tools/src/error.rs new file mode 100644 index 00000000000..33aebdb3c53 --- /dev/null +++ b/governance/tools/src/error.rs @@ -0,0 +1,47 @@ +//! Error types + +use num_derive::FromPrimitive; +use solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, +}; +use thiserror::Error; + +/// Errors that may be returned by the GovernanceTools +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum GovernanceToolsError { + /// Account already initialized + #[error("Account already initialized")] + AccountAlreadyInitialized = 1100, + + /// Account doesn't exist + #[error("Account doesn't exist")] + AccountDoesNotExist, + + /// Invalid account owner + #[error("Invalid account owner")] + InvalidAccountOwner, + + /// Invalid Account type + #[error("Invalid Account type")] + InvalidAccountType, +} + +impl PrintProgramError for GovernanceToolsError { + fn print(&self) { + msg!("GOVERNANCE-TOOLS-ERROR: {}", &self.to_string()); + } +} + +impl From for ProgramError { + fn from(e: GovernanceToolsError) -> Self { + ProgramError::Custom(e as u32) + } +} + +impl DecodeError for GovernanceToolsError { + fn type_of() -> &'static str { + "Governance Tools Error" + } +} diff --git a/governance/tools/src/lib.rs b/governance/tools/src/lib.rs new file mode 100644 index 00000000000..5537a42d369 --- /dev/null +++ b/governance/tools/src/lib.rs @@ -0,0 +1,2 @@ +pub mod account; +pub mod error; diff --git a/governance/voter-weight-addin/program/Cargo.toml b/governance/voter-weight-addin/program/Cargo.toml index abc5468551e..e7812434d2c 100644 --- a/governance/voter-weight-addin/program/Cargo.toml +++ b/governance/voter-weight-addin/program/Cargo.toml @@ -21,8 +21,8 @@ serde = "1.0.127" serde_derive = "1.0.103" solana-program = "1.7.11" spl-token = { version = "3.2", path = "../../../token/program", features = [ "no-entrypoint" ] } -spl-governance= { version = "2.1.1", path ="../../program", features = [ "no-entrypoint" ]} -spl-governance-chat= { version = "0.1.0", path ="../../chat/program", features = [ "no-entrypoint" ]} +spl-governance= { version = "2.1.2", path ="../../program", features = [ "no-entrypoint" ]} +spl-governance-tools= { version = "0.1.0", path ="../../tools"} thiserror = "1.0" diff --git a/governance/voter-weight-addin/program/src/processor.rs b/governance/voter-weight-addin/program/src/processor.rs index 01cacd7ace2..e630b225466 100644 --- a/governance/voter-weight-addin/program/src/processor.rs +++ b/governance/voter-weight-addin/program/src/processor.rs @@ -5,8 +5,6 @@ use spl_governance::{ addins::voter_weight::{VoterWeightAccountType, VoterWeightRecord}, state::token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, }; -// TODO: Move to shared governance tools -use spl_governance_chat::tools::account::create_and_serialize_account; use solana_program::{ account_info::{next_account_info, AccountInfo}, @@ -15,6 +13,7 @@ use solana_program::{ program_error::ProgramError, pubkey::Pubkey, }; +use spl_governance_tools::account::create_and_serialize_account; use crate::instruction::VoterWeightAddinInstruction;