Governance: Voter-weight-addin cleanup (#2512)
* chore: Ensure voter-weight-addin is built for tests fix: build addin during test run fix: build voter weight addin for tests using the addin only chore: use mutex to build addin only once chore: move build guard to separate file chore: update governance version for chat * chore: create tools crate for common utility functions in governance ecosystem * chore: add test-sdk and tools readme * chore: rename reserved addins to specific names * chore: remove todo comment * chore: remove unnecessary var drop * chore: move all account tools to shared crate * chore: fix chat compilation * chore: move program_id to first position
This commit is contained in:
parent
f95e390dd4
commit
d6d0b92ae7
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -13,6 +13,7 @@ members = [
|
|||
"governance/voter-weight-addin/program",
|
||||
"governance/program",
|
||||
"governance/test-sdk",
|
||||
"governance/tools",
|
||||
"governance/chat/program",
|
||||
"libraries/math",
|
||||
"memo/program",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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(())
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
//! Utility functions
|
||||
|
||||
pub mod account;
|
|
@ -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 <maintainers@solana.foundation>"]
|
||||
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"]
|
||||
|
|
|
@ -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<VoterWeightRecord, ProgramError> {
|
||||
get_account_data::<VoterWeightRecord>(voter_weight_record_info, program_id)
|
||||
get_account_data::<VoterWeightRecord>(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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -8,15 +8,13 @@ use solana_program::{
|
|||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
};
|
||||
use spl_governance_tools::account::create_and_serialize_account_signed;
|
||||
|
||||
use crate::{
|
||||
state::{
|
||||
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,
|
||||
};
|
||||
|
||||
/// Processes AddSignatory instruction
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! Program state processor
|
||||
|
||||
use crate::{
|
||||
state::{
|
||||
use crate::state::{
|
||||
enums::GovernanceAccountType,
|
||||
governance::{
|
||||
assert_valid_create_governance_args, get_account_governance_address_seeds, Governance,
|
||||
|
@ -9,8 +8,6 @@ use crate::{
|
|||
},
|
||||
realm::get_realm_data,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
},
|
||||
tools::account::create_and_serialize_account_signed,
|
||||
};
|
||||
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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -11,12 +11,9 @@ 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::{
|
||||
tools::bpf_loader_upgradeable::{
|
||||
assert_program_upgrade_authority_is_signer, set_program_upgrade_authority,
|
||||
},
|
||||
},
|
||||
};
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
};
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,16 +5,14 @@ use solana_program::{
|
|||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use spl_governance_tools::account::dispose_account;
|
||||
|
||||
use crate::{
|
||||
state::{
|
||||
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 borsh::BorshSerialize;
|
||||
|
|
|
@ -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,
|
||||
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,
|
||||
};
|
||||
|
||||
/// Processes RemoveInstruction instruction
|
||||
|
|
|
@ -6,13 +6,11 @@ use solana_program::{
|
|||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use spl_governance_tools::account::dispose_account;
|
||||
|
||||
use crate::{
|
||||
state::{
|
||||
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,
|
||||
};
|
||||
|
||||
/// Processes RemoveSignatory instruction
|
||||
|
|
|
@ -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],
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Governance, ProgramError> {
|
||||
get_account_data::<Governance>(governance_info, program_id)
|
||||
get_account_data::<Governance>(program_id, governance_info)
|
||||
}
|
||||
|
||||
/// Deserializes Governance account, checks owner program and asserts governance belongs to the given ream
|
||||
|
|
|
@ -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<Proposal, ProgramError> {
|
||||
get_account_data::<Proposal>(proposal_info, program_id)
|
||||
get_account_data::<Proposal>(program_id, proposal_info)
|
||||
}
|
||||
|
||||
/// Deserializes Proposal and validates it belongs to the given Governance and Governing Mint
|
||||
|
|
|
@ -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<ProposalInstruction, ProgramError> {
|
||||
get_account_data::<ProposalInstruction>(proposal_instruction_info, program_id)
|
||||
get_account_data::<ProposalInstruction>(program_id, proposal_instruction_info)
|
||||
}
|
||||
|
||||
/// Deserializes and returns ProposalInstruction account and checks it belongs to the given Proposal
|
||||
|
|
|
@ -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<Realm, ProgramError> {
|
||||
get_account_data::<Realm>(realm_info, program_id)
|
||||
get_account_data::<Realm>(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<Realm, ProgramError> {
|
||||
let realm_data = get_account_data::<Realm>(realm_info, program_id)?;
|
||||
let realm_data = get_account_data::<Realm>(program_id, realm_info)?;
|
||||
|
||||
if realm_data.authority.is_none() {
|
||||
return Err(GovernanceError::RealmHasNoAuthority.into());
|
||||
|
|
|
@ -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<Pubkey>,
|
||||
|
||||
/// Reserved for community max vote weight addin
|
||||
pub reserved_1: Option<Pubkey>,
|
||||
/// 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<Pubkey>,
|
||||
|
||||
/// Reserved for council voter weight addin
|
||||
pub reserved_2: Option<Pubkey>,
|
||||
/// Addin providing voter weights for council token
|
||||
/// Note: This field is not implemented in the current version
|
||||
pub council_voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Reserved for council max vote weight addin
|
||||
pub reserved_3: Option<Pubkey>,
|
||||
/// 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<Pubkey>,
|
||||
|
||||
/// Reserved
|
||||
pub reserved: [u8; 128],
|
||||
|
@ -56,7 +56,7 @@ pub fn get_realm_config_data(
|
|||
program_id: &Pubkey,
|
||||
realm_config_info: &AccountInfo,
|
||||
) -> Result<RealmConfigAccount, ProgramError> {
|
||||
get_account_data::<RealmConfigAccount>(realm_config_info, program_id)
|
||||
get_account_data::<RealmConfigAccount>(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],
|
||||
};
|
||||
|
||||
|
|
|
@ -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<SignatoryRecord, ProgramError> {
|
||||
get_account_data::<SignatoryRecord>(signatory_record_info, program_id)
|
||||
get_account_data::<SignatoryRecord>(program_id, signatory_record_info)
|
||||
}
|
||||
|
||||
/// Deserializes SignatoryRecord and validates its PDA
|
||||
|
|
|
@ -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<TokenOwnerRecord, ProgramError> {
|
||||
get_account_data::<TokenOwnerRecord>(token_owner_record_info, program_id)
|
||||
get_account_data::<TokenOwnerRecord>(program_id, token_owner_record_info)
|
||||
}
|
||||
|
||||
/// Deserializes TokenOwnerRecord account and checks its PDA against the provided seeds
|
||||
|
|
|
@ -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<VoteRecord, ProgramError> {
|
||||
get_account_data::<VoteRecord>(vote_record_info, program_id)
|
||||
get_account_data::<VoteRecord>(program_id, vote_record_info)
|
||||
}
|
||||
|
||||
/// Deserializes VoteRecord and checks it belongs to the provided Proposal and Governing Token Owner
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! Utility functions
|
||||
|
||||
pub mod account;
|
||||
|
||||
pub mod spl_token;
|
||||
|
||||
pub mod bpf_loader_upgradeable;
|
||||
|
|
Binary file not shown.
|
@ -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]
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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::<u8> = 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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::{
|
||||
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),
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Governance Test SDK
|
||||
|
||||
Governance test SDK is a set of test utility functions used across the governance programs ecosystem
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "spl-governance-tools"
|
||||
version = "0.1.0"
|
||||
description = "Solana Program Library Governance Tools"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
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"
|
|
@ -0,0 +1,3 @@
|
|||
# Governance Tool
|
||||
|
||||
Governance tools is a set of general purpose utility functions used across the governance programs ecosystem
|
|
@ -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<T: BorshDeserialize + IsInitialized>(
|
||||
account_info: &AccountInfo,
|
||||
owner_program_id: &Pubkey,
|
||||
account_info: &AccountInfo,
|
||||
) -> Result<T, ProgramError> {
|
||||
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<T: BorshDeserialize + PartialEq>(
|
|||
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(())
|
|
@ -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<E>(&self) {
|
||||
msg!("GOVERNANCE-TOOLS-ERROR: {}", &self.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GovernanceToolsError> for ProgramError {
|
||||
fn from(e: GovernanceToolsError) -> Self {
|
||||
ProgramError::Custom(e as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for GovernanceToolsError {
|
||||
fn type_of() -> &'static str {
|
||||
"Governance Tools Error"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod account;
|
||||
pub mod error;
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue