Governance: Voters weights add-in (#2450)
* feat: setup and configure voter weight addin feat: add use_voter_weight_add_in flag to realm config chore: use spl-governance 1.1.1 version chore: make clippy happy chore: add test to deserialise v1 CreateRealm instruction from v2 feat: add voter-weight-addin skeleton project chore: build voter-weight-addin before governance fix: temp workaround to make spl_governance_voter_weight_addin available in CI chore: add tests with voter-weight-addin feat: implement deposit instruction for voter weight addin feat: add voter_weight_expiry fix: set voter_weight_expiry chore: restore positive execute tests chore: restore ignored tests wip: pass voter weight accounts to create_account_governance2 wip: read voter weight account chore: make clippy happy wip: add realm and validation to voter_weight deposit fix: update addin chore: make clippy happy chore: fix voter_weight_record names feat: use voter weight provided by addin when governance created chore: update addin chore: remove governance stake pool program feat: remove time offset from revise chore: fix build feat: create RealmAddins account when realm with addin is created chore: make clippy happy feat: set voter weight addin using SetRealmConfig instruction chore: make clippy happy chore: update comments chore: reorder SetrealmConfig accounts chore: infer use_community_voter_weight_addin chore: infer use_community_voter_weight_addin chore: update voter weight addin comments feat: use voter weight addin id from RealmAddins account * feat: use voter weight addin to create proposal * feat: use voter weight addin to cast vote * chore: make clippy happy * feat: use voter weight addin to create token governance * feat: use voter weight addin to create mint governance * feat: use voter weight adding to create program governance * chore: create assert_can_withdraw_governing_tokens() helper function * chore: fix compilation * fix: ensure governance authority signed transaction to create governance * feat: implement CreateTokenOwnerRecord instruction * chore: fix chat tests * chore: update comments * chore: rename RealmAddins account to RealmConfig account * chore: add more reserved space to GovernanceConfig account * chore: update instruction comments * chore: update comments * chore: fix compilation * chore: remove ignore directive for tests * feat: panic when depositing tokens into a realm with voter weight addin * chore: rename community_voter_weight to community_voter_weight_addin * feat: make payer account optional for SetRealmConfig
This commit is contained in:
parent
1c417ffa4f
commit
c99f4195f1
|
@ -3657,6 +3657,24 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "spl-governance"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae3df1aa25c5f5ce7a6595959b1b02c6ae6ea35274379ee64bcf80bae11a767"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
"borsh",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"solana-program",
|
||||
"spl-token 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-governance"
|
||||
version = "2.1.1"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"assert_matches",
|
||||
|
@ -3671,6 +3689,7 @@ dependencies = [
|
|||
"solana-program",
|
||||
"solana-program-test",
|
||||
"solana-sdk",
|
||||
"spl-governance 1.1.1",
|
||||
"spl-governance-test-sdk",
|
||||
"spl-token 3.2.0",
|
||||
"thiserror",
|
||||
|
@ -3693,7 +3712,7 @@ dependencies = [
|
|||
"solana-program",
|
||||
"solana-program-test",
|
||||
"solana-sdk",
|
||||
"spl-governance",
|
||||
"spl-governance 2.1.1",
|
||||
"spl-governance-test-sdk",
|
||||
"spl-token 3.2.0",
|
||||
"thiserror",
|
||||
|
@ -3717,6 +3736,30 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-governance-voter-weight-addin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"assert_matches",
|
||||
"base64 0.13.0",
|
||||
"bincode",
|
||||
"borsh",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"proptest",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"solana-program",
|
||||
"solana-program-test",
|
||||
"solana-sdk",
|
||||
"spl-governance 2.1.1",
|
||||
"spl-governance-chat",
|
||||
"spl-governance-test-sdk",
|
||||
"spl-token 3.2.0",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-math"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -10,6 +10,7 @@ members = [
|
|||
"examples/rust/transfer-lamports",
|
||||
"feature-proposal/program",
|
||||
"feature-proposal/cli",
|
||||
"governance/voter-weight-addin/program",
|
||||
"governance/program",
|
||||
"governance/test-sdk",
|
||||
"governance/chat/program",
|
||||
|
|
|
@ -21,7 +21,7 @@ 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 = "1.1.0", path ="../../program", features = [ "no-entrypoint" ]}
|
||||
spl-governance= { version = "2.1.0", path ="../../program", features = [ "no-entrypoint" ]}
|
||||
thiserror = "1.0"
|
||||
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ impl GovernanceChatProgramTest {
|
|||
&governing_token_mint_keypair.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
None,
|
||||
None,
|
||||
name.clone(),
|
||||
1,
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
|
@ -155,11 +156,13 @@ impl GovernanceChatProgramTest {
|
|||
&governed_account_address,
|
||||
&token_owner_record_address,
|
||||
&self.bench.payer.pubkey(),
|
||||
&token_owner.pubkey(),
|
||||
None,
|
||||
governance_config,
|
||||
);
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[create_account_governance_ix], None)
|
||||
.process_transaction(&[create_account_governance_ix], Some(&[&token_owner]))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -173,7 +176,7 @@ impl GovernanceChatProgramTest {
|
|||
|
||||
let proposal_name = "Proposal #1".to_string();
|
||||
let description_link = "Proposal Description".to_string();
|
||||
let proposal_index = 0;
|
||||
let proposal_index: u32 = 0;
|
||||
|
||||
let create_proposal_ix = create_proposal(
|
||||
&self.governance_program_id,
|
||||
|
@ -181,6 +184,7 @@ impl GovernanceChatProgramTest {
|
|||
&token_owner_record_address,
|
||||
&token_owner.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
None,
|
||||
&realm_address,
|
||||
proposal_name,
|
||||
description_link.clone(),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "spl-governance"
|
||||
version = "1.1.1"
|
||||
version = "2.1.1"
|
||||
description = "Solana Program Library Governance Program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana-program-library"
|
||||
|
@ -30,6 +30,8 @@ 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"]
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
//! Governance add-ins interfaces
|
||||
pub mod voter_weight;
|
|
@ -0,0 +1,110 @@
|
|||
//! VoterWeight Addin interface
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
use solana_program::{
|
||||
account_info::AccountInfo,
|
||||
clock::{Clock, Slot},
|
||||
program_error::ProgramError,
|
||||
program_pack::IsInitialized,
|
||||
pubkey::Pubkey,
|
||||
sysvar::Sysvar,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::GovernanceError,
|
||||
state::token_owner_record::TokenOwnerRecord,
|
||||
tools::account::{get_account_data, AccountMaxSize},
|
||||
};
|
||||
|
||||
/// VoterWeight account type
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoterWeightAccountType {
|
||||
/// Default uninitialized account state
|
||||
Uninitialized,
|
||||
|
||||
/// Voter Weight Record
|
||||
VoterWeightRecord,
|
||||
}
|
||||
|
||||
/// VoterWeight Record account
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct VoterWeightRecord {
|
||||
/// VoterWeightRecord account type
|
||||
pub account_type: VoterWeightAccountType,
|
||||
|
||||
/// The Realm the VoterWeightRecord belongs to
|
||||
pub realm: Pubkey,
|
||||
|
||||
/// Governing Token Mint the VoterWeightRecord is associated with
|
||||
/// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only
|
||||
// The mint here is to link the record to either community or council mint of the realm
|
||||
pub governing_token_mint: Pubkey,
|
||||
|
||||
/// The owner of the governing token and voter
|
||||
pub governing_token_owner: Pubkey,
|
||||
|
||||
/// Voter's weight
|
||||
pub voter_weight: u64,
|
||||
|
||||
/// The slot when the voting weight expires
|
||||
/// It should be set to None if the weight never expires
|
||||
/// If the voter weight decays with time, for example for time locked based weights, then the expiry must be set
|
||||
/// As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction
|
||||
/// and the expiry set to the current slot to provide up to date weight
|
||||
pub voter_weight_expiry: Option<Slot>,
|
||||
}
|
||||
|
||||
impl AccountMaxSize for VoterWeightRecord {}
|
||||
|
||||
impl IsInitialized for VoterWeightRecord {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.account_type == VoterWeightAccountType::VoterWeightRecord
|
||||
}
|
||||
}
|
||||
|
||||
impl VoterWeightRecord {
|
||||
/// Asserts the VoterWeightRecord hasn't expired
|
||||
pub fn assert_is_up_to_date(&self) -> Result<(), ProgramError> {
|
||||
if let Some(voter_weight_expiry) = self.voter_weight_expiry {
|
||||
let slot = Clock::get().unwrap().slot;
|
||||
|
||||
if slot > voter_weight_expiry {
|
||||
return Err(GovernanceError::VoterWeightRecordExpired.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes VoterWeightRecord account and checks owner program
|
||||
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)
|
||||
}
|
||||
|
||||
/// Deserializes VoterWeightRecord account, checks owner program and asserts it's for the same realm, mint and token owner as the provided TokenOwnerRecord
|
||||
pub fn get_voter_weight_record_data_for_token_owner_record(
|
||||
program_id: &Pubkey,
|
||||
voter_weight_record_info: &AccountInfo,
|
||||
token_owner_record: &TokenOwnerRecord,
|
||||
) -> Result<VoterWeightRecord, ProgramError> {
|
||||
let voter_weight_record_data =
|
||||
get_voter_weight_record_data(program_id, voter_weight_record_info)?;
|
||||
|
||||
if voter_weight_record_data.realm != token_owner_record.realm {
|
||||
return Err(GovernanceError::InvalidVoterWeightRecordForRealm.into());
|
||||
}
|
||||
|
||||
if voter_weight_record_data.governing_token_mint != token_owner_record.governing_token_mint {
|
||||
return Err(GovernanceError::InvalidVoterWeightRecordForGoverningTokenMint.into());
|
||||
}
|
||||
|
||||
if voter_weight_record_data.governing_token_owner != token_owner_record.governing_token_owner {
|
||||
return Err(GovernanceError::InvalidVoterWeightRecordForTokenOwner.into());
|
||||
}
|
||||
|
||||
Ok(voter_weight_record_data)
|
||||
}
|
|
@ -323,6 +323,34 @@ pub enum GovernanceError {
|
|||
/// All proposals must be finalized to withdraw governing tokens
|
||||
#[error("All proposals must be finalized to withdraw governing tokens")]
|
||||
AllProposalsMustBeFinalisedToWithdrawGoverningTokens,
|
||||
|
||||
/// Invalid VoterWeightRecord for Realm
|
||||
#[error("Invalid VoterWeightRecord for Realm")]
|
||||
InvalidVoterWeightRecordForRealm,
|
||||
|
||||
/// Invalid VoterWeightRecord for GoverningTokenMint
|
||||
#[error("Invalid VoterWeightRecord for GoverningTokenMint")]
|
||||
InvalidVoterWeightRecordForGoverningTokenMint,
|
||||
|
||||
/// Invalid VoterWeightRecord for TokenOwner
|
||||
#[error("Invalid VoterWeightRecord for TokenOwner")]
|
||||
InvalidVoterWeightRecordForTokenOwner,
|
||||
|
||||
/// VoterWeightRecord expired
|
||||
#[error("VoterWeightRecord expired")]
|
||||
VoterWeightRecordExpired,
|
||||
|
||||
/// Invalid RealmConfig for Realm
|
||||
#[error("Invalid RealmConfig for Realm")]
|
||||
InvalidRealmConfigForRealm,
|
||||
|
||||
/// TokenOwnerRecord already exists
|
||||
#[error("TokenOwnerRecord already exists")]
|
||||
TokenOwnerRecordAlreadyExists,
|
||||
|
||||
/// Governing token deposits not allowed
|
||||
#[error("Governing token deposits not allowed")]
|
||||
GoverningTokenDepositsNotAllowed,
|
||||
}
|
||||
|
||||
impl PrintProgramError for GovernanceError {
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
proposal::get_proposal_address,
|
||||
proposal_instruction::{get_proposal_instruction_address, InstructionData},
|
||||
realm::{get_governing_token_holding_address, get_realm_address, RealmConfigArgs},
|
||||
realm_config::get_realm_config_address,
|
||||
signatory_record::get_signatory_record_address,
|
||||
token_owner_record::get_token_owner_record_address,
|
||||
vote_record::get_vote_record_address,
|
||||
|
@ -50,9 +51,13 @@ pub enum GovernanceInstruction {
|
|||
/// 5. `[]` System
|
||||
/// 6. `[]` SPL Token
|
||||
/// 7. `[]` Sysvar Rent
|
||||
|
||||
/// 8. `[]` Council Token Mint - optional
|
||||
/// 9. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint]
|
||||
/// The account will be created with the Realm PDA as its owner
|
||||
|
||||
/// 10. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 11. `[]` Optional Community Voter Weight Addin Program Id
|
||||
CreateRealm {
|
||||
#[allow(dead_code)]
|
||||
/// UTF-8 encoded Governance Realm name
|
||||
|
@ -113,6 +118,9 @@ pub enum GovernanceInstruction {
|
|||
/// 4. `[signer]` Payer
|
||||
/// 5. `[]` System program
|
||||
/// 6. `[]` Sysvar Rent
|
||||
/// 7. `[signer]` Governance authority
|
||||
/// 8. `[]` Optional Realm Config
|
||||
/// 9. `[]` Optional Voter Weight Record
|
||||
CreateAccountGovernance {
|
||||
/// Governance config
|
||||
#[allow(dead_code)]
|
||||
|
@ -131,6 +139,9 @@ pub enum GovernanceInstruction {
|
|||
/// 7. `[]` bpf_upgradeable_loader program
|
||||
/// 8. `[]` System program
|
||||
/// 9. `[]` Sysvar Rent
|
||||
/// 10. `[signer]` Governance authority
|
||||
/// 11. `[]` Optional Realm Config
|
||||
/// 12. `[]` Optional Voter Weight Record
|
||||
CreateProgramGovernance {
|
||||
/// Governance config
|
||||
#[allow(dead_code)]
|
||||
|
@ -154,6 +165,8 @@ pub enum GovernanceInstruction {
|
|||
/// 6. `[]` System program
|
||||
/// 7. `[]` Rent sysvar
|
||||
/// 8. `[]` Clock sysvar
|
||||
/// 9. `[]` Optional Realm Config
|
||||
/// 10. `[]` Optional Voter Weight Record
|
||||
CreateProposal {
|
||||
#[allow(dead_code)]
|
||||
/// UTF-8 encoded name of the proposal
|
||||
|
@ -263,6 +276,8 @@ pub enum GovernanceInstruction {
|
|||
/// 8. `[]` System program
|
||||
/// 9. `[]` Rent sysvar
|
||||
/// 10. `[]` Clock sysvar
|
||||
/// 11. `[]` Optional Realm Config
|
||||
/// 12. `[]` Optional Voter Weight Record
|
||||
CastVote {
|
||||
#[allow(dead_code)]
|
||||
/// Yes/No vote
|
||||
|
@ -317,6 +332,9 @@ pub enum GovernanceInstruction {
|
|||
/// 6. `[]` SPL Token program
|
||||
/// 7. `[]` System program
|
||||
/// 8. `[]` Sysvar Rent
|
||||
/// 8. `[signer]` Governance authority
|
||||
/// 9. `[]` Optional Realm Config
|
||||
/// 10. `[]` Optional Voter Weight Record
|
||||
CreateMintGovernance {
|
||||
#[allow(dead_code)]
|
||||
/// Governance config
|
||||
|
@ -340,6 +358,9 @@ pub enum GovernanceInstruction {
|
|||
/// 6. `[]` SPL Token program
|
||||
/// 7. `[]` System program
|
||||
/// 8. `[]` Sysvar Rent
|
||||
/// 9. `[signer]` Governance authority
|
||||
/// 10. `[]` Optional Realm Config
|
||||
/// 11. `[]` Optional Voter Weight Record
|
||||
CreateTokenGovernance {
|
||||
#[allow(dead_code)]
|
||||
/// Governance config
|
||||
|
@ -393,11 +414,26 @@ pub enum GovernanceInstruction {
|
|||
/// If that's required then it must be done before executing this instruction
|
||||
/// 3. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint]
|
||||
/// The account will be created with the Realm PDA as its owner
|
||||
/// 4. `[]` System
|
||||
/// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 6. `[signer]` Optional Payer
|
||||
/// 7. `[]` Optional Community Voter Weight Addin Program Id
|
||||
SetRealmConfig {
|
||||
#[allow(dead_code)]
|
||||
/// Realm config args
|
||||
config_args: RealmConfigArgs,
|
||||
},
|
||||
|
||||
/// Creates TokenOwnerRecord with 0 deposit amount
|
||||
/// It's used to register TokenOwner when voter weight addin is used and the Governance program doesn't take deposits
|
||||
///
|
||||
/// 0. `[]` Realm account
|
||||
/// 1. `[]` Governing Token Owner account
|
||||
/// 2. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 3. `[]` Governing Token Mint
|
||||
/// 4. `[signer]` Payer
|
||||
/// 5. `[]` System
|
||||
CreateTokenOwnerRecord {},
|
||||
}
|
||||
|
||||
/// Creates CreateRealm instruction
|
||||
|
@ -409,6 +445,7 @@ pub fn create_realm(
|
|||
community_token_mint: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
council_token_mint: Option<Pubkey>,
|
||||
community_voter_weight_addin: Option<Pubkey>,
|
||||
// Args
|
||||
name: String,
|
||||
min_community_tokens_to_create_governance: u64,
|
||||
|
@ -440,11 +477,26 @@ pub fn create_realm(
|
|||
false
|
||||
};
|
||||
|
||||
let realm_config_address = get_realm_config_address(program_id, &realm_address);
|
||||
accounts.push(AccountMeta::new(realm_config_address, false));
|
||||
|
||||
let use_community_voter_weight_addin =
|
||||
if let Some(community_voter_weight_addin) = community_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
community_voter_weight_addin,
|
||||
false,
|
||||
));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let instruction = GovernanceInstruction::CreateRealm {
|
||||
config_args: RealmConfigArgs {
|
||||
use_council_mint,
|
||||
min_community_tokens_to_create_governance,
|
||||
community_mint_max_vote_weight_source,
|
||||
use_community_voter_weight_addin,
|
||||
},
|
||||
name,
|
||||
};
|
||||
|
@ -572,7 +624,8 @@ pub fn set_governance_delegate(
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates CreateAccountGovernance instruction
|
||||
/// Creates CreateAccountGovernance instruction using optional voter weight addin
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_account_governance(
|
||||
program_id: &Pubkey,
|
||||
// Accounts
|
||||
|
@ -580,13 +633,15 @@ pub fn create_account_governance(
|
|||
governed_account: &Pubkey,
|
||||
token_owner_record: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
governance_authority: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
config: GovernanceConfig,
|
||||
) -> Instruction {
|
||||
let account_governance_address =
|
||||
get_account_governance_address(program_id, realm, governed_account);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(account_governance_address, false),
|
||||
AccountMeta::new_readonly(*governed_account, false),
|
||||
|
@ -594,8 +649,11 @@ pub fn create_account_governance(
|
|||
AccountMeta::new_readonly(*payer, true),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*governance_authority, true),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateAccountGovernance { config };
|
||||
|
||||
Instruction {
|
||||
|
@ -615,6 +673,8 @@ pub fn create_program_governance(
|
|||
governed_program_upgrade_authority: &Pubkey,
|
||||
token_owner_record: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
governance_authority: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
config: GovernanceConfig,
|
||||
transfer_upgrade_authority: bool,
|
||||
|
@ -623,7 +683,7 @@ pub fn create_program_governance(
|
|||
get_program_governance_address(program_id, realm, governed_program);
|
||||
let governed_program_data_address = get_program_data_address(governed_program);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(program_governance_address, false),
|
||||
AccountMeta::new_readonly(*governed_program, false),
|
||||
|
@ -634,8 +694,11 @@ pub fn create_program_governance(
|
|||
AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*governance_authority, true),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateProgramGovernance {
|
||||
config,
|
||||
transfer_upgrade_authority,
|
||||
|
@ -658,13 +721,15 @@ pub fn create_mint_governance(
|
|||
governed_mint_authority: &Pubkey,
|
||||
token_owner_record: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
governance_authority: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
config: GovernanceConfig,
|
||||
transfer_mint_authority: bool,
|
||||
) -> Instruction {
|
||||
let mint_governance_address = get_mint_governance_address(program_id, realm, governed_mint);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(mint_governance_address, false),
|
||||
AccountMeta::new(*governed_mint, false),
|
||||
|
@ -674,8 +739,11 @@ pub fn create_mint_governance(
|
|||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*governance_authority, true),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateMintGovernance {
|
||||
config,
|
||||
transfer_mint_authority,
|
||||
|
@ -698,13 +766,15 @@ pub fn create_token_governance(
|
|||
governed_token_owner: &Pubkey,
|
||||
token_owner_record: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
governance_authority: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
config: GovernanceConfig,
|
||||
transfer_token_owner: bool,
|
||||
) -> Instruction {
|
||||
let token_governance_address = get_token_governance_address(program_id, realm, governed_token);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(token_governance_address, false),
|
||||
AccountMeta::new(*governed_token, false),
|
||||
|
@ -714,8 +784,11 @@ pub fn create_token_governance(
|
|||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*governance_authority, true),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateTokenGovernance {
|
||||
config,
|
||||
transfer_token_owner,
|
||||
|
@ -737,6 +810,7 @@ pub fn create_proposal(
|
|||
proposal_owner_record: &Pubkey,
|
||||
governance_authority: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
realm: &Pubkey,
|
||||
name: String,
|
||||
|
@ -751,7 +825,7 @@ pub fn create_proposal(
|
|||
&proposal_index.to_le_bytes(),
|
||||
);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(proposal_address, false),
|
||||
AccountMeta::new(*governance, false),
|
||||
|
@ -763,6 +837,8 @@ pub fn create_proposal(
|
|||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateProposal {
|
||||
name,
|
||||
description_link,
|
||||
|
@ -879,13 +955,14 @@ pub fn cast_vote(
|
|||
governance_authority: &Pubkey,
|
||||
governing_token_mint: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
// Args
|
||||
vote: Vote,
|
||||
) -> Instruction {
|
||||
let vote_record_address =
|
||||
get_vote_record_address(program_id, proposal, voter_token_owner_record);
|
||||
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new_readonly(*governance, false),
|
||||
AccountMeta::new(*proposal, false),
|
||||
|
@ -900,6 +977,8 @@ pub fn cast_vote(
|
|||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
];
|
||||
|
||||
with_voter_weight_accounts(program_id, &mut accounts, realm, voter_weight_record);
|
||||
|
||||
let instruction = GovernanceInstruction::CastVote { vote };
|
||||
|
||||
Instruction {
|
||||
|
@ -1165,13 +1244,15 @@ pub fn set_realm_authority(
|
|||
}
|
||||
|
||||
/// Creates SetRealmConfig instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_realm_config(
|
||||
program_id: &Pubkey,
|
||||
// Accounts
|
||||
realm: &Pubkey,
|
||||
realm_authority: &Pubkey,
|
||||
council_token_mint: Option<Pubkey>,
|
||||
|
||||
payer: &Pubkey,
|
||||
community_voter_weight_addin: Option<Pubkey>,
|
||||
// Args
|
||||
min_community_tokens_to_create_governance: u64,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource,
|
||||
|
@ -1192,11 +1273,31 @@ pub fn set_realm_config(
|
|||
false
|
||||
};
|
||||
|
||||
accounts.push(AccountMeta::new_readonly(system_program::id(), false));
|
||||
|
||||
// Always pass realm_config_address because it's needed when use_community_voter_weight_addin is set to true
|
||||
// but also when it's set to false and the addin is being removed from the realm
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
accounts.push(AccountMeta::new(realm_config_address, false));
|
||||
|
||||
let use_community_voter_weight_addin =
|
||||
if let Some(community_voter_weight_addin) = community_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new(*payer, true));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
community_voter_weight_addin,
|
||||
false,
|
||||
));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let instruction = GovernanceInstruction::SetRealmConfig {
|
||||
config_args: RealmConfigArgs {
|
||||
use_council_mint,
|
||||
min_community_tokens_to_create_governance,
|
||||
community_mint_max_vote_weight_source,
|
||||
use_community_voter_weight_addin,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1206,3 +1307,51 @@ pub fn set_realm_config(
|
|||
data: instruction.try_to_vec().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds voter weight accounts to the given accounts if voter_weight_record is Some
|
||||
pub fn with_voter_weight_accounts(
|
||||
program_id: &Pubkey,
|
||||
accounts: &mut Vec<AccountMeta>,
|
||||
realm: &Pubkey,
|
||||
voter_weight_record: Option<Pubkey>,
|
||||
) {
|
||||
if let Some(voter_weight_record) = voter_weight_record {
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
accounts.push(AccountMeta::new_readonly(realm_config_address, false));
|
||||
accounts.push(AccountMeta::new_readonly(voter_weight_record, false));
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates CreateTokenOwnerRecord instruction
|
||||
pub fn create_token_owner_record(
|
||||
program_id: &Pubkey,
|
||||
// Accounts
|
||||
realm: &Pubkey,
|
||||
governing_token_owner: &Pubkey,
|
||||
governing_token_mint: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
) -> Instruction {
|
||||
let token_owner_record_address = get_token_owner_record_address(
|
||||
program_id,
|
||||
realm,
|
||||
governing_token_mint,
|
||||
governing_token_owner,
|
||||
);
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new_readonly(*governing_token_owner, false),
|
||||
AccountMeta::new(token_owner_record_address, false),
|
||||
AccountMeta::new_readonly(*governing_token_mint, false),
|
||||
AccountMeta::new_readonly(*payer, true),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
];
|
||||
|
||||
let instruction = GovernanceInstruction::CreateTokenOwnerRecord {};
|
||||
|
||||
Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data: instruction.try_to_vec().unwrap(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![deny(missing_docs)]
|
||||
//! A Governance program for the Solana blockchain.
|
||||
|
||||
pub mod addins;
|
||||
pub mod entrypoint;
|
||||
pub mod error;
|
||||
pub mod instruction;
|
||||
|
|
|
@ -9,6 +9,7 @@ mod process_create_program_governance;
|
|||
mod process_create_proposal;
|
||||
mod process_create_realm;
|
||||
mod process_create_token_governance;
|
||||
mod process_create_token_owner_record;
|
||||
mod process_deposit_governing_tokens;
|
||||
mod process_execute_instruction;
|
||||
mod process_finalize_vote;
|
||||
|
@ -36,6 +37,7 @@ use process_create_program_governance::*;
|
|||
use process_create_proposal::*;
|
||||
use process_create_realm::*;
|
||||
use process_create_token_governance::*;
|
||||
use process_create_token_owner_record::*;
|
||||
use process_deposit_governing_tokens::*;
|
||||
use process_execute_instruction::*;
|
||||
use process_finalize_vote::*;
|
||||
|
@ -176,5 +178,8 @@ pub fn process_instruction(
|
|||
GovernanceInstruction::SetRealmConfig { config_args } => {
|
||||
process_set_realm_config(program_id, accounts, config_args)
|
||||
}
|
||||
GovernanceInstruction::CreateTokenOwnerRecord {} => {
|
||||
process_create_token_owner_record(program_id, accounts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,23 +98,28 @@ pub fn process_cast_vote(
|
|||
.checked_add(1)
|
||||
.unwrap();
|
||||
|
||||
let vote_amount = voter_token_owner_record_data.governing_token_deposit_amount;
|
||||
let voter_weight = voter_token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
// Calculate Proposal voting weights
|
||||
let vote_weight = match vote {
|
||||
Vote::Yes => {
|
||||
proposal_data.yes_votes_count = proposal_data
|
||||
.yes_votes_count
|
||||
.checked_add(vote_amount)
|
||||
.checked_add(voter_weight)
|
||||
.unwrap();
|
||||
VoteWeight::Yes(vote_amount)
|
||||
VoteWeight::Yes(voter_weight)
|
||||
}
|
||||
Vote::No => {
|
||||
proposal_data.no_votes_count = proposal_data
|
||||
.no_votes_count
|
||||
.checked_add(vote_amount)
|
||||
.checked_add(voter_weight)
|
||||
.unwrap();
|
||||
VoteWeight::No(vote_amount)
|
||||
VoteWeight::No(voter_weight)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -40,13 +40,24 @@ pub fn process_create_account_governance(
|
|||
let rent_sysvar_info = next_account_info(account_info_iter)?; // 6
|
||||
let rent = &Rent::from_account_info(rent_sysvar_info)?;
|
||||
|
||||
let governance_authority_info = next_account_info(account_info_iter)?; // 7
|
||||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let voter_weight = token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
|
||||
|
||||
let account_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::AccountGovernance,
|
||||
|
|
|
@ -48,13 +48,24 @@ pub fn process_create_mint_governance(
|
|||
let rent_sysvar_info = next_account_info(account_info_iter)?; // 8
|
||||
let rent = &Rent::from_account_info(rent_sysvar_info)?;
|
||||
|
||||
let governance_authority_info = next_account_info(account_info_iter)?; // 9
|
||||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let voter_weight = token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
|
||||
|
||||
let mint_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::MintGovernance,
|
||||
|
|
|
@ -52,13 +52,24 @@ pub fn process_create_program_governance(
|
|||
let rent_sysvar_info = next_account_info(account_info_iter)?; // 9
|
||||
let rent = &Rent::from_account_info(rent_sysvar_info)?;
|
||||
|
||||
let governance_authority_info = next_account_info(account_info_iter)?; // 10
|
||||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let voter_weight = token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
|
||||
|
||||
let program_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::ProgramGovernance,
|
||||
|
|
|
@ -68,8 +68,19 @@ pub fn process_create_proposal(
|
|||
proposal_owner_record_data
|
||||
.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let voter_weight = proposal_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
// Ensure proposal owner (TokenOwner) has enough tokens to create proposal and no outstanding proposals
|
||||
proposal_owner_record_data.assert_can_create_proposal(&realm_data, &governance_data.config)?;
|
||||
proposal_owner_record_data.assert_can_create_proposal(
|
||||
&realm_data,
|
||||
&governance_data.config,
|
||||
voter_weight,
|
||||
)?;
|
||||
|
||||
proposal_owner_record_data.outstanding_proposal_count = proposal_owner_record_data
|
||||
.outstanding_proposal_count
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::{
|
|||
assert_valid_realm_config_args, get_governing_token_holding_address_seeds,
|
||||
get_realm_address_seeds, Realm, RealmConfig, RealmConfigArgs,
|
||||
},
|
||||
realm_config::{get_realm_config_address_seeds, RealmConfigAccount},
|
||||
},
|
||||
tools::{
|
||||
account::create_and_serialize_account_signed, spl_token::create_spl_token_account_signed,
|
||||
|
@ -62,8 +63,8 @@ pub fn process_create_realm(
|
|||
)?;
|
||||
|
||||
let council_token_mint_address = if config_args.use_council_mint {
|
||||
let council_token_mint_info = next_account_info(account_info_iter)?;
|
||||
let council_token_holding_info = next_account_info(account_info_iter)?;
|
||||
let council_token_mint_info = next_account_info(account_info_iter)?; // 8
|
||||
let council_token_holding_info = next_account_info(account_info_iter)?; // 9
|
||||
|
||||
create_spl_token_account_signed(
|
||||
payer_info,
|
||||
|
@ -83,6 +84,31 @@ pub fn process_create_realm(
|
|||
None
|
||||
};
|
||||
|
||||
if config_args.use_community_voter_weight_addin {
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 10
|
||||
let community_voter_weight_addin_info = next_account_info(account_info_iter)?; //11
|
||||
|
||||
let realm_config_data = RealmConfigAccount {
|
||||
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,
|
||||
reserved: [0; 128],
|
||||
};
|
||||
|
||||
create_and_serialize_account_signed::<RealmConfigAccount>(
|
||||
payer_info,
|
||||
realm_config_info,
|
||||
&realm_config_data,
|
||||
&get_realm_config_address_seeds(realm_info.key),
|
||||
program_id,
|
||||
system_info,
|
||||
rent,
|
||||
)?;
|
||||
}
|
||||
|
||||
let realm_data = Realm {
|
||||
account_type: GovernanceAccountType::Realm,
|
||||
community_mint: *governance_token_mint_info.key,
|
||||
|
@ -92,11 +118,12 @@ pub fn process_create_realm(
|
|||
authority: Some(*realm_authority_info.key),
|
||||
config: RealmConfig {
|
||||
council_mint: council_token_mint_address,
|
||||
reserved: [0; 8],
|
||||
reserved: [0; 7],
|
||||
community_mint_max_vote_weight_source: config_args
|
||||
.community_mint_max_vote_weight_source,
|
||||
min_community_tokens_to_create_governance: config_args
|
||||
.min_community_tokens_to_create_governance,
|
||||
use_community_voter_weight_addin: config_args.use_community_voter_weight_addin,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -48,13 +48,24 @@ pub fn process_create_token_governance(
|
|||
let rent_sysvar_info = next_account_info(account_info_iter)?; // 8
|
||||
let rent = &Rent::from_account_info(rent_sysvar_info)?;
|
||||
|
||||
let governance_authority_info = next_account_info(account_info_iter)?; // 9
|
||||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let voter_weight = token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
|
||||
|
||||
let token_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::TokenGovernance,
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
//! Program state processor
|
||||
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::GovernanceError,
|
||||
state::{
|
||||
enums::GovernanceAccountType,
|
||||
realm::get_realm_data,
|
||||
token_owner_record::{get_token_owner_record_address_seeds, TokenOwnerRecord},
|
||||
},
|
||||
tools::account::create_and_serialize_account_signed,
|
||||
};
|
||||
|
||||
/// Processes CreateTokenOwnerRecord instruction
|
||||
pub fn process_create_token_owner_record(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let realm_info = next_account_info(account_info_iter)?; // 0
|
||||
let governing_token_owner_info = next_account_info(account_info_iter)?; // 1
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 2
|
||||
let governing_token_mint_info = next_account_info(account_info_iter)?; // 3
|
||||
let payer_info = next_account_info(account_info_iter)?; // 4
|
||||
let system_info = next_account_info(account_info_iter)?; // 5
|
||||
let rent = Rent::get().unwrap();
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
realm_data.assert_is_valid_governing_token_mint(governing_token_mint_info.key)?;
|
||||
|
||||
if !token_owner_record_info.data_is_empty() {
|
||||
return Err(GovernanceError::TokenOwnerRecordAlreadyExists.into());
|
||||
}
|
||||
|
||||
let token_owner_record_data = TokenOwnerRecord {
|
||||
account_type: GovernanceAccountType::TokenOwnerRecord,
|
||||
realm: *realm_info.key,
|
||||
governing_token_owner: *governing_token_owner_info.key,
|
||||
governing_token_deposit_amount: 0,
|
||||
governing_token_mint: *governing_token_mint_info.key,
|
||||
governance_delegate: None,
|
||||
unrelinquished_votes_count: 0,
|
||||
total_votes_count: 0,
|
||||
outstanding_proposal_count: 0,
|
||||
reserved: [0; 7],
|
||||
};
|
||||
|
||||
create_and_serialize_account_signed(
|
||||
payer_info,
|
||||
token_owner_record_info,
|
||||
&token_owner_record_data,
|
||||
&get_token_owner_record_address_seeds(
|
||||
realm_info.key,
|
||||
governing_token_mint_info.key,
|
||||
governing_token_owner_info.key,
|
||||
),
|
||||
program_id,
|
||||
system_info,
|
||||
&rent,
|
||||
)
|
||||
}
|
|
@ -50,6 +50,8 @@ pub fn process_deposit_governing_tokens(
|
|||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let governing_token_mint = get_spl_token_mint(governing_token_holding_info)?;
|
||||
|
||||
realm_data.asset_governing_tokens_deposits_allowed(&governing_token_mint)?;
|
||||
|
||||
realm_data.assert_is_valid_governing_token_mint_and_holding(
|
||||
program_id,
|
||||
realm_info.key,
|
||||
|
|
|
@ -5,18 +5,27 @@ use solana_program::{
|
|||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::GovernanceError,
|
||||
state::realm::{assert_valid_realm_config_args, get_realm_data_for_authority, RealmConfigArgs},
|
||||
state::{
|
||||
enums::GovernanceAccountType,
|
||||
realm::{assert_valid_realm_config_args, get_realm_data_for_authority, RealmConfigArgs},
|
||||
realm_config::{
|
||||
get_realm_config_address_seeds, get_realm_config_data_for_realm, RealmConfigAccount,
|
||||
},
|
||||
},
|
||||
tools::account::create_and_serialize_account_signed,
|
||||
};
|
||||
|
||||
/// Processes SetRealmConfig instruction
|
||||
pub fn process_set_realm_config(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
config_args: RealmConfigArgs,
|
||||
realm_config_args: RealmConfigArgs,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
|
@ -30,10 +39,12 @@ pub fn process_set_realm_config(
|
|||
return Err(GovernanceError::RealmAuthorityMustSign.into());
|
||||
}
|
||||
|
||||
assert_valid_realm_config_args(&config_args)?;
|
||||
assert_valid_realm_config_args(&realm_config_args)?;
|
||||
|
||||
if config_args.use_council_mint {
|
||||
let council_token_mint_info = next_account_info(account_info_iter)?;
|
||||
// Setup council
|
||||
if realm_config_args.use_council_mint {
|
||||
let council_token_mint_info = next_account_info(account_info_iter)?; // 2
|
||||
let _council_token_holding_info = next_account_info(account_info_iter)?; // 3
|
||||
|
||||
// Council mint can only be at present set to none (removed) and changing it to other mint is not supported
|
||||
// It might be implemented in future versions but it needs careful planning
|
||||
|
@ -53,10 +64,56 @@ pub fn process_set_realm_config(
|
|||
realm_data.config.council_mint = None;
|
||||
}
|
||||
|
||||
let system_info = next_account_info(account_info_iter)?; // 4
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 5
|
||||
|
||||
// Setup community voter weight addin
|
||||
if realm_config_args.use_community_voter_weight_addin {
|
||||
let payer_info = next_account_info(account_info_iter)?; // 6
|
||||
let community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 7
|
||||
|
||||
if realm_config_info.data_is_empty() {
|
||||
let realm_config_data = RealmConfigAccount {
|
||||
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,
|
||||
reserved: [0; 128],
|
||||
};
|
||||
|
||||
let rent = Rent::get().unwrap();
|
||||
|
||||
create_and_serialize_account_signed::<RealmConfigAccount>(
|
||||
payer_info,
|
||||
realm_config_info,
|
||||
&realm_config_data,
|
||||
&get_realm_config_address_seeds(realm_info.key),
|
||||
program_id,
|
||||
system_info,
|
||||
&rent,
|
||||
)?;
|
||||
} else {
|
||||
let mut realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
realm_config_data.community_voter_weight_addin =
|
||||
Some(*community_voter_weight_addin_info.key);
|
||||
realm_config_data.serialize(&mut *realm_config_info.data.borrow_mut())?;
|
||||
}
|
||||
} else if realm_data.config.use_community_voter_weight_addin {
|
||||
let mut realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
realm_config_data.community_voter_weight_addin = None;
|
||||
realm_config_data.serialize(&mut *realm_config_info.data.borrow_mut())?;
|
||||
}
|
||||
|
||||
realm_data.config.community_mint_max_vote_weight_source =
|
||||
config_args.community_mint_max_vote_weight_source;
|
||||
realm_config_args.community_mint_max_vote_weight_source;
|
||||
realm_data.config.min_community_tokens_to_create_governance =
|
||||
config_args.min_community_tokens_to_create_governance;
|
||||
realm_config_args.min_community_tokens_to_create_governance;
|
||||
realm_data.config.use_community_voter_weight_addin =
|
||||
realm_config_args.use_community_voter_weight_addin;
|
||||
|
||||
realm_data.serialize(&mut *realm_info.data.borrow_mut())?;
|
||||
|
||||
|
|
|
@ -58,13 +58,7 @@ pub fn process_withdraw_governing_tokens(
|
|||
&token_owner_record_address_seeds,
|
||||
)?;
|
||||
|
||||
if token_owner_record_data.unrelinquished_votes_count > 0 {
|
||||
return Err(GovernanceError::AllVotesMustBeRelinquishedToWithdrawGoverningTokens.into());
|
||||
}
|
||||
|
||||
if token_owner_record_data.outstanding_proposal_count > 0 {
|
||||
return Err(GovernanceError::AllProposalsMustBeFinalisedToWithdrawGoverningTokens.into());
|
||||
}
|
||||
token_owner_record_data.assert_can_withdraw_governing_tokens()?;
|
||||
|
||||
transfer_spl_tokens_signed(
|
||||
governing_token_holding_info,
|
||||
|
|
|
@ -38,6 +38,9 @@ pub enum GovernanceAccountType {
|
|||
|
||||
/// Token Governance account
|
||||
TokenGovernance,
|
||||
|
||||
/// Realm config account
|
||||
RealmConfig,
|
||||
}
|
||||
|
||||
impl Default for GovernanceAccountType {
|
||||
|
|
|
@ -5,6 +5,7 @@ pub mod governance;
|
|||
pub mod proposal;
|
||||
pub mod proposal_instruction;
|
||||
pub mod realm;
|
||||
pub mod realm_config;
|
||||
pub mod signatory_record;
|
||||
pub mod token_owner_record;
|
||||
pub mod vote_record;
|
||||
|
|
|
@ -565,7 +565,8 @@ mod test {
|
|||
name: "test-realm".to_string(),
|
||||
config: RealmConfig {
|
||||
council_mint: Some(Pubkey::new_unique()),
|
||||
reserved: [0; 8],
|
||||
reserved: [0; 7],
|
||||
use_community_voter_weight_addin: false,
|
||||
|
||||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
|
|
|
@ -26,14 +26,21 @@ pub struct RealmConfigArgs {
|
|||
|
||||
/// The source used for community mint max vote weight source
|
||||
pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource,
|
||||
|
||||
/// Indicates whether an external addin program should be used to provide community voters weights
|
||||
/// If yes then the voters weight program account must be passed to the instruction
|
||||
pub use_community_voter_weight_addin: bool,
|
||||
}
|
||||
|
||||
/// Realm Config defining Realm parameters.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmConfig {
|
||||
/// Indicates whether an external addin program should be used to provide voters weights for the community mint
|
||||
pub use_community_voter_weight_addin: bool,
|
||||
|
||||
/// Reserved space for future versions
|
||||
pub reserved: [u8; 8],
|
||||
pub reserved: [u8; 7],
|
||||
|
||||
/// Min number of community tokens required to create a governance
|
||||
pub min_community_tokens_to_create_governance: u64,
|
||||
|
@ -118,6 +125,21 @@ impl Realm {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Asserts the given governing token can be deposited into the realm
|
||||
pub fn asset_governing_tokens_deposits_allowed(
|
||||
&self,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
// If the deposit is for the community token and the realm uses community voter weight addin then panic
|
||||
if self.config.use_community_voter_weight_addin
|
||||
&& self.community_mint == *governing_token_mint
|
||||
{
|
||||
return Err(GovernanceError::GoverningTokenDepositsNotAllowed.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether realm account exists, is initialized and owned by Governance program
|
||||
|
@ -222,6 +244,9 @@ pub fn assert_valid_realm_config_args(config_args: &RealmConfigArgs) -> Result<(
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::instruction::GovernanceInstruction;
|
||||
use solana_program::borsh::try_from_slice_unchecked;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
@ -235,7 +260,8 @@ mod test {
|
|||
name: "test-realm".to_string(),
|
||||
config: RealmConfig {
|
||||
council_mint: Some(Pubkey::new_unique()),
|
||||
reserved: [0; 8],
|
||||
use_community_voter_weight_addin: false,
|
||||
reserved: [0; 7],
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::Absolute(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
|
@ -246,4 +272,76 @@ mod test {
|
|||
|
||||
assert_eq!(realm.get_max_size(), Some(size));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_v2_realm_account_from_v1() {
|
||||
// Arrange
|
||||
let realm_v1 = spl_governance_v1::state::realm::Realm {
|
||||
account_type: spl_governance_v1::state::enums::GovernanceAccountType::Realm,
|
||||
community_mint: Pubkey::new_unique(),
|
||||
config: spl_governance_v1::state::realm::RealmConfig {
|
||||
council_mint: Some(Pubkey::new_unique()),
|
||||
reserved: [0; 8],
|
||||
community_mint_max_vote_weight_source:
|
||||
spl_governance_v1::state::enums::MintMaxVoteWeightSource::Absolute(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
},
|
||||
reserved: [0; 8],
|
||||
authority: Some(Pubkey::new_unique()),
|
||||
name: "test-realm-v1".to_string(),
|
||||
};
|
||||
|
||||
let mut realm_v1_data = vec![];
|
||||
realm_v1.serialize(&mut realm_v1_data).unwrap();
|
||||
|
||||
// Act
|
||||
let realm_v2: Realm = try_from_slice_unchecked(&realm_v1_data).unwrap();
|
||||
|
||||
// Assert
|
||||
assert!(!realm_v2.config.use_community_voter_weight_addin);
|
||||
assert_eq!(realm_v2.account_type, GovernanceAccountType::Realm);
|
||||
assert_eq!(
|
||||
realm_v2.config.min_community_tokens_to_create_governance,
|
||||
realm_v1.config.min_community_tokens_to_create_governance,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_v1_create_realm_instruction_from_v2() {
|
||||
// Arrange
|
||||
let create_realm_ix = GovernanceInstruction::CreateRealm {
|
||||
name: "test-realm".to_string(),
|
||||
config_args: RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
min_community_tokens_to_create_governance: 100,
|
||||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
use_community_voter_weight_addin: false,
|
||||
},
|
||||
};
|
||||
|
||||
let mut create_realm_ix_data = vec![];
|
||||
create_realm_ix
|
||||
.serialize(&mut create_realm_ix_data)
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let create_realm_ix_v1: spl_governance_v1::instruction::GovernanceInstruction =
|
||||
try_from_slice_unchecked(&create_realm_ix_data).unwrap();
|
||||
|
||||
// Assert
|
||||
if let spl_governance_v1::instruction::GovernanceInstruction::CreateRealm {
|
||||
name,
|
||||
config_args,
|
||||
} = create_realm_ix_v1
|
||||
{
|
||||
assert_eq!("test-realm", name);
|
||||
assert_eq!(
|
||||
spl_governance_v1::state::enums::MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
config_args.community_mint_max_vote_weight_source
|
||||
);
|
||||
} else {
|
||||
panic!("Can't deserialize v1 CreateRealm instruction from v2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
//! RealmConfig account
|
||||
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
use crate::{
|
||||
error::GovernanceError,
|
||||
state::enums::GovernanceAccountType,
|
||||
tools::account::{get_account_data, AccountMaxSize},
|
||||
};
|
||||
|
||||
/// RealmConfig account
|
||||
/// The account is an optional extension to RealmConfig stored on Realm account
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmConfigAccount {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
||||
/// The realm the config belong to
|
||||
pub realm: Pubkey,
|
||||
|
||||
/// 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>,
|
||||
|
||||
/// Reserved for council voter weight addin
|
||||
pub reserved_2: Option<Pubkey>,
|
||||
|
||||
/// Reserved for council max vote weight addin
|
||||
pub reserved_3: Option<Pubkey>,
|
||||
|
||||
/// Reserved
|
||||
pub reserved: [u8; 128],
|
||||
}
|
||||
|
||||
impl AccountMaxSize for RealmConfigAccount {
|
||||
fn get_max_size(&self) -> Option<usize> {
|
||||
Some(1 + 32 + 33 * 4 + 128)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsInitialized for RealmConfigAccount {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.account_type == GovernanceAccountType::RealmConfig
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes RealmConfig account and checks owner program
|
||||
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)
|
||||
}
|
||||
|
||||
/// Deserializes RealmConfig account and checks the owner program and the Realm it belongs to
|
||||
pub fn get_realm_config_data_for_realm(
|
||||
program_id: &Pubkey,
|
||||
realm_config_info: &AccountInfo,
|
||||
realm: &Pubkey,
|
||||
) -> Result<RealmConfigAccount, ProgramError> {
|
||||
let realm_config_data = get_realm_config_data(program_id, realm_config_info)?;
|
||||
|
||||
if realm_config_data.realm != *realm {
|
||||
return Err(GovernanceError::InvalidRealmConfigForRealm.into());
|
||||
}
|
||||
|
||||
Ok(realm_config_data)
|
||||
}
|
||||
|
||||
/// Returns RealmConfig PDA seeds
|
||||
pub fn get_realm_config_address_seeds(realm: &Pubkey) -> [&[u8]; 2] {
|
||||
[b"realm-config", realm.as_ref()]
|
||||
}
|
||||
|
||||
/// Returns RealmConfig PDA address
|
||||
pub fn get_realm_config_address(program_id: &Pubkey, realm: &Pubkey) -> Pubkey {
|
||||
Pubkey::find_program_address(&get_realm_config_address_seeds(realm), program_id).0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::state::{enums::GovernanceAccountType, realm_config::RealmConfigAccount};
|
||||
|
||||
#[test]
|
||||
fn test_max_size() {
|
||||
let realm_config = RealmConfigAccount {
|
||||
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()),
|
||||
reserved: [0; 128],
|
||||
};
|
||||
|
||||
let size = realm_config.try_to_vec().unwrap().len();
|
||||
|
||||
assert_eq!(realm_config.get_max_size(), Some(size));
|
||||
}
|
||||
}
|
|
@ -1,15 +1,23 @@
|
|||
//! Token Owner Record Account
|
||||
|
||||
use std::slice::Iter;
|
||||
|
||||
use crate::{
|
||||
addins::voter_weight::get_voter_weight_record_data_for_token_owner_record,
|
||||
error::GovernanceError,
|
||||
state::{enums::GovernanceAccountType, governance::GovernanceConfig, realm::Realm},
|
||||
state::{
|
||||
enums::GovernanceAccountType, governance::GovernanceConfig, realm::Realm,
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
},
|
||||
tools::account::{get_account_data, AccountMaxSize},
|
||||
PROGRAM_AUTHORITY_SEED,
|
||||
};
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized,
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
program_error::ProgramError,
|
||||
program_pack::IsInitialized,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
|
@ -95,8 +103,9 @@ impl TokenOwnerRecord {
|
|||
&self,
|
||||
realm_data: &Realm,
|
||||
config: &GovernanceConfig,
|
||||
voter_weight: u64,
|
||||
) -> Result<(), ProgramError> {
|
||||
let min_tokens_to_create_proposal =
|
||||
let min_weight_to_create_proposal =
|
||||
if self.governing_token_mint == realm_data.community_mint {
|
||||
config.min_community_tokens_to_create_proposal
|
||||
} else if Some(self.governing_token_mint) == realm_data.config.council_mint {
|
||||
|
@ -105,11 +114,11 @@ impl TokenOwnerRecord {
|
|||
return Err(GovernanceError::InvalidGoverningTokenMint.into());
|
||||
};
|
||||
|
||||
if self.governing_token_deposit_amount < min_tokens_to_create_proposal {
|
||||
if voter_weight < min_weight_to_create_proposal {
|
||||
return Err(GovernanceError::NotEnoughTokensToCreateProposal.into());
|
||||
}
|
||||
|
||||
// The number of outstanding proposals is currently restricted to 1
|
||||
// The number of outstanding proposals is currently restricted to 10
|
||||
// If there is a need to change it in the future then it should be added to realm or governance config
|
||||
if self.outstanding_proposal_count >= 10 {
|
||||
return Err(GovernanceError::TooManyOutstandingProposals.into());
|
||||
|
@ -119,8 +128,12 @@ impl TokenOwnerRecord {
|
|||
}
|
||||
|
||||
/// Asserts TokenOwner has enough tokens to be allowed to create governance
|
||||
pub fn assert_can_create_governance(&self, realm_data: &Realm) -> Result<(), ProgramError> {
|
||||
let min_tokens_to_create_governance =
|
||||
pub fn assert_can_create_governance(
|
||||
&self,
|
||||
realm_data: &Realm,
|
||||
voter_weight: u64,
|
||||
) -> Result<(), ProgramError> {
|
||||
let min_weight_to_create_governance =
|
||||
if self.governing_token_mint == realm_data.community_mint {
|
||||
realm_data.config.min_community_tokens_to_create_governance
|
||||
} else if Some(self.governing_token_mint) == realm_data.config.council_mint {
|
||||
|
@ -130,13 +143,30 @@ impl TokenOwnerRecord {
|
|||
return Err(GovernanceError::InvalidGoverningTokenMint.into());
|
||||
};
|
||||
|
||||
if self.governing_token_deposit_amount < min_tokens_to_create_governance {
|
||||
if voter_weight < min_weight_to_create_governance {
|
||||
return Err(GovernanceError::NotEnoughTokensToCreateGovernance.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Asserts TokenOwner can withdraw tokens from Realm
|
||||
pub fn assert_can_withdraw_governing_tokens(&self) -> Result<(), ProgramError> {
|
||||
if self.unrelinquished_votes_count > 0 {
|
||||
return Err(
|
||||
GovernanceError::AllVotesMustBeRelinquishedToWithdrawGoverningTokens.into(),
|
||||
);
|
||||
}
|
||||
|
||||
if self.outstanding_proposal_count > 0 {
|
||||
return Err(
|
||||
GovernanceError::AllProposalsMustBeFinalisedToWithdrawGoverningTokens.into(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decreases outstanding_proposal_count
|
||||
pub fn decrease_outstanding_proposal_count(&mut self) {
|
||||
// Previous versions didn't use the count and it can be already 0
|
||||
|
@ -146,6 +176,36 @@ impl TokenOwnerRecord {
|
|||
self.outstanding_proposal_count.checked_sub(1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves voter's weight using either the amount deposited into the realm or weight provided by voter weight addin (if configured)
|
||||
pub fn resolve_voter_weight(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
account_info_iter: &mut Iter<AccountInfo>,
|
||||
realm: &Pubkey,
|
||||
realm_data: &Realm,
|
||||
) -> Result<u64, ProgramError> {
|
||||
// if the realm uses addin for community voter weight then use the externally provided weight
|
||||
if realm_data.config.use_community_voter_weight_addin
|
||||
&& realm_data.community_mint == self.governing_token_mint
|
||||
{
|
||||
let realm_config_info = next_account_info(account_info_iter)?;
|
||||
let voter_weight_record_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm)?;
|
||||
|
||||
let voter_weight_record_data = get_voter_weight_record_data_for_token_owner_record(
|
||||
&realm_config_data.community_voter_weight_addin.unwrap(),
|
||||
voter_weight_record_info,
|
||||
self,
|
||||
)?;
|
||||
voter_weight_record_data.assert_is_up_to_date()?;
|
||||
Ok(voter_weight_record_data.voter_weight)
|
||||
} else {
|
||||
Ok(self.governing_token_deposit_amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns TokenOwnerRecord PDA address
|
||||
|
|
Binary file not shown.
|
@ -18,7 +18,8 @@ async fn test_add_signatory() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -64,7 +65,8 @@ async fn test_add_signatory_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -82,7 +84,8 @@ async fn test_add_signatory_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let other_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = other_token_owner_record_cookie.token_owner;
|
||||
|
||||
|
@ -110,7 +113,8 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -128,7 +132,8 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() {
|
|||
|
||||
let other_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.address = other_token_owner_record_cookie.address;
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ async fn test_cancel_proposal() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -66,7 +67,8 @@ async fn test_cancel_proposal_with_already_completed_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -112,7 +114,8 @@ async fn test_cancel_proposal_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -130,7 +133,8 @@ async fn test_cancel_proposal_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ async fn test_cast_vote() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -98,7 +99,8 @@ async fn test_cast_vote_with_invalid_governance_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -148,7 +150,8 @@ async fn test_cast_vote_with_invalid_mint_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -188,7 +191,8 @@ async fn test_cast_vote_with_invalid_token_owner_record_mint_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -207,7 +211,8 @@ async fn test_cast_vote_with_invalid_token_owner_record_mint_error() {
|
|||
// Try to use token_owner_record for Council Mint with Community Proposal
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.address = token_owner_record_cookie2.address;
|
||||
|
||||
|
@ -234,7 +239,8 @@ async fn test_cast_vote_with_invalid_token_owner_record_from_different_realm_err
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -255,7 +261,8 @@ async fn test_cast_vote_with_invalid_token_owner_record_from_different_realm_err
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie2)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.address = token_owner_record_cookie2.address;
|
||||
|
||||
|
@ -279,7 +286,8 @@ async fn test_cast_vote_with_governance_authority_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -298,7 +306,8 @@ async fn test_cast_vote_with_governance_authority_must_sign_error() {
|
|||
// Try to use a different owner to sign
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
||||
|
@ -325,7 +334,8 @@ async fn test_cast_vote_with_vote_tipped_to_succeeded() {
|
|||
|
||||
let token_owner_record_cookie1 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -338,11 +348,13 @@ async fn test_cast_vote_with_vote_tipped_to_succeeded() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let token_owner_record_cookie3 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governance_test
|
||||
.mint_community_tokens(&realm_cookie, 20)
|
||||
|
@ -413,7 +425,8 @@ async fn test_cast_vote_with_vote_tipped_to_defeated() {
|
|||
// 100 votes
|
||||
let token_owner_record_cookie1 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -427,12 +440,14 @@ async fn test_cast_vote_with_vote_tipped_to_defeated() {
|
|||
// 100 votes
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// 100 votes
|
||||
let token_owner_record_cookie3 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Total 320 votes
|
||||
governance_test
|
||||
|
@ -507,7 +522,8 @@ async fn test_cast_vote_with_threshold_below_50_and_vote_not_tipped() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance_using_config(
|
||||
|
@ -560,7 +576,8 @@ async fn test_cast_vote_with_voting_time_expired_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -610,7 +627,8 @@ async fn test_cast_vote_with_cast_twice_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -16,7 +16,8 @@ async fn test_create_account_governance() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let account_governance_cookie = governance_test
|
||||
|
@ -49,7 +50,8 @@ async fn test_create_account_governance_with_invalid_realm_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -88,7 +90,8 @@ async fn test_create_account_governance_with_invalid_config_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Arrange
|
||||
let mut config = governance_test.get_default_governance_config();
|
||||
|
@ -144,7 +147,8 @@ async fn test_create_account_governance_with_not_enough_community_tokens_error()
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
|
@ -177,7 +181,8 @@ async fn test_create_account_governance_with_not_enough_council_tokens_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
|
|
|
@ -18,7 +18,8 @@ async fn test_create_mint_governance() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let mint_governance_cookie = governance_test
|
||||
|
@ -57,7 +58,8 @@ async fn test_create_mint_governance_without_transferring_mint_authority() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_mint_cookie.transfer_mint_authority = false;
|
||||
// Act
|
||||
|
@ -98,7 +100,8 @@ async fn test_create_mint_governance_without_transferring_mint_authority_with_in
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_mint_cookie.transfer_mint_authority = false;
|
||||
governed_mint_cookie.mint_authority = Keypair::new();
|
||||
|
@ -129,7 +132,8 @@ async fn test_create_mint_governance_without_transferring_mint_authority_with_au
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_mint_cookie.transfer_mint_authority = false;
|
||||
|
||||
|
@ -142,7 +146,7 @@ async fn test_create_mint_governance_without_transferring_mint_authority_with_au
|
|||
|i| {
|
||||
i.accounts[3].is_signer = false; // governed_mint_authority
|
||||
},
|
||||
Some(&[]),
|
||||
Some(&[&token_owner_record_cookie.token_owner]),
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -162,7 +166,8 @@ async fn test_create_mint_governance_with_invalid_mint_authority_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_mint_cookie.mint_authority = Keypair::new();
|
||||
|
||||
|
@ -191,7 +196,8 @@ async fn test_create_mint_governance_with_invalid_realm_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
|
|
@ -20,7 +20,8 @@ async fn test_create_program_governance() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let program_governance_cookie = governance_test
|
||||
|
@ -61,7 +62,8 @@ async fn test_create_program_governance_without_transferring_upgrade_authority()
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_program_cookie.transfer_upgrade_authority = false;
|
||||
|
||||
|
@ -108,7 +110,8 @@ async fn test_create_program_governance_without_transferring_upgrade_authority_w
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_program_cookie.transfer_upgrade_authority = false;
|
||||
governed_program_cookie.upgrade_authority = Keypair::new();
|
||||
|
@ -139,7 +142,8 @@ async fn test_create_program_governance_without_transferring_upgrade_authority_w
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_program_cookie.transfer_upgrade_authority = false;
|
||||
|
||||
|
@ -152,7 +156,7 @@ async fn test_create_program_governance_without_transferring_upgrade_authority_w
|
|||
|i| {
|
||||
i.accounts[4].is_signer = false; // governed_program_upgrade_authority
|
||||
},
|
||||
Some(&[]),
|
||||
Some(&[&token_owner_record_cookie.token_owner]),
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -172,7 +176,8 @@ async fn test_create_program_governance_with_incorrect_upgrade_authority_error()
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_program_cookie.upgrade_authority = Keypair::new();
|
||||
|
||||
|
@ -201,7 +206,8 @@ async fn test_create_program_governance_with_invalid_realm_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let program_governance_cookie = governance_test
|
||||
.with_program_governance(
|
||||
|
|
|
@ -19,7 +19,8 @@ async fn test_create_community_proposal() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -66,7 +67,8 @@ async fn test_create_multiple_proposals() {
|
|||
|
||||
let community_token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -79,7 +81,8 @@ async fn test_create_multiple_proposals() {
|
|||
|
||||
let council_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let community_proposal_cookie = governance_test
|
||||
|
@ -131,7 +134,8 @@ async fn test_create_proposal_with_not_authorized_governance_authority_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -168,7 +172,8 @@ async fn test_create_proposal_with_governance_delegate_signer() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -210,7 +215,8 @@ async fn test_create_proposal_with_not_enough_community_tokens_error() {
|
|||
|
||||
let token_owner_record_cookie1 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -226,7 +232,8 @@ async fn test_create_proposal_with_not_enough_community_tokens_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
|
@ -252,7 +259,8 @@ async fn test_create_proposal_with_not_enough_council_tokens_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -284,7 +292,8 @@ async fn test_create_proposal_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -297,7 +306,8 @@ async fn test_create_proposal_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let council_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
|
@ -331,7 +341,8 @@ async fn test_create_proposal_with_invalid_governing_token_mint_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -366,7 +377,8 @@ async fn test_create_community_proposal_using_council_tokens() {
|
|||
|
||||
let mut community_token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -379,7 +391,8 @@ async fn test_create_community_proposal_using_council_tokens() {
|
|||
|
||||
let council_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Change the proposal owner to council token owner
|
||||
community_token_owner_record_cookie.address = council_token_owner_record_cookie.address;
|
||||
|
@ -420,7 +433,8 @@ async fn test_create_council_proposal_using_community_tokens() {
|
|||
|
||||
let mut council_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -433,7 +447,8 @@ async fn test_create_council_proposal_using_community_tokens() {
|
|||
|
||||
let community_token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Change the proposal owner to community token owner
|
||||
council_token_owner_record_cookie.address = community_token_owner_record_cookie.address;
|
||||
|
|
|
@ -33,6 +33,7 @@ async fn test_create_realm_with_non_default_config() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(1),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
|
@ -18,7 +18,8 @@ async fn test_create_token_governance() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let token_governance_cookie = governance_test
|
||||
|
@ -54,7 +55,8 @@ async fn test_create_token_governance_without_transferring_token_owner() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_token_cookie.transfer_token_owner = false;
|
||||
|
||||
|
@ -96,7 +98,8 @@ async fn test_create_token_governance_without_transferring_token_owner_with_inva
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_token_cookie.transfer_token_owner = false;
|
||||
governed_token_cookie.token_owner = Keypair::new();
|
||||
|
@ -127,7 +130,8 @@ async fn test_create_token_governance_without_transferring_token_owner_with_owne
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_token_cookie.transfer_token_owner = false;
|
||||
|
||||
|
@ -140,7 +144,7 @@ async fn test_create_token_governance_without_transferring_token_owner_with_owne
|
|||
|i| {
|
||||
i.accounts[3].is_signer = false; // governed_token_owner
|
||||
},
|
||||
Some(&[]),
|
||||
Some(&[&token_owner_record_cookie.token_owner]),
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -160,7 +164,8 @@ async fn test_create_token_governance_with_invalid_token_owner_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governed_token_cookie.token_owner = Keypair::new();
|
||||
|
||||
|
@ -189,7 +194,8 @@ async fn test_create_token_governance_with_invalid_realm_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let token_governance_cookie = governance_test
|
||||
.with_token_governance(
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use solana_program_test::*;
|
||||
|
||||
mod program_test;
|
||||
|
||||
use program_test::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_token_owner_record() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
// Act
|
||||
let token_owner_record_cookie = governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
// Assert
|
||||
let token_owner_record_account = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(0, token_owner_record_account.governing_token_deposit_amount);
|
||||
|
||||
assert_eq!(
|
||||
token_owner_record_cookie.account,
|
||||
token_owner_record_account
|
||||
);
|
||||
}
|
|
@ -18,7 +18,8 @@ async fn test_deposit_initial_community_tokens() {
|
|||
// Act
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
|
@ -61,7 +62,8 @@ async fn test_deposit_initial_council_tokens() {
|
|||
// Act
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
let token_owner_record = governance_test
|
||||
|
@ -100,7 +102,8 @@ async fn test_deposit_subsequent_community_tokens() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let deposit_amount = 5;
|
||||
let total_deposit_amount = token_owner_record_cookie
|
||||
|
@ -146,7 +149,8 @@ async fn test_deposit_subsequent_council_tokens() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let deposit_amount = 5;
|
||||
let total_deposit_amount = token_owner_record_cookie
|
||||
|
@ -283,7 +287,8 @@ async fn test_deposit_community_tokens_with_malicious_holding_account_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governance_test
|
||||
.bench
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![cfg(feature = "test-bpf-all")]
|
||||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
mod program_test;
|
||||
|
||||
|
@ -26,7 +26,8 @@ async fn test_execute_mint_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -72,7 +73,7 @@ async fn test_execute_mint_instruction() {
|
|||
.advance_clock_by_min_timespan(proposal_instruction_cookie.account.hold_up_time as u64)
|
||||
.await;
|
||||
|
||||
let clock = governance_test.get_clock().await;
|
||||
let clock = governance_test.bench.get_clock().await;
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -122,7 +123,8 @@ async fn test_execute_transfer_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut token_governance_cookie = governance_test
|
||||
.with_token_governance(
|
||||
|
@ -168,7 +170,7 @@ async fn test_execute_transfer_instruction() {
|
|||
.advance_clock_by_min_timespan(proposal_instruction_cookie.account.hold_up_time as u64)
|
||||
.await;
|
||||
|
||||
let clock = governance_test.get_clock().await;
|
||||
let clock = governance_test.bench.get_clock().await;
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -218,7 +220,8 @@ async fn test_execute_upgrade_program_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut program_governance_cookie = governance_test
|
||||
.with_program_governance(
|
||||
|
@ -275,6 +278,7 @@ async fn test_execute_upgrade_program_instruction() {
|
|||
);
|
||||
|
||||
let err = governance_test
|
||||
.bench
|
||||
.process_transaction(&[governed_program_instruction.clone()], None)
|
||||
.await
|
||||
.err()
|
||||
|
@ -283,7 +287,7 @@ async fn test_execute_upgrade_program_instruction() {
|
|||
// solana_bpf_rust_upgradable returns CustomError == 42
|
||||
assert_eq!(ProgramError::Custom(42), err);
|
||||
|
||||
let clock = governance_test.get_clock().await;
|
||||
let clock = governance_test.bench.get_clock().await;
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -321,6 +325,7 @@ async fn test_execute_upgrade_program_instruction() {
|
|||
governance_test.advance_clock().await;
|
||||
|
||||
let err = governance_test
|
||||
.bench
|
||||
.process_transaction(&[governed_program_instruction.clone()], None)
|
||||
.await
|
||||
.err()
|
||||
|
@ -342,7 +347,8 @@ async fn test_execute_instruction_with_invalid_state_errors() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -504,7 +510,8 @@ async fn test_execute_instruction_for_other_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -553,13 +560,16 @@ async fn test_execute_instruction_for_other_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proposal_cookie2 = governance_test
|
||||
.with_proposal(&token_owner_record_cookie2, &mut mint_governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governance_test.advance_clock().await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.execute_instruction(&proposal_cookie2, &proposal_instruction_cookie)
|
||||
|
@ -584,7 +594,8 @@ async fn test_execute_mint_instruction_twice_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
|
|
@ -25,7 +25,8 @@ async fn test_finalize_vote_to_succeeded() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance_using_config(
|
||||
|
@ -117,7 +118,8 @@ async fn test_finalize_vote_to_defeated() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -184,7 +186,8 @@ async fn test_finalize_vote_with_invalid_mint_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -243,7 +246,8 @@ async fn test_finalize_vote_with_invalid_governance_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -21,7 +21,8 @@ async fn test_execute_flag_instruction_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -107,7 +108,8 @@ async fn test_execute_instruction_after_flagged_with_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -196,7 +198,8 @@ async fn test_execute_second_instruction_after_first_instruction_flagged_with_er
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -281,7 +284,8 @@ async fn test_flag_instruction_error_with_instruction_already_executed_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
|
@ -365,7 +369,8 @@ async fn test_flag_instruction_error_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -408,7 +413,8 @@ async fn test_flag_instruction_error_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to maliciously sign using different owner signature
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
|
|
@ -17,7 +17,8 @@ async fn test_insert_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -69,7 +70,8 @@ async fn test_insert_multiple_instructions() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -117,7 +119,8 @@ async fn test_insert_instruction_with_invalid_index_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -154,7 +157,8 @@ async fn test_insert_instruction_with_instruction_already_exists_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -202,7 +206,8 @@ async fn test_insert_instruction_with_invalid_hold_up_time_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance_using_config(
|
||||
|
@ -242,7 +247,8 @@ async fn test_insert_instruction_with_not_editable_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -282,7 +288,8 @@ async fn test_insert_instruction_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -300,7 +307,8 @@ async fn test_insert_instruction_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
||||
|
@ -328,7 +336,8 @@ async fn test_insert_instruction_with_invalid_governance_for_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -18,7 +18,8 @@ async fn test_relinquish_voted_proposal() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -79,7 +80,8 @@ async fn test_relinquish_active_yes_vote() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -146,7 +148,8 @@ async fn test_relinquish_active_no_vote() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -213,7 +216,8 @@ async fn test_relinquish_vote_with_invalid_mint_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -259,7 +263,8 @@ async fn test_relinquish_vote_with_governance_authority_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -288,7 +293,8 @@ async fn test_relinquish_vote_with_governance_authority_must_sign_error() {
|
|||
// Try to use a different owner to sign
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
||||
|
@ -318,7 +324,8 @@ async fn test_relinquish_vote_with_invalid_vote_record_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -331,7 +338,8 @@ async fn test_relinquish_vote_with_invalid_vote_record_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Total 400 tokens
|
||||
governance_test
|
||||
|
@ -382,7 +390,8 @@ async fn test_relinquish_vote_with_already_relinquished_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -17,7 +17,8 @@ async fn test_remove_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -77,7 +78,8 @@ async fn test_replace_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -147,7 +149,8 @@ async fn test_remove_front_instruction() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -210,7 +213,8 @@ async fn test_remove_instruction_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -233,7 +237,8 @@ async fn test_remove_instruction_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner;
|
||||
|
||||
|
@ -265,7 +270,8 @@ async fn test_remove_instruction_with_proposal_not_editable_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -319,7 +325,8 @@ async fn test_remove_instruction_with_instruction_from_other_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -342,7 +349,8 @@ async fn test_remove_instruction_with_instruction_from_other_proposal_error() {
|
|||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut proposal_cookie2 = governance_test
|
||||
.with_proposal(&token_owner_record_cookie2, &mut account_governance_cookie)
|
||||
|
|
|
@ -18,7 +18,8 @@ async fn test_remove_signatory() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -75,7 +76,8 @@ async fn test_remove_signatory_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -98,7 +100,8 @@ async fn test_remove_signatory_with_owner_or_delegate_must_sign_error() {
|
|||
|
||||
let other_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.token_owner = other_token_owner_record_cookie.token_owner;
|
||||
|
||||
|
@ -130,7 +133,8 @@ async fn test_remove_signatory_with_invalid_proposal_owner_error() {
|
|||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -153,7 +157,8 @@ async fn test_remove_signatory_with_invalid_proposal_owner_error() {
|
|||
|
||||
let other_token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
token_owner_record_cookie.address = other_token_owner_record_cookie.address;
|
||||
|
||||
|
@ -182,7 +187,8 @@ async fn test_remove_signatory_with_not_editable_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -241,7 +247,8 @@ async fn test_remove_signatory_with_already_signed_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -22,7 +22,8 @@ async fn test_set_governance_config() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -157,7 +158,8 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -16,7 +16,8 @@ async fn test_set_community_governance_delegate() {
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -41,7 +42,8 @@ async fn test_set_governance_delegate_to_none() {
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governance_test
|
||||
.with_community_governance_delegate(&realm_cookie, &mut token_owner_record_cookie)
|
||||
|
@ -73,7 +75,8 @@ async fn test_set_council_governance_delegate() {
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -98,7 +101,8 @@ async fn test_set_community_governance_delegate_with_owner_must_sign_error() {
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let hacker_governance_delegate = Keypair::new();
|
||||
|
||||
|
@ -136,7 +140,8 @@ async fn test_set_community_governance_delegate_signed_by_governance_delegate()
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
governance_test
|
||||
.with_community_governance_delegate(&realm_cookie, &mut token_owner_record_cookie)
|
||||
|
|
|
@ -23,6 +23,7 @@ async fn test_set_realm_config() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
@ -52,6 +53,7 @@ async fn test_set_realm_config_with_authority_must_sign_error() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
@ -83,6 +85,7 @@ async fn test_set_realm_config_with_no_authority_error() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
governance_test
|
||||
|
@ -119,6 +122,7 @@ async fn test_set_realm_config_with_invalid_authority_error() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let realm_cookie2 = governance_test.with_realm().await;
|
||||
|
@ -150,6 +154,7 @@ async fn test_set_realm_config_with_remove_council() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
@ -179,6 +184,7 @@ async fn test_set_realm_config_with_council_change_error() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
// Try to replace council mint
|
||||
|
@ -210,6 +216,7 @@ async fn test_set_realm_config_with_council_restore_error() {
|
|||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
governance_test
|
||||
|
|
|
@ -17,7 +17,8 @@ async fn test_sign_off_proposal() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -75,7 +76,8 @@ async fn test_sign_off_proposal_with_signatory_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
|
|
@ -22,7 +22,8 @@ async fn test_withdraw_community_tokens() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -61,7 +62,8 @@ async fn test_withdraw_council_tokens() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
|
@ -100,7 +102,8 @@ async fn test_withdraw_community_tokens_with_owner_must_sign_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let hacker_token_destination = Pubkey::new_unique();
|
||||
|
||||
|
@ -136,7 +139,8 @@ async fn test_withdraw_community_tokens_with_token_owner_record_address_mismatch
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let vote_record_address = get_token_owner_record_address(
|
||||
&governance_test.program_id,
|
||||
|
@ -147,7 +151,8 @@ async fn test_withdraw_community_tokens_with_token_owner_record_address_mismatch
|
|||
|
||||
let hacker_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut instruction = withdraw_governing_tokens(
|
||||
&governance_test.program_id,
|
||||
|
@ -185,7 +190,9 @@ async fn test_withdraw_governing_tokens_with_unrelinquished_votes_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
|
@ -229,7 +236,8 @@ async fn test_withdraw_governing_tokens_after_relinquishing_vote() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
|
@ -280,7 +288,8 @@ async fn test_withdraw_tokens_with_malicious_holding_account_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to maliciously withdraw from other token account owned by realm
|
||||
|
||||
|
@ -333,7 +342,9 @@ async fn test_withdraw_governing_tokens_with_outstanding_proposals_error() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
|
@ -372,7 +383,9 @@ async fn test_withdraw_governing_tokens_after_proposal_cancelled() {
|
|||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use solana_program::{instruction::Instruction, pubkey::Pubkey};
|
||||
use solana_sdk::signature::Keypair;
|
||||
use spl_governance::state::{
|
||||
governance::Governance, proposal::Proposal, proposal_instruction::ProposalInstruction,
|
||||
realm::Realm, signatory_record::SignatoryRecord, token_owner_record::TokenOwnerRecord,
|
||||
vote_record::VoteRecord,
|
||||
use spl_governance::{
|
||||
addins::voter_weight::VoterWeightRecord,
|
||||
state::{
|
||||
governance::Governance, proposal::Proposal, proposal_instruction::ProposalInstruction,
|
||||
realm::Realm, realm_config::RealmConfigAccount, signatory_record::SignatoryRecord,
|
||||
token_owner_record::TokenOwnerRecord, vote_record::VoteRecord,
|
||||
},
|
||||
};
|
||||
|
||||
use spl_governance_test_sdk::tools::clone_keypair;
|
||||
|
@ -27,6 +30,14 @@ pub struct RealmCookie {
|
|||
pub council_token_holding_account: Option<Pubkey>,
|
||||
|
||||
pub realm_authority: Option<Keypair>,
|
||||
|
||||
pub realm_config: Option<RealmConfigCookie>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RealmConfigCookie {
|
||||
pub address: Pubkey,
|
||||
pub account: RealmConfigAccount,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -44,6 +55,8 @@ pub struct TokenOwnerRecordCookie {
|
|||
pub governance_authority: Option<Keypair>,
|
||||
|
||||
pub governance_delegate: Keypair,
|
||||
|
||||
pub voter_weight_record: Option<VoterWeightRecordCookie>,
|
||||
}
|
||||
|
||||
impl TokenOwnerRecordCookie {
|
||||
|
@ -145,3 +158,9 @@ pub struct ProposalInstructionCookie {
|
|||
pub account: ProposalInstruction,
|
||||
pub instruction: Instruction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VoterWeightRecordCookie {
|
||||
pub address: Pubkey,
|
||||
pub account: VoterWeightRecord,
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use solana_program::{
|
|||
program_error::ProgramError,
|
||||
program_pack::{IsInitialized, Pack},
|
||||
pubkey::Pubkey,
|
||||
system_program,
|
||||
};
|
||||
|
||||
use solana_program_test::*;
|
||||
|
@ -14,13 +15,15 @@ use solana_program_test::*;
|
|||
use solana_sdk::signature::{Keypair, Signer};
|
||||
|
||||
use spl_governance::{
|
||||
addins::voter_weight::{VoterWeightAccountType, VoterWeightRecord},
|
||||
instruction::{
|
||||
add_signatory, cancel_proposal, cast_vote, create_account_governance,
|
||||
create_mint_governance, create_program_governance, create_proposal, create_realm,
|
||||
create_token_governance, deposit_governing_tokens, execute_instruction, finalize_vote,
|
||||
flag_instruction_error, insert_instruction, relinquish_vote, remove_instruction,
|
||||
remove_signatory, set_governance_config, set_governance_delegate, set_realm_authority,
|
||||
set_realm_config, sign_off_proposal, withdraw_governing_tokens, Vote,
|
||||
create_token_governance, create_token_owner_record, deposit_governing_tokens,
|
||||
execute_instruction, finalize_vote, flag_instruction_error, insert_instruction,
|
||||
relinquish_vote, remove_instruction, remove_signatory, set_governance_config,
|
||||
set_governance_delegate, set_realm_authority, set_realm_config, sign_off_proposal,
|
||||
withdraw_governing_tokens, Vote,
|
||||
},
|
||||
processor::process_instruction,
|
||||
state::{
|
||||
|
@ -41,6 +44,7 @@ use spl_governance::{
|
|||
get_governing_token_holding_address, get_realm_address, Realm, RealmConfig,
|
||||
RealmConfigArgs,
|
||||
},
|
||||
realm_config::{get_realm_config_address, RealmConfigAccount},
|
||||
signatory_record::{get_signatory_record_address, SignatoryRecord},
|
||||
token_owner_record::{get_token_owner_record_address, TokenOwnerRecord},
|
||||
vote_record::{get_vote_record_address, VoteRecord},
|
||||
|
@ -49,7 +53,10 @@ use spl_governance::{
|
|||
};
|
||||
|
||||
pub mod cookies;
|
||||
use crate::program_test::cookies::SignatoryRecordCookie;
|
||||
|
||||
use crate::program_test::cookies::{
|
||||
RealmConfigCookie, SignatoryRecordCookie, VoterWeightRecordCookie,
|
||||
};
|
||||
|
||||
use spl_governance_test_sdk::{
|
||||
tools::{clone_keypair, NopOverride},
|
||||
|
@ -66,10 +73,24 @@ pub struct GovernanceProgramTest {
|
|||
pub bench: ProgramTestBench,
|
||||
pub next_realm_id: u8,
|
||||
pub program_id: Pubkey,
|
||||
pub voter_weight_addin_id: Option<Pubkey>,
|
||||
}
|
||||
|
||||
impl GovernanceProgramTest {
|
||||
#[allow(dead_code)]
|
||||
pub async fn start_new() -> Self {
|
||||
Self::start_impl(false).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn start_with_voter_weight_addin() -> Self {
|
||||
Self::start_impl(true).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn start_impl(use_voter_weight_addin: bool) -> Self {
|
||||
let mut programs = vec![];
|
||||
|
||||
let program_id = Pubkey::from_str("Governance111111111111111111111111111111111").unwrap();
|
||||
|
||||
let program = TestBenchProgram {
|
||||
|
@ -78,25 +99,48 @@ impl GovernanceProgramTest {
|
|||
process_instruction: processor!(process_instruction),
|
||||
};
|
||||
|
||||
let bench = ProgramTestBench::start_new(&[program]).await;
|
||||
programs.push(program);
|
||||
|
||||
let voter_weight_addin_id = if use_voter_weight_addin {
|
||||
let voter_weight_addin_id =
|
||||
Pubkey::from_str("VoterWeight11111111111111111111111111111111").unwrap();
|
||||
|
||||
let vote_weight_addin = TestBenchProgram {
|
||||
program_name: "spl_governance_voter_weight_addin",
|
||||
program_id: voter_weight_addin_id,
|
||||
process_instruction: None,
|
||||
};
|
||||
|
||||
programs.push(vote_weight_addin);
|
||||
Some(voter_weight_addin_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let bench = ProgramTestBench::start_new(&programs).await;
|
||||
|
||||
Self {
|
||||
bench,
|
||||
next_realm_id: 0,
|
||||
program_id,
|
||||
voter_weight_addin_id,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_default_realm_config_args(&mut self) -> RealmConfigArgs {
|
||||
RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: self.voter_weight_addin_id.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_realm(&mut self) -> RealmCookie {
|
||||
let config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
min_community_tokens_to_create_governance: 10,
|
||||
};
|
||||
|
||||
self.with_realm_using_config_args(&config_args).await
|
||||
let realm_config_args = self.get_default_realm_config_args();
|
||||
self.with_realm_using_config_args(&realm_config_args).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -157,12 +201,19 @@ impl GovernanceProgramTest {
|
|||
|
||||
let realm_authority = Keypair::new();
|
||||
|
||||
let community_voter_weight_addin = if config_args.use_community_voter_weight_addin {
|
||||
self.voter_weight_addin_id
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let create_realm_instruction = create_realm(
|
||||
&self.program_id,
|
||||
&realm_authority.pubkey(),
|
||||
&community_token_mint_keypair.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
council_token_mint_pubkey,
|
||||
community_voter_weight_addin,
|
||||
name.clone(),
|
||||
config_args.min_community_tokens_to_create_governance,
|
||||
config_args.community_mint_max_vote_weight_source.clone(),
|
||||
|
@ -182,16 +233,34 @@ impl GovernanceProgramTest {
|
|||
authority: Some(realm_authority.pubkey()),
|
||||
config: RealmConfig {
|
||||
council_mint: council_token_mint_pubkey,
|
||||
reserved: [0; 8],
|
||||
reserved: [0; 7],
|
||||
|
||||
min_community_tokens_to_create_governance: config_args
|
||||
.min_community_tokens_to_create_governance,
|
||||
community_mint_max_vote_weight_source: config_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone(),
|
||||
use_community_voter_weight_addin: false,
|
||||
},
|
||||
};
|
||||
|
||||
let realm_config_cookie = if config_args.use_community_voter_weight_addin {
|
||||
Some(RealmConfigCookie {
|
||||
address: get_realm_config_address(&self.program_id, &realm_address),
|
||||
account: RealmConfigAccount {
|
||||
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,
|
||||
reserved: [0; 128],
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
RealmCookie {
|
||||
address: realm_address,
|
||||
account,
|
||||
|
@ -202,6 +271,7 @@ impl GovernanceProgramTest {
|
|||
council_token_holding_account: council_token_holding_address,
|
||||
council_mint_authority: council_token_mint_authority,
|
||||
realm_authority: Some(realm_authority),
|
||||
realm_config: realm_config_cookie,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +294,7 @@ impl GovernanceProgramTest {
|
|||
&realm_cookie.account.community_mint,
|
||||
&self.bench.context.payer.pubkey(),
|
||||
Some(council_mint),
|
||||
None,
|
||||
name.clone(),
|
||||
min_community_tokens_to_create_governance,
|
||||
community_mint_max_vote_weight_source,
|
||||
|
@ -243,11 +314,12 @@ impl GovernanceProgramTest {
|
|||
authority: Some(realm_authority.pubkey()),
|
||||
config: RealmConfig {
|
||||
council_mint: Some(council_mint),
|
||||
reserved: [0; 8],
|
||||
reserved: [0; 7],
|
||||
|
||||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
min_community_tokens_to_create_governance,
|
||||
use_community_voter_weight_addin: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -272,6 +344,7 @@ impl GovernanceProgramTest {
|
|||
realm_cookie.council_mint_authority.as_ref().unwrap(),
|
||||
)),
|
||||
realm_authority: Some(realm_authority),
|
||||
realm_config: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +352,7 @@ impl GovernanceProgramTest {
|
|||
pub async fn with_community_token_deposit(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
self.with_initial_governing_token_deposit(
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
|
@ -289,12 +362,64 @@ impl GovernanceProgramTest {
|
|||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_token_owner_record(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
let token_owner = Keypair::new();
|
||||
|
||||
let create_token_owner_record_ix = create_token_owner_record(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&token_owner.pubkey(),
|
||||
&realm_cookie.account.community_mint,
|
||||
&self.bench.payer.pubkey(),
|
||||
);
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[create_token_owner_record_ix], None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let account = TokenOwnerRecord {
|
||||
account_type: GovernanceAccountType::TokenOwnerRecord,
|
||||
realm: realm_cookie.address,
|
||||
governing_token_mint: realm_cookie.account.community_mint,
|
||||
governing_token_owner: token_owner.pubkey(),
|
||||
governing_token_deposit_amount: 0,
|
||||
governance_delegate: None,
|
||||
unrelinquished_votes_count: 0,
|
||||
total_votes_count: 0,
|
||||
outstanding_proposal_count: 0,
|
||||
reserved: [0; 7],
|
||||
};
|
||||
|
||||
let token_owner_record_address = get_token_owner_record_address(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
&token_owner.pubkey(),
|
||||
);
|
||||
|
||||
TokenOwnerRecordCookie {
|
||||
address: token_owner_record_address,
|
||||
account,
|
||||
token_source_amount: 0,
|
||||
token_source: Pubkey::new_unique(),
|
||||
token_owner,
|
||||
governance_authority: None,
|
||||
governance_delegate: Keypair::new(),
|
||||
voter_weight_record: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_community_token_deposit_amount(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
amount: u64,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
self.with_initial_governing_token_deposit(
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
|
@ -343,7 +468,7 @@ impl GovernanceProgramTest {
|
|||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
amount: u64,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
self.with_initial_governing_token_deposit(
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
|
@ -357,7 +482,7 @@ impl GovernanceProgramTest {
|
|||
pub async fn with_council_token_deposit(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
self.with_initial_governing_token_deposit(
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
|
@ -374,7 +499,7 @@ impl GovernanceProgramTest {
|
|||
governing_mint: &Pubkey,
|
||||
governing_mint_authority: &Keypair,
|
||||
amount: u64,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
let token_owner = Keypair::new();
|
||||
let token_source = Keypair::new();
|
||||
|
||||
|
@ -406,8 +531,7 @@ impl GovernanceProgramTest {
|
|||
&[deposit_governing_tokens_instruction],
|
||||
Some(&[&token_owner]),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await?;
|
||||
|
||||
let token_owner_record_address = get_token_owner_record_address(
|
||||
&self.program_id,
|
||||
|
@ -431,7 +555,7 @@ impl GovernanceProgramTest {
|
|||
|
||||
let governance_delegate = Keypair::from_base58_string(&token_owner.to_base58_string());
|
||||
|
||||
TokenOwnerRecordCookie {
|
||||
Ok(TokenOwnerRecordCookie {
|
||||
address: token_owner_record_address,
|
||||
account,
|
||||
|
||||
|
@ -440,7 +564,8 @@ impl GovernanceProgramTest {
|
|||
token_owner,
|
||||
governance_authority: None,
|
||||
governance_delegate,
|
||||
}
|
||||
voter_weight_record: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -622,9 +747,9 @@ impl GovernanceProgramTest {
|
|||
pub async fn set_realm_config(
|
||||
&mut self,
|
||||
realm_cookie: &mut RealmCookie,
|
||||
config_args: &RealmConfigArgs,
|
||||
realm_config_args: &RealmConfigArgs,
|
||||
) -> Result<(), ProgramError> {
|
||||
self.set_realm_config_using_instruction(realm_cookie, config_args, NopOverride, None)
|
||||
self.set_realm_config_using_instruction(realm_cookie, realm_config_args, NopOverride, None)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -632,23 +757,33 @@ impl GovernanceProgramTest {
|
|||
pub async fn set_realm_config_using_instruction<F: Fn(&mut Instruction)>(
|
||||
&mut self,
|
||||
realm_cookie: &mut RealmCookie,
|
||||
config_args: &RealmConfigArgs,
|
||||
realm_config_args: &RealmConfigArgs,
|
||||
instruction_override: F,
|
||||
signers_override: Option<&[&Keypair]>,
|
||||
) -> Result<(), ProgramError> {
|
||||
let council_token_mint = if config_args.use_council_mint {
|
||||
let council_token_mint = if realm_config_args.use_council_mint {
|
||||
realm_cookie.account.config.council_mint
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let community_voter_weight_addin = if realm_config_args.use_community_voter_weight_addin {
|
||||
self.voter_weight_addin_id
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut set_realm_config_ix = set_realm_config(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.realm_authority.as_ref().unwrap().pubkey(),
|
||||
council_token_mint,
|
||||
config_args.min_community_tokens_to_create_governance,
|
||||
config_args.community_mint_max_vote_weight_source.clone(),
|
||||
&self.bench.payer.pubkey(),
|
||||
community_voter_weight_addin,
|
||||
realm_config_args.min_community_tokens_to_create_governance,
|
||||
realm_config_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone(),
|
||||
);
|
||||
|
||||
instruction_override(&mut set_realm_config_ix);
|
||||
|
@ -660,8 +795,31 @@ impl GovernanceProgramTest {
|
|||
realm_cookie
|
||||
.account
|
||||
.config
|
||||
.community_mint_max_vote_weight_source =
|
||||
config_args.community_mint_max_vote_weight_source.clone();
|
||||
.community_mint_max_vote_weight_source = realm_config_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone();
|
||||
|
||||
if realm_config_args.use_community_voter_weight_addin {
|
||||
let community_voter_weight_addin_index = if realm_config_args.use_council_mint {
|
||||
7
|
||||
} else {
|
||||
5
|
||||
};
|
||||
realm_cookie.realm_config = Some(RealmConfigCookie {
|
||||
address: get_realm_config_address(&self.program_id, &realm_cookie.address),
|
||||
account: RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: realm_cookie.address,
|
||||
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,
|
||||
reserved: [0; 128],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[set_realm_config_ix], Some(signers))
|
||||
|
@ -820,12 +978,21 @@ impl GovernanceProgramTest {
|
|||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
governance_config: &GovernanceConfig,
|
||||
) -> Result<GovernanceCookie, ProgramError> {
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let create_account_governance_instruction = create_account_governance(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&governed_account_cookie.address,
|
||||
&token_owner_record_cookie.address,
|
||||
&self.bench.payer.pubkey(),
|
||||
&token_owner_record_cookie.token_owner.pubkey(),
|
||||
voter_weight_record,
|
||||
governance_config.clone(),
|
||||
);
|
||||
|
||||
|
@ -839,7 +1006,10 @@ impl GovernanceProgramTest {
|
|||
};
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[create_account_governance_instruction], None)
|
||||
.process_transaction(
|
||||
&[create_account_governance_instruction],
|
||||
Some(&[&token_owner_record_cookie.token_owner]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let account_governance_address = get_account_governance_address(
|
||||
|
@ -957,6 +1127,13 @@ impl GovernanceProgramTest {
|
|||
) -> Result<GovernanceCookie, ProgramError> {
|
||||
let config = self.get_default_governance_config();
|
||||
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut create_program_governance_instruction = create_program_governance(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
|
@ -964,13 +1141,18 @@ impl GovernanceProgramTest {
|
|||
&governed_program_cookie.upgrade_authority.pubkey(),
|
||||
&token_owner_record_cookie.address,
|
||||
&self.bench.payer.pubkey(),
|
||||
&token_owner_record_cookie.token_owner.pubkey(),
|
||||
voter_weight_record,
|
||||
config.clone(),
|
||||
governed_program_cookie.transfer_upgrade_authority,
|
||||
);
|
||||
|
||||
instruction_override(&mut create_program_governance_instruction);
|
||||
|
||||
let default_signers = &[&governed_program_cookie.upgrade_authority];
|
||||
let default_signers = &[
|
||||
&governed_program_cookie.upgrade_authority,
|
||||
&token_owner_record_cookie.token_owner,
|
||||
];
|
||||
let signers = signers_override.unwrap_or(default_signers);
|
||||
|
||||
self.bench
|
||||
|
@ -1027,6 +1209,13 @@ impl GovernanceProgramTest {
|
|||
) -> Result<GovernanceCookie, ProgramError> {
|
||||
let config = self.get_default_governance_config();
|
||||
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut create_mint_governance_instruction = create_mint_governance(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
|
@ -1034,13 +1223,18 @@ impl GovernanceProgramTest {
|
|||
&governed_mint_cookie.mint_authority.pubkey(),
|
||||
&token_owner_record_cookie.address,
|
||||
&self.bench.payer.pubkey(),
|
||||
&token_owner_record_cookie.token_owner.pubkey(),
|
||||
voter_weight_record,
|
||||
config.clone(),
|
||||
governed_mint_cookie.transfer_mint_authority,
|
||||
);
|
||||
|
||||
instruction_override(&mut create_mint_governance_instruction);
|
||||
|
||||
let default_signers = &[&governed_mint_cookie.mint_authority];
|
||||
let default_signers = &[
|
||||
&governed_mint_cookie.mint_authority,
|
||||
&token_owner_record_cookie.token_owner,
|
||||
];
|
||||
let signers = signers_override.unwrap_or(default_signers);
|
||||
|
||||
self.bench
|
||||
|
@ -1097,6 +1291,13 @@ impl GovernanceProgramTest {
|
|||
) -> Result<GovernanceCookie, ProgramError> {
|
||||
let config = self.get_default_governance_config();
|
||||
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut create_token_governance_instruction = create_token_governance(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
|
@ -1104,13 +1305,18 @@ impl GovernanceProgramTest {
|
|||
&governed_token_cookie.token_owner.pubkey(),
|
||||
&token_owner_record_cookie.address,
|
||||
&self.bench.payer.pubkey(),
|
||||
&token_owner_record_cookie.token_owner.pubkey(),
|
||||
voter_weight_record,
|
||||
config.clone(),
|
||||
governed_token_cookie.transfer_token_owner,
|
||||
);
|
||||
|
||||
instruction_override(&mut create_token_governance_instruction);
|
||||
|
||||
let default_signers = &[&governed_token_cookie.token_owner];
|
||||
let default_signers = &[
|
||||
&governed_token_cookie.token_owner,
|
||||
&token_owner_record_cookie.token_owner,
|
||||
];
|
||||
let signers = signers_override.unwrap_or(default_signers);
|
||||
|
||||
self.bench
|
||||
|
@ -1189,12 +1395,20 @@ impl GovernanceProgramTest {
|
|||
|
||||
let governance_authority = token_owner_record_cookie.get_governance_authority();
|
||||
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut create_proposal_instruction = create_proposal(
|
||||
&self.program_id,
|
||||
&governance_cookie.address,
|
||||
&token_owner_record_cookie.address,
|
||||
&governance_authority.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
voter_weight_record,
|
||||
&governance_cookie.account.realm,
|
||||
name.clone(),
|
||||
description_link.clone(),
|
||||
|
@ -1465,6 +1679,13 @@ impl GovernanceProgramTest {
|
|||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
vote: Vote,
|
||||
) -> Result<VoteRecordCookie, ProgramError> {
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
Some(voter_weight_record.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let vote_instruction = cast_vote(
|
||||
&self.program_id,
|
||||
&token_owner_record_cookie.account.realm,
|
||||
|
@ -1475,6 +1696,7 @@ impl GovernanceProgramTest {
|
|||
&token_owner_record_cookie.token_owner.pubkey(),
|
||||
&proposal_cookie.account.governing_token_mint,
|
||||
&self.bench.payer.pubkey(),
|
||||
voter_weight_record,
|
||||
vote.clone(),
|
||||
);
|
||||
|
||||
|
@ -1847,9 +2069,17 @@ impl GovernanceProgramTest {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_realm_account(&mut self, root_governance_address: &Pubkey) -> Realm {
|
||||
pub async fn get_realm_account(&mut self, realm_address: &Pubkey) -> Realm {
|
||||
self.bench.get_borsh_account::<Realm>(realm_address).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_realm_config_data(
|
||||
&mut self,
|
||||
realm_config_address: &Pubkey,
|
||||
) -> RealmConfigAccount {
|
||||
self.bench
|
||||
.get_borsh_account::<Realm>(root_governance_address)
|
||||
.get_borsh_account::<RealmConfigAccount>(realm_config_address)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -1951,4 +2181,56 @@ impl GovernanceProgramTest {
|
|||
pub async fn get_mint_account(&mut self, address: &Pubkey) -> spl_token::state::Mint {
|
||||
self.get_packed_account(address).await
|
||||
}
|
||||
|
||||
/// ----------- VoterWeight Addin -----------------------------
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_voter_weight_addin_deposit(
|
||||
&mut self,
|
||||
token_owner_record_cookie: &mut TokenOwnerRecordCookie,
|
||||
) -> Result<VoterWeightRecordCookie, ProgramError> {
|
||||
let voter_weight_record_account = Keypair::new();
|
||||
|
||||
// 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),
|
||||
AccountMeta::new_readonly(
|
||||
token_owner_record_cookie.account.governing_token_mint,
|
||||
false,
|
||||
),
|
||||
AccountMeta::new_readonly(token_owner_record_cookie.address, false),
|
||||
AccountMeta::new(voter_weight_record_account.pubkey(), true),
|
||||
AccountMeta::new_readonly(self.bench.payer.pubkey(), true),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
];
|
||||
|
||||
let deposit_ix = Instruction {
|
||||
program_id: self.voter_weight_addin_id.unwrap(),
|
||||
accounts,
|
||||
data: vec![1, 100, 0, 0, 0, 0, 0, 0, 0], // 1 - Deposit instruction, 100 amount (u64)
|
||||
};
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[deposit_ix], Some(&[&voter_weight_record_account]))
|
||||
.await?;
|
||||
|
||||
let voter_weight_record_cookie = VoterWeightRecordCookie {
|
||||
address: voter_weight_record_account.pubkey(),
|
||||
account: VoterWeightRecord {
|
||||
account_type: VoterWeightAccountType::VoterWeightRecord,
|
||||
realm: token_owner_record_cookie.account.realm,
|
||||
governing_token_mint: token_owner_record_cookie.account.governing_token_mint,
|
||||
governing_token_owner: token_owner_record_cookie.account.governing_token_owner,
|
||||
voter_weight: 100,
|
||||
voter_weight_expiry: None,
|
||||
},
|
||||
};
|
||||
|
||||
token_owner_record_cookie.voter_weight_record = Some(voter_weight_record_cookie.clone());
|
||||
|
||||
Ok(voter_weight_record_cookie)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use solana_program_test::*;
|
||||
|
||||
mod program_test;
|
||||
|
||||
use program_test::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_realm_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
// Act
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_account_data.config.use_community_voter_weight_addin);
|
||||
|
||||
let realm_config_cookie = realm_cookie.realm_config.unwrap();
|
||||
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_data(&realm_config_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_voter_weight_addin_for_realm_without_addins() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_realm_config_args();
|
||||
realm_config_args.use_community_voter_weight_addin = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
realm_config_args.use_community_voter_weight_addin = true;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_account_data.config.use_community_voter_weight_addin);
|
||||
|
||||
let realm_config_cookie = realm_cookie.realm_config.unwrap();
|
||||
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_data(&realm_config_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_voter_weight_addin_for_realm_without_council_and_addins() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_realm_config_args();
|
||||
realm_config_args.use_community_voter_weight_addin = false;
|
||||
realm_config_args.use_council_mint = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
realm_config_args.use_community_voter_weight_addin = true;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_account_data.config.use_community_voter_weight_addin);
|
||||
|
||||
let realm_config_cookie = realm_cookie.realm_config.unwrap();
|
||||
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_data(&realm_config_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_voter_weight_addin_for_realm_with_existing_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_realm_config_args();
|
||||
realm_config_args.use_community_voter_weight_addin = true;
|
||||
|
||||
let community_voter_weight_addin_address = Pubkey::new_unique();
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config_using_instruction(
|
||||
&mut realm_cookie,
|
||||
&realm_config_args,
|
||||
|i| i.accounts[7].pubkey = community_voter_weight_addin_address,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_account_data.config.use_community_voter_weight_addin);
|
||||
|
||||
let realm_config_cookie = realm_cookie.realm_config.unwrap();
|
||||
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_data(&realm_config_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(
|
||||
realm_config_data.community_voter_weight_addin,
|
||||
Some(community_voter_weight_addin_address)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_without_addins() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_realm_config_args();
|
||||
realm_config_args.use_community_voter_weight_addin = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
realm_config_args.use_community_voter_weight_addin = false;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(!realm_account_data.config.use_community_voter_weight_addin);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_with_existing_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_realm_config_args();
|
||||
realm_config_args.use_community_voter_weight_addin = false;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(!realm_account_data.config.use_community_voter_weight_addin);
|
||||
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_data(&realm_cookie.realm_config.unwrap().address)
|
||||
.await;
|
||||
|
||||
assert!(realm_config_data.community_voter_weight_addin.is_none());
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use solana_program_test::*;
|
||||
|
||||
mod program_test;
|
||||
|
||||
use program_test::*;
|
||||
use spl_governance::{error::GovernanceError, instruction::Vote, state::enums::VoteWeight};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_account_governance_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// // Assert
|
||||
let account_governance_account = governance_test
|
||||
.get_governance_account(&account_governance_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
account_governance_cookie.account,
|
||||
account_governance_account
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_proposal_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let proposal_cookie = governance_test
|
||||
.with_proposal(&token_owner_record_cookie, &mut account_governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// // Assert
|
||||
let proposal_account = governance_test
|
||||
.get_proposal_account(&proposal_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(proposal_cookie.account, proposal_account);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_vote_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proposal_cookie = governance_test
|
||||
.with_signed_off_proposal(&token_owner_record_cookie, &mut account_governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let vote_record_cookie = governance_test
|
||||
.with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Yes)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let vote_record_account = governance_test
|
||||
.get_vote_record_account(&vote_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(VoteWeight::Yes(100), vote_record_account.vote_weight);
|
||||
|
||||
let proposal_account = governance_test
|
||||
.get_proposal_account(&proposal_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(100, proposal_account.yes_votes_count);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_token_governance_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_token_cookie = governance_test.with_governed_token().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let token_governance_cookie = governance_test
|
||||
.with_token_governance(
|
||||
&realm_cookie,
|
||||
&governed_token_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// // Assert
|
||||
let token_governance_account = governance_test
|
||||
.get_governance_account(&token_governance_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(token_governance_cookie.account, token_governance_account);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_mint_governance_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_mint_cookie = governance_test.with_governed_mint().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let mint_governance_cookie = governance_test
|
||||
.with_mint_governance(
|
||||
&realm_cookie,
|
||||
&governed_mint_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// // Assert
|
||||
let mint_governance_account = governance_test
|
||||
.get_governance_account(&mint_governance_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(mint_governance_cookie.account, mint_governance_account);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_program_governance_with_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let governed_program_cookie = governance_test.with_governed_program().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut token_owner_record_cookie =
|
||||
governance_test.with_token_owner_record(&realm_cookie).await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_deposit(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let program_governance_cookie = governance_test
|
||||
.with_program_governance(
|
||||
&realm_cookie,
|
||||
&governed_program_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
let program_governance_account = governance_test
|
||||
.get_governance_account(&program_governance_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
program_governance_cookie.account,
|
||||
program_governance_account
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_realm_with_voter_weight_addin_with_deposits_not_allowed() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
// Act
|
||||
|
||||
let err = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::GoverningTokenDepositsNotAllowed.into()
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Governance Voter Weight Addin
|
||||
|
||||
Governance Voter Weight Addin is a skeleton program which can be used as a template to create custom voter weight addins
|
|
@ -0,0 +1,39 @@
|
|||
[package]
|
||||
name = "spl-governance-voter-weight-addin"
|
||||
version = "0.1.0"
|
||||
description = "Solana Program Library Governance Voter Weight Addin Program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana-program-library"
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
test-bpf = []
|
||||
|
||||
[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.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" ]}
|
||||
thiserror = "1.0"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.5.0"
|
||||
base64 = "0.13"
|
||||
proptest = "1.0"
|
||||
solana-program-test = "1.7.11"
|
||||
solana-sdk = "1.7.11"
|
||||
spl-governance-test-sdk = { version = "0.1.0", path ="../../test-sdk"}
|
||||
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,22 @@
|
|||
//! Program entrypoint
|
||||
#![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))]
|
||||
|
||||
use crate::{error::VoterWeightAddinError, processor};
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
|
||||
program_error::PrintProgramError, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
if let Err(error) = processor::process_instruction(program_id, accounts, instruction_data) {
|
||||
// catch the error so we can print it
|
||||
error.print::<VoterWeightAddinError>();
|
||||
return Err(error);
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//! 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 VoterWeightAddin program
|
||||
#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
|
||||
pub enum VoterWeightAddinError {}
|
||||
|
||||
impl PrintProgramError for VoterWeightAddinError {
|
||||
fn print<E>(&self) {
|
||||
msg!("VOTER-WEIGHT-ADDIN-ERROR: {}", &self.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VoterWeightAddinError> for ProgramError {
|
||||
fn from(e: VoterWeightAddinError) -> Self {
|
||||
ProgramError::Custom(e as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for VoterWeightAddinError {
|
||||
fn type_of() -> &'static str {
|
||||
"Voter Weight Addin Error"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//! Program instructions
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
/// Instructions supported by the VoterWeightInstruction addin program
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum VoterWeightAddinInstruction {
|
||||
/// Revises voter weight providing up to date voter weight
|
||||
///
|
||||
/// 0. `[]` Governance Program Id
|
||||
/// 1. `[]` Realm account
|
||||
/// 2. `[]` Governing Token mint
|
||||
/// 3. `[]` TokenOwnerRecord
|
||||
/// 4. `[writable]` VoterWeightRecord
|
||||
Revise {},
|
||||
|
||||
/// Deposits governing token
|
||||
/// 0. `[]` Governance Program Id
|
||||
/// 1. `[]` Realm account
|
||||
/// 2. `[]` Governing Token mint
|
||||
/// 3. `[]` TokenOwnerRecord
|
||||
/// 4. `[writable]` VoterWeightRecord
|
||||
/// 5. `[signer]` Payer
|
||||
/// 6. `[]` System
|
||||
Deposit {
|
||||
/// The deposit amount
|
||||
#[allow(dead_code)]
|
||||
amount: u64,
|
||||
},
|
||||
|
||||
/// Withdraws deposited tokens
|
||||
/// Note: This instruction should ensure the tokens can be withdrawn form the Realm
|
||||
/// by calling TokenOwnerRecord.assert_can_withdraw_governing_tokens()
|
||||
///
|
||||
/// 0. `[]` Governance Program Id
|
||||
/// 1. `[]` Realm account
|
||||
/// 2. `[]` Governing Token mint
|
||||
/// 3. `[]` TokenOwnerRecord
|
||||
/// 4. `[writable]` VoterWeightRecord
|
||||
Withdraw {},
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#![deny(missing_docs)]
|
||||
//! Governance VoterWeight Addin program
|
||||
|
||||
pub mod entrypoint;
|
||||
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;
|
|
@ -0,0 +1,84 @@
|
|||
//! Program processor
|
||||
|
||||
use borsh::BorshDeserialize;
|
||||
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},
|
||||
entrypoint::ProgramResult,
|
||||
msg,
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
use crate::instruction::VoterWeightAddinInstruction;
|
||||
|
||||
/// Processes an instruction
|
||||
pub fn process_instruction(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
input: &[u8],
|
||||
) -> ProgramResult {
|
||||
let instruction = VoterWeightAddinInstruction::try_from_slice(input)
|
||||
.map_err(|_| ProgramError::InvalidInstructionData)?;
|
||||
|
||||
msg!("GOVERNANCE-VOTER-WEIGHT-INSTRUCTION: {:?}", instruction);
|
||||
|
||||
match instruction {
|
||||
VoterWeightAddinInstruction::Revise {} => Ok(()),
|
||||
VoterWeightAddinInstruction::Deposit { amount } => {
|
||||
process_deposit(program_id, accounts, amount)
|
||||
}
|
||||
VoterWeightAddinInstruction::Withdraw {} => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes Deposit instruction
|
||||
pub fn process_deposit(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
amount: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let governance_program_info = next_account_info(account_info_iter)?; // 0
|
||||
let realm_info = next_account_info(account_info_iter)?; // 1
|
||||
let governing_token_mint_info = next_account_info(account_info_iter)?; // 2
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 3
|
||||
let voter_weight_record_info = next_account_info(account_info_iter)?; // 4
|
||||
let payer_info = next_account_info(account_info_iter)?; // 5
|
||||
let system_info = next_account_info(account_info_iter)?; // 6
|
||||
|
||||
let token_owner_record_data = get_token_owner_record_data_for_realm_and_governing_mint(
|
||||
governance_program_info.key,
|
||||
token_owner_record_info,
|
||||
realm_info.key,
|
||||
governing_token_mint_info.key,
|
||||
)?;
|
||||
|
||||
// TODO: Custom deposit logic and validation goes here
|
||||
|
||||
let voter_weight_record_data = VoterWeightRecord {
|
||||
account_type: VoterWeightAccountType::VoterWeightRecord,
|
||||
realm: *realm_info.key,
|
||||
governing_token_mint: *governing_token_mint_info.key,
|
||||
governing_token_owner: token_owner_record_data.governing_token_owner,
|
||||
voter_weight: amount,
|
||||
voter_weight_expiry: None,
|
||||
};
|
||||
|
||||
create_and_serialize_account(
|
||||
payer_info,
|
||||
voter_weight_record_info,
|
||||
&voter_weight_record_data,
|
||||
program_id,
|
||||
system_info,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue