Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 6070eb5

Browse files
authored
Governance: Allow realm authority create governances (#2828)
* feat: make it possible for realm authority to create governances * chore: refactor create governance authority check into a single instruction * chore: add tests to create governance with ream authority signer * chore: make clippy happy * chore: update comments * chore: fix merge conflicts Co-authored-by: Jon Cinque [email protected]
1 parent aee41fc commit 6070eb5

File tree

8 files changed

+187
-89
lines changed

8 files changed

+187
-89
lines changed

governance/program/src/instruction.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub enum GovernanceInstruction {
114114
/// 0. `[]` Realm account the created Governance belongs to
115115
/// 1. `[writable]` Account Governance account. PDA seeds: ['account-governance', realm, governed_account]
116116
/// 2. `[]` Account governed by this Governance
117-
/// 3. `[]` Governing TokenOwnerRecord account
117+
/// 3. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)
118118
/// 4. `[signer]` Payer
119119
/// 5. `[]` System program
120120
/// 6. `[]` Sysvar Rent
@@ -134,7 +134,7 @@ pub enum GovernanceInstruction {
134134
/// 2. `[]` Program governed by this Governance account
135135
/// 3. `[writable]` Program Data account of the Program governed by this Governance account
136136
/// 4. `[signer]` Current Upgrade Authority account of the Program governed by this Governance account
137-
/// 5. `[]` Governing TokenOwnerRecord account
137+
/// 5. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)
138138
/// 6. `[signer]` Payer
139139
/// 7. `[]` bpf_upgradeable_loader program
140140
/// 8. `[]` System program
@@ -345,7 +345,7 @@ pub enum GovernanceInstruction {
345345
/// 1. `[writable]` Mint Governance account. PDA seeds: ['mint-governance', realm, governed_mint]
346346
/// 2. `[writable]` Mint governed by this Governance account
347347
/// 3. `[signer]` Current Mint authority (MintTokens and optionally FreezeAccount)
348-
/// 4. `[]` Governing TokenOwnerRecord account
348+
/// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)
349349
/// 5. `[signer]` Payer
350350
/// 6. `[]` SPL Token program
351351
/// 7. `[]` System program
@@ -371,7 +371,7 @@ pub enum GovernanceInstruction {
371371
/// 1. `[writable]` Token Governance account. PDA seeds: ['token-governance', realm, governed_token]
372372
/// 2. `[writable]` Token account governed by this Governance account
373373
/// 3. `[signer]` Current token account authority (AccountOwner and optionally CloseAccount)
374-
/// 4. `[]` Governing TokenOwnerRecord account
374+
/// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)
375375
/// 5. `[signer]` Payer
376376
/// 6. `[]` SPL Token program
377377
/// 7. `[]` System program
@@ -688,7 +688,7 @@ pub fn create_account_governance(
688688
governed_account: &Pubkey,
689689
token_owner_record: &Pubkey,
690690
payer: &Pubkey,
691-
governance_authority: &Pubkey,
691+
create_authority: &Pubkey,
692692
voter_weight_record: Option<Pubkey>,
693693
// Args
694694
config: GovernanceConfig,
@@ -704,7 +704,7 @@ pub fn create_account_governance(
704704
AccountMeta::new(*payer, true),
705705
AccountMeta::new_readonly(system_program::id(), false),
706706
AccountMeta::new_readonly(sysvar::rent::id(), false),
707-
AccountMeta::new_readonly(*governance_authority, true),
707+
AccountMeta::new_readonly(*create_authority, true),
708708
];
709709

710710
with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None);
@@ -728,7 +728,7 @@ pub fn create_program_governance(
728728
governed_program_upgrade_authority: &Pubkey,
729729
token_owner_record: &Pubkey,
730730
payer: &Pubkey,
731-
governance_authority: &Pubkey,
731+
create_authority: &Pubkey,
732732
voter_weight_record: Option<Pubkey>,
733733
// Args
734734
config: GovernanceConfig,
@@ -749,7 +749,7 @@ pub fn create_program_governance(
749749
AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false),
750750
AccountMeta::new_readonly(system_program::id(), false),
751751
AccountMeta::new_readonly(sysvar::rent::id(), false),
752-
AccountMeta::new_readonly(*governance_authority, true),
752+
AccountMeta::new_readonly(*create_authority, true),
753753
];
754754

755755
with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None);
@@ -776,7 +776,7 @@ pub fn create_mint_governance(
776776
governed_mint_authority: &Pubkey,
777777
token_owner_record: &Pubkey,
778778
payer: &Pubkey,
779-
governance_authority: &Pubkey,
779+
create_authority: &Pubkey,
780780
voter_weight_record: Option<Pubkey>,
781781
// Args
782782
config: GovernanceConfig,
@@ -794,7 +794,7 @@ pub fn create_mint_governance(
794794
AccountMeta::new_readonly(spl_token::id(), false),
795795
AccountMeta::new_readonly(system_program::id(), false),
796796
AccountMeta::new_readonly(sysvar::rent::id(), false),
797-
AccountMeta::new_readonly(*governance_authority, true),
797+
AccountMeta::new_readonly(*create_authority, true),
798798
];
799799

800800
with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None);
@@ -821,7 +821,7 @@ pub fn create_token_governance(
821821
governed_token_owner: &Pubkey,
822822
token_owner_record: &Pubkey,
823823
payer: &Pubkey,
824-
governance_authority: &Pubkey,
824+
create_authority: &Pubkey,
825825
voter_weight_record: Option<Pubkey>,
826826
// Args
827827
config: GovernanceConfig,
@@ -839,7 +839,7 @@ pub fn create_token_governance(
839839
AccountMeta::new_readonly(spl_token::id(), false),
840840
AccountMeta::new_readonly(system_program::id(), false),
841841
AccountMeta::new_readonly(sysvar::rent::id(), false),
842-
AccountMeta::new_readonly(*governance_authority, true),
842+
AccountMeta::new_readonly(*create_authority, true),
843843
];
844844

845845
with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None);

governance/program/src/processor/process_create_account_governance.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::state::{
77
GovernanceConfig,
88
},
99
realm::get_realm_data,
10-
token_owner_record::get_token_owner_record_data_for_realm,
1110
};
1211
use solana_program::{
1312
account_info::{next_account_info, AccountInfo},
@@ -16,7 +15,7 @@ use solana_program::{
1615
rent::Rent,
1716
sysvar::Sysvar,
1817
};
19-
use spl_governance_addin_api::voter_weight::VoterWeightAction;
18+
2019
use spl_governance_tools::account::create_and_serialize_account_signed;
2120

2221
/// Processes CreateAccountGovernance instruction
@@ -39,30 +38,20 @@ pub fn process_create_account_governance(
3938
let rent_sysvar_info = next_account_info(account_info_iter)?; // 6
4039
let rent = &Rent::from_account_info(rent_sysvar_info)?;
4140

42-
let governance_authority_info = next_account_info(account_info_iter)?; // 7
41+
let create_authority_info = next_account_info(account_info_iter)?; // 7
4342

4443
assert_valid_create_governance_args(program_id, &config, realm_info)?;
4544

4645
let realm_data = get_realm_data(program_id, realm_info)?;
47-
let token_owner_record_data =
48-
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
49-
50-
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
51-
52-
let realm_config_info = next_account_info(account_info_iter)?; // 8
5346

54-
let voter_weight = token_owner_record_data.resolve_voter_weight(
47+
realm_data.assert_can_create_governance(
5548
program_id,
56-
realm_config_info,
57-
account_info_iter,
58-
realm_info.key,
59-
&realm_data,
60-
VoterWeightAction::CreateGovernance,
6149
realm_info.key,
50+
token_owner_record_info,
51+
create_authority_info,
52+
account_info_iter, // 8, 9
6253
)?;
6354

64-
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
65-
6655
let account_governance_data = Governance {
6756
account_type: GovernanceAccountType::AccountGovernance,
6857
realm: *realm_info.key,

governance/program/src/processor/process_create_mint_governance.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::{
88
GovernanceConfig,
99
},
1010
realm::get_realm_data,
11-
token_owner_record::get_token_owner_record_data_for_realm,
1211
},
1312
tools::spl_token::{
1413
assert_spl_token_mint_authority_is_signer, set_spl_token_account_authority,
@@ -22,7 +21,7 @@ use solana_program::{
2221
rent::Rent,
2322
sysvar::Sysvar,
2423
};
25-
use spl_governance_addin_api::voter_weight::VoterWeightAction;
24+
2625
use spl_governance_tools::account::create_and_serialize_account_signed;
2726
use spl_token::{instruction::AuthorityType, state::Mint};
2827

@@ -51,30 +50,20 @@ pub fn process_create_mint_governance(
5150
let rent_sysvar_info = next_account_info(account_info_iter)?; // 8
5251
let rent = &Rent::from_account_info(rent_sysvar_info)?;
5352

54-
let governance_authority_info = next_account_info(account_info_iter)?; // 9
53+
let create_authority_info = next_account_info(account_info_iter)?; // 9
5554

5655
assert_valid_create_governance_args(program_id, &config, realm_info)?;
5756

5857
let realm_data = get_realm_data(program_id, realm_info)?;
59-
let token_owner_record_data =
60-
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
61-
62-
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
63-
64-
let realm_config_info = next_account_info(account_info_iter)?; // 10
6558

66-
let voter_weight = token_owner_record_data.resolve_voter_weight(
59+
realm_data.assert_can_create_governance(
6760
program_id,
68-
realm_config_info,
69-
account_info_iter,
70-
realm_info.key,
71-
&realm_data,
72-
VoterWeightAction::CreateGovernance,
7361
realm_info.key,
62+
token_owner_record_info,
63+
create_authority_info,
64+
account_info_iter, // 10, 11
7465
)?;
7566

76-
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
77-
7867
let mint_governance_data = Governance {
7968
account_type: GovernanceAccountType::MintGovernance,
8069
realm: *realm_info.key,

governance/program/src/processor/process_create_program_governance.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::{
99
GovernanceConfig,
1010
},
1111
realm::get_realm_data,
12-
token_owner_record::get_token_owner_record_data_for_realm,
1312
},
1413
tools::bpf_loader_upgradeable::{
1514
assert_program_upgrade_authority_is_signer, set_program_upgrade_authority,
@@ -22,7 +21,7 @@ use solana_program::{
2221
rent::Rent,
2322
sysvar::Sysvar,
2423
};
25-
use spl_governance_addin_api::voter_weight::VoterWeightAction;
24+
2625
use spl_governance_tools::account::create_and_serialize_account_signed;
2726

2827
/// Processes CreateProgramGovernance instruction
@@ -51,30 +50,20 @@ pub fn process_create_program_governance(
5150
let rent_sysvar_info = next_account_info(account_info_iter)?; // 9
5251
let rent = &Rent::from_account_info(rent_sysvar_info)?;
5352

54-
let governance_authority_info = next_account_info(account_info_iter)?; // 10
53+
let create_authority_info = next_account_info(account_info_iter)?; // 10
5554

5655
assert_valid_create_governance_args(program_id, &config, realm_info)?;
5756

5857
let realm_data = get_realm_data(program_id, realm_info)?;
59-
let token_owner_record_data =
60-
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
61-
62-
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
63-
64-
let realm_config_info = next_account_info(account_info_iter)?; // 11
6558

66-
let voter_weight = token_owner_record_data.resolve_voter_weight(
59+
realm_data.assert_can_create_governance(
6760
program_id,
68-
realm_config_info,
69-
account_info_iter,
70-
realm_info.key,
71-
&realm_data,
72-
VoterWeightAction::CreateGovernance,
7361
realm_info.key,
62+
token_owner_record_info,
63+
create_authority_info,
64+
account_info_iter, // 10, 11
7465
)?;
7566

76-
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
77-
7867
let program_governance_data = Governance {
7968
account_type: GovernanceAccountType::ProgramGovernance,
8069
realm: *realm_info.key,

governance/program/src/processor/process_create_token_governance.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::{
88
GovernanceConfig,
99
},
1010
realm::get_realm_data,
11-
token_owner_record::get_token_owner_record_data_for_realm,
1211
},
1312
tools::spl_token::{assert_spl_token_owner_is_signer, set_spl_token_account_authority},
1413
};
@@ -20,7 +19,7 @@ use solana_program::{
2019
rent::Rent,
2120
sysvar::Sysvar,
2221
};
23-
use spl_governance_addin_api::voter_weight::VoterWeightAction;
22+
2423
use spl_governance_tools::account::create_and_serialize_account_signed;
2524
use spl_token::{instruction::AuthorityType, state::Account};
2625

@@ -49,30 +48,20 @@ pub fn process_create_token_governance(
4948
let rent_sysvar_info = next_account_info(account_info_iter)?; // 8
5049
let rent = &Rent::from_account_info(rent_sysvar_info)?;
5150

52-
let governance_authority_info = next_account_info(account_info_iter)?; // 9
51+
let create_authority_info = next_account_info(account_info_iter)?; // 9
5352

5453
assert_valid_create_governance_args(program_id, &config, realm_info)?;
5554

5655
let realm_data = get_realm_data(program_id, realm_info)?;
57-
let token_owner_record_data =
58-
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm_info.key)?;
59-
60-
token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
61-
62-
let realm_config_info = next_account_info(account_info_iter)?; //10
6356

64-
let voter_weight = token_owner_record_data.resolve_voter_weight(
57+
realm_data.assert_can_create_governance(
6558
program_id,
66-
realm_config_info,
67-
account_info_iter,
68-
realm_info.key,
69-
&realm_data,
70-
VoterWeightAction::CreateGovernance,
7159
realm_info.key,
60+
token_owner_record_info,
61+
create_authority_info,
62+
account_info_iter, // 10, 11
7263
)?;
7364

74-
token_owner_record_data.assert_can_create_governance(&realm_data, voter_weight)?;
75-
7665
let token_governance_data = Governance {
7766
account_type: GovernanceAccountType::TokenGovernance,
7867
realm: *realm_info.key,

governance/program/src/state/realm.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
//! Realm Account
22
3+
use std::slice::Iter;
4+
35
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
46
use solana_program::{
5-
account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized,
7+
account_info::{next_account_info, AccountInfo},
8+
program_error::ProgramError,
9+
program_pack::IsInitialized,
610
pubkey::Pubkey,
711
};
12+
use spl_governance_addin_api::voter_weight::VoterWeightAction;
813
use spl_governance_tools::account::{assert_is_valid_account, get_account_data, AccountMaxSize};
914

1015
use crate::{
1116
error::GovernanceError,
12-
state::enums::{GovernanceAccountType, MintMaxVoteWeightSource},
17+
state::{
18+
enums::{GovernanceAccountType, MintMaxVoteWeightSource},
19+
token_owner_record::get_token_owner_record_data_for_realm,
20+
},
1321
PROGRAM_AUTHORITY_SEED,
1422
};
1523

@@ -163,6 +171,47 @@ impl Realm {
163171

164172
Ok(())
165173
}
174+
175+
/// Assert the given create authority can create governance
176+
pub fn assert_can_create_governance(
177+
&self,
178+
program_id: &Pubkey,
179+
realm: &Pubkey,
180+
token_owner_record_info: &AccountInfo,
181+
create_authority_info: &AccountInfo,
182+
account_info_iter: &mut Iter<AccountInfo>,
183+
) -> Result<(), ProgramError> {
184+
// Check if create_authority_info is realm_authority and if yes then it must signed the transaction
185+
if self.authority == Some(*create_authority_info.key) {
186+
return if !create_authority_info.is_signer {
187+
Err(GovernanceError::RealmAuthorityMustSign.into())
188+
} else {
189+
Ok(())
190+
};
191+
}
192+
193+
// If realm_authority hasn't signed then check if TokenOwner or Delegate signed and can crate governance
194+
let token_owner_record_data =
195+
get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm)?;
196+
197+
token_owner_record_data.assert_token_owner_or_delegate_is_signer(create_authority_info)?;
198+
199+
let realm_config_info = next_account_info(account_info_iter)?;
200+
201+
let voter_weight = token_owner_record_data.resolve_voter_weight(
202+
program_id,
203+
realm_config_info,
204+
account_info_iter,
205+
realm,
206+
self,
207+
VoterWeightAction::CreateGovernance,
208+
realm,
209+
)?;
210+
211+
token_owner_record_data.assert_can_create_governance(self, voter_weight)?;
212+
213+
Ok(())
214+
}
166215
}
167216

168217
/// Checks whether realm account exists, is initialized and owned by Governance program

0 commit comments

Comments
 (0)