Governance: Council membership & plugins (#3344)
* chore: Use GovernanceTokenConfig * wip: add council_token_config to RealmConfigAccount * chore: update comment * wip: use GoverningTokenConfigArgs for community token config * chore: Change Proxy token type to Dormant * chore: Update comments * chore: Use GoverningTokenConfigAccountArgs for instructions creators * chore: Use default GoverningTokenType * chore: Make community_token_args optional * chore: Make Clippy happy * chore: Update comments * chore: Always create RealmConfigAccount * chore: Set CouncilTokenConfig when realm is created * feat: Update RealmConfigArgs in SetRealmConfig * chore: Make Clippy happy * chore: Assert RealmConfigAccount PDA * wip: Use default RealmConfigAccount if the account doesn't exist * chore: Remove use_community_voter_weight_addin and use_max_community_voter_weight_addin from RealmConfig * chore: code review cleanup * wip: Use voter weight addin for Council * feat: Use max_voter_weight_plugin for Council * feat: Impl RevokeGoverningTokens instruction * chore: Make Clippy happy * feat: Enforce governing token withdraw and deposit rules * feat: Support minting deposits * feat: Do not enforce token source owner for deposit validation * chore: test_deposit_community_tokens_using_mint * chore: Remove not implemented comment * fix: Fix progrma id for resolving realm config for chat * chore: Update instructions comments * feat: Do not allow community Liquid token change to Membership * chore: test_set_realm_config_with_liquid_community_token_cannot_be_changed_to_memebership_error * chore: test_set_realm_config_for_community_token * chore: use GoverningTokenConfig for test args * chore: Refactor SetRealmConfigArgs * chore: Update RealmSetupArgs names * chore: test_set_realm_config_for_council_token_config * chore: Revoke council tokens tests * chore: test_revoke_council_tokens_with_realm_authority_must_sign_error * chore: test_revoke_council_tokens_with_invalid_realm_authority_error * chore: test_revoke_council_tokens_with_invalid_token_holding_error * chore: RevokeGoverningToken tests * chore: Dormant and Membership tokens tests * chore: Using council plugin tests * chore: RealmConfigAccount validation tests * chore: Update Dormant token type configs * fix: Reset legacy fields * chore: Use Default macro for derivable defaults * Chore: use assert functions to validate spl-token account and mint * chore: Update Membership tokens comments * chore: Pass governing_token_config_args as reference * chore: Use single statement to return InvalidRevokeAmount error * chore: Make Clippy happy - add derived Eq Co-authored-by: Jon Cinque
This commit is contained in:
parent
83b5dabf02
commit
6dfc68db13
|
@ -6,7 +6,7 @@ use spl_governance_tools::account::AccountMaxSize;
|
|||
|
||||
/// MaxVoterWeightRecord account
|
||||
/// The account is used as an api interface to provide max voting power to the governance program from external addin contracts
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct MaxVoterWeightRecord {
|
||||
/// VoterWeightRecord discriminator sha256("account:MaxVoterWeightRecord")[..8]
|
||||
/// Note: The discriminator size must match the addin implementing program discriminator size
|
||||
|
|
|
@ -5,7 +5,7 @@ use solana_program::{clock::Slot, program_pack::IsInitialized, pubkey::Pubkey};
|
|||
use spl_governance_tools::account::AccountMaxSize;
|
||||
|
||||
/// The governance action VoterWeight is evaluated for
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoterWeightAction {
|
||||
/// Cast vote for a proposal. Target: Proposal
|
||||
CastVote,
|
||||
|
@ -26,7 +26,7 @@ pub enum VoterWeightAction {
|
|||
|
||||
/// VoterWeightRecord account
|
||||
/// The account is used as an api interface to provide voting power to the governance program from external addin contracts
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct VoterWeightRecord {
|
||||
/// VoterWeightRecord discriminator sha256("account:VoterWeightRecord")[..8]
|
||||
/// Note: The discriminator size must match the addin implementing program discriminator size
|
||||
|
|
|
@ -11,7 +11,7 @@ use spl_governance_addin_api::voter_weight::VoterWeightAction;
|
|||
|
||||
/// Instructions supported by the VoterWeight addin program
|
||||
/// This program is a mock program used by spl-governance for testing and not real addin
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum VoterWeightAddinInstruction {
|
||||
/// Sets up VoterWeightRecord owned by the program
|
||||
|
|
|
@ -11,7 +11,7 @@ use spl_governance::instruction::with_realm_config_accounts;
|
|||
use crate::state::MessageBody;
|
||||
|
||||
/// Instructions supported by the GovernanceChat program
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GovernanceChatInstruction {
|
||||
/// Posts a message with a comment for a Proposal
|
||||
|
|
|
@ -18,7 +18,8 @@ use solana_program::{
|
|||
};
|
||||
use spl_governance::state::{
|
||||
governance::get_governance_data_for_realm, proposal::get_proposal_data_for_governance,
|
||||
realm::get_realm_data, token_owner_record::get_token_owner_record_data_for_realm,
|
||||
realm::get_realm_data, realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
};
|
||||
use spl_governance_addin_api::voter_weight::VoterWeightAction;
|
||||
use spl_governance_tools::account::create_and_serialize_account;
|
||||
|
@ -92,14 +93,15 @@ pub fn process_post_message(
|
|||
governance_info.key,
|
||||
)?;
|
||||
|
||||
let realm_config_info = next_account_info(account_info_iter)?; //10
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 10
|
||||
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(governance_program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
let voter_weight = token_owner_record_data.resolve_voter_weight(
|
||||
governance_program_id,
|
||||
realm_config_info,
|
||||
account_info_iter, // 11
|
||||
realm_info.key,
|
||||
account_info_iter, // voter_weight_record *11
|
||||
&realm_data,
|
||||
&realm_config_data,
|
||||
VoterWeightAction::CommentProposal,
|
||||
proposal_info.key,
|
||||
)?;
|
||||
|
|
|
@ -8,7 +8,7 @@ use solana_program::{
|
|||
use spl_governance_tools::account::{assert_is_valid_account_of_type, AccountMaxSize};
|
||||
|
||||
/// Defines all GovernanceChat accounts types
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum GovernanceChatAccountType {
|
||||
/// Default uninitialized account state
|
||||
Uninitialized,
|
||||
|
@ -18,7 +18,7 @@ pub enum GovernanceChatAccountType {
|
|||
}
|
||||
|
||||
/// Chat message body
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum MessageBody {
|
||||
/// Text message encoded as utf-8 string
|
||||
Text(String),
|
||||
|
@ -29,7 +29,7 @@ pub enum MessageBody {
|
|||
}
|
||||
|
||||
/// Chat message
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ChatMessage {
|
||||
/// Account type
|
||||
pub account_type: GovernanceChatAccountType,
|
||||
|
|
|
@ -13,7 +13,8 @@ use spl_governance::{
|
|||
enums::{MintMaxVoteWeightSource, VoteThreshold},
|
||||
governance::{get_governance_address, GovernanceConfig},
|
||||
proposal::{get_proposal_address, VoteType},
|
||||
realm::get_realm_address,
|
||||
realm::{get_realm_address, GoverningTokenConfigAccountArgs},
|
||||
realm_config::GoverningTokenType,
|
||||
token_owner_record::get_token_owner_record_address,
|
||||
},
|
||||
};
|
||||
|
@ -108,13 +109,19 @@ impl GovernanceChatProgramTest {
|
|||
|
||||
let realm_authority = Keypair::new();
|
||||
|
||||
let community_token_config_args = GoverningTokenConfigAccountArgs {
|
||||
voter_weight_addin: self.voter_weight_addin_id,
|
||||
max_voter_weight_addin: None,
|
||||
token_type: GoverningTokenType::default(),
|
||||
};
|
||||
|
||||
let create_realm_ix = create_realm(
|
||||
&self.governance_program_id,
|
||||
&realm_authority.pubkey(),
|
||||
&governing_token_mint_keypair.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
None,
|
||||
self.voter_weight_addin_id,
|
||||
Some(community_token_config_args),
|
||||
None,
|
||||
name.clone(),
|
||||
1,
|
||||
|
|
|
@ -261,23 +261,23 @@ pub enum GovernanceError {
|
|||
|
||||
/// Governance PDA must sign
|
||||
#[error("Governance PDA must sign")]
|
||||
GovernancePdaMustSign,
|
||||
GovernancePdaMustSign, // 561
|
||||
|
||||
/// Transaction already flagged with error
|
||||
#[error("Transaction already flagged with error")]
|
||||
TransactionAlreadyFlaggedWithError,
|
||||
TransactionAlreadyFlaggedWithError, // 562
|
||||
|
||||
/// Invalid Realm for Governance
|
||||
#[error("Invalid Realm for Governance")]
|
||||
InvalidRealmForGovernance,
|
||||
InvalidRealmForGovernance, // 563
|
||||
|
||||
/// Invalid Authority for Realm
|
||||
#[error("Invalid Authority for Realm")]
|
||||
InvalidAuthorityForRealm,
|
||||
InvalidAuthorityForRealm, // 564
|
||||
|
||||
/// Realm has no authority
|
||||
#[error("Realm has no authority")]
|
||||
RealmHasNoAuthority,
|
||||
RealmHasNoAuthority, // 565
|
||||
|
||||
/// Realm authority must sign
|
||||
#[error("Realm authority must sign")]
|
||||
|
@ -285,7 +285,7 @@ pub enum GovernanceError {
|
|||
|
||||
/// Invalid governing token holding account
|
||||
#[error("Invalid governing token holding account")]
|
||||
InvalidGoverningTokenHoldingAccount,
|
||||
InvalidGoverningTokenHoldingAccount, // 567
|
||||
|
||||
/// Realm council mint change is not supported
|
||||
#[error("Realm council mint change is not supported")]
|
||||
|
@ -406,6 +406,34 @@ pub enum GovernanceError {
|
|||
/// Cannot Relinquish in Finalizing state
|
||||
#[error("Cannot Relinquish in Finalizing state")]
|
||||
CannotRelinquishInFinalizingState,
|
||||
|
||||
/// Invalid RealmConfig account address
|
||||
#[error("Invalid RealmConfig account address")]
|
||||
InvalidRealmConfigAddress,
|
||||
|
||||
/// Cannot deposit dormant tokens
|
||||
#[error("Cannot deposit dormant tokens")]
|
||||
CannotDepositDormantTokens, // 599
|
||||
|
||||
/// Cannot withdraw membership tokens
|
||||
#[error("Cannot withdraw membership tokens")]
|
||||
CannotWithdrawMembershipTokens, // 600
|
||||
|
||||
/// Cannot revoke GoverningTokens
|
||||
#[error("Cannot revoke GoverningTokens")]
|
||||
CannotRevokeGoverningTokens, // 601
|
||||
|
||||
/// Invalid Revoke amount
|
||||
#[error("Invalid Revoke amount")]
|
||||
InvalidRevokeAmount, // 602
|
||||
|
||||
/// Invalid GoverningToken source
|
||||
#[error("Invalid GoverningToken source")]
|
||||
InvalidGoverningTokenSource, // 603
|
||||
|
||||
/// Cannot change community TokenType to Memebership
|
||||
#[error("Cannot change community TokenType to Memebership")]
|
||||
CannotChangeCommunityTokenTypeToMemebership, // 604
|
||||
}
|
||||
|
||||
impl PrintProgramError for GovernanceError {
|
||||
|
|
|
@ -11,8 +11,11 @@ use crate::{
|
|||
program_metadata::get_program_metadata_address,
|
||||
proposal::{get_proposal_address, VoteType},
|
||||
proposal_transaction::{get_proposal_transaction_address, InstructionData},
|
||||
realm::SetRealmAuthorityAction,
|
||||
realm::{get_governing_token_holding_address, get_realm_address, RealmConfigArgs},
|
||||
realm::{
|
||||
get_governing_token_holding_address, get_realm_address,
|
||||
GoverningTokenConfigAccountArgs, RealmConfigArgs,
|
||||
},
|
||||
realm::{GoverningTokenConfigArgs, SetRealmAuthorityAction},
|
||||
realm_config::get_realm_config_address,
|
||||
signatory_record::get_signatory_record_address,
|
||||
token_owner_record::get_token_owner_record_address,
|
||||
|
@ -29,7 +32,7 @@ use solana_program::{
|
|||
};
|
||||
|
||||
/// Instructions supported by the Governance program
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GovernanceInstruction {
|
||||
/// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint
|
||||
|
@ -48,9 +51,13 @@ pub enum GovernanceInstruction {
|
|||
/// 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. `[]` Optional Community Voter Weight Addin Program Id
|
||||
/// 11. `[]` Optional Max Community Voter Weight Addin Program Id
|
||||
/// 12. `[writable]` Optional RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 10. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
|
||||
/// 11. `[]` Optional Community Voter Weight Addin Program Id
|
||||
/// 12. `[]` Optional Max Community Voter Weight Addin Program Id
|
||||
///
|
||||
/// 13. `[]` Optional Council Voter Weight Addin Program Id
|
||||
/// 14. `[]` Optional Max Council Voter Weight Addin Program Id
|
||||
CreateRealm {
|
||||
#[allow(dead_code)]
|
||||
/// UTF-8 encoded Governance Realm name
|
||||
|
@ -65,16 +72,18 @@ pub enum GovernanceInstruction {
|
|||
/// Note: If subsequent (top up) deposit is made and there are active votes for the Voter then the vote weights won't be updated automatically
|
||||
/// It can be done by relinquishing votes on active Proposals and voting again with the new weight
|
||||
///
|
||||
/// 0. `[]` Governance Realm account
|
||||
/// 0. `[]` Realm account
|
||||
/// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint]
|
||||
/// 2. `[writable]` Governing Token Source account. All tokens from the account will be transferred to the Holding account
|
||||
/// 2. `[writable]` Governing Token Source account. It can be either spl-token TokenAccount or MintAccount
|
||||
/// Tokens will be transferred or minted to the Holding account
|
||||
/// 3. `[signer]` Governing Token Owner account
|
||||
/// 4. `[signer]` Governing Token Transfer authority
|
||||
/// 5. `[writable]` Token Owner Record account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 4. `[signer]` Governing Token Source account authority
|
||||
/// It should be owner for TokenAccount and mint_auhtority for MintAccount
|
||||
/// 5. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 6. `[signer]` Payer
|
||||
/// 7. `[]` System
|
||||
/// 8. `[]` SPL Token
|
||||
/// 9. `[]` Sysvar Rent
|
||||
/// 8. `[]` SPL Token program
|
||||
/// 9. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
DepositGoverningTokens {
|
||||
/// The amount to deposit into the realm
|
||||
#[allow(dead_code)]
|
||||
|
@ -85,12 +94,13 @@ pub enum GovernanceInstruction {
|
|||
/// Note: It's only possible to withdraw tokens if the Voter doesn't have any outstanding active votes
|
||||
/// If there are any outstanding votes then they must be relinquished before tokens could be withdrawn
|
||||
///
|
||||
/// 0. `[]` Governance Realm account
|
||||
/// 0. `[]` Realm account
|
||||
/// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint]
|
||||
/// 2. `[writable]` Governing Token Destination account. All tokens will be transferred to this account
|
||||
/// 3. `[signer]` Governing Token Owner account
|
||||
/// 4. `[writable]` Token Owner Record account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 5. `[]` SPL Token
|
||||
/// 4. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 5. `[]` SPL Token program
|
||||
/// 6. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
WithdrawGoverningTokens {},
|
||||
|
||||
/// Sets Governance Delegate for the given Realm and Governing Token Mint (Community or Council)
|
||||
|
@ -117,7 +127,7 @@ pub enum GovernanceInstruction {
|
|||
/// 5. `[]` System program
|
||||
/// 6. `[]` Sysvar Rent
|
||||
/// 7. `[signer]` Governance authority
|
||||
/// 8. `[]` Realm Config
|
||||
/// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 9. `[]` Optional Voter Weight Record
|
||||
CreateGovernance {
|
||||
/// Governance config
|
||||
|
@ -138,7 +148,7 @@ pub enum GovernanceInstruction {
|
|||
/// 8. `[]` System program
|
||||
/// 9. `[]` Sysvar Rent
|
||||
/// 10. `[signer]` Governance authority
|
||||
/// 11. `[]` Realm Config
|
||||
/// 11. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 12. `[]` Optional Voter Weight Record
|
||||
CreateProgramGovernance {
|
||||
/// Governance config
|
||||
|
@ -162,7 +172,7 @@ pub enum GovernanceInstruction {
|
|||
/// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate)
|
||||
/// 6. `[signer]` Payer
|
||||
/// 7. `[]` System program
|
||||
/// 8. `[]` Realm Config
|
||||
/// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 9. `[]` Optional Voter Weight Record
|
||||
CreateProposal {
|
||||
#[allow(dead_code)]
|
||||
|
@ -295,7 +305,7 @@ pub enum GovernanceInstruction {
|
|||
/// Note: In the current version only Council veto is supported
|
||||
/// 8. `[signer]` Payer
|
||||
/// 9. `[]` System program
|
||||
/// 10. `[]` Realm Config
|
||||
/// 10. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 11. `[]` Optional Voter Weight Record
|
||||
/// 12. `[]` Optional Max Voter Weight Record
|
||||
CastVote {
|
||||
|
@ -311,7 +321,7 @@ pub enum GovernanceInstruction {
|
|||
/// 2. `[writable]` Proposal account
|
||||
/// 3. `[writable]` TokenOwnerRecord of the Proposal owner
|
||||
/// 4. `[]` Governing Token Mint
|
||||
/// 5. `[]` Realm Config
|
||||
/// 5. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 6. `[]` Optional Max Voter Weight Record
|
||||
FinalizeVote {},
|
||||
|
||||
|
@ -355,7 +365,7 @@ pub enum GovernanceInstruction {
|
|||
/// 7. `[]` System program
|
||||
/// 8. `[]` Sysvar Rent
|
||||
/// 8. `[signer]` Governance authority
|
||||
/// 9. `[]` Realm Config
|
||||
/// 9. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 10. `[]` Optional Voter Weight Record
|
||||
CreateMintGovernance {
|
||||
#[allow(dead_code)]
|
||||
|
@ -381,7 +391,7 @@ pub enum GovernanceInstruction {
|
|||
/// 7. `[]` System program
|
||||
/// 8. `[]` Sysvar Rent
|
||||
/// 9. `[signer]` Governance authority
|
||||
/// 10. `[]` Realm Config
|
||||
/// 10. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 11. `[]` Optional Voter Weight Record
|
||||
CreateTokenGovernance {
|
||||
#[allow(dead_code)]
|
||||
|
@ -438,10 +448,14 @@ pub enum GovernanceInstruction {
|
|||
/// The account will be created with the Realm PDA as its owner
|
||||
/// 4. `[]` System
|
||||
/// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
|
||||
///
|
||||
/// 6. `[]` Optional Community Voter Weight Addin Program Id
|
||||
/// 7. `[]` Optional Max Community Voter Weight Addin Program Id
|
||||
/// 8. `[signer]` Optional Payer
|
||||
///
|
||||
/// 8. `[]` Optional Council Voter Weight Addin Program Id
|
||||
/// 9. `[]` Optional Max Council Voter Weight Addin Program Id
|
||||
///
|
||||
/// 10. `[signer]` Optional Payer. Required if RealmConfig doesn't exist and needs to be created
|
||||
SetRealmConfig {
|
||||
#[allow(dead_code)]
|
||||
/// Realm config args
|
||||
|
@ -475,6 +489,22 @@ pub enum GovernanceInstruction {
|
|||
/// 2. `[signer]` Payer
|
||||
/// 3. `[]` System
|
||||
CreateNativeTreasury,
|
||||
|
||||
/// Revokes (burns) membership governing tokens for the given TokenOwnerRecord and hence takes away governance power from the TokenOwner
|
||||
/// Note: If there are active votes for the TokenOwner then the vote weights won't be updated automatically
|
||||
///
|
||||
/// 0. `[]` Realm account
|
||||
/// 1. `[signer]` Realm authority
|
||||
/// 2. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint]
|
||||
/// 3. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner]
|
||||
/// 4. `[writable]` GoverningTokenMint
|
||||
/// 5. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
|
||||
/// 6. `[]` SPL Token program
|
||||
RevokeGoverningTokens {
|
||||
/// The amount to revoke
|
||||
#[allow(dead_code)]
|
||||
amount: u64,
|
||||
},
|
||||
}
|
||||
|
||||
/// Creates CreateRealm instruction
|
||||
|
@ -486,8 +516,9 @@ pub fn create_realm(
|
|||
community_token_mint: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
council_token_mint: Option<Pubkey>,
|
||||
community_voter_weight_addin: Option<Pubkey>,
|
||||
max_community_voter_weight_addin: Option<Pubkey>,
|
||||
// Accounts Args
|
||||
community_token_config_args: Option<GoverningTokenConfigAccountArgs>,
|
||||
council_token_config_args: Option<GoverningTokenConfigAccountArgs>,
|
||||
// Args
|
||||
name: String,
|
||||
min_community_weight_to_create_governance: u64,
|
||||
|
@ -519,40 +550,22 @@ pub fn create_realm(
|
|||
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 realm_config_address = get_realm_config_address(program_id, &realm_address);
|
||||
accounts.push(AccountMeta::new(realm_config_address, false));
|
||||
|
||||
let use_max_community_voter_weight_addin =
|
||||
if let Some(max_community_voter_weight_addin) = max_community_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
max_community_voter_weight_addin,
|
||||
false,
|
||||
));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let community_token_config_args =
|
||||
with_governing_token_config_args(&mut accounts, community_token_config_args);
|
||||
|
||||
if use_community_voter_weight_addin || use_max_community_voter_weight_addin {
|
||||
let realm_config_address = get_realm_config_address(program_id, &realm_address);
|
||||
accounts.push(AccountMeta::new(realm_config_address, false));
|
||||
}
|
||||
let council_token_config_args =
|
||||
with_governing_token_config_args(&mut accounts, council_token_config_args);
|
||||
|
||||
let instruction = GovernanceInstruction::CreateRealm {
|
||||
config_args: RealmConfigArgs {
|
||||
use_council_mint,
|
||||
min_community_weight_to_create_governance,
|
||||
community_mint_max_vote_weight_source,
|
||||
use_community_voter_weight_addin,
|
||||
use_max_community_voter_weight_addin,
|
||||
community_token_config_args,
|
||||
council_token_config_args,
|
||||
},
|
||||
name,
|
||||
};
|
||||
|
@ -572,7 +585,7 @@ pub fn deposit_governing_tokens(
|
|||
realm: &Pubkey,
|
||||
governing_token_source: &Pubkey,
|
||||
governing_token_owner: &Pubkey,
|
||||
governing_token_transfer_authority: &Pubkey,
|
||||
governing_token_source_authority: &Pubkey,
|
||||
payer: &Pubkey,
|
||||
// Args
|
||||
amount: u64,
|
||||
|
@ -588,16 +601,19 @@ pub fn deposit_governing_tokens(
|
|||
let governing_token_holding_address =
|
||||
get_governing_token_holding_address(program_id, realm, governing_token_mint);
|
||||
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(governing_token_holding_address, false),
|
||||
AccountMeta::new(*governing_token_source, false),
|
||||
AccountMeta::new_readonly(*governing_token_owner, true),
|
||||
AccountMeta::new_readonly(*governing_token_transfer_authority, true),
|
||||
AccountMeta::new_readonly(*governing_token_source_authority, true),
|
||||
AccountMeta::new(token_owner_record_address, false),
|
||||
AccountMeta::new(*payer, true),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(realm_config_address, false),
|
||||
];
|
||||
|
||||
let instruction = GovernanceInstruction::DepositGoverningTokens { amount };
|
||||
|
@ -629,6 +645,8 @@ pub fn withdraw_governing_tokens(
|
|||
let governing_token_holding_address =
|
||||
get_governing_token_holding_address(program_id, realm, governing_token_mint);
|
||||
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new(governing_token_holding_address, false),
|
||||
|
@ -636,6 +654,7 @@ pub fn withdraw_governing_tokens(
|
|||
AccountMeta::new_readonly(*governing_token_owner, true),
|
||||
AccountMeta::new(token_owner_record_address, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(realm_config_address, false),
|
||||
];
|
||||
|
||||
let instruction = GovernanceInstruction::WithdrawGoverningTokens {};
|
||||
|
@ -1355,8 +1374,9 @@ pub fn set_realm_config(
|
|||
realm_authority: &Pubkey,
|
||||
council_token_mint: Option<Pubkey>,
|
||||
payer: &Pubkey,
|
||||
community_voter_weight_addin: Option<Pubkey>,
|
||||
max_community_voter_weight_addin: Option<Pubkey>,
|
||||
// Accounts Args
|
||||
community_token_config_args: Option<GoverningTokenConfigAccountArgs>,
|
||||
council_token_config_args: Option<GoverningTokenConfigAccountArgs>,
|
||||
// Args
|
||||
min_community_weight_to_create_governance: u64,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource,
|
||||
|
@ -1384,39 +1404,21 @@ pub fn set_realm_config(
|
|||
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_readonly(
|
||||
community_voter_weight_addin,
|
||||
false,
|
||||
));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let community_token_config_args =
|
||||
with_governing_token_config_args(&mut accounts, community_token_config_args);
|
||||
|
||||
let use_max_community_voter_weight_addin =
|
||||
if let Some(max_community_voter_weight_addin) = max_community_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
max_community_voter_weight_addin,
|
||||
false,
|
||||
));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let council_token_config_args =
|
||||
with_governing_token_config_args(&mut accounts, council_token_config_args);
|
||||
|
||||
if use_community_voter_weight_addin || use_max_community_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new(*payer, true));
|
||||
}
|
||||
accounts.push(AccountMeta::new(*payer, true));
|
||||
|
||||
let instruction = GovernanceInstruction::SetRealmConfig {
|
||||
config_args: RealmConfigArgs {
|
||||
use_council_mint,
|
||||
min_community_weight_to_create_governance,
|
||||
community_mint_max_vote_weight_source,
|
||||
use_community_voter_weight_addin,
|
||||
use_max_community_voter_weight_addin,
|
||||
community_token_config_args,
|
||||
council_token_config_args,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1536,3 +1538,77 @@ pub fn create_native_treasury(
|
|||
data: instruction.try_to_vec().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates RevokeGoverningTokens instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn revoke_governing_tokens(
|
||||
program_id: &Pubkey,
|
||||
// Accounts
|
||||
realm: &Pubkey,
|
||||
realm_authority: &Pubkey,
|
||||
governing_token_owner: &Pubkey,
|
||||
governing_token_mint: &Pubkey,
|
||||
// Args
|
||||
amount: u64,
|
||||
) -> Instruction {
|
||||
let token_owner_record_address = get_token_owner_record_address(
|
||||
program_id,
|
||||
realm,
|
||||
governing_token_mint,
|
||||
governing_token_owner,
|
||||
);
|
||||
|
||||
let governing_token_holding_address =
|
||||
get_governing_token_holding_address(program_id, realm, governing_token_mint);
|
||||
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*realm, false),
|
||||
AccountMeta::new_readonly(*realm_authority, true),
|
||||
AccountMeta::new(governing_token_holding_address, false),
|
||||
AccountMeta::new(token_owner_record_address, false),
|
||||
AccountMeta::new(*governing_token_mint, false),
|
||||
AccountMeta::new_readonly(realm_config_address, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
];
|
||||
|
||||
let instruction = GovernanceInstruction::RevokeGoverningTokens { amount };
|
||||
|
||||
Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data: instruction.try_to_vec().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds accounts specified by GoverningTokenConfigAccountArgs
|
||||
/// and returns GoverningTokenConfigArgs
|
||||
pub fn with_governing_token_config_args(
|
||||
accounts: &mut Vec<AccountMeta>,
|
||||
governing_token_config_args: Option<GoverningTokenConfigAccountArgs>,
|
||||
) -> GoverningTokenConfigArgs {
|
||||
let governing_token_config_args = governing_token_config_args.unwrap_or_default();
|
||||
|
||||
let use_voter_weight_addin =
|
||||
if let Some(voter_weight_addin) = governing_token_config_args.voter_weight_addin {
|
||||
accounts.push(AccountMeta::new_readonly(voter_weight_addin, false));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let use_max_voter_weight_addin =
|
||||
if let Some(max_voter_weight_addin) = governing_token_config_args.max_voter_weight_addin {
|
||||
accounts.push(AccountMeta::new_readonly(max_voter_weight_addin, false));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
GoverningTokenConfigArgs {
|
||||
use_voter_weight_addin,
|
||||
use_max_voter_weight_addin,
|
||||
token_type: governing_token_config_args.token_type,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ mod process_insert_transaction;
|
|||
mod process_relinquish_vote;
|
||||
mod process_remove_signatory;
|
||||
mod process_remove_transaction;
|
||||
mod process_revoke_governing_tokens;
|
||||
mod process_set_governance_config;
|
||||
mod process_set_governance_delegate;
|
||||
mod process_set_realm_authority;
|
||||
|
@ -48,6 +49,7 @@ use process_insert_transaction::*;
|
|||
use process_relinquish_vote::*;
|
||||
use process_remove_signatory::*;
|
||||
use process_remove_transaction::*;
|
||||
use process_revoke_governing_tokens::*;
|
||||
use process_set_governance_config::*;
|
||||
use process_set_governance_delegate::*;
|
||||
use process_set_realm_authority::*;
|
||||
|
@ -213,5 +215,9 @@ pub fn process_instruction(
|
|||
GovernanceInstruction::CreateNativeTreasury {} => {
|
||||
process_create_native_treasury(program_id, accounts)
|
||||
}
|
||||
|
||||
GovernanceInstruction::RevokeGoverningTokens { amount } => {
|
||||
process_revoke_governing_tokens(program_id, accounts, amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::{
|
|||
governance::get_governance_data_for_realm,
|
||||
proposal::get_proposal_data_for_governance_and_governing_mint,
|
||||
realm::get_realm_data_for_governing_token_mint,
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::{
|
||||
get_token_owner_record_data_for_proposal_owner,
|
||||
get_token_owner_record_data_for_realm_and_governing_mint,
|
||||
|
@ -104,17 +105,14 @@ pub fn process_cast_vote(
|
|||
.checked_add(1)
|
||||
.unwrap();
|
||||
|
||||
// Note: When both voter_weight and max_voter_weight addins are used the realm_config will be deserialized twice in resolve_voter_weight() and resolve_max_voter_weight()
|
||||
// It can't be deserialized eagerly because some realms won't have the config if they don't use any of the advanced options
|
||||
// This extra deserialisation should be acceptable to keep things simple and encapsulated.
|
||||
let realm_config_info = next_account_info(account_info_iter)?; //9
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 9
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
let voter_weight = voter_token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
realm_config_info,
|
||||
account_info_iter, // voter_weight_record 10
|
||||
realm_info.key,
|
||||
account_info_iter, // voter_weight_record *10
|
||||
&realm_data,
|
||||
&realm_config_data,
|
||||
VoterWeightAction::CastVote,
|
||||
proposal_info.key,
|
||||
)?;
|
||||
|
@ -152,12 +150,11 @@ pub fn process_cast_vote(
|
|||
}
|
||||
|
||||
let max_voter_weight = proposal_data.resolve_max_voter_weight(
|
||||
program_id,
|
||||
realm_config_info,
|
||||
vote_governing_token_mint_info,
|
||||
account_info_iter, // max_voter_weight_record 11
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
&realm_config_data,
|
||||
vote_governing_token_mint_info,
|
||||
&vote_kind,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
|||
ProposalOption, ProposalV2, VoteType,
|
||||
},
|
||||
realm::get_realm_data_for_governing_token_mint,
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
vote_record::VoteKind,
|
||||
},
|
||||
|
@ -82,13 +83,13 @@ pub fn process_create_proposal(
|
|||
.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
|
||||
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 10
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
let voter_weight = proposal_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
realm_config_info,
|
||||
account_info_iter,
|
||||
realm_info.key,
|
||||
account_info_iter, // voter_weight_record *11
|
||||
&realm_data,
|
||||
&realm_config_data,
|
||||
VoterWeightAction::CreateProposal,
|
||||
governance_info.key,
|
||||
)?;
|
||||
|
|
|
@ -17,7 +17,10 @@ use crate::{
|
|||
assert_valid_realm_config_args, get_governing_token_holding_address_seeds,
|
||||
get_realm_address_seeds, RealmConfig, RealmConfigArgs, RealmV2,
|
||||
},
|
||||
realm_config::{get_realm_config_address_seeds, RealmConfigAccount},
|
||||
realm_config::{
|
||||
get_realm_config_address_seeds, resolve_governing_token_config, RealmConfigAccount,
|
||||
Reserved110,
|
||||
},
|
||||
},
|
||||
tools::spl_token::create_spl_token_account_signed,
|
||||
};
|
||||
|
@ -27,7 +30,7 @@ pub fn process_create_realm(
|
|||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
name: String,
|
||||
config_args: RealmConfigArgs,
|
||||
realm_config_args: RealmConfigArgs,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
|
@ -46,8 +49,9 @@ pub fn process_create_realm(
|
|||
return Err(GovernanceError::RealmAlreadyExists.into());
|
||||
}
|
||||
|
||||
assert_valid_realm_config_args(&config_args)?;
|
||||
assert_valid_realm_config_args(&realm_config_args)?;
|
||||
|
||||
// Create Community token holding account
|
||||
create_spl_token_account_signed(
|
||||
payer_info,
|
||||
governance_token_holding_info,
|
||||
|
@ -61,7 +65,8 @@ pub fn process_create_realm(
|
|||
rent,
|
||||
)?;
|
||||
|
||||
let council_token_mint_address = if config_args.use_council_mint {
|
||||
// Create Council token holding account
|
||||
let council_token_mint_address = if realm_config_args.use_council_mint {
|
||||
let council_token_mint_info = next_account_info(account_info_iter)?; // 8
|
||||
let council_token_holding_info = next_account_info(account_info_iter)?; // 9
|
||||
|
||||
|
@ -83,48 +88,40 @@ pub fn process_create_realm(
|
|||
None
|
||||
};
|
||||
|
||||
// Setup config for addins
|
||||
// Create and serialzie RealmConfig
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 10
|
||||
|
||||
let community_voter_weight_addin = if config_args.use_community_voter_weight_addin {
|
||||
let community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 10
|
||||
Some(*community_voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
// 11, 12
|
||||
let community_token_config = resolve_governing_token_config(
|
||||
account_info_iter,
|
||||
&realm_config_args.community_token_config_args,
|
||||
)?;
|
||||
|
||||
// 13, 14
|
||||
let council_token_config = resolve_governing_token_config(
|
||||
account_info_iter,
|
||||
&realm_config_args.council_token_config_args,
|
||||
)?;
|
||||
|
||||
let realm_config_data = RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: *realm_info.key,
|
||||
community_token_config,
|
||||
council_token_config,
|
||||
reserved: Reserved110::default(),
|
||||
};
|
||||
|
||||
let max_community_voter_weight_addin = if config_args.use_max_community_voter_weight_addin {
|
||||
let max_community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 11
|
||||
Some(*max_community_voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if config_args.use_community_voter_weight_addin
|
||||
|| config_args.use_max_community_voter_weight_addin
|
||||
{
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 12
|
||||
|
||||
let realm_config_data = RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: *realm_info.key,
|
||||
community_voter_weight_addin,
|
||||
max_community_voter_weight_addin,
|
||||
council_voter_weight_addin: None,
|
||||
council_max_vote_weight_addin: 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,
|
||||
)?;
|
||||
}
|
||||
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,
|
||||
)?;
|
||||
|
||||
// Create and serialize Realm
|
||||
let realm_data = RealmV2 {
|
||||
account_type: GovernanceAccountType::RealmV2,
|
||||
community_mint: *governance_token_mint_info.key,
|
||||
|
@ -135,12 +132,12 @@ pub fn process_create_realm(
|
|||
config: RealmConfig {
|
||||
council_mint: council_token_mint_address,
|
||||
reserved: [0; 6],
|
||||
community_mint_max_vote_weight_source: config_args
|
||||
community_mint_max_vote_weight_source: realm_config_args
|
||||
.community_mint_max_vote_weight_source,
|
||||
min_community_weight_to_create_governance: config_args
|
||||
min_community_weight_to_create_governance: realm_config_args
|
||||
.min_community_weight_to_create_governance,
|
||||
use_community_voter_weight_addin: config_args.use_community_voter_weight_addin,
|
||||
use_max_community_voter_weight_addin: config_args.use_max_community_voter_weight_addin,
|
||||
legacy1: 0,
|
||||
legacy2: 0,
|
||||
},
|
||||
voting_proposal_count: 0,
|
||||
reserved_v2: [0; 128],
|
||||
|
|
|
@ -14,12 +14,16 @@ use crate::{
|
|||
state::{
|
||||
enums::GovernanceAccountType,
|
||||
realm::get_realm_data,
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::{
|
||||
get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds,
|
||||
TokenOwnerRecordV2,
|
||||
},
|
||||
},
|
||||
tools::spl_token::{get_spl_token_mint, get_spl_token_owner, transfer_spl_tokens},
|
||||
tools::spl_token::{
|
||||
get_spl_token_mint, is_spl_token_account, is_spl_token_mint, mint_spl_tokens_to,
|
||||
transfer_spl_tokens,
|
||||
},
|
||||
};
|
||||
|
||||
/// Processes DepositGoverningTokens instruction
|
||||
|
@ -34,11 +38,12 @@ pub fn process_deposit_governing_tokens(
|
|||
let governing_token_holding_info = next_account_info(account_info_iter)?; // 1
|
||||
let governing_token_source_info = next_account_info(account_info_iter)?; // 2
|
||||
let governing_token_owner_info = next_account_info(account_info_iter)?; // 3
|
||||
let governing_token_transfer_authority_info = next_account_info(account_info_iter)?; // 4
|
||||
let governing_token_source_authority_info = next_account_info(account_info_iter)?; // 4
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 5
|
||||
let payer_info = next_account_info(account_info_iter)?; // 6
|
||||
let system_info = next_account_info(account_info_iter)?; // 7
|
||||
let spl_token_info = next_account_info(account_info_iter)?; // 8
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 9
|
||||
|
||||
let rent = Rent::get()?;
|
||||
|
||||
|
@ -52,13 +57,32 @@ pub fn process_deposit_governing_tokens(
|
|||
governing_token_holding_info.key,
|
||||
)?;
|
||||
|
||||
transfer_spl_tokens(
|
||||
governing_token_source_info,
|
||||
governing_token_holding_info,
|
||||
governing_token_transfer_authority_info,
|
||||
amount,
|
||||
spl_token_info,
|
||||
)?;
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
realm_config_data.assert_can_deposit_governing_token(&realm_data, &governing_token_mint)?;
|
||||
|
||||
if is_spl_token_account(governing_token_source_info) {
|
||||
// If the source is spl-token token account then transfer tokens from it
|
||||
transfer_spl_tokens(
|
||||
governing_token_source_info,
|
||||
governing_token_holding_info,
|
||||
governing_token_source_authority_info,
|
||||
amount,
|
||||
spl_token_info,
|
||||
)?;
|
||||
} else if is_spl_token_mint(governing_token_source_info) {
|
||||
// If it's a mint then mint the tokens
|
||||
mint_spl_tokens_to(
|
||||
governing_token_source_info,
|
||||
governing_token_holding_info,
|
||||
governing_token_source_authority_info,
|
||||
amount,
|
||||
spl_token_info,
|
||||
)?;
|
||||
} else {
|
||||
return Err(GovernanceError::InvalidGoverningTokenSource.into());
|
||||
}
|
||||
|
||||
let token_owner_record_address_seeds = get_token_owner_record_address_seeds(
|
||||
realm_info.key,
|
||||
|
@ -68,11 +92,7 @@ pub fn process_deposit_governing_tokens(
|
|||
|
||||
if token_owner_record_info.data_is_empty() {
|
||||
// Deposited tokens can only be withdrawn by the owner so let's make sure the owner signed the transaction
|
||||
let governing_token_owner = get_spl_token_owner(governing_token_source_info)?;
|
||||
|
||||
if !(governing_token_owner == *governing_token_owner_info.key
|
||||
&& governing_token_owner_info.is_signer)
|
||||
{
|
||||
if !governing_token_owner_info.is_signer {
|
||||
return Err(GovernanceError::GoverningTokenOwnerMustSign.into());
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use solana_program::{
|
|||
use crate::state::{
|
||||
governance::get_governance_data_for_realm,
|
||||
proposal::get_proposal_data_for_governance_and_governing_mint,
|
||||
realm::get_realm_data_for_governing_token_mint,
|
||||
realm::get_realm_data_for_governing_token_mint, realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::get_token_owner_record_data_for_proposal_owner, vote_record::VoteKind,
|
||||
};
|
||||
|
||||
|
@ -43,15 +43,16 @@ pub fn process_finalize_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> P
|
|||
governing_token_mint_info.key,
|
||||
)?;
|
||||
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 5
|
||||
let realm_config_info = next_account_info(account_info_iter)?; //5
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
let max_voter_weight = proposal_data.resolve_max_voter_weight(
|
||||
program_id,
|
||||
realm_config_info,
|
||||
governing_token_mint_info,
|
||||
account_info_iter, // *6
|
||||
realm_info.key,
|
||||
&realm_data,
|
||||
&realm_config_data,
|
||||
governing_token_mint_info,
|
||||
&VoteKind::Electorate,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
//! Program state processor
|
||||
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::GovernanceError,
|
||||
state::{
|
||||
realm::{get_realm_address_seeds, get_realm_data_for_authority},
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint,
|
||||
},
|
||||
tools::spl_token::burn_spl_tokens_signed,
|
||||
};
|
||||
|
||||
/// Processes RevokeGoverningTokens instruction
|
||||
pub fn process_revoke_governing_tokens(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
amount: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let realm_info = next_account_info(account_info_iter)?; // 0
|
||||
let realm_authority_info = next_account_info(account_info_iter)?; // 1
|
||||
|
||||
let governing_token_holding_info = next_account_info(account_info_iter)?; // 2
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 3
|
||||
let governing_token_mint_info = next_account_info(account_info_iter)?; // 4
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 5
|
||||
|
||||
let spl_token_info = next_account_info(account_info_iter)?; // 6
|
||||
|
||||
let realm_data =
|
||||
get_realm_data_for_authority(program_id, realm_info, realm_authority_info.key)?;
|
||||
|
||||
if !realm_authority_info.is_signer {
|
||||
return Err(GovernanceError::RealmAuthorityMustSign.into());
|
||||
}
|
||||
|
||||
realm_data.assert_is_valid_governing_token_mint_and_holding(
|
||||
program_id,
|
||||
realm_info.key,
|
||||
governing_token_mint_info.key,
|
||||
governing_token_holding_info.key,
|
||||
)?;
|
||||
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
realm_config_data
|
||||
.assert_can_revoke_governing_token(&realm_data, governing_token_mint_info.key)?;
|
||||
|
||||
let mut token_owner_record_data = get_token_owner_record_data_for_realm_and_governing_mint(
|
||||
program_id,
|
||||
token_owner_record_info,
|
||||
realm_info.key,
|
||||
governing_token_mint_info.key,
|
||||
)?;
|
||||
|
||||
token_owner_record_data.governing_token_deposit_amount = token_owner_record_data
|
||||
.governing_token_deposit_amount
|
||||
.checked_sub(amount)
|
||||
.ok_or(GovernanceError::InvalidRevokeAmount)?;
|
||||
|
||||
token_owner_record_data.serialize(&mut *token_owner_record_info.data.borrow_mut())?;
|
||||
|
||||
burn_spl_tokens_signed(
|
||||
governing_token_holding_info,
|
||||
governing_token_mint_info,
|
||||
realm_info,
|
||||
&get_realm_address_seeds(&realm_data.name),
|
||||
program_id,
|
||||
amount,
|
||||
spl_token_info,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -13,10 +13,10 @@ use spl_governance_tools::account::create_and_serialize_account_signed;
|
|||
use crate::{
|
||||
error::GovernanceError,
|
||||
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,
|
||||
get_realm_config_address_seeds, get_realm_config_data_for_realm,
|
||||
resolve_governing_token_config, RealmConfigAccount,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -75,87 +75,60 @@ pub fn process_set_realm_config(
|
|||
}
|
||||
|
||||
let system_info = next_account_info(account_info_iter)?; // 4
|
||||
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 5
|
||||
let mut realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
// Setup config for addins
|
||||
realm_config_data.assert_can_change_config(&realm_config_args)?;
|
||||
|
||||
let community_voter_weight_addin = if realm_config_args.use_community_voter_weight_addin {
|
||||
let community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 6
|
||||
Some(*community_voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Setup configs for tokens (plugins and token types)
|
||||
|
||||
let max_community_voter_weight_addin = if realm_config_args.use_max_community_voter_weight_addin
|
||||
{
|
||||
let max_community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 7
|
||||
Some(*max_community_voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// 6, 7
|
||||
let community_token_config = resolve_governing_token_config(
|
||||
account_info_iter,
|
||||
&realm_config_args.community_token_config_args,
|
||||
)?;
|
||||
|
||||
// 8, 9
|
||||
let council_token_config = resolve_governing_token_config(
|
||||
account_info_iter,
|
||||
&realm_config_args.council_token_config_args,
|
||||
)?;
|
||||
|
||||
realm_config_data.community_token_config = community_token_config;
|
||||
realm_config_data.council_token_config = council_token_config;
|
||||
|
||||
// Update or create RealmConfigAccount
|
||||
if realm_config_info.data_is_empty() {
|
||||
// For older Realms (pre v3) RealmConfigAccount might not exist yet and we have to create it
|
||||
|
||||
// If any of the addins is needed then update or create (if doesn't exist yet) RealmConfigAccount
|
||||
let update_realm_config = if realm_config_args.use_community_voter_weight_addin
|
||||
|| realm_config_args.use_max_community_voter_weight_addin
|
||||
{
|
||||
// We need the payer to pay for the new account if it's created
|
||||
let payer_info = next_account_info(account_info_iter)?; // 8
|
||||
let payer_info = next_account_info(account_info_iter)?; // 10
|
||||
let rent = Rent::get()?;
|
||||
|
||||
// If RealmConfigAccount doesn't exist yet then create it
|
||||
if realm_config_info.data_is_empty() {
|
||||
let realm_config_data = RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: *realm_info.key,
|
||||
community_voter_weight_addin,
|
||||
max_community_voter_weight_addin,
|
||||
council_voter_weight_addin: None,
|
||||
council_max_vote_weight_addin: None,
|
||||
reserved: [0; 128],
|
||||
};
|
||||
|
||||
let rent = Rent::get()?;
|
||||
|
||||
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,
|
||||
)?;
|
||||
false // RealmConfigAccount didn't exist and was created
|
||||
} else {
|
||||
true // RealmConfigAccount existed before and needs to be updated
|
||||
}
|
||||
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 {
|
||||
// True: If RealmConfigAccount existed before we have to update it to remove the addins which are not used any longer
|
||||
// False: We don't want to setup the addins and RealmConfigAccount didn't exist before
|
||||
realm_data.config.use_community_voter_weight_addin
|
||||
|| realm_data.config.use_max_community_voter_weight_addin
|
||||
};
|
||||
|
||||
if update_realm_config {
|
||||
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 = community_voter_weight_addin;
|
||||
realm_config_data.max_community_voter_weight_addin = max_community_voter_weight_addin;
|
||||
|
||||
realm_config_data.serialize(&mut *realm_config_info.data.borrow_mut())?;
|
||||
}
|
||||
|
||||
// Update RealmConfig (Realm.config field)
|
||||
realm_data.config.community_mint_max_vote_weight_source =
|
||||
realm_config_args.community_mint_max_vote_weight_source;
|
||||
|
||||
realm_data.config.min_community_weight_to_create_governance =
|
||||
realm_config_args.min_community_weight_to_create_governance;
|
||||
|
||||
realm_data.config.use_community_voter_weight_addin =
|
||||
realm_config_args.use_community_voter_weight_addin;
|
||||
|
||||
realm_data.config.use_max_community_voter_weight_addin =
|
||||
realm_config_args.use_max_community_voter_weight_addin;
|
||||
realm_data.config.legacy1 = 0;
|
||||
realm_data.config.legacy2 = 0;
|
||||
|
||||
realm_data.serialize(&mut *realm_info.data.borrow_mut())?;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
error::GovernanceError,
|
||||
state::{
|
||||
realm::{get_realm_address_seeds, get_realm_data},
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
token_owner_record::{
|
||||
get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds,
|
||||
},
|
||||
|
@ -30,6 +31,7 @@ pub fn process_withdraw_governing_tokens(
|
|||
let governing_token_owner_info = next_account_info(account_info_iter)?; // 3
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
let spl_token_info = next_account_info(account_info_iter)?; // 5
|
||||
let realm_config_info = next_account_info(account_info_iter)?; // 6
|
||||
|
||||
if !governing_token_owner_info.is_signer {
|
||||
return Err(GovernanceError::GoverningTokenOwnerMustSign.into());
|
||||
|
@ -45,6 +47,11 @@ pub fn process_withdraw_governing_tokens(
|
|||
governing_token_holding_info.key,
|
||||
)?;
|
||||
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?;
|
||||
|
||||
realm_config_data.assert_can_withdraw_governing_token(&realm_data, &governing_token_mint)?;
|
||||
|
||||
let token_owner_record_address_seeds = get_token_owner_record_address_seeds(
|
||||
realm_info.key,
|
||||
&governing_token_mint,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
/// Defines all Governance accounts types
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum GovernanceAccountType {
|
||||
/// Default uninitialized account state
|
||||
Uninitialized,
|
||||
|
@ -96,7 +96,7 @@ impl Default for GovernanceAccountType {
|
|||
}
|
||||
|
||||
/// What state a Proposal is in
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum ProposalState {
|
||||
/// Draft - Proposal enters Draft state when it's created
|
||||
Draft,
|
||||
|
@ -141,7 +141,7 @@ impl Default for ProposalState {
|
|||
/// The type of the vote threshold used to resolve a vote on a Proposal
|
||||
///
|
||||
/// Note: In the current version only YesVotePercentage and Disabled thresholds are supported
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoteThreshold {
|
||||
/// Voting threshold of Yes votes in % required to tip the vote (Approval Quorum)
|
||||
/// It's the percentage of tokens out of the entire pool of governance tokens eligible to vote
|
||||
|
@ -173,7 +173,7 @@ pub enum VoteThreshold {
|
|||
/// The type of vote tipping to use on a Proposal.
|
||||
///
|
||||
/// Vote tipping means that under some conditions voting will complete early.
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoteTipping {
|
||||
/// Tip when there is no way for another option to win and the vote threshold
|
||||
/// has been reached. This ignores voters withdrawing their votes.
|
||||
|
@ -192,7 +192,7 @@ pub enum VoteTipping {
|
|||
}
|
||||
|
||||
/// The status of instruction execution
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum TransactionExecutionStatus {
|
||||
/// Transaction was not executed yet
|
||||
None,
|
||||
|
@ -205,7 +205,7 @@ pub enum TransactionExecutionStatus {
|
|||
}
|
||||
|
||||
/// Transaction execution flags defining how instructions are executed for a Proposal
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum InstructionExecutionFlags {
|
||||
/// No execution flags are specified
|
||||
/// Instructions can be executed individually, in any order, as soon as they hold_up time expires
|
||||
|
@ -224,7 +224,7 @@ pub enum InstructionExecutionFlags {
|
|||
|
||||
/// The source of max vote weight used for voting
|
||||
/// Values below 100% mint supply can be used when the governing token is fully minted but not distributed yet
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum MintMaxVoteWeightSource {
|
||||
/// Fraction (10^10 precision) of the governing mint supply is used as max vote weight
|
||||
/// The default is 100% (10^10) to use all available mint supply for voting
|
||||
|
|
|
@ -21,7 +21,7 @@ use spl_governance_tools::{
|
|||
};
|
||||
|
||||
/// Governance config
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct GovernanceConfig {
|
||||
/// The type of the vote threshold used for community vote
|
||||
/// Note: In the current version only YesVotePercentage and Disabled thresholds are supported
|
||||
|
@ -56,7 +56,7 @@ pub struct GovernanceConfig {
|
|||
}
|
||||
|
||||
/// Governance Account
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct GovernanceV2 {
|
||||
/// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -18,7 +18,7 @@ use solana_program::{
|
|||
|
||||
/// Governance Realm Account
|
||||
/// Account PDA seeds" ['governance', name]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmV1 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -53,7 +53,7 @@ impl IsInitialized for RealmV1 {
|
|||
|
||||
/// Governance Token Owner Record
|
||||
/// Account PDA seeds: ['governance', realm, token_mint, token_owner ]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct TokenOwnerRecordV1 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -101,7 +101,7 @@ impl IsInitialized for TokenOwnerRecordV1 {
|
|||
}
|
||||
|
||||
/// Governance Account
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct GovernanceV1 {
|
||||
/// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -171,7 +171,7 @@ impl IsInitialized for GovernanceV1 {
|
|||
}
|
||||
|
||||
/// Governance Proposal
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProposalV1 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -260,7 +260,7 @@ impl IsInitialized for ProposalV1 {
|
|||
}
|
||||
|
||||
/// Account PDA seeds: ['governance', proposal, signatory]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct SignatoryRecordV1 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -282,7 +282,7 @@ impl IsInitialized for SignatoryRecordV1 {
|
|||
}
|
||||
|
||||
/// Proposal instruction V1
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProposalInstructionV1 {
|
||||
/// Governance Account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -315,7 +315,7 @@ impl IsInitialized for ProposalInstructionV1 {
|
|||
}
|
||||
|
||||
/// Vote with number of votes
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoteWeightV1 {
|
||||
/// Yes vote
|
||||
Yes(u64),
|
||||
|
@ -325,7 +325,7 @@ pub enum VoteWeightV1 {
|
|||
}
|
||||
|
||||
/// Proposal VoteRecord
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct VoteRecordV1 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -6,7 +6,7 @@ use spl_governance_tools::account::AccountMaxSize;
|
|||
|
||||
/// Treasury account
|
||||
/// The account has no data and can be used as a payer for instruction signed by Governance PDAs or as a native SOL treasury
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct NativeTreasury {}
|
||||
|
||||
impl AccountMaxSize for NativeTreasury {
|
||||
|
|
|
@ -10,7 +10,7 @@ use spl_governance_tools::account::{get_account_data, AccountMaxSize};
|
|||
use crate::state::enums::GovernanceAccountType;
|
||||
|
||||
/// Program metadata account. It stores information about the particular SPL-Governance program instance
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProgramMetadata {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -30,7 +30,6 @@ use crate::{
|
|||
governance::GovernanceConfig,
|
||||
proposal_transaction::ProposalTransactionV2,
|
||||
realm::RealmV2,
|
||||
realm_config::get_realm_config_data_for_realm,
|
||||
vote_record::Vote,
|
||||
vote_record::VoteKind,
|
||||
},
|
||||
|
@ -38,8 +37,10 @@ use crate::{
|
|||
};
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
use crate::state::realm_config::RealmConfigAccount;
|
||||
|
||||
/// Proposal option vote result
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum OptionVoteResult {
|
||||
/// Vote on the option is not resolved yet
|
||||
None,
|
||||
|
@ -52,7 +53,7 @@ pub enum OptionVoteResult {
|
|||
}
|
||||
|
||||
/// Proposal Option
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProposalOption {
|
||||
/// Option label
|
||||
pub label: String,
|
||||
|
@ -74,7 +75,7 @@ pub struct ProposalOption {
|
|||
}
|
||||
|
||||
/// Proposal vote type
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoteType {
|
||||
/// Single choice vote with mutually exclusive choices
|
||||
/// In the SingeChoice mode there can ever be a single winner
|
||||
|
@ -103,7 +104,7 @@ pub enum VoteType {
|
|||
}
|
||||
|
||||
/// Governance Proposal
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProposalV2 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -472,30 +473,28 @@ impl ProposalV2 {
|
|||
max_voter_weight.max(total_vote_weight)
|
||||
}
|
||||
|
||||
/// Resolves max voter weight
|
||||
/// Resolves max voter weight using either 1) voting governing_token_mint supply or 2) max voter weight if configured for the token mint
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn resolve_max_voter_weight(
|
||||
&mut self,
|
||||
program_id: &Pubkey,
|
||||
realm_config_info: &AccountInfo,
|
||||
vote_governing_token_mint_info: &AccountInfo,
|
||||
account_info_iter: &mut Iter<AccountInfo>,
|
||||
realm: &Pubkey,
|
||||
realm_data: &RealmV2,
|
||||
realm_config_data: &RealmConfigAccount,
|
||||
vote_governing_token_mint_info: &AccountInfo,
|
||||
vote_kind: &VoteKind,
|
||||
) -> Result<u64, ProgramError> {
|
||||
// if the realm uses addin for max community voter weight then use the externally provided max weight
|
||||
if realm_data.config.use_max_community_voter_weight_addin
|
||||
&& realm_data.community_mint == *vote_governing_token_mint_info.key
|
||||
// if the Realm is configured to use max voter weight for the given voting governing_token_mint then use the externally provided max_voter_weight
|
||||
// instead of the supply based max
|
||||
if let Some(max_voter_weight_addin) = realm_config_data
|
||||
.get_token_config(realm_data, vote_governing_token_mint_info.key)?
|
||||
.max_voter_weight_addin
|
||||
{
|
||||
let realm_config_data =
|
||||
get_realm_config_data_for_realm(program_id, realm_config_info, realm)?;
|
||||
|
||||
let max_voter_weight_record_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let max_voter_weight_record_data =
|
||||
get_max_voter_weight_record_data_for_realm_and_governing_token_mint(
|
||||
&realm_config_data.max_community_voter_weight_addin.unwrap(),
|
||||
&max_voter_weight_addin,
|
||||
max_voter_weight_record_info,
|
||||
realm,
|
||||
vote_governing_token_mint_info.key,
|
||||
|
@ -1166,8 +1165,8 @@ mod test {
|
|||
config: RealmConfig {
|
||||
council_mint: Some(Pubkey::new_unique()),
|
||||
reserved: [0; 6],
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
legacy1: 0,
|
||||
legacy2: 0,
|
||||
|
||||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
|
|
|
@ -25,7 +25,7 @@ use solana_program::{
|
|||
use spl_governance_tools::account::{get_account_data, AccountMaxSize};
|
||||
|
||||
/// InstructionData wrapper. It can be removed once Borsh serialization for Instruction is supported in the SDK
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct InstructionData {
|
||||
/// Pubkey of the instruction processor that executes this instruction
|
||||
pub program_id: Pubkey,
|
||||
|
@ -36,7 +36,7 @@ pub struct InstructionData {
|
|||
}
|
||||
|
||||
/// Account metadata used to define Instructions
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct AccountMetaData {
|
||||
/// An account's public key
|
||||
pub pubkey: Pubkey,
|
||||
|
@ -83,7 +83,7 @@ impl From<&InstructionData> for Instruction {
|
|||
}
|
||||
|
||||
/// Account for an instruction to be executed for Proposal
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct ProposalTransactionV2 {
|
||||
/// Governance Account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -21,14 +21,17 @@ use crate::{
|
|||
state::{
|
||||
enums::{GovernanceAccountType, MintMaxVoteWeightSource},
|
||||
legacy::RealmV1,
|
||||
realm_config::GoverningTokenType,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
vote_record::VoteKind,
|
||||
},
|
||||
PROGRAM_AUTHORITY_SEED,
|
||||
};
|
||||
|
||||
use crate::state::realm_config::get_realm_config_data_for_realm;
|
||||
|
||||
/// Realm Config instruction args
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmConfigArgs {
|
||||
/// Indicates whether council_mint should be used
|
||||
/// If yes then council_mint account must also be passed to the instruction
|
||||
|
@ -40,17 +43,45 @@ 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,
|
||||
/// Community token config args
|
||||
pub community_token_config_args: GoverningTokenConfigArgs,
|
||||
|
||||
/// Indicates whether an external addin program should be used to provide max voters weight for the community mint
|
||||
/// Council token config args
|
||||
pub council_token_config_args: GoverningTokenConfigArgs,
|
||||
}
|
||||
|
||||
/// Realm Config instruction args
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)]
|
||||
pub struct GoverningTokenConfigArgs {
|
||||
/// Indicates whether an external addin program should be used to provide voters weights
|
||||
/// If yes then the voters weight program account must be passed to the instruction
|
||||
pub use_voter_weight_addin: bool,
|
||||
|
||||
/// Indicates whether an external addin program should be used to provide max voters weight for the token
|
||||
/// If yes then the max voter weight program account must be passed to the instruction
|
||||
pub use_max_community_voter_weight_addin: bool,
|
||||
pub use_max_voter_weight_addin: bool,
|
||||
|
||||
/// Governing token type defines how the token is used for governance
|
||||
pub token_type: GoverningTokenType,
|
||||
}
|
||||
|
||||
/// Realm Config instruction args with account parametres
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)]
|
||||
pub struct GoverningTokenConfigAccountArgs {
|
||||
/// Specifies an external plugin program which should be used to provide voters weights
|
||||
/// for the given goventing token
|
||||
pub voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Specifies an external an external plugin program should be used to provide max voters weight
|
||||
/// for the given goventing token
|
||||
pub max_voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Governing token type defines how the token is used for governance power
|
||||
pub token_type: GoverningTokenType,
|
||||
}
|
||||
|
||||
/// SetRealmAuthority instruction action
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum SetRealmAuthorityAction {
|
||||
/// Sets realm authority without any checks
|
||||
/// Uncheck option allows to set the realm authority to non governance accounts
|
||||
|
@ -66,13 +97,17 @@ pub enum SetRealmAuthorityAction {
|
|||
}
|
||||
|
||||
/// Realm Config defining Realm parameters.
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, 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,
|
||||
/// Legacy field introdcued and used in V2 as use_community_voter_weight_addin: bool
|
||||
/// If the field is going to be reused in future version it must be taken under consideration
|
||||
/// that for some Realms it might be already set to 1
|
||||
pub legacy1: u8,
|
||||
|
||||
/// Indicates whether an external addin program should be used to provide max voter weight for the community mint
|
||||
pub use_max_community_voter_weight_addin: bool,
|
||||
/// Legacy field introdcued and used in V2 as use_max_community_voter_weight_addin: bool
|
||||
/// If the field is going to be reused in future version it must be taken under consideration
|
||||
/// that for some Realms it might be already set to 1
|
||||
pub legacy2: u8,
|
||||
|
||||
/// Reserved space for future versions
|
||||
pub reserved: [u8; 6],
|
||||
|
@ -89,7 +124,7 @@ pub struct RealmConfig {
|
|||
|
||||
/// Governance Realm Account
|
||||
/// Account PDA seeds" ['governance', name]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmV2 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -251,13 +286,13 @@ impl RealmV2 {
|
|||
token_owner_record_data.assert_token_owner_or_delegate_is_signer(create_authority_info)?;
|
||||
|
||||
let realm_config_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 = token_owner_record_data.resolve_voter_weight(
|
||||
program_id,
|
||||
realm_config_info,
|
||||
account_info_iter,
|
||||
realm,
|
||||
self,
|
||||
&realm_config_data,
|
||||
VoterWeightAction::CreateGovernance,
|
||||
realm,
|
||||
)?;
|
||||
|
@ -399,8 +434,10 @@ pub fn get_governing_token_holding_address(
|
|||
}
|
||||
|
||||
/// Asserts given realm config args are correct
|
||||
pub fn assert_valid_realm_config_args(config_args: &RealmConfigArgs) -> Result<(), ProgramError> {
|
||||
match config_args.community_mint_max_vote_weight_source {
|
||||
pub fn assert_valid_realm_config_args(
|
||||
realm_config_args: &RealmConfigArgs,
|
||||
) -> Result<(), ProgramError> {
|
||||
match realm_config_args.community_mint_max_vote_weight_source {
|
||||
MintMaxVoteWeightSource::SupplyFraction(fraction) => {
|
||||
if !(1..=MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE).contains(&fraction) {
|
||||
return Err(GovernanceError::InvalidMaxVoteWeightSupplyFraction.into());
|
||||
|
@ -433,8 +470,8 @@ mod test {
|
|||
name: "test-realm".to_string(),
|
||||
config: RealmConfig {
|
||||
council_mint: Some(Pubkey::new_unique()),
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
legacy1: 0,
|
||||
legacy2: 0,
|
||||
reserved: [0; 6],
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::Absolute(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
|
@ -450,7 +487,7 @@ mod test {
|
|||
}
|
||||
|
||||
/// Realm Config instruction args
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmConfigArgsV1 {
|
||||
/// Indicates whether council_mint should be used
|
||||
/// If yes then council_mint account must also be passed to the instruction
|
||||
|
@ -464,7 +501,7 @@ mod test {
|
|||
}
|
||||
|
||||
/// Instructions supported by the Governance program
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum GovernanceInstructionV1 {
|
||||
/// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint
|
||||
CreateRealm {
|
||||
|
@ -495,8 +532,8 @@ mod test {
|
|||
min_community_weight_to_create_governance: 100,
|
||||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
community_token_config_args: GoverningTokenConfigArgs::default(),
|
||||
council_token_config_args: GoverningTokenConfigArgs::default(),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//! RealmConfig account
|
||||
use std::slice::Iter;
|
||||
|
||||
use solana_program::account_info::next_account_info;
|
||||
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized,
|
||||
|
@ -10,9 +13,90 @@ use spl_governance_tools::account::{get_account_data, AccountMaxSize};
|
|||
|
||||
use crate::{error::GovernanceError, state::enums::GovernanceAccountType};
|
||||
|
||||
use crate::state::realm::GoverningTokenConfigArgs;
|
||||
|
||||
use crate::state::realm::{RealmConfigArgs, RealmV2};
|
||||
|
||||
/// The type of the governing token defines:
|
||||
/// 1) Who retains the authority over deposited tokens
|
||||
/// 2) Which token instructions Deposit, Withdraw and Revoke (burn) are allowed
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum GoverningTokenType {
|
||||
/// Liquid token is a token which is fully liquid and the token owner retains full authority over it
|
||||
/// Deposit - Yes
|
||||
/// Withdraw - Yes
|
||||
/// Revoke - No, Realm authority cannot revoke liquid tokens
|
||||
Liquid,
|
||||
|
||||
/// Membership token is a token controlled by Realm authority
|
||||
/// Deposit - Yes, membership tokens can be deposited to gain governance power
|
||||
/// The membership tokens are conventionally minted into the holding account to keep them out of members possesion
|
||||
/// Withdraw - No, after membership tokens are deposited they are no longer transferable and can't be withdrawn
|
||||
/// Revoke - Yes, Realm authority can Revoke (burn) membership tokens
|
||||
Membership,
|
||||
|
||||
/// Dormant token is a token which is only a placeholder and its deposits are not accepted and not used for governance power within the Realm
|
||||
///
|
||||
/// The Dormant token type is used when only a single voting population is operational. For example a Multisig starter DAO uses Council only
|
||||
/// and sets Community as Dormant to indicate its not utilised for any governance power.
|
||||
/// Once the starter DAO decides to decentralise then it can change the Community token to Liquid
|
||||
///
|
||||
/// Note: When an external voter weight plugin which takes deposits of the token is used then the type should be set to Dormant
|
||||
/// to make the intention explicit
|
||||
///
|
||||
/// Deposit - No, dormant tokens can't be deposited into the Realm
|
||||
/// Withdraw - Yes, tokens can still be withdrawn from Realm to support scenario where the config is changed while some tokens are still deposited
|
||||
/// Revoke - No, Realm authority cannot revoke dormant tokens
|
||||
Dormant,
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for GoverningTokenType {
|
||||
fn default() -> Self {
|
||||
GoverningTokenType::Liquid
|
||||
}
|
||||
}
|
||||
|
||||
/// GoverningTokenConfig specifies configuration for Realm governing token (Community or Council)
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)]
|
||||
pub struct GoverningTokenConfig {
|
||||
/// Plugin providing voter weights for the governing token
|
||||
pub voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Plugin providing max voter weight for the governing token
|
||||
pub max_voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Governing token type
|
||||
pub token_type: GoverningTokenType,
|
||||
|
||||
/// Reserved space for future versions
|
||||
pub reserved: [u8; 8],
|
||||
}
|
||||
|
||||
/// Reserved 110 bytes
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct Reserved110 {
|
||||
/// Reserved 64 bytes
|
||||
pub reserved64: [u8; 64],
|
||||
/// Reserved 32 bytes
|
||||
pub reserved32: [u8; 32],
|
||||
/// Reserved 4 bytes
|
||||
pub reserved14: [u8; 14],
|
||||
}
|
||||
|
||||
impl Default for Reserved110 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
reserved64: [0; 64],
|
||||
reserved32: [0; 32],
|
||||
reserved14: [0; 14],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// RealmConfig account
|
||||
/// The account is an optional extension to RealmConfig stored on Realm account
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct RealmConfigAccount {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -20,23 +104,14 @@ pub struct RealmConfigAccount {
|
|||
/// The realm the config belong to
|
||||
pub realm: Pubkey,
|
||||
|
||||
/// Addin providing voter weights for community token
|
||||
pub community_voter_weight_addin: Option<Pubkey>,
|
||||
/// Community token config
|
||||
pub community_token_config: GoverningTokenConfig,
|
||||
|
||||
/// Addin providing max vote weight for community token
|
||||
/// Note: This field is not implemented in the current version
|
||||
pub max_community_voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Addin providing voter weights for council token
|
||||
/// Note: This field is not implemented in the current version
|
||||
pub council_voter_weight_addin: Option<Pubkey>,
|
||||
|
||||
/// Addin providing max vote weight for council token
|
||||
/// Note: This field is not implemented in the current version
|
||||
pub council_max_vote_weight_addin: Option<Pubkey>,
|
||||
/// Council token config
|
||||
pub council_token_config: GoverningTokenConfig,
|
||||
|
||||
/// Reserved
|
||||
pub reserved: [u8; 128],
|
||||
pub reserved: Reserved110,
|
||||
}
|
||||
|
||||
impl AccountMaxSize for RealmConfigAccount {
|
||||
|
@ -51,6 +126,98 @@ impl IsInitialized for RealmConfigAccount {
|
|||
}
|
||||
}
|
||||
|
||||
impl RealmConfigAccount {
|
||||
/// Returns GoverningTokenConfig for the given governing_token_mint
|
||||
pub fn get_token_config(
|
||||
&self,
|
||||
realm_data: &RealmV2,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> Result<&GoverningTokenConfig, ProgramError> {
|
||||
let token_config = if *governing_token_mint == realm_data.community_mint {
|
||||
&self.community_token_config
|
||||
} else if Some(*governing_token_mint) == realm_data.config.council_mint {
|
||||
&self.council_token_config
|
||||
} else {
|
||||
return Err(GovernanceError::InvalidGoverningTokenMint.into());
|
||||
};
|
||||
|
||||
Ok(token_config)
|
||||
}
|
||||
|
||||
/// Assertes the given governing token can be revoked
|
||||
pub fn assert_can_revoke_governing_token(
|
||||
&self,
|
||||
realm_data: &RealmV2,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
let governing_token_type = &self
|
||||
.get_token_config(realm_data, governing_token_mint)?
|
||||
.token_type;
|
||||
|
||||
match governing_token_type {
|
||||
GoverningTokenType::Membership => Ok(()),
|
||||
GoverningTokenType::Liquid | GoverningTokenType::Dormant => {
|
||||
Err(GovernanceError::CannotRevokeGoverningTokens.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Assertes the given governing token can be deposited
|
||||
pub fn assert_can_deposit_governing_token(
|
||||
&self,
|
||||
realm_data: &RealmV2,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
let governing_token_type = &self
|
||||
.get_token_config(realm_data, governing_token_mint)?
|
||||
.token_type;
|
||||
|
||||
match governing_token_type {
|
||||
GoverningTokenType::Membership | GoverningTokenType::Liquid => Ok(()),
|
||||
// Note: Preventing deposits of the Dormant type tokens is not a direct security concern
|
||||
// It only makes the intention of not using deposited tokens as governnace power stronger
|
||||
GoverningTokenType::Dormant => Err(GovernanceError::CannotDepositDormantTokens.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Assertes the given governing token can be withdrawn
|
||||
pub fn assert_can_withdraw_governing_token(
|
||||
&self,
|
||||
realm_data: &RealmV2,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
let governing_token_type = &self
|
||||
.get_token_config(realm_data, governing_token_mint)?
|
||||
.token_type;
|
||||
|
||||
match governing_token_type {
|
||||
GoverningTokenType::Dormant | GoverningTokenType::Liquid => Ok(()),
|
||||
GoverningTokenType::Membership => {
|
||||
Err(GovernanceError::CannotWithdrawMembershipTokens.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts the given RealmConfigArgs represent a valid Realm configuraiton change
|
||||
pub fn assert_can_change_config(
|
||||
&self,
|
||||
realm_config_args: &RealmConfigArgs,
|
||||
) -> Result<(), ProgramError> {
|
||||
// Existing community token type can't be changed to Membership because it would
|
||||
// give the Realm authority the right to burn members tokens which should not be the case because the tokens belong to the members
|
||||
// On the other had for the Council token it's acceptable and in fact desired change becuase council tokens denote memebership
|
||||
// which should be controled by the Realm
|
||||
if self.community_token_config.token_type != GoverningTokenType::Membership
|
||||
&& realm_config_args.community_token_config_args.token_type
|
||||
== GoverningTokenType::Membership
|
||||
{
|
||||
return Err(GovernanceError::CannotChangeCommunityTokenTypeToMemebership.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes RealmConfig account and checks owner program
|
||||
pub fn get_realm_config_data(
|
||||
program_id: &Pubkey,
|
||||
|
@ -59,17 +226,39 @@ pub fn get_realm_config_data(
|
|||
get_account_data::<RealmConfigAccount>(program_id, realm_config_info)
|
||||
}
|
||||
|
||||
/// Deserializes RealmConfig account and checks the owner program and the Realm it belongs to
|
||||
/// If the account exists then desrialises it into RealmConfigAccount struct and checks the owner program and the Realm it belongs to
|
||||
/// If the accoutn doesn't exist then it checks its address is derived from the given owner program and Realm and returns default RealmConfigAccount
|
||||
pub fn get_realm_config_data_for_realm(
|
||||
program_id: &Pubkey,
|
||||
realm_config_info: &AccountInfo,
|
||||
realm: &Pubkey,
|
||||
) -> Result<RealmConfigAccount, ProgramError> {
|
||||
let realm_config_data = get_realm_config_data(program_id, realm_config_info)?;
|
||||
let realm_config_data = if realm_config_info.data_is_empty() {
|
||||
// If RealmConfigAccount doesn't exist yet then validate its PDA
|
||||
// PDA validation is required because RealmConfigAccount might not exist for legacy Realms
|
||||
// and then its absense is used as default RealmConfigAccount value with no plugins and Liquid governance tokens
|
||||
let realm_config_address = get_realm_config_address(program_id, realm);
|
||||
|
||||
if realm_config_data.realm != *realm {
|
||||
return Err(GovernanceError::InvalidRealmConfigForRealm.into());
|
||||
}
|
||||
if realm_config_address != *realm_config_info.key {
|
||||
return Err(GovernanceError::InvalidRealmConfigAddress.into());
|
||||
}
|
||||
|
||||
RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: *realm,
|
||||
community_token_config: GoverningTokenConfig::default(),
|
||||
council_token_config: GoverningTokenConfig::default(),
|
||||
reserved: Reserved110::default(),
|
||||
}
|
||||
} else {
|
||||
let realm_config_data = get_realm_config_data(program_id, realm_config_info)?;
|
||||
|
||||
if realm_config_data.realm != *realm {
|
||||
return Err(GovernanceError::InvalidRealmConfigForRealm.into());
|
||||
}
|
||||
|
||||
realm_config_data
|
||||
};
|
||||
|
||||
Ok(realm_config_data)
|
||||
}
|
||||
|
@ -83,6 +272,32 @@ pub fn get_realm_config_address_seeds(realm: &Pubkey) -> [&[u8]; 2] {
|
|||
pub fn get_realm_config_address(program_id: &Pubkey, realm: &Pubkey) -> Pubkey {
|
||||
Pubkey::find_program_address(&get_realm_config_address_seeds(realm), program_id).0
|
||||
}
|
||||
/// Resolves GoverningTokenConfig from GoverningTokenConfigArgs and instruction accounts
|
||||
pub fn resolve_governing_token_config(
|
||||
account_info_iter: &mut Iter<AccountInfo>,
|
||||
governing_token_config_args: &GoverningTokenConfigArgs,
|
||||
) -> Result<GoverningTokenConfig, ProgramError> {
|
||||
let voter_weight_addin = if governing_token_config_args.use_voter_weight_addin {
|
||||
let voter_weight_addin_info = next_account_info(account_info_iter)?;
|
||||
Some(*voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let max_voter_weight_addin = if governing_token_config_args.use_max_voter_weight_addin {
|
||||
let max_voter_weight_addin_info = next_account_info(account_info_iter)?;
|
||||
Some(*max_voter_weight_addin_info.key)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(GoverningTokenConfig {
|
||||
voter_weight_addin,
|
||||
max_voter_weight_addin,
|
||||
token_type: governing_token_config_args.token_type.clone(),
|
||||
reserved: [0; 8],
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
@ -94,11 +309,19 @@ mod test {
|
|||
let realm_config = RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmV2,
|
||||
realm: Pubkey::new_unique(),
|
||||
community_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
max_community_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
council_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
council_max_vote_weight_addin: Some(Pubkey::new_unique()),
|
||||
reserved: [0; 128],
|
||||
community_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
max_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
token_type: GoverningTokenType::Liquid,
|
||||
reserved: [0; 8],
|
||||
},
|
||||
council_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
max_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
token_type: GoverningTokenType::Liquid,
|
||||
reserved: [0; 8],
|
||||
},
|
||||
reserved: Reserved110::default(),
|
||||
};
|
||||
|
||||
let size = realm_config.try_to_vec().unwrap().len();
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::{error::GovernanceError, PROGRAM_AUTHORITY_SEED};
|
|||
use crate::state::{enums::GovernanceAccountType, legacy::SignatoryRecordV1};
|
||||
|
||||
/// Account PDA seeds: ['governance', proposal, signatory]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct SignatoryRecordV2 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
error::GovernanceError,
|
||||
state::{
|
||||
enums::GovernanceAccountType, governance::GovernanceConfig, legacy::TokenOwnerRecordV1,
|
||||
realm::RealmV2, realm_config::get_realm_config_data_for_realm,
|
||||
realm::RealmV2,
|
||||
},
|
||||
PROGRAM_AUTHORITY_SEED,
|
||||
};
|
||||
|
@ -26,9 +26,11 @@ use solana_program::{
|
|||
use spl_governance_addin_api::voter_weight::VoterWeightAction;
|
||||
use spl_governance_tools::account::{get_account_data, AccountMaxSize};
|
||||
|
||||
use crate::state::realm_config::RealmConfigAccount;
|
||||
|
||||
/// Governance Token Owner Record
|
||||
/// Account PDA seeds: ['governance', realm, token_mint, token_owner ]
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct TokenOwnerRecordV2 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
@ -189,25 +191,22 @@ impl TokenOwnerRecordV2 {
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn resolve_voter_weight(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
realm_config_info: &AccountInfo,
|
||||
account_info_iter: &mut Iter<AccountInfo>,
|
||||
realm: &Pubkey,
|
||||
realm_data: &RealmV2,
|
||||
realm_config_data: &RealmConfigAccount,
|
||||
weight_action: VoterWeightAction,
|
||||
weight_action_target: &Pubkey,
|
||||
) -> 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
|
||||
// if the Realm is configured to use voter weight plugin for our governing_token_mint then use the externally provided voter_weight
|
||||
// instead of governing_token_deposit_amount
|
||||
if let Some(voter_weight_addin) = realm_config_data
|
||||
.get_token_config(realm_data, &self.governing_token_mint)?
|
||||
.voter_weight_addin
|
||||
{
|
||||
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_addin,
|
||||
voter_weight_record_info,
|
||||
self,
|
||||
)?;
|
||||
|
|
|
@ -25,10 +25,10 @@ use crate::state::{
|
|||
/// Voter choice for a proposal option
|
||||
/// In the current version only 1) Single choice and 2) Multiple choices proposals are supported
|
||||
/// In the future versions we can add support for 1) Quadratic voting, 2) Ranked choice voting and 3) Weighted voting
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct VoteChoice {
|
||||
/// The rank given to the choice by voter
|
||||
/// Note: The filed is not used in the current version
|
||||
/// Note: The field is not used in the current version
|
||||
pub rank: u8,
|
||||
|
||||
/// The voter's weight percentage given by the voter to the choice
|
||||
|
@ -47,7 +47,7 @@ impl VoteChoice {
|
|||
}
|
||||
|
||||
/// User's vote
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum Vote {
|
||||
/// Vote approving choices
|
||||
Approve(Vec<VoteChoice>),
|
||||
|
@ -64,7 +64,7 @@ pub enum Vote {
|
|||
}
|
||||
|
||||
/// VoteKind defines the type of the vote being cast
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub enum VoteKind {
|
||||
/// Electorate vote is cast by the voting population identified by governing_token_mint
|
||||
/// Approve, Deny and Abstain votes are Electorate votes
|
||||
|
@ -83,7 +83,7 @@ pub fn get_vote_kind(vote: &Vote) -> VoteKind {
|
|||
}
|
||||
|
||||
/// Proposal VoteRecord
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)]
|
||||
pub struct VoteRecordV2 {
|
||||
/// Governance account type
|
||||
pub account_type: GovernanceAccountType,
|
||||
|
|
|
@ -121,6 +121,37 @@ pub fn transfer_spl_tokens<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Mint SPL Tokens
|
||||
pub fn mint_spl_tokens_to<'a>(
|
||||
mint_info: &AccountInfo<'a>,
|
||||
destination_info: &AccountInfo<'a>,
|
||||
mint_authority_info: &AccountInfo<'a>,
|
||||
amount: u64,
|
||||
spl_token_info: &AccountInfo<'a>,
|
||||
) -> ProgramResult {
|
||||
let mint_to_ix = spl_token::instruction::mint_to(
|
||||
&spl_token::id(),
|
||||
mint_info.key,
|
||||
destination_info.key,
|
||||
mint_authority_info.key,
|
||||
&[],
|
||||
amount,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
invoke(
|
||||
&mint_to_ix,
|
||||
&[
|
||||
spl_token_info.clone(),
|
||||
mint_authority_info.clone(),
|
||||
mint_info.clone(),
|
||||
destination_info.clone(),
|
||||
],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Transfers SPL Tokens from a token account owned by the provided PDA authority with seeds
|
||||
pub fn transfer_spl_tokens_signed<'a>(
|
||||
source_info: &AccountInfo<'a>,
|
||||
|
@ -170,6 +201,55 @@ pub fn transfer_spl_tokens_signed<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Burns SPL Tokens from a token account owned by the provided PDA authority with seeds
|
||||
pub fn burn_spl_tokens_signed<'a>(
|
||||
token_account_info: &AccountInfo<'a>,
|
||||
token_mint_info: &AccountInfo<'a>,
|
||||
authority_info: &AccountInfo<'a>,
|
||||
authority_seeds: &[&[u8]],
|
||||
program_id: &Pubkey,
|
||||
amount: u64,
|
||||
spl_token_info: &AccountInfo<'a>,
|
||||
) -> ProgramResult {
|
||||
let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id);
|
||||
|
||||
if authority_address != *authority_info.key {
|
||||
msg!(
|
||||
"Burn SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected",
|
||||
authority_info.key,
|
||||
authority_address
|
||||
);
|
||||
return Err(ProgramError::InvalidSeeds);
|
||||
}
|
||||
|
||||
let burn_ix = spl_token::instruction::burn(
|
||||
&spl_token::id(),
|
||||
token_account_info.key,
|
||||
token_mint_info.key,
|
||||
authority_info.key,
|
||||
&[],
|
||||
amount,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut signers_seeds = authority_seeds.to_vec();
|
||||
let bump = &[bump_seed];
|
||||
signers_seeds.push(bump);
|
||||
|
||||
invoke_signed(
|
||||
&burn_ix,
|
||||
&[
|
||||
spl_token_info.clone(),
|
||||
token_account_info.clone(),
|
||||
token_mint_info.clone(),
|
||||
authority_info.clone(),
|
||||
],
|
||||
&[&signers_seeds[..]],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Asserts the given account_info represents a valid SPL Token account which is initialized and belongs to spl_token program
|
||||
pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<(), ProgramError> {
|
||||
if account_info.data_is_empty() {
|
||||
|
@ -195,6 +275,11 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the given account_info is spl-token token account
|
||||
pub fn is_spl_token_account(account_info: &AccountInfo) -> bool {
|
||||
assert_is_valid_spl_token_account(account_info).is_ok()
|
||||
}
|
||||
|
||||
/// Asserts the given mint_info represents a valid SPL Token Mint account which is initialized and belongs to spl_token program
|
||||
pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), ProgramError> {
|
||||
if mint_info.data_is_empty() {
|
||||
|
@ -210,7 +295,7 @@ pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), Pro
|
|||
}
|
||||
|
||||
// In token program [36, 8, 1, is_initialized(1), 36] is the layout
|
||||
let data = mint_info.try_borrow_data().unwrap();
|
||||
let data = mint_info.try_borrow_data()?;
|
||||
let is_initialized = array_ref![data, 45, 1];
|
||||
|
||||
if is_initialized == &[0] {
|
||||
|
@ -220,6 +305,11 @@ pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), Pro
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the given account_info is be spl-token mint account
|
||||
pub fn is_spl_token_mint(mint_info: &AccountInfo) -> bool {
|
||||
assert_is_valid_spl_token_mint(mint_info).is_ok()
|
||||
}
|
||||
|
||||
/// Computationally cheap method to get mint from a token account
|
||||
/// It reads mint without deserializing full account data
|
||||
pub fn get_spl_token_mint(token_account_info: &AccountInfo) -> Result<Pubkey, ProgramError> {
|
||||
|
|
|
@ -8,7 +8,10 @@ use solana_program_test::tokio;
|
|||
use program_test::*;
|
||||
use spl_governance::{
|
||||
error::GovernanceError,
|
||||
state::enums::{ProposalState, VoteThreshold, VoteTipping},
|
||||
state::{
|
||||
enums::{ProposalState, VoteThreshold, VoteTipping},
|
||||
vote_record::Vote,
|
||||
},
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -1243,3 +1246,52 @@ async fn test_cast_council_vote() {
|
|||
proposal_account.vote_threshold
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_vote_with_invalid_realm_config_account_address_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut governance_cookie = governance_test
|
||||
.with_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 governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try bypass config check by using none existing config account
|
||||
let realm_config_address = Pubkey::new_unique();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_cast_vote_using_instruction(
|
||||
&proposal_cookie,
|
||||
&token_owner_record_cookie,
|
||||
Vote::Deny,
|
||||
|i| {
|
||||
i.accounts[10].pubkey = realm_config_address; // realm_config_address
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into());
|
||||
}
|
||||
|
|
|
@ -542,3 +542,41 @@ async fn test_create_proposal_with_disabled_community_vote_error() {
|
|||
GovernanceError::GoverningTokenMintNotAllowedToVote.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_proposal_with_invalid_realm_config_account_address_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut governance_cookie = governance_test
|
||||
.with_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try bypass config check by using none existing config account
|
||||
let realm_config_address = Pubkey::new_unique();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_proposal_using_instruction(&token_owner_record_cookie, &mut governance_cookie, |i| {
|
||||
i.accounts[8].pubkey = realm_config_address;
|
||||
})
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into());
|
||||
}
|
||||
|
|
|
@ -5,12 +5,9 @@ use solana_program_test::*;
|
|||
mod program_test;
|
||||
|
||||
use program_test::*;
|
||||
use spl_governance::state::{
|
||||
enums::MintMaxVoteWeightSource,
|
||||
realm::{get_realm_address, RealmConfigArgs},
|
||||
};
|
||||
use spl_governance::state::{enums::MintMaxVoteWeightSource, realm::get_realm_address};
|
||||
|
||||
use self::args::SetRealmConfigArgs;
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_realm() {
|
||||
|
@ -33,23 +30,16 @@ async fn test_create_realm_with_non_default_config() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
let realm_setup_args = RealmSetupArgs {
|
||||
use_council_mint: false,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(1),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
min_community_weight_to_create_governance: 1,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Act
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
// Assert
|
||||
|
|
|
@ -7,7 +7,12 @@ mod program_test;
|
|||
|
||||
use program_test::*;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use spl_governance::{error::GovernanceError, instruction::deposit_governing_tokens};
|
||||
use spl_governance::{
|
||||
error::GovernanceError, instruction::deposit_governing_tokens,
|
||||
state::realm_config::GoverningTokenType,
|
||||
};
|
||||
|
||||
use crate::program_test::args::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deposit_initial_community_tokens() {
|
||||
|
@ -235,55 +240,6 @@ async fn test_deposit_initial_community_tokens_with_owner_must_sign_error() {
|
|||
// Assert
|
||||
assert_eq!(error, GovernanceError::GoverningTokenOwnerMustSign.into());
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn test_deposit_initial_community_tokens_with_invalid_owner_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let token_owner = Keypair::new();
|
||||
let transfer_authority = Keypair::new();
|
||||
let token_source = Keypair::new();
|
||||
|
||||
let invalid_owner = Keypair::new();
|
||||
|
||||
let amount = 10;
|
||||
|
||||
governance_test
|
||||
.bench
|
||||
.create_token_account_with_transfer_authority(
|
||||
&token_source,
|
||||
&realm_cookie.account.community_mint,
|
||||
&realm_cookie.community_mint_authority,
|
||||
amount,
|
||||
&token_owner,
|
||||
&transfer_authority.pubkey(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let deposit_ix = deposit_governing_tokens(
|
||||
&governance_test.program_id,
|
||||
&realm_cookie.address,
|
||||
&token_source.pubkey(),
|
||||
&invalid_owner.pubkey(),
|
||||
&transfer_authority.pubkey(),
|
||||
&governance_test.bench.context.payer.pubkey(),
|
||||
amount,
|
||||
&realm_cookie.account.community_mint,
|
||||
);
|
||||
|
||||
// // Act
|
||||
|
||||
let error = governance_test
|
||||
.bench
|
||||
.process_transaction(&[deposit_ix], Some(&[&transfer_authority, &invalid_owner]))
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(error, GovernanceError::GoverningTokenOwnerMustSign.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deposit_community_tokens_with_malicious_holding_account_error() {
|
||||
|
@ -340,3 +296,62 @@ async fn test_deposit_community_tokens_with_malicious_holding_account_error() {
|
|||
GovernanceError::InvalidGoverningTokenHoldingAccount.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deposit_community_tokens_using_mint() {
|
||||
// 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_initial_governing_token_deposit_using_mint(
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
&realm_cookie.community_mint_authority,
|
||||
10,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let token_owner_record = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(token_owner_record_cookie.account, token_owner_record);
|
||||
|
||||
let holding_account = governance_test
|
||||
.get_token_account(&realm_cookie.community_token_holding_account)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
token_owner_record.governing_token_deposit_amount,
|
||||
holding_account.amount
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deposit_comunity_tokens_with_cannot_deposit_dormant_tokens_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Dormant;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(err, GovernanceError::CannotDepositDormantTokens.into());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,468 @@
|
|||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use solana_program_test::*;
|
||||
|
||||
mod program_test;
|
||||
|
||||
use program_test::*;
|
||||
|
||||
use spl_governance::{
|
||||
error::GovernanceError,
|
||||
state::{realm::get_governing_token_holding_address, realm_config::GoverningTokenType},
|
||||
};
|
||||
use spl_governance_test_sdk::tools::NopOverride;
|
||||
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_community_tokens() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.community_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.revoke_community_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let token_owner_record = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(token_owner_record.governing_token_deposit_amount, 0);
|
||||
|
||||
let holding_account = governance_test
|
||||
.get_token_account(&realm_cookie.community_token_holding_account)
|
||||
.await;
|
||||
|
||||
assert_eq!(holding_account.amount, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.revoke_council_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let token_owner_record = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(token_owner_record.governing_token_deposit_amount, 0);
|
||||
|
||||
let holding_account = governance_test
|
||||
.get_token_account(&realm_cookie.council_token_holding_account.unwrap())
|
||||
.await;
|
||||
|
||||
assert_eq!(holding_account.amount, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_community_tokens_with_cannot_revoke_liquid_token_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_community_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::CannotRevokeGoverningTokens.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_community_tokens_with_cannot_revoke_dormant_token_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.community_token_config_args.token_type = GoverningTokenType::Dormant;
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_community_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::CannotRevokeGoverningTokens.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_realm_authority_must_sign_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[1].is_signer = false, // realm_authority
|
||||
Some(&[]),
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::RealmAuthorityMustSign.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_invalid_realm_authority_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to use fake auhtority
|
||||
let realm_authority = Keypair::new();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[1].pubkey = realm_authority.pubkey(), // realm_authority
|
||||
Some(&[&realm_authority]),
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::InvalidAuthorityForRealm.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_invalid_token_holding_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to revoke from the community holding account
|
||||
let governing_token_holding_address = get_governing_token_holding_address(
|
||||
&governance_test.program_id,
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
);
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[2].pubkey = governing_token_holding_address, // governing_token_holding_address
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::InvalidGoverningTokenHoldingAccount.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_other_realm_config_account_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try use other Realm config
|
||||
let realm_cookie2 = governance_test.with_realm().await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[5].pubkey = realm_cookie2.realm_config.address, //realm_config_address
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::InvalidRealmConfigForRealm.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_invalid_realm_config_account_address_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try bypass config check by using none existing config account
|
||||
let realm_config_address = Pubkey::new_unique();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[5].pubkey = realm_config_address, // realm_config_address
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_token_owner_record_for_different_mint_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to revoke from the community token owner record
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
1,
|
||||
|i| i.accounts[3].pubkey = token_owner_record_cookie2.address, // token_owner_record_address
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::InvalidGoverningMintForTokenOwnerRecord.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_too_large_amount_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
200,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
assert_eq!(err, GovernanceError::InvalidRevokeAmount.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_revoke_council_tokens_with_partial_revoke_amount() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.revoke_governing_tokens_using_instruction(
|
||||
&realm_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
5,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let token_owner_record = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(token_owner_record.governing_token_deposit_amount, 95);
|
||||
}
|
|
@ -8,10 +8,10 @@ mod program_test;
|
|||
use program_test::*;
|
||||
use spl_governance::{
|
||||
error::GovernanceError,
|
||||
state::{enums::MintMaxVoteWeightSource, realm::RealmConfigArgs},
|
||||
state::{realm::GoverningTokenConfigAccountArgs, realm_config::GoverningTokenType},
|
||||
};
|
||||
|
||||
use self::args::SetRealmConfigArgs;
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config() {
|
||||
|
@ -20,25 +20,12 @@ async fn test_set_realm_config() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -57,27 +44,14 @@ async fn test_set_realm_config_with_authority_must_sign_error() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Act
|
||||
|
||||
let err = governance_test
|
||||
.set_realm_config_using_instruction(
|
||||
&mut realm_cookie,
|
||||
&set_realm_config_args,
|
||||
&realm_setup_args,
|
||||
|i| i.accounts[1].is_signer = false,
|
||||
Some(&[]),
|
||||
)
|
||||
|
@ -96,20 +70,7 @@ async fn test_set_realm_config_with_no_authority_error() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
governance_test
|
||||
.set_realm_authority(&realm_cookie, None)
|
||||
|
@ -121,7 +82,7 @@ async fn test_set_realm_config_with_no_authority_error() {
|
|||
let err = governance_test
|
||||
.set_realm_config_using_instruction(
|
||||
&mut realm_cookie,
|
||||
&set_realm_config_args,
|
||||
&realm_setup_args,
|
||||
|i| i.accounts[1].is_signer = false,
|
||||
Some(&[]),
|
||||
)
|
||||
|
@ -140,20 +101,7 @@ async fn test_set_realm_config_with_invalid_authority_error() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let realm_cookie2 = governance_test.with_realm().await;
|
||||
|
||||
|
@ -163,7 +111,7 @@ async fn test_set_realm_config_with_invalid_authority_error() {
|
|||
// Act
|
||||
|
||||
let err = governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
@ -179,24 +127,12 @@ async fn test_set_realm_config_with_remove_council() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: false,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -216,27 +152,14 @@ async fn test_set_realm_config_with_council_change_error() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Try to replace council mint
|
||||
realm_cookie.account.config.council_mint = serde::__private::Some(Pubkey::new_unique());
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
@ -255,33 +178,21 @@ async fn test_set_realm_config_with_council_restore_error() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: false,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
let mut set_realm_config_args = SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
};
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to restore council mint after removing it
|
||||
set_realm_config_args.realm_config_args.use_council_mint = true;
|
||||
realm_setup_args.use_council_mint = true;
|
||||
realm_cookie.account.config.council_mint = serde::__private::Some(Pubkey::new_unique());
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
@ -292,3 +203,134 @@ async fn test_set_realm_config_with_council_restore_error() {
|
|||
GovernanceError::RealmCouncilMintChangeIsNotSupported.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config_with_liquid_community_token_cannot_be_changed_to_memebership_error()
|
||||
{
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Try to change Community token type to Membership
|
||||
realm_setup_args.community_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::CannotChangeCommunityTokenTypeToMemebership.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config_for_community_token_config() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Change Community token type to Dormant and set plugins
|
||||
realm_setup_args.community_token_config_args = GoverningTokenConfigAccountArgs {
|
||||
voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
max_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
token_type: GoverningTokenType::Dormant,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_config_account = governance_test
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account.community_token_config.token_type,
|
||||
GoverningTokenType::Dormant
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account
|
||||
.community_token_config
|
||||
.voter_weight_addin,
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account
|
||||
.community_token_config
|
||||
.max_voter_weight_addin,
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_realm_config_for_council_token_config() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Change Council token type to Membership and set plugins
|
||||
realm_setup_args.council_token_config_args = GoverningTokenConfigAccountArgs {
|
||||
voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
max_voter_weight_addin: Some(Pubkey::new_unique()),
|
||||
token_type: GoverningTokenType::Membership,
|
||||
};
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_config_account = governance_test
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account.council_token_config.token_type,
|
||||
GoverningTokenType::Membership
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account.council_token_config.voter_weight_addin,
|
||||
realm_setup_args
|
||||
.council_token_config_args
|
||||
.voter_weight_addin
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
realm_config_account
|
||||
.council_token_config
|
||||
.max_voter_weight_addin,
|
||||
realm_setup_args
|
||||
.council_token_config_args
|
||||
.max_voter_weight_addin
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,10 +9,13 @@ use program_test::*;
|
|||
use solana_sdk::signature::Signer;
|
||||
|
||||
use spl_governance::{
|
||||
error::GovernanceError, instruction::withdraw_governing_tokens,
|
||||
state::token_owner_record::get_token_owner_record_address,
|
||||
error::GovernanceError,
|
||||
instruction::withdraw_governing_tokens,
|
||||
state::{realm_config::GoverningTokenType, token_owner_record::get_token_owner_record_address},
|
||||
};
|
||||
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_withdraw_community_tokens() {
|
||||
// Arrange
|
||||
|
@ -420,3 +423,65 @@ async fn test_withdraw_governing_tokens_after_proposal_cancelled() {
|
|||
source_account.amount
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_withdraw_council_tokens_with_cannot_withdraw_membership_tokens_error() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_config_args = RealmSetupArgs::default();
|
||||
realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_config_args)
|
||||
.await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.withdraw_council_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(err, GovernanceError::CannotWithdrawMembershipTokens.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_withdraw_dormant_community_tokens() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
realm_setup_args.community_token_config_args.token_type = GoverningTokenType::Dormant;
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.withdraw_community_tokens(&realm_cookie, &token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
let token_owner_record = governance_test
|
||||
.get_token_owner_record_account(&token_owner_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(0, token_owner_record.governing_token_deposit_amount);
|
||||
}
|
||||
|
|
|
@ -1,28 +1,70 @@
|
|||
use solana_program::pubkey::Pubkey;
|
||||
use spl_governance::state::{enums::MintMaxVoteWeightSource, realm::RealmConfigArgs};
|
||||
use spl_governance::state::{
|
||||
enums::MintMaxVoteWeightSource, realm::GoverningTokenConfigAccountArgs,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SetRealmConfigArgs {
|
||||
pub realm_config_args: RealmConfigArgs,
|
||||
pub community_voter_weight_addin: Option<Pubkey>,
|
||||
pub max_community_voter_weight_addin: Option<Pubkey>,
|
||||
pub struct RealmSetupArgs {
|
||||
pub use_council_mint: bool,
|
||||
pub min_community_weight_to_create_governance: u64,
|
||||
pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource,
|
||||
pub community_token_config_args: GoverningTokenConfigAccountArgs,
|
||||
pub council_token_config_args: GoverningTokenConfigAccountArgs,
|
||||
}
|
||||
|
||||
impl Default for SetRealmConfigArgs {
|
||||
impl Default for RealmSetupArgs {
|
||||
fn default() -> Self {
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
};
|
||||
|
||||
Self {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin: None,
|
||||
max_community_voter_weight_addin: None,
|
||||
use_council_mint: true,
|
||||
community_token_config_args: GoverningTokenConfigAccountArgs::default(),
|
||||
council_token_config_args: GoverningTokenConfigAccountArgs::default(),
|
||||
min_community_weight_to_create_governance: 10,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PluginSetupArgs {
|
||||
pub use_community_voter_weight_addin: bool,
|
||||
pub use_max_community_voter_weight_addin: bool,
|
||||
pub use_council_voter_weight_addin: bool,
|
||||
pub use_max_council_voter_weight_addin: bool,
|
||||
}
|
||||
|
||||
impl PluginSetupArgs {
|
||||
#[allow(dead_code)]
|
||||
pub const COMMUNITY_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs {
|
||||
use_community_voter_weight_addin: true,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
use_council_voter_weight_addin: false,
|
||||
use_max_council_voter_weight_addin: false,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
pub const COMMUNITY_MAX_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs {
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: true,
|
||||
use_council_voter_weight_addin: false,
|
||||
use_max_council_voter_weight_addin: false,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
pub const COUNCIL_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs {
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
use_council_voter_weight_addin: true,
|
||||
use_max_council_voter_weight_addin: false,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
pub const COUNCIL_MAX_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs {
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
use_council_voter_weight_addin: false,
|
||||
use_max_council_voter_weight_addin: true,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
pub const ALL: PluginSetupArgs = PluginSetupArgs {
|
||||
use_community_voter_weight_addin: true,
|
||||
use_max_community_voter_weight_addin: true,
|
||||
use_council_voter_weight_addin: true,
|
||||
use_max_council_voter_weight_addin: true,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub struct RealmCookie {
|
|||
|
||||
pub realm_authority: Option<Keypair>,
|
||||
|
||||
pub realm_config: Option<RealmConfigCookie>,
|
||||
pub realm_config: RealmConfigCookie,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -20,9 +20,9 @@ use spl_governance::{
|
|||
create_native_treasury, create_program_governance, create_proposal, create_realm,
|
||||
create_token_governance, create_token_owner_record, deposit_governing_tokens,
|
||||
execute_transaction, finalize_vote, flag_transaction_error, insert_transaction,
|
||||
relinquish_vote, remove_signatory, remove_transaction, set_governance_config,
|
||||
set_governance_delegate, set_realm_authority, set_realm_config, sign_off_proposal,
|
||||
upgrade_program_metadata, withdraw_governing_tokens,
|
||||
relinquish_vote, remove_signatory, remove_transaction, revoke_governing_tokens,
|
||||
set_governance_config, set_governance_delegate, set_realm_authority, set_realm_config,
|
||||
sign_off_proposal, upgrade_program_metadata, withdraw_governing_tokens,
|
||||
},
|
||||
processor::process_instruction,
|
||||
state::{
|
||||
|
@ -41,10 +41,12 @@ use spl_governance::{
|
|||
get_proposal_transaction_address, InstructionData, ProposalTransactionV2,
|
||||
},
|
||||
realm::{
|
||||
get_governing_token_holding_address, get_realm_address, RealmConfig, RealmConfigArgs,
|
||||
RealmV2, SetRealmAuthorityAction,
|
||||
get_governing_token_holding_address, get_realm_address,
|
||||
GoverningTokenConfigAccountArgs, RealmConfig, RealmV2, SetRealmAuthorityAction,
|
||||
},
|
||||
realm_config::{
|
||||
get_realm_config_address, GoverningTokenConfig, RealmConfigAccount, Reserved110,
|
||||
},
|
||||
realm_config::{get_realm_config_address, RealmConfigAccount},
|
||||
signatory_record::{get_signatory_record_address, SignatoryRecordV2},
|
||||
token_owner_record::{get_token_owner_record_address, TokenOwnerRecordV2},
|
||||
vote_record::{get_vote_record_address, Vote, VoteChoice, VoteRecordV2},
|
||||
|
@ -73,8 +75,8 @@ use spl_governance_test_sdk::{
|
|||
ProgramTestBench,
|
||||
};
|
||||
|
||||
use self::{
|
||||
args::SetRealmConfigArgs,
|
||||
use crate::{
|
||||
args::{PluginSetupArgs, RealmSetupArgs},
|
||||
cookies::{
|
||||
GovernanceCookie, GovernedAccountCookie, GovernedMintCookie, GovernedProgramCookie,
|
||||
GovernedTokenCookie, MaxVoterWeightRecordCookie, NativeTreasuryCookie,
|
||||
|
@ -178,47 +180,52 @@ impl GovernanceProgramTest {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_default_set_realm_config_args(&mut self) -> SetRealmConfigArgs {
|
||||
let realm_config_args = RealmConfigArgs {
|
||||
use_council_mint: true,
|
||||
community_mint_max_vote_weight_source: MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
min_community_weight_to_create_governance: 10,
|
||||
use_community_voter_weight_addin: self.voter_weight_addin_id.is_some(),
|
||||
use_max_community_voter_weight_addin: self.max_voter_weight_addin_id.is_some(),
|
||||
};
|
||||
|
||||
let community_voter_weight_addin = if realm_config_args.use_community_voter_weight_addin {
|
||||
self.voter_weight_addin_id
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let max_community_voter_weight_addin =
|
||||
if realm_config_args.use_max_community_voter_weight_addin {
|
||||
self.max_voter_weight_addin_id
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
SetRealmConfigArgs {
|
||||
realm_config_args,
|
||||
community_voter_weight_addin,
|
||||
max_community_voter_weight_addin,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_realm(&mut self) -> RealmCookie {
|
||||
let set_realm_config_args = self.get_default_set_realm_config_args();
|
||||
self.with_realm_using_config_args(&set_realm_config_args)
|
||||
.await
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
self.with_realm_using_args(&realm_setup_args).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_realm_using_config_args(
|
||||
pub async fn with_realm_using_addins(
|
||||
&mut self,
|
||||
set_realm_config_args: &SetRealmConfigArgs,
|
||||
plugin_setup_args: PluginSetupArgs,
|
||||
) -> RealmCookie {
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
if plugin_setup_args.use_community_voter_weight_addin {
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = self.voter_weight_addin_id;
|
||||
}
|
||||
|
||||
if plugin_setup_args.use_max_community_voter_weight_addin {
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = self.max_voter_weight_addin_id;
|
||||
}
|
||||
|
||||
if plugin_setup_args.use_council_voter_weight_addin {
|
||||
realm_setup_args
|
||||
.council_token_config_args
|
||||
.voter_weight_addin = self.voter_weight_addin_id;
|
||||
}
|
||||
|
||||
if plugin_setup_args.use_max_council_voter_weight_addin {
|
||||
realm_setup_args
|
||||
.council_token_config_args
|
||||
.max_voter_weight_addin = self.max_voter_weight_addin_id;
|
||||
}
|
||||
|
||||
let realm_cookie = self.with_realm_using_args(&realm_setup_args).await;
|
||||
|
||||
realm_cookie
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_realm_using_args(
|
||||
&mut self,
|
||||
realm_setup_args: &RealmSetupArgs,
|
||||
) -> RealmCookie {
|
||||
let name = format!("Realm #{}", self.next_realm_id).to_string();
|
||||
self.next_realm_id += 1;
|
||||
|
@ -246,7 +253,7 @@ impl GovernanceProgramTest {
|
|||
council_token_mint_pubkey,
|
||||
council_token_holding_address,
|
||||
council_token_mint_authority,
|
||||
) = if set_realm_config_args.realm_config_args.use_council_mint {
|
||||
) = if realm_setup_args.use_council_mint {
|
||||
let council_token_mint_keypair = Keypair::new();
|
||||
let council_token_mint_authority = Keypair::new();
|
||||
|
||||
|
@ -275,20 +282,43 @@ impl GovernanceProgramTest {
|
|||
|
||||
let realm_authority = Keypair::new();
|
||||
|
||||
let community_token_args = GoverningTokenConfigAccountArgs {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.community_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
};
|
||||
|
||||
let council_token_args = GoverningTokenConfigAccountArgs {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.council_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
};
|
||||
|
||||
let create_realm_ix = create_realm(
|
||||
&self.program_id,
|
||||
&realm_authority.pubkey(),
|
||||
&community_token_mint_keypair.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
council_token_mint_pubkey,
|
||||
set_realm_config_args.community_voter_weight_addin,
|
||||
set_realm_config_args.max_community_voter_weight_addin,
|
||||
Some(community_token_args),
|
||||
Some(council_token_args),
|
||||
name.clone(),
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.min_community_weight_to_create_governance,
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
realm_setup_args.min_community_weight_to_create_governance,
|
||||
realm_setup_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone(),
|
||||
);
|
||||
|
@ -309,41 +339,51 @@ impl GovernanceProgramTest {
|
|||
council_mint: council_token_mint_pubkey,
|
||||
reserved: [0; 6],
|
||||
|
||||
min_community_weight_to_create_governance: set_realm_config_args
|
||||
.realm_config_args
|
||||
min_community_weight_to_create_governance: realm_setup_args
|
||||
.min_community_weight_to_create_governance,
|
||||
community_mint_max_vote_weight_source: set_realm_config_args
|
||||
.realm_config_args
|
||||
community_mint_max_vote_weight_source: realm_setup_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone(),
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
legacy1: 0,
|
||||
legacy2: 0,
|
||||
},
|
||||
voting_proposal_count: 0,
|
||||
reserved_v2: [0; 128],
|
||||
};
|
||||
|
||||
let realm_config_cookie = if set_realm_config_args.community_voter_weight_addin.is_some()
|
||||
|| set_realm_config_args
|
||||
.max_community_voter_weight_addin
|
||||
.is_some()
|
||||
{
|
||||
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: set_realm_config_args
|
||||
.community_voter_weight_addin,
|
||||
max_community_voter_weight_addin: set_realm_config_args
|
||||
.max_community_voter_weight_addin,
|
||||
council_voter_weight_addin: None,
|
||||
council_max_vote_weight_addin: None,
|
||||
reserved: [0; 128],
|
||||
let realm_config_cookie = RealmConfigCookie {
|
||||
address: get_realm_config_address(&self.program_id, &realm_address),
|
||||
account: RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: realm_address,
|
||||
reserved: Reserved110::default(),
|
||||
community_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.community_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
reserved: [0; 8],
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
council_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.council_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
reserved: [0; 8],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
RealmCookie {
|
||||
|
@ -405,8 +445,8 @@ impl GovernanceProgramTest {
|
|||
community_mint_max_vote_weight_source:
|
||||
MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION,
|
||||
min_community_weight_to_create_governance,
|
||||
use_community_voter_weight_addin: false,
|
||||
use_max_community_voter_weight_addin: false,
|
||||
legacy1: 0,
|
||||
legacy2: 0,
|
||||
},
|
||||
voting_proposal_count: 0,
|
||||
reserved_v2: [0; 128],
|
||||
|
@ -421,6 +461,17 @@ impl GovernanceProgramTest {
|
|||
let council_token_holding_address =
|
||||
get_governing_token_holding_address(&self.program_id, &realm_address, &council_mint);
|
||||
|
||||
let realm_config_cookie = RealmConfigCookie {
|
||||
address: get_realm_config_address(&self.program_id, &realm_address),
|
||||
account: RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: realm_address,
|
||||
council_token_config: GoverningTokenConfig::default(),
|
||||
reserved: Reserved110::default(),
|
||||
community_token_config: GoverningTokenConfig::default(),
|
||||
},
|
||||
};
|
||||
|
||||
RealmCookie {
|
||||
address: realm_address,
|
||||
account,
|
||||
|
@ -433,7 +484,7 @@ impl GovernanceProgramTest {
|
|||
realm_cookie.council_mint_authority.as_ref().unwrap(),
|
||||
)),
|
||||
realm_authority: Some(realm_authority),
|
||||
realm_config: None,
|
||||
realm_config: realm_config_cookie,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,6 +508,28 @@ impl GovernanceProgramTest {
|
|||
pub async fn with_community_token_owner_record(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
self.with_token_owner_record(realm_cookie, &realm_cookie.account.community_mint)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_council_token_owner_record(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
self.with_token_owner_record(
|
||||
realm_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_token_owner_record(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
governing_token_mint: &Pubkey,
|
||||
) -> TokenOwnerRecordCookie {
|
||||
let token_owner = Keypair::new();
|
||||
|
||||
|
@ -464,7 +537,7 @@ impl GovernanceProgramTest {
|
|||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&token_owner.pubkey(),
|
||||
&realm_cookie.account.community_mint,
|
||||
governing_token_mint,
|
||||
&self.bench.payer.pubkey(),
|
||||
);
|
||||
|
||||
|
@ -476,7 +549,7 @@ impl GovernanceProgramTest {
|
|||
let account = TokenOwnerRecordV2 {
|
||||
account_type: GovernanceAccountType::TokenOwnerRecordV2,
|
||||
realm: realm_cookie.address,
|
||||
governing_token_mint: realm_cookie.account.community_mint,
|
||||
governing_token_mint: *governing_token_mint,
|
||||
governing_token_owner: token_owner.pubkey(),
|
||||
governing_token_deposit_amount: 0,
|
||||
governance_delegate: None,
|
||||
|
@ -490,7 +563,7 @@ impl GovernanceProgramTest {
|
|||
let token_owner_record_address = get_token_owner_record_address(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.community_mint,
|
||||
governing_token_mint,
|
||||
&token_owner.pubkey(),
|
||||
);
|
||||
|
||||
|
@ -741,6 +814,73 @@ impl GovernanceProgramTest {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_initial_governing_token_deposit_using_mint(
|
||||
&mut self,
|
||||
realm_address: &Pubkey,
|
||||
governing_mint: &Pubkey,
|
||||
governing_mint_authority: &Keypair,
|
||||
amount: u64,
|
||||
token_owner: Option<Keypair>,
|
||||
) -> Result<TokenOwnerRecordCookie, ProgramError> {
|
||||
let token_owner = token_owner.unwrap_or(Keypair::new());
|
||||
let token_source = Keypair::new();
|
||||
|
||||
let deposit_governing_tokens_ix = deposit_governing_tokens(
|
||||
&self.program_id,
|
||||
realm_address,
|
||||
governing_mint,
|
||||
&token_owner.pubkey(),
|
||||
&governing_mint_authority.pubkey(),
|
||||
&self.bench.payer.pubkey(),
|
||||
amount,
|
||||
governing_mint,
|
||||
);
|
||||
|
||||
self.bench
|
||||
.process_transaction(
|
||||
&[deposit_governing_tokens_ix],
|
||||
Some(&[&token_owner, &governing_mint_authority]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let token_owner_record_address = get_token_owner_record_address(
|
||||
&self.program_id,
|
||||
realm_address,
|
||||
governing_mint,
|
||||
&token_owner.pubkey(),
|
||||
);
|
||||
|
||||
let account = TokenOwnerRecordV2 {
|
||||
account_type: GovernanceAccountType::TokenOwnerRecordV2,
|
||||
realm: *realm_address,
|
||||
governing_token_mint: *governing_mint,
|
||||
governing_token_owner: token_owner.pubkey(),
|
||||
governing_token_deposit_amount: amount,
|
||||
governance_delegate: None,
|
||||
unrelinquished_votes_count: 0,
|
||||
total_votes_count: 0,
|
||||
outstanding_proposal_count: 0,
|
||||
reserved: [0; 7],
|
||||
reserved_v2: [0; 128],
|
||||
};
|
||||
|
||||
let governance_delegate = Keypair::from_base58_string(&token_owner.to_base58_string());
|
||||
|
||||
Ok(TokenOwnerRecordCookie {
|
||||
address: token_owner_record_address,
|
||||
account,
|
||||
|
||||
token_source_amount: amount,
|
||||
token_source: token_source.pubkey(),
|
||||
token_owner,
|
||||
governance_authority: None,
|
||||
governance_delegate,
|
||||
voter_weight_record: None,
|
||||
max_voter_weight_record: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn mint_community_tokens(&mut self, realm_cookie: &RealmCookie, amount: u64) {
|
||||
let token_account_keypair = Keypair::new();
|
||||
|
@ -974,62 +1114,36 @@ impl GovernanceProgramTest {
|
|||
pub async fn set_realm_config(
|
||||
&mut self,
|
||||
realm_cookie: &mut RealmCookie,
|
||||
set_realm_config_args: &SetRealmConfigArgs,
|
||||
realm_setup_args: &RealmSetupArgs,
|
||||
) -> Result<(), ProgramError> {
|
||||
self.set_realm_config_using_instruction(
|
||||
realm_cookie,
|
||||
set_realm_config_args,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
self.set_realm_config_using_instruction(realm_cookie, realm_setup_args, NopOverride, None)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn set_realm_config_using_instruction<F: Fn(&mut Instruction)>(
|
||||
&mut self,
|
||||
realm_cookie: &mut RealmCookie,
|
||||
set_realm_config_args: &SetRealmConfigArgs,
|
||||
realm_setup_args: &RealmSetupArgs,
|
||||
instruction_override: F,
|
||||
signers_override: Option<&[&Keypair]>,
|
||||
) -> Result<(), ProgramError> {
|
||||
let council_token_mint = if set_realm_config_args.realm_config_args.use_council_mint {
|
||||
let council_token_mint = if realm_setup_args.use_council_mint {
|
||||
realm_cookie.account.config.council_mint
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let community_voter_weight_addin = if set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin
|
||||
{
|
||||
set_realm_config_args.community_voter_weight_addin
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let max_community_voter_weight_addin = if set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin
|
||||
{
|
||||
set_realm_config_args.max_community_voter_weight_addin
|
||||
} 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,
|
||||
&self.bench.payer.pubkey(),
|
||||
community_voter_weight_addin,
|
||||
max_community_voter_weight_addin,
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.min_community_weight_to_create_governance,
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
Some(realm_setup_args.community_token_config_args.clone()),
|
||||
Some(realm_setup_args.council_token_config_args.clone()),
|
||||
realm_setup_args.min_community_weight_to_create_governance,
|
||||
realm_setup_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone(),
|
||||
);
|
||||
|
@ -1043,32 +1157,44 @@ impl GovernanceProgramTest {
|
|||
realm_cookie
|
||||
.account
|
||||
.config
|
||||
.community_mint_max_vote_weight_source = set_realm_config_args
|
||||
.realm_config_args
|
||||
.community_mint_max_vote_weight_source = realm_setup_args
|
||||
.community_mint_max_vote_weight_source
|
||||
.clone();
|
||||
|
||||
if set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin
|
||||
|| set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin
|
||||
{
|
||||
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,
|
||||
max_community_voter_weight_addin,
|
||||
council_voter_weight_addin: None,
|
||||
council_max_vote_weight_addin: None,
|
||||
reserved: [0; 128],
|
||||
realm_cookie.realm_config = RealmConfigCookie {
|
||||
address: get_realm_config_address(&self.program_id, &realm_cookie.address),
|
||||
account: RealmConfigAccount {
|
||||
account_type: GovernanceAccountType::RealmConfig,
|
||||
realm: realm_cookie.address,
|
||||
reserved: Reserved110::default(),
|
||||
community_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.community_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
reserved: [0; 8],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
council_token_config: GoverningTokenConfig {
|
||||
voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.voter_weight_addin,
|
||||
max_voter_weight_addin: realm_setup_args
|
||||
.council_token_config_args
|
||||
.max_voter_weight_addin,
|
||||
token_type: realm_setup_args
|
||||
.council_token_config_args
|
||||
.token_type
|
||||
.clone(),
|
||||
reserved: [0; 8],
|
||||
},
|
||||
},
|
||||
};
|
||||
self.bench
|
||||
.process_transaction(&[set_realm_config_ix], Some(signers))
|
||||
.await
|
||||
|
@ -1129,6 +1255,73 @@ impl GovernanceProgramTest {
|
|||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn revoke_community_tokens(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
) -> Result<(), ProgramError> {
|
||||
self.revoke_governing_tokens_using_instruction(
|
||||
realm_cookie,
|
||||
token_owner_record_cookie,
|
||||
&realm_cookie.account.community_mint,
|
||||
token_owner_record_cookie
|
||||
.account
|
||||
.governing_token_deposit_amount,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn revoke_council_tokens(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
) -> Result<(), ProgramError> {
|
||||
self.revoke_governing_tokens_using_instruction(
|
||||
realm_cookie,
|
||||
token_owner_record_cookie,
|
||||
&realm_cookie.account.config.council_mint.unwrap(),
|
||||
token_owner_record_cookie
|
||||
.account
|
||||
.governing_token_deposit_amount,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn revoke_governing_tokens_using_instruction<F: Fn(&mut Instruction)>(
|
||||
&mut self,
|
||||
realm_cookie: &RealmCookie,
|
||||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
governing_token_mint: &Pubkey,
|
||||
amount: u64,
|
||||
instruction_override: F,
|
||||
signers_override: Option<&[&Keypair]>,
|
||||
) -> Result<(), ProgramError> {
|
||||
let mut revoke_governing_tokens_ix = revoke_governing_tokens(
|
||||
&self.program_id,
|
||||
&realm_cookie.address,
|
||||
&realm_cookie.account.authority.unwrap(),
|
||||
&token_owner_record_cookie.account.governing_token_owner,
|
||||
governing_token_mint,
|
||||
amount,
|
||||
);
|
||||
|
||||
instruction_override(&mut revoke_governing_tokens_ix);
|
||||
|
||||
let default_signers = &[realm_cookie.realm_authority.as_ref().unwrap()];
|
||||
let signers = signers_override.unwrap_or(default_signers);
|
||||
|
||||
self.bench
|
||||
.process_transaction(&[revoke_governing_tokens_ix], Some(signers))
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_governed_account(&mut self) -> GovernedAccountCookie {
|
||||
GovernedAccountCookie {
|
||||
|
@ -2157,13 +2350,31 @@ impl GovernanceProgramTest {
|
|||
self.with_cast_vote(proposal_cookie, token_owner_record_cookie, vote)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_cast_vote(
|
||||
&mut self,
|
||||
proposal_cookie: &ProposalCookie,
|
||||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
vote: Vote,
|
||||
) -> Result<VoteRecordCookie, ProgramError> {
|
||||
self.with_cast_vote_using_instruction(
|
||||
proposal_cookie,
|
||||
token_owner_record_cookie,
|
||||
vote,
|
||||
NopOverride,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn with_cast_vote_using_instruction<F: Fn(&mut Instruction)>(
|
||||
&mut self,
|
||||
proposal_cookie: &ProposalCookie,
|
||||
token_owner_record_cookie: &TokenOwnerRecordCookie,
|
||||
vote: Vote,
|
||||
instruction_override: F,
|
||||
signers_override: Option<&[&Keypair]>,
|
||||
) -> Result<VoteRecordCookie, ProgramError> {
|
||||
let voter_weight_record =
|
||||
if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record {
|
||||
|
@ -2180,7 +2391,7 @@ impl GovernanceProgramTest {
|
|||
None
|
||||
};
|
||||
|
||||
let cast_vote_ix = cast_vote(
|
||||
let mut cast_vote_ix = cast_vote(
|
||||
&self.program_id,
|
||||
&token_owner_record_cookie.account.realm,
|
||||
&proposal_cookie.account.governance,
|
||||
|
@ -2195,11 +2406,13 @@ impl GovernanceProgramTest {
|
|||
vote.clone(),
|
||||
);
|
||||
|
||||
instruction_override(&mut cast_vote_ix);
|
||||
|
||||
let default_signers = &[&token_owner_record_cookie.token_owner];
|
||||
let signers = signers_override.unwrap_or(default_signers);
|
||||
|
||||
self.bench
|
||||
.process_transaction(
|
||||
&[cast_vote_ix],
|
||||
Some(&[&token_owner_record_cookie.token_owner]),
|
||||
)
|
||||
.process_transaction(&[cast_vote_ix], Some(signers))
|
||||
.await?;
|
||||
|
||||
let vote_amount = token_owner_record_cookie
|
||||
|
@ -2628,7 +2841,7 @@ impl GovernanceProgramTest {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_realm_config_data(
|
||||
pub async fn get_realm_config_account(
|
||||
&mut self,
|
||||
realm_config_address: &Pubkey,
|
||||
) -> RealmConfigAccount {
|
||||
|
|
|
@ -7,36 +7,46 @@ mod program_test;
|
|||
|
||||
use program_test::*;
|
||||
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_realm_with_all_addins() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.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);
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -44,56 +54,44 @@ async fn test_set_all_addins_for_realm_without_addins() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_community_voter_weight_addin
|
||||
);
|
||||
|
||||
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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -101,58 +99,46 @@ async fn test_set_all_addin_for_realm_without_council_and_addins() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args.realm_config_args.use_council_mint = false;
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_community_voter_weight_addin
|
||||
);
|
||||
|
||||
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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -162,60 +148,61 @@ async fn test_set_all_realm_addins_for_realm_with_all_addins() {
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
let max_community_voter_weight_addin_address = Pubkey::new_unique();
|
||||
|
||||
set_realm_config_args.max_community_voter_weight_addin =
|
||||
Some(max_community_voter_weight_addin_address);
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = Some(max_community_voter_weight_addin_address);
|
||||
|
||||
let community_voter_weight_addin_address = Pubkey::new_unique();
|
||||
set_realm_config_args.community_voter_weight_addin = Some(community_voter_weight_addin_address);
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = Some(community_voter_weight_addin_address);
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_community_voter_weight_addin
|
||||
);
|
||||
|
||||
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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
assert_eq!(
|
||||
realm_config_data.max_community_voter_weight_addin,
|
||||
realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin,
|
||||
Some(max_community_voter_weight_addin_address)
|
||||
);
|
||||
assert_eq!(
|
||||
realm_config_data.community_voter_weight_addin,
|
||||
realm_config_data.community_token_config.voter_weight_addin,
|
||||
Some(community_voter_weight_addin_address)
|
||||
);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -223,48 +210,42 @@ async fn test_set_realm_config_without_addins_for_realm_without_addins() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = None;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = None;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
!realm_account_data
|
||||
.config
|
||||
.use_max_community_voter_weight_addin
|
||||
);
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_none());
|
||||
|
||||
assert!(!realm_account_data.config.use_community_voter_weight_addin);
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -273,35 +254,28 @@ async fn test_set_realm_config_without_any_addins_for_realm_with_existing_addins
|
|||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_config_data.max_community_voter_weight_addin.is_none());
|
||||
assert!(realm_config_data.community_voter_weight_addin.is_none());
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_none());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
|
|
@ -7,34 +7,37 @@ mod program_test;
|
|||
|
||||
use program_test::*;
|
||||
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_realm_with_max_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -42,50 +45,35 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_without_addins() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -93,52 +81,37 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_without_council_and_add
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
|
||||
set_realm_config_args.realm_config_args.use_council_mint = false;
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -148,46 +121,42 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_with_existing_voter_wei
|
|||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = governance_test.max_voter_weight_addin_id;
|
||||
|
||||
let max_community_voter_weight_addin_address = Pubkey::new_unique();
|
||||
set_realm_config_args.max_community_voter_weight_addin =
|
||||
Some(max_community_voter_weight_addin_address);
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = Some(max_community_voter_weight_addin_address);
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
realm_account_data
|
||||
.config
|
||||
.use_max_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
assert_eq!(
|
||||
realm_config_data.max_community_voter_weight_addin,
|
||||
realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin,
|
||||
Some(max_community_voter_weight_addin_address)
|
||||
);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -195,38 +164,33 @@ async fn test_set_realm_config_with_no_max_voter_weight_addin_for_realm_without_
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.max_voter_weight_addin = None;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
!realm_account_data
|
||||
.config
|
||||
.use_max_community_voter_weight_addin
|
||||
);
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -235,30 +199,28 @@ async fn test_set_realm_config_with_no_max_voter_weight_addin_for_realm_with_exi
|
|||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_max_community_voter_weight_addin = false;
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_config_data.max_community_voter_weight_addin.is_none());
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.max_voter_weight_addin
|
||||
.is_none());
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use solana_program_test::*;
|
|||
|
||||
mod program_test;
|
||||
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
use program_test::*;
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -12,25 +13,30 @@ async fn test_create_realm_with_voter_weight_addin() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -38,41 +44,38 @@ 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 set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = None;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -80,42 +83,37 @@ 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 set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
set_realm_config_args.realm_config_args.use_council_mint = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&set_realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -123,43 +121,44 @@ async fn test_set_realm_voter_weight_addin_for_realm_with_existing_voter_weight_
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_cookie = governance_test.with_realm().await;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
let mut set_realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = governance_test.voter_weight_addin_id;
|
||||
|
||||
set_realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = true;
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
let community_voter_weight_addin_address = Pubkey::new_unique();
|
||||
set_realm_config_args.community_voter_weight_addin = Some(community_voter_weight_addin_address);
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = Some(community_voter_weight_addin_address);
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(realm_config_cookie.account, realm_config_data);
|
||||
assert_eq!(realm_cookie.realm_config.account, realm_config_data);
|
||||
assert_eq!(
|
||||
realm_config_data.community_voter_weight_addin,
|
||||
realm_config_data.community_token_config.voter_weight_addin,
|
||||
Some(community_voter_weight_addin_address)
|
||||
);
|
||||
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -167,33 +166,37 @@ async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_without_addi
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await;
|
||||
|
||||
let mut realm_config_args = governance_test.get_default_set_realm_config_args();
|
||||
realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = None;
|
||||
|
||||
let mut realm_cookie = governance_test
|
||||
.with_realm_using_config_args(&realm_config_args)
|
||||
.with_realm_using_args(&realm_setup_args)
|
||||
.await;
|
||||
|
||||
realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
realm_setup_args
|
||||
.community_token_config_args
|
||||
.voter_weight_addin = None;
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let realm_account_data = governance_test
|
||||
.get_realm_account(&realm_cookie.address)
|
||||
let realm_config_data = governance_test
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(!realm_account_data.config.use_community_voter_weight_addin);
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -202,29 +205,23 @@ async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_with_existin
|
|||
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_set_realm_config_args();
|
||||
realm_config_args
|
||||
.realm_config_args
|
||||
.use_community_voter_weight_addin = false;
|
||||
let realm_setup_args = RealmSetupArgs::default();
|
||||
|
||||
// Act
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_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)
|
||||
.get_realm_config_account(&realm_cookie.realm_config.address)
|
||||
.await;
|
||||
|
||||
assert!(realm_config_data.community_voter_weight_addin.is_none());
|
||||
assert!(realm_config_data
|
||||
.community_token_config
|
||||
.voter_weight_addin
|
||||
.is_none());
|
||||
}
|
||||
|
|
|
@ -4,15 +4,18 @@ use solana_program_test::*;
|
|||
|
||||
mod program_test;
|
||||
|
||||
use program_test::args::*;
|
||||
use program_test::*;
|
||||
use spl_governance::state::enums::ProposalState;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_vote_with_all_addin() {
|
||||
async fn test_cast_community_vote_with_all_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::ALL)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -67,12 +70,76 @@ async fn test_cast_vote_with_all_addin() {
|
|||
assert_eq!(proposal_account.state, ProposalState::Voting)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_council_vote_with_all_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::ALL)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_council_token_owner_record(&realm_cookie)
|
||||
.await;
|
||||
|
||||
// voter weight 120
|
||||
governance_test
|
||||
.with_voter_weight_addin_record(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// max voter weight 250
|
||||
governance_test
|
||||
.with_max_voter_weight_addin_record_impl(&mut token_owner_record_cookie, 250, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let mut governance_cookie = governance_test
|
||||
.with_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 governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
|
||||
let vote_record_cookie = governance_test
|
||||
.with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
let vote_record_account = governance_test
|
||||
.get_vote_record_account(&vote_record_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(120, vote_record_account.voter_weight);
|
||||
|
||||
let proposal_account = governance_test
|
||||
.get_proposal_account(&proposal_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(proposal_account.state, ProposalState::Voting)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tip_vote_with_all_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::ALL)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -132,7 +199,9 @@ async fn test_finalize_vote_with_all_addin() {
|
|||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_all_addins().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::ALL)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
|
|
@ -4,16 +4,19 @@ use solana_program_test::*;
|
|||
|
||||
mod program_test;
|
||||
|
||||
use program_test::args::*;
|
||||
use program_test::*;
|
||||
use spl_governance::{error::GovernanceError, state::enums::ProposalState};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_vote_with_max_voter_weight_addin() {
|
||||
async fn test_cast_vote_with_community_max_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
@ -56,13 +59,66 @@ async fn test_cast_vote_with_max_voter_weight_addin() {
|
|||
assert_eq!(proposal_account.state, ProposalState::Voting)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_vote_with_council_max_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COUNCIL_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit(&realm_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Bump MaxVoterWeight to 200
|
||||
governance_test
|
||||
.with_max_voter_weight_addin_record(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut governance_cookie = governance_test
|
||||
.with_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 governance_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
governance_test
|
||||
.with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
|
||||
let proposal_account = governance_test
|
||||
.get_proposal_account(&proposal_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(proposal_account.state, ProposalState::Voting)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tip_vote_with_max_voter_weight_addin() {
|
||||
// Arrange
|
||||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 180
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
@ -112,7 +168,9 @@ async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_vote
|
|||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
@ -162,7 +220,9 @@ async fn test_finalize_vote_with_max_voter_weight_addin() {
|
|||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
@ -233,7 +293,9 @@ async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast
|
|||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
@ -304,7 +366,9 @@ async fn test_cast_vote_with_max_voter_weight_addin_and_expired_record_error() {
|
|||
let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
let realm_cookie = governance_test.with_realm().await;
|
||||
let realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
// TokenOwnerRecord with voting power of 100
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
|
|
|
@ -5,7 +5,9 @@ use solana_program_test::*;
|
|||
|
||||
mod program_test;
|
||||
|
||||
use program_test::args::*;
|
||||
use program_test::*;
|
||||
|
||||
use spl_governance::{
|
||||
error::GovernanceError,
|
||||
state::vote_record::{Vote, VoteChoice},
|
||||
|
@ -13,12 +15,14 @@ use spl_governance::{
|
|||
use spl_governance_addin_api::voter_weight::VoterWeightAction;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_governance_with_voter_weight_addin() {
|
||||
async fn test_create_governance_with_community_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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -47,13 +51,52 @@ async fn test_create_governance_with_voter_weight_addin() {
|
|||
assert_eq!(governance_cookie.account, governance_account);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_governance_with_council_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_using_addins(PluginSetupArgs::COUNCIL_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_council_token_owner_record(&realm_cookie)
|
||||
.await;
|
||||
|
||||
governance_test
|
||||
.with_voter_weight_addin_record(&mut token_owner_record_cookie)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Act
|
||||
let governance_cookie = governance_test
|
||||
.with_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// // Assert
|
||||
let governance_account = governance_test
|
||||
.get_governance_account(&governance_cookie.address)
|
||||
.await;
|
||||
|
||||
assert_eq!(governance_cookie.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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -93,7 +136,9 @@ async fn test_cast_vote_with_voter_weight_addin() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -152,7 +197,9 @@ async fn test_create_token_governance_with_voter_weight_addin() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -187,7 +234,9 @@ async fn test_create_mint_governance_with_voter_weight_addin() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -222,7 +271,9 @@ async fn test_create_program_governance_with_voter_weight_addin() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -260,7 +311,9 @@ async fn test_create_governance_with_voter_weight_action_error() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -298,7 +351,9 @@ async fn test_create_governance_with_voter_weight_expiry_error() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -338,7 +393,9 @@ async fn test_cast_vote_with_voter_weight_action_error() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -394,7 +451,9 @@ async fn test_create_governance_with_voter_weight_action_target_error() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -437,7 +496,9 @@ async fn test_create_proposal_with_voter_weight_action_error() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
@ -481,7 +542,9 @@ async fn test_create_governance_with_voter_weight_record() {
|
|||
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 realm_cookie = governance_test
|
||||
.with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT)
|
||||
.await;
|
||||
|
||||
let mut token_owner_record_cookie = governance_test
|
||||
.with_community_token_owner_record(&realm_cookie)
|
||||
|
|
|
@ -15,7 +15,7 @@ use spl_governance::{
|
|||
};
|
||||
use spl_governance_test_sdk::tools::clone_keypair;
|
||||
|
||||
use self::args::SetRealmConfigArgs;
|
||||
use crate::program_test::args::RealmSetupArgs;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_cast_veto_vote() {
|
||||
|
@ -431,11 +431,11 @@ async fn test_cast_veto_vote_with_no_council_error() {
|
|||
.unwrap();
|
||||
|
||||
// Remove Council
|
||||
let mut set_realm_config_args = SetRealmConfigArgs::default();
|
||||
set_realm_config_args.realm_config_args.use_council_mint = false;
|
||||
let mut realm_setup_args = RealmSetupArgs::default();
|
||||
realm_setup_args.use_council_mint = false;
|
||||
|
||||
governance_test
|
||||
.set_realm_config(&mut realm_cookie, &set_realm_config_args)
|
||||
.set_realm_config(&mut realm_cookie, &realm_setup_args)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
Loading…
Reference in New Issue