Governance: Assert tokens to create governance (#2206)
* feat: assert owner has enough tokens to create proposal * chore: test min tokens to create governance * chore: bump version
This commit is contained in:
parent
7a593f5da2
commit
2e4b49b72c
|
@ -3776,7 +3776,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-governance"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"assert_matches",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "spl-governance"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
description = "Solana Program Library Governance Program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana-program-library"
|
||||
|
|
|
@ -311,6 +311,10 @@ pub enum GovernanceError {
|
|||
/// Invalid max vote weight supply fraction
|
||||
#[error("Invalid max vote weight supply fraction")]
|
||||
InvalidMaxVoteWeightSupplyFraction,
|
||||
|
||||
/// Owner doesn't have enough governing tokens to create Governance
|
||||
#[error("Owner doesn't have enough governing tokens to create Governance")]
|
||||
NotEnoughTokensToCreateGovernance,
|
||||
}
|
||||
|
||||
impl PrintProgramError for GovernanceError {
|
||||
|
|
|
@ -7,6 +7,8 @@ use crate::{
|
|||
assert_valid_create_governance_args, get_account_governance_address_seeds, Governance,
|
||||
GovernanceConfig,
|
||||
},
|
||||
realm::get_realm_data,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
},
|
||||
tools::account::create_and_serialize_account_signed,
|
||||
};
|
||||
|
@ -30,7 +32,7 @@ pub fn process_create_account_governance(
|
|||
let account_governance_info = next_account_info(account_info_iter)?; // 1
|
||||
let governed_account_info = next_account_info(account_info_iter)?; // 2
|
||||
|
||||
let _token_owner_record_info = next_account_info(account_info_iter)?; // 3
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 3
|
||||
|
||||
let payer_info = next_account_info(account_info_iter)?; // 4
|
||||
let system_info = next_account_info(account_info_iter)?; // 5
|
||||
|
@ -40,6 +42,12 @@ pub fn process_create_account_governance(
|
|||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
|
||||
let account_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::AccountGovernance,
|
||||
realm: *realm_info.key,
|
||||
|
|
|
@ -7,6 +7,8 @@ use crate::{
|
|||
assert_valid_create_governance_args, get_mint_governance_address_seeds, Governance,
|
||||
GovernanceConfig,
|
||||
},
|
||||
realm::get_realm_data,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
},
|
||||
tools::{
|
||||
account::create_and_serialize_account_signed,
|
||||
|
@ -36,7 +38,7 @@ pub fn process_create_mint_governance(
|
|||
let governed_mint_info = next_account_info(account_info_iter)?; // 2
|
||||
let governed_mint_authority_info = next_account_info(account_info_iter)?; // 3
|
||||
|
||||
let _token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
|
||||
let payer_info = next_account_info(account_info_iter)?; // 5
|
||||
let spl_token_info = next_account_info(account_info_iter)?; // 6
|
||||
|
@ -48,6 +50,12 @@ pub fn process_create_mint_governance(
|
|||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
|
||||
let mint_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::MintGovernance,
|
||||
realm: *realm_info.key,
|
||||
|
|
|
@ -8,6 +8,8 @@ use crate::{
|
|||
assert_valid_create_governance_args, get_program_governance_address_seeds,
|
||||
GovernanceConfig,
|
||||
},
|
||||
realm::get_realm_data,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
},
|
||||
tools::{
|
||||
account::create_and_serialize_account_signed,
|
||||
|
@ -40,7 +42,7 @@ pub fn process_create_program_governance(
|
|||
let governed_program_data_info = next_account_info(account_info_iter)?; // 2
|
||||
let governed_program_upgrade_authority_info = next_account_info(account_info_iter)?; // 3
|
||||
|
||||
let _token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
|
||||
let payer_info = next_account_info(account_info_iter)?; // 5
|
||||
let bpf_upgrade_loader_info = next_account_info(account_info_iter)?; // 6
|
||||
|
@ -52,6 +54,12 @@ pub fn process_create_program_governance(
|
|||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
|
||||
let program_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::ProgramGovernance,
|
||||
realm: *realm_info.key,
|
||||
|
|
|
@ -7,6 +7,8 @@ use crate::{
|
|||
assert_valid_create_governance_args, get_token_governance_address_seeds, Governance,
|
||||
GovernanceConfig,
|
||||
},
|
||||
realm::get_realm_data,
|
||||
token_owner_record::get_token_owner_record_data_for_realm,
|
||||
},
|
||||
tools::{
|
||||
account::create_and_serialize_account_signed,
|
||||
|
@ -36,7 +38,7 @@ pub fn process_create_token_governance(
|
|||
let governed_token_info = next_account_info(account_info_iter)?; // 2
|
||||
let governed_token_owner_info = next_account_info(account_info_iter)?; // 3
|
||||
|
||||
let _token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
let token_owner_record_info = next_account_info(account_info_iter)?; // 4
|
||||
|
||||
let payer_info = next_account_info(account_info_iter)?; // 5
|
||||
let spl_token_info = next_account_info(account_info_iter)?; // 6
|
||||
|
@ -48,6 +50,12 @@ pub fn process_create_token_governance(
|
|||
|
||||
assert_valid_create_governance_args(program_id, &config, realm_info)?;
|
||||
|
||||
let realm_data = get_realm_data(program_id, realm_info)?;
|
||||
let token_owner_record_data =
|
||||
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
|
||||
|
||||
token_owner_record_data.assert_can_create_governance(&realm_data)?;
|
||||
|
||||
let token_governance_data = Governance {
|
||||
account_type: GovernanceAccountType::TokenGovernance,
|
||||
realm: *realm_info.key,
|
||||
|
|
|
@ -105,6 +105,25 @@ impl TokenOwnerRecord {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Asserts TokenOwner has enough tokens to be allowed to create governance
|
||||
pub fn assert_can_create_governance(&self, realm_data: &Realm) -> Result<(), ProgramError> {
|
||||
let min_tokens_to_create_governance =
|
||||
if self.governing_token_mint == realm_data.community_mint {
|
||||
realm_data.config.min_community_tokens_to_create_governance
|
||||
} else if Some(self.governing_token_mint) == realm_data.config.council_mint {
|
||||
// For council tokens it's enough to be in possession of any number of tokens
|
||||
1
|
||||
} else {
|
||||
return Err(GovernanceError::InvalidGoverningTokenMint.into());
|
||||
};
|
||||
|
||||
if self.governing_token_deposit_amount < min_tokens_to_create_governance {
|
||||
return Err(GovernanceError::NotEnoughTokensToCreateGovernance.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns TokenOwnerRecord PDA address
|
||||
|
|
|
@ -130,3 +130,69 @@ async fn test_create_account_governance_with_invalid_config_error() {
|
|||
|
||||
assert_eq!(err, GovernanceError::InvalidVoteThresholdPercentage.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_account_governance_with_not_enough_community_tokens_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;
|
||||
|
||||
// Set token deposit amount below the required threshold
|
||||
let token_amount = 4;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::NotEnoughTokensToCreateGovernance.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_account_governance_with_not_enough_council_tokens_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;
|
||||
|
||||
// Set token deposit amount below the required threshold
|
||||
let token_amount: u64 = 0;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_council_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
assert_eq!(
|
||||
err,
|
||||
GovernanceError::NotEnoughTokensToCreateGovernance.into()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -202,25 +202,29 @@ async fn test_create_proposal_with_not_enough_community_tokens_error() {
|
|||
let realm_cookie = governance_test.with_realm().await;
|
||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
||||
|
||||
// Set token deposit amount below the required threshold
|
||||
let token_amount = 4;
|
||||
|
||||
let token_owner_record_cookie = governance_test
|
||||
.with_community_token_deposit_amount(&realm_cookie, token_amount)
|
||||
let token_owner_record_cookie1 = governance_test
|
||||
.with_community_token_deposit(&realm_cookie)
|
||||
.await;
|
||||
|
||||
let mut account_governance_cookie = governance_test
|
||||
.with_account_governance(
|
||||
&realm_cookie,
|
||||
&governed_account_cookie,
|
||||
&token_owner_record_cookie,
|
||||
&token_owner_record_cookie1,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Set token deposit amount below the required threshold
|
||||
let token_amount = 4;
|
||||
|
||||
let token_owner_record_cookie2 = governance_test
|
||||
.with_community_token_deposit_amount(&realm_cookie, token_amount)
|
||||
.await;
|
||||
|
||||
// Act
|
||||
let err = governance_test
|
||||
.with_proposal(&token_owner_record_cookie, &mut account_governance_cookie)
|
||||
.with_proposal(&token_owner_record_cookie2, &mut account_governance_cookie)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
|
Loading…
Reference in New Issue