From b0f135a1581c89617426fc5e4b9b2ac94bd35ec5 Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 8 Nov 2023 10:31:49 +0000 Subject: [PATCH] cleanup: cleanup: governance --- governance/addin-api/src/max_voter_weight.rs | 10 +- governance/addin-api/src/voter_weight.rs | 8 +- governance/program/src/error.rs | 5 +- governance/program/src/instruction.rs | 225 ++++++++++-------- .../process_create_mint_governance.rs | 2 +- .../process_create_token_governance.rs | 2 +- .../processor/process_execute_transaction.rs | 2 +- governance/program/src/state/proposal.rs | 53 +++-- governance/program/src/state/realm.rs | 7 +- governance/program/src/state/realm_config.rs | 15 +- governance/program/src/state/vote_record.rs | 5 +- governance/program/src/tools/spl_token.rs | 9 +- .../tests/process_refund_proposal_deposit.rs | 24 +- governance/program/tests/program_test/mod.rs | 17 +- .../use_realm_with_max_voter_weight_addin.rs | 10 +- governance/tools/src/account.rs | 5 +- 16 files changed, 218 insertions(+), 181 deletions(-) diff --git a/governance/addin-api/src/max_voter_weight.rs b/governance/addin-api/src/max_voter_weight.rs index bde3b2d883b..24c992460de 100644 --- a/governance/addin-api/src/max_voter_weight.rs +++ b/governance/addin-api/src/max_voter_weight.rs @@ -12,10 +12,10 @@ use { #[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 to - /// ensure it's stored in the private space of the account data and it's - /// unique + /// sha256("account:MaxVoterWeightRecord")[..8] + /// Note: The discriminator size must match the addin implementing program + /// discriminator size to ensure it's stored in the private space of the + /// account data and it's unique pub account_discriminator: [u8; 8], /// The Realm the MaxVoterWeightRecord belongs to @@ -35,7 +35,7 @@ pub struct MaxVoterWeightRecord { /// The slot when the max voting weight expires /// It should be set to None if the weight never expires /// If the max vote weight decays with time, for example for time locked - /// based weights, then the expiry must be set As a pattern Revise + /// based weights, then the expiry must be set. As a pattern Revise /// instruction to update the max weight should be invoked before governance /// instruction within the same transaction and the expiry set to the /// current slot to provide up to date weight diff --git a/governance/addin-api/src/voter_weight.rs b/governance/addin-api/src/voter_weight.rs index f13526f8fdc..61ad330bc1c 100644 --- a/governance/addin-api/src/voter_weight.rs +++ b/governance/addin-api/src/voter_weight.rs @@ -59,7 +59,7 @@ pub struct VoterWeightRecord { /// The slot when the voting weight expires /// It should be set to None if the weight never expires /// If the voter weight decays with time, for example for time locked based - /// weights, then the expiry must be set As a common pattern Revise + /// weights, then the expiry must be set. As a common pattern Revise /// instruction to update the weight should be invoked before governance /// instruction within the same transaction and the expiry set to the /// current slot to provide up to date weight @@ -67,16 +67,16 @@ pub struct VoterWeightRecord { /// The governance action the voter's weight pertains to /// It allows to provided voter's weight specific to the particular action - /// the weight is evaluated for When the action is provided then the + /// the weight is evaluated for. When the action is provided then the /// governance program asserts the executing action is the same as specified /// by the addin pub weight_action: Option, /// The target the voter's weight action pertains to /// It allows to provided voter's weight specific to the target the weight - /// is evaluated for For example when addin supplies weight to vote on a + /// is evaluated for. For example when addin supplies weight to vote on a /// particular proposal then it must specify the proposal as the action - /// target When the target is provided then the governance program + /// target. When the target is provided then the governance program /// asserts the target is the same as specified by the addin pub weight_action_target: Option, diff --git a/governance/program/src/error.rs b/governance/program/src/error.rs index e4b1ddeaa6b..02c04f54255 100644 --- a/governance/program/src/error.rs +++ b/governance/program/src/error.rs @@ -11,12 +11,13 @@ use { }; /// Errors that may be returned by the Governance program +// Start Governance custom errors from 500 to avoid conflicts with programs +// invoked via CPI #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] pub enum GovernanceError { /// Invalid instruction passed to program #[error("Invalid instruction passed to program")] - InvalidInstruction = 500, /* Start Governance custom errors from 500 to avoid conflicts - * with programs invoked via CPI */ + InvalidInstruction = 500, /// Realm with the given name and governing mints already exists #[error("Realm with the given name and governing mints already exists")] diff --git a/governance/program/src/instruction.rs b/governance/program/src/instruction.rs index 924803fbf74..3a48a48ad20 100644 --- a/governance/program/src/instruction.rs +++ b/governance/program/src/instruction.rs @@ -42,27 +42,26 @@ pub enum GovernanceInstruction { /// Creates Governance Realm account which aggregates governances for given /// Community Mint and optional Council Mint /// - /// 0. `[writable]` Governance Realm account. PDA seeds:['governance',name] + /// 0. `[writable]` Governance Realm account. + /// * PDA seeds:['governance',name] /// 1. `[]` Realm authority /// 2. `[]` Community Token Mint - /// 3. `[writable]` Community Token Holding account. PDA seeds: - /// ['governance',realm,community_mint] The account will be created with - /// the Realm PDA as its owner + /// 3. `[writable]` Community Token Holding account. + /// * PDA seeds: ['governance',realm,community_mint] + /// The account will be created with the Realm PDA as its owner /// 4. `[signer]` Payer /// 5. `[]` System /// 6. `[]` SPL Token /// 7. `[]` Sysvar Rent - /// 8. `[]` Council Token Mint - optional /// 9. `[writable]` Council Token Holding account - optional unless council - /// is used. PDA seeds: ['governance',realm,council_mint] The account - /// will be created with the Realm PDA as its owner - - /// 10. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm] - + /// is used. + /// * PDA seeds: ['governance',realm,council_mint] + /// The account will be created with the Realm PDA as its owner + /// 10. `[writable]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 11. `[]` Optional Community Voter Weight Addin Program Id /// 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 { @@ -83,20 +82,22 @@ pub enum GovernanceInstruction { /// again with the new weight /// /// 0. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: - /// ['governance',realm, governing_token_mint] + /// 1. `[writable]` Governing Token Holding account. + /// * PDA seeds: ['governance',realm, governing_token_mint] /// 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 Source account authority It should be /// owner for TokenAccount and mint_authority for MintAccount - /// 5. `[writable]` TokenOwnerRecord account. PDA seeds: - /// ['governance',realm, governing_token_mint, governing_token_owner] + /// 5. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] /// 6. `[signer]` Payer /// 7. `[]` System /// 8. `[]` SPL Token program - /// 9. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 9. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] DepositGoverningTokens { /// The amount to deposit into the realm #[allow(dead_code)] @@ -104,27 +105,31 @@ pub enum GovernanceInstruction { }, /// Withdraws governing tokens (Community or Council) from Governance Realm - /// and downgrades your voter weight within the Realm 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 + /// and downgrades your voter weight within the Realm. + /// 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. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: - /// ['governance',realm, governing_token_mint] + /// 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]` TokenOwnerRecord account. PDA seeds: - /// ['governance',realm, governing_token_mint, governing_token_owner] + /// 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] + /// 6. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] WithdrawGoverningTokens {}, /// Sets Governance Delegate for the given Realm and Governing Token Mint - /// (Community or Council) The Delegate would have voting rights and - /// could vote on behalf of the Governing Token Owner The Delegate would - /// also be able to create Proposals on behalf of the Governing Token Owner + /// (Community or Council). The Delegate would have voting rights and + /// could vote on behalf of the Governing Token Owner. The Delegate would + /// also be able to create Proposals on behalf of the Governing Token + /// Owner. /// Note: This doesn't take voting rights from the Token Owner who still can /// vote and change governance_delegate /// @@ -140,8 +145,8 @@ pub enum GovernanceInstruction { /// Solana account or asset /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Account Governance account. PDA seeds: - /// ['account-governance', realm, governed_account] + /// 1. `[writable]` Account Governance account. + /// * PDA seeds: ['account-governance', realm, governed_account] /// 2. `[]` Account governed by this Governance Note: The account doesn't /// have to exist and can be only used as a unique identifier for the /// Governance account @@ -151,7 +156,8 @@ pub enum GovernanceInstruction { /// 5. `[]` System program /// 6. `[]` Sysvar Rent /// 7. `[signer]` Governance authority - /// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 8. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 9. `[]` Optional Voter Weight Record CreateGovernance { /// Governance config @@ -162,8 +168,8 @@ pub enum GovernanceInstruction { /// Creates Program Governance account which governs an upgradable program /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Program Governance account. PDA seeds: - /// ['program-governance', realm, governed_program] + /// 1. `[writable]` Program Governance account. + /// * PDA seeds: ['program-governance', realm, governed_program] /// 2. `[]` Program governed by this Governance account /// 3. `[writable]` Program Data account of the Program governed by this /// Governance account @@ -176,7 +182,8 @@ pub enum GovernanceInstruction { /// 8. `[]` System program /// 9. `[]` Sysvar Rent /// 10. `[signer]` Governance authority - /// 11. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 11. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 12. `[]` Optional Voter Weight Record CreateProgramGovernance { /// Governance config @@ -195,8 +202,9 @@ pub enum GovernanceInstruction { /// point in the future /// /// 0. `[]` Realm account the created Proposal belongs to - /// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, - /// governing_token_mint, proposal_seed] + /// 1. `[writable]` Proposal account. + /// * PDA seeds ['governance',governance, governing_token_mint, + /// proposal_seed] /// 2. `[writable]` Governance account /// 3. `[writable]` TokenOwnerRecord account of the Proposal owner /// 4. `[]` Governing Token Mint the Proposal is created for @@ -204,14 +212,16 @@ pub enum GovernanceInstruction { /// Delegate) /// 6. `[signer]` Payer /// 7. `[]` System program - /// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 8. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 9. `[]` Optional Voter Weight Record - /// 10.`[writable]` Optional ProposalDeposit account. PDA seeds: - /// ['proposal-deposit', proposal, deposit payer] Proposal deposit - /// is required when there are more active proposals than the configured - /// deposit exempt amount The deposit is paid by the Payer of the - /// transaction and can be reclaimed using RefundProposalDeposit once the - /// Proposal is no longer active + /// 10.`[writable]` Optional ProposalDeposit account. + /// * PDA seeds: ['proposal-deposit', proposal, deposit payer] + /// Proposal deposit is required when there are more active proposals + /// than the configured deposit exempt amount. + /// The deposit is paid by the Payer of the transaction and can be + /// reclaimed using RefundProposalDeposit once the Proposal is no + /// longer active. CreateProposal { #[allow(dead_code)] /// UTF-8 encoded name of the proposal @@ -275,8 +285,8 @@ pub enum GovernanceInstruction { /// 2. `[]` TokenOwnerRecord account of the Proposal owner /// 3. `[signer]` Governance Authority (Token Owner or Governance /// Delegate) - /// 4. `[writable]` ProposalTransaction, account. PDA seeds: - /// ['governance', proposal, option_index, index] + /// 4. `[writable]` ProposalTransaction, account. + /// * PDA seeds: ['governance', proposal, option_index, index] /// 5. `[signer]` Payer /// 6. `[]` System program /// 7. `[]` Rent sysvar @@ -345,23 +355,25 @@ pub enum GovernanceInstruction { /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord of the Proposal owner - /// 4. `[writable]` TokenOwnerRecord of the voter. PDA seeds: - /// ['governance',realm, vote_governing_token_mint, - /// governing_token_owner] + /// 4. `[writable]` TokenOwnerRecord of the voter. + /// * PDA seeds: ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] /// 5. `[signer]` Governance Authority (Token Owner or Governance /// Delegate) - /// 6. `[writable]` Proposal VoteRecord account. PDA seeds: - /// ['governance',proposal,token_owner_record] + /// 6. `[writable]` Proposal VoteRecord account. + /// * PDA seeds: ['governance',proposal,token_owner_record] /// 7. `[]` The Governing Token Mint which is used to cast the vote - /// (vote_governing_token_mint) The voting token mint is the - /// governing_token_mint of the Proposal for Approve, Deny and Abstain - /// votes For Veto vote the voting token mint is the mint of the - /// opposite voting population Council mint to veto Community proposals - /// and Community mint to veto Council proposals Note: In the current - /// version only Council veto is supported + /// (vote_governing_token_mint). + /// The voting token mint is the governing_token_mint of the Proposal + /// for Approve, Deny and Abstain votes. + /// For Veto vote the voting token mint is the mint of the opposite + /// voting population Council mint to veto Community proposals and + /// Community mint to veto Council proposals. + /// Note: In the current version only Council veto is supported /// 8. `[signer]` Payer /// 9. `[]` System program - /// 10. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 10. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 11. `[]` Optional Voter Weight Record /// 12. `[]` Optional Max Voter Weight Record CastVote { @@ -378,25 +390,26 @@ pub enum GovernanceInstruction { /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord of the Proposal owner /// 4. `[]` Governing Token Mint - /// 5. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 5. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 6. `[]` Optional Max Voter Weight Record FinalizeVote {}, /// Relinquish Vote removes voter weight from a Proposal and removes it - /// from voter's active votes If the Proposal is still being voted on - /// then the voter's weight won't count towards the vote outcome If the + /// from voter's active votes. If the Proposal is still being voted on + /// then the voter's weight won't count towards the vote outcome. If the /// Proposal is already in decided state then the instruction has no impact - /// on the Proposal and only allows voters to prune their outstanding + /// on the Proposal and only allows voters to prune their outstanding /// votes in case they wanted to withdraw Governing tokens from the Realm /// /// 0. `[]` Realm account /// 1. `[]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[writable]` TokenOwnerRecord account. PDA seeds: - /// ['governance',realm, vote_governing_token_mint, - /// governing_token_owner] - /// 4. `[writable]` Proposal VoteRecord account. PDA seeds: - /// ['governance',proposal, token_owner_record] + /// 3. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] + /// 4. `[writable]` Proposal VoteRecord account. + /// * PDA seeds: ['governance',proposal, token_owner_record] /// 5. `[]` The Governing Token Mint which was used to cast the vote /// (vote_governing_token_mint) /// 6. `[signer]` Optional Governance Authority (Token Owner or Governance @@ -422,8 +435,8 @@ pub enum GovernanceInstruction { /// Creates Mint Governance account which governs a mint /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Mint Governance account. PDA seeds: - /// ['mint-governance', realm, governed_mint] + /// 1. `[writable]` Mint Governance account. + /// * PDA seeds: ['mint-governance', realm, governed_mint] /// 2. `[writable]` Mint governed by this Governance account /// 3. `[signer]` Current Mint authority (MintTokens and optionally /// FreezeAccount) @@ -434,7 +447,8 @@ pub enum GovernanceInstruction { /// 7. `[]` System program /// 8. `[]` Sysvar Rent /// 8. `[signer]` Governance authority - /// 9. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 9. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 10. `[]` Optional Voter Weight Record CreateMintGovernance { #[allow(dead_code)] @@ -443,8 +457,8 @@ pub enum GovernanceInstruction { #[allow(dead_code)] /// Indicates whether Mint's authorities (MintTokens, FreezeAccount) - /// should be transferred to the Governance PDA If it's set to - /// false then it can be done at a later time However the + /// should be transferred to the Governance PDA. If it's set to + /// false then it can be done at a later time. However the /// instruction would validate the current mint authority signed the /// transaction nonetheless transfer_mint_authorities: bool, @@ -453,8 +467,8 @@ pub enum GovernanceInstruction { /// Creates Token Governance account which governs a token account /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Token Governance account. PDA seeds: - /// ['token-governance', realm, governed_token] + /// 1. `[writable]` Token Governance account. + /// * PDA seeds: ['token-governance', realm, governed_token] /// 2. `[writable]` Token account governed by this Governance account /// 3. `[signer]` Current token account authority (AccountOwner and /// optionally CloseAccount) @@ -465,7 +479,8 @@ pub enum GovernanceInstruction { /// 7. `[]` System program /// 8. `[]` Sysvar Rent /// 9. `[signer]` Governance authority - /// 10. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 10. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 11. `[]` Optional Voter Weight Record CreateTokenGovernance { #[allow(dead_code)] @@ -493,10 +508,10 @@ pub enum GovernanceInstruction { /// Flags a transaction and its parent Proposal with error status /// It can be used by Proposal owner in case the transaction is permanently - /// broken and can't be executed Note: This instruction is a workaround - /// because currently it's not possible to catch errors from CPI calls - /// and the Governance program has no way to know when instruction - /// failed and flag it automatically + /// broken and can't be executed. + /// Note: This instruction is a workaround because currently it's not + /// possible to catch errors from CPI calls and the Governance program has + /// no way to know when instruction failed and flag it automatically. /// /// 0. `[writable]` Proposal account /// 1. `[]` TokenOwnerRecord account of the Proposal owner @@ -520,24 +535,24 @@ pub enum GovernanceInstruction { /// Sets realm config /// 0. `[writable]` Realm account /// 1. `[signer]` Realm authority - /// 2. `[]` Council Token Mint - optional Note: In the current version - /// it's only possible to remove council mint (set it to None) After - /// setting council to None it won't be possible to withdraw the tokens - /// from the Realm any longer If that's required then it must be done - /// before executing this instruction + /// 2. `[]` Council Token Mint - optional + /// Note: In the current version it's only possible to remove council + /// mint (set it to None). + /// After setting council to None it won't be possible to withdraw the + /// tokens from the Realm any longer. + /// If that's required then it must be done before executing this + /// instruction. /// 3. `[writable]` Council Token Holding account - optional unless - /// council is used. PDA seeds: ['governance',realm,council_mint] The - /// account will be created with the Realm PDA as its owner + /// council is used. + /// * PDA seeds: ['governance',realm,council_mint] The account will be + /// created with the Realm PDA as its owner /// 4. `[]` System - /// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', - /// realm] - /// + /// 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. `[]` 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 { @@ -552,8 +567,9 @@ pub enum GovernanceInstruction { /// /// 0. `[]` Realm account /// 1. `[]` Governing Token Owner account - /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: - /// ['governance',realm, governing_token_mint, governing_token_owner] + /// 2. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] /// 3. `[]` Governing Token Mint /// 4. `[signer]` Payer /// 5. `[]` System @@ -563,7 +579,8 @@ pub enum GovernanceInstruction { /// The instruction dumps information implied by the program's code into a /// persistent account /// - /// 0. `[writable]` ProgramMetadata account. PDA seeds: ['metadata'] + /// 0. `[writable]` ProgramMetadata account. + /// * PDA seeds: ['metadata'] /// 1. `[signer]` Payer /// 2. `[]` System UpdateProgramMetadata {}, @@ -573,29 +590,31 @@ pub enum GovernanceInstruction { /// signed by Governance PDAs or as a native SOL treasury /// /// 0. `[]` Governance account the treasury account is for - /// 1. `[writable]` NativeTreasury account. PDA seeds: ['native-treasury', - /// governance] + /// 1. `[writable]` NativeTreasury account. + /// * PDA seeds: ['native-treasury', governance] /// 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 + /// TokenOwner. Note: If there are active votes for the TokenOwner then /// the vote weights won't be updated automatically /// /// 0. `[]` Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: - /// ['governance',realm, governing_token_mint] - /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: - /// ['governance',realm, governing_token_mint, governing_token_owner] + /// 1. `[writable]` Governing Token Holding account. + /// * PDA seeds: ['governance',realm, governing_token_mint] + /// 2. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] /// 3. `[writable]` GoverningTokenMint /// 4. `[signer]` Revoke authority which can be either of: /// 1) GoverningTokenMint mint_authority to forcefully revoke /// the membership tokens /// 2) GoverningTokenOwner who voluntarily revokes their own /// membership - /// 5. `[]` RealmConfig account. PDA seeds: ['realm-config', realm] + /// 5. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 6. `[]` SPL Token program RevokeGoverningTokens { /// The amount to revoke @@ -609,8 +628,8 @@ pub enum GovernanceInstruction { /// deposit payer /// /// 0. `[]` Proposal account - /// 1. `[writable]` ProposalDeposit account. PDA seeds: - /// ['proposal-deposit', proposal, deposit payer] + /// 1. `[writable]` ProposalDeposit account. + /// * PDA seeds: ['proposal-deposit', proposal, deposit payer] /// 2. `[writable]` Proposal deposit payer (beneficiary) account RefundProposalDeposit {}, diff --git a/governance/program/src/processor/process_create_mint_governance.rs b/governance/program/src/processor/process_create_mint_governance.rs index dfd62300753..0c4d3769368 100644 --- a/governance/program/src/processor/process_create_mint_governance.rs +++ b/governance/program/src/processor/process_create_mint_governance.rs @@ -101,7 +101,7 @@ pub fn process_create_mint_governance( // If the mint has freeze_authority then transfer it as well let mint_data = Mint::unpack(&governed_mint_info.data.borrow())?; // Note: The code assumes mint_authority==freeze_authority - // If this is not the case then the caller should set freeze_authority + // If this is not the case then the caller should set freeze_authority // accordingly before making the transfer if mint_data.freeze_authority.is_some() { set_spl_token_account_authority( diff --git a/governance/program/src/processor/process_create_token_governance.rs b/governance/program/src/processor/process_create_token_governance.rs index 89abec02089..039a4e3d65f 100644 --- a/governance/program/src/processor/process_create_token_governance.rs +++ b/governance/program/src/processor/process_create_token_governance.rs @@ -99,7 +99,7 @@ pub fn process_create_token_governance( // If the token account has close_authority then transfer it as well let token_account_data = Account::unpack(&governed_token_info.data.borrow())?; // Note: The code assumes owner==close_authority - // If this is not the case then the caller should set close_authority + // If this is not the case then the caller should set close_authority // accordingly before making the transfer if token_account_data.close_authority.is_some() { set_spl_token_account_authority( diff --git a/governance/program/src/processor/process_execute_transaction.rs b/governance/program/src/processor/process_execute_transaction.rs index 580d67ff43c..c6ac935b8af 100644 --- a/governance/program/src/processor/process_execute_transaction.rs +++ b/governance/program/src/processor/process_execute_transaction.rs @@ -50,7 +50,7 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] .map(Instruction::from); // In the current implementation accounts for all instructions are passed to - // each instruction invocation This is an overhead but shouldn't be a + // each instruction invocation. This is an overhead but shouldn't be a // showstopper because if we can invoke the parent instruction with that many // accounts then we should also be able to invoke all the nested ones // TODO: Optimize the invocation to split the provided accounts for each diff --git a/governance/program/src/state/proposal.rs b/governance/program/src/state/proposal.rs index 82ca5780ef6..30ae07ff95a 100644 --- a/governance/program/src/state/proposal.rs +++ b/governance/program/src/state/proposal.rs @@ -74,9 +74,10 @@ pub struct ProposalOption { pub enum VoteType { /// Single choice vote with mutually exclusive choices /// In the SingeChoice mode there can ever be a single winner - /// If multiple options score the same highest vote then the Proposal is not - /// resolved and considered as Failed Note: Yes/No vote is a single - /// choice (Yes) vote with the deny option (No) + /// If multiple options score the same highest vote then the Proposal is + /// not resolved and considered as Failed. + /// Note: Yes/No vote is a single choice (Yes) vote with the deny + /// option (No) SingleChoice, /// Multiple options can be selected with up to max_voter_options per voter @@ -122,9 +123,10 @@ pub enum MultiChoiceType { /// approved option FullWeight, - /// Multiple options can be approved with weight allocated proportionally to - /// the percentage of the total weight The full weight has to be voted - /// among the approved options, i.e., 100% of the weight has to be allocated + /// Multiple options can be approved with weight allocated proportionally + /// to the percentage of the total weight. + /// The full weight has to be voted among the approved options, i.e., + /// 100% of the weight has to be allocated Weighted, } @@ -215,21 +217,23 @@ pub struct ProposalV2 { pub execution_flags: InstructionExecutionFlags, /// The max vote weight for the Governing Token mint at the time Proposal - /// was decided It's used to show correct vote results for historical - /// proposals in cases when the mint supply or max weight source changed - /// after vote was completed. + /// was decided. + /// It's used to show correct vote results for historical proposals in + /// cases when the mint supply or max weight source changed after vote was + /// completed. pub max_vote_weight: Option, /// Max voting time for the proposal if different from parent Governance - /// (only higher value possible) Note: This field is not used in the - /// current version + /// (only higher value possible). + /// Note: This field is not used in the current version pub max_voting_time: Option, /// The vote threshold at the time Proposal was decided /// It's used to show correct vote results for historical proposals in cases /// when the threshold was changed for governance config after vote was - /// completed. TODO: Use this field to override the threshold from - /// parent Governance (only higher value possible) + /// completed. + /// TODO: Use this field to override the threshold from parent Governance + /// (only higher value possible) pub vote_threshold: Option, /// Reserved space for future versions @@ -682,8 +686,8 @@ impl ProposalV2 { } /// Checks if vote can be tipped and automatically transitioned to - /// Succeeded, Defeated or Vetoed state If yes then Some(ProposalState) - /// is returned and None otherwise + /// Succeeded, Defeated or Vetoed state. + /// If yes then Some(ProposalState) is returned and None otherwise pub fn try_get_tipped_vote_state( &mut self, max_voter_weight: u64, @@ -705,21 +709,22 @@ impl ProposalV2 { } /// Checks if Electorate vote can be tipped and automatically transitioned - /// to Succeeded or Defeated state If yes then Some(ProposalState) is - /// returned and None otherwise + /// to Succeeded or Defeated state. + /// If yes then Some(ProposalState) is returned and None otherwise fn try_get_tipped_electorate_vote_state( &mut self, max_voter_weight: u64, vote_tipping: &VoteTipping, min_vote_threshold_weight: u64, ) -> Option { - // Vote tipping is currently supported for SingleChoice votes with single Yes - // and No (rejection) options only Note: Tipping for multiple options - // (single choice and multiple choices) should be possible but it requires a - // great deal of considerations and I decided to fight it another - // day + // Vote tipping is currently supported for SingleChoice votes with + // single Yes and No (rejection) options only. + // Note: Tipping for multiple options (single choice and multiple + // choices) should be possible but it requires a great deal of + // considerations and I decided to fight it another day if self.vote_type != VoteType::SingleChoice - // Tipping should not be allowed for opinion only proposals (surveys without rejection) to allow everybody's voice to be heard + // Tipping should not be allowed for opinion only proposals (surveys + // without rejection) to allow everybody's voice to be heard || self.deny_vote_weight.is_none() || self.options.len() != 1 { @@ -935,7 +940,7 @@ impl ProposalV2 { max_winning_options: _, } => { // Calculate the total percentage for all choices for weighted - // choice vote The total must add up + // choice vote. The total must add up // to exactly 100% total_choice_weight_percentage = total_choice_weight_percentage .checked_add(choice.weight_percentage) diff --git a/governance/program/src/state/realm.rs b/governance/program/src/state/realm.rs index a389ae8304e..bcef081c88c 100644 --- a/governance/program/src/state/realm.rs +++ b/governance/program/src/state/realm.rs @@ -88,9 +88,10 @@ pub enum SetRealmAuthorityAction { /// Sets realm authority and checks the new new authority is one of the /// realm's governances - // Note: This is not a security feature because governance creation is only gated with - // min_community_weight_to_create_governance The check is done to prevent scenarios - // where the authority could be accidentally set to a wrong or none existing account + // Note: This is not a security feature because governance creation is only + // gated with min_community_weight_to_create_governance. + // The check is done to prevent scenarios where the authority could be + // accidentally set to a wrong or none existing account. SetChecked, /// Removes realm authority diff --git a/governance/program/src/state/realm_config.rs b/governance/program/src/state/realm_config.rs index 6666c7ca1d7..d334c338166 100644 --- a/governance/program/src/state/realm_config.rs +++ b/governance/program/src/state/realm_config.rs @@ -25,18 +25,20 @@ use { #[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 + /// 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 possession + /// power. + /// The membership tokens are conventionally minted into the holding + /// account to keep them out of members possession. /// 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 + /// 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 @@ -55,7 +57,8 @@ pub enum GoverningTokenType { /// 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 + /// deposited. + /// Revoke - No, Realm authority cannot revoke dormant tokens Dormant, } diff --git a/governance/program/src/state/vote_record.rs b/governance/program/src/state/vote_record.rs index 1007cc08a7b..050f8fd9c3d 100644 --- a/governance/program/src/state/vote_record.rs +++ b/governance/program/src/state/vote_record.rs @@ -22,8 +22,9 @@ use { /// Voter choice for a proposal option /// In the current version only 1) Single choice, 2) Multiple choices proposals -/// and 3) Weighted voting are supported In the future versions we can add -/// support for 1) Quadratic voting and 2) Ranked choice voting +/// and 3) Weighted voting are supported. +/// In the future versions we can add support for 1) Quadratic voting and +/// 2) Ranked choice voting #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoteChoice { /// The rank given to the choice by voter diff --git a/governance/program/src/tools/spl_token.rs b/governance/program/src/tools/spl_token.rs index 141ee7041b2..a5f19ce0ee2 100644 --- a/governance/program/src/tools/spl_token.rs +++ b/governance/program/src/tools/spl_token.rs @@ -269,8 +269,13 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<( return Err(GovernanceError::SplTokenInvalidTokenAccountData.into()); } - // TokeAccount layout: mint(32), owner(32), amount(8), delegate(36), state(1), - // ... + // TokenAccount layout: + // mint(32) + // owner(32) + // amount(8) + // delegate(36) + // state(1) + // ... let data = account_info.try_borrow_data()?; let state = array_ref![data, 108, 1]; diff --git a/governance/program/tests/process_refund_proposal_deposit.rs b/governance/program/tests/process_refund_proposal_deposit.rs index 042b1e54d7d..a19370cff20 100644 --- a/governance/program/tests/process_refund_proposal_deposit.rs +++ b/governance/program/tests/process_refund_proposal_deposit.rs @@ -306,18 +306,18 @@ async fn test_refund_proposal_deposit_with_invalid_proposal_deposit_account_erro .unwrap(); // Act - let err = - governance_test - .refund_proposal_deposit_using_instruction( - &proposal_cookie, - |i| { - i.accounts[1].pubkey = proposal_cookie.address; // Try to drain the Proposal account - }, - None, - ) - .await - .err() - .unwrap(); + let err = governance_test + .refund_proposal_deposit_using_instruction( + &proposal_cookie, + |i| { + // Try to drain the Proposal account + i.accounts[1].pubkey = proposal_cookie.address; + }, + None, + ) + .await + .err() + .unwrap(); // Assert diff --git a/governance/program/tests/program_test/mod.rs b/governance/program/tests/program_test/mod.rs index fcd23b31020..aa8c45f8683 100644 --- a/governance/program/tests/program_test/mod.rs +++ b/governance/program/tests/program_test/mod.rs @@ -142,11 +142,13 @@ impl GovernanceProgramTest { use_voter_weight_addin: bool, use_max_voter_weight_addin: bool, ) -> Self { - // We only ensure the addin mock program is built but it doesn't detect changes - // If the addin is changed then it needs to be manually rebuilt - // Note: The crate of the mock is built when spl-governance is built but we also - // need spl_governance_addin_mock.so And we can't use build.rs - // script because cargo build-sbf hangs when executed from the script + // We only ensure the addin mock program is built but it doesn't detect + // changes. + // If the addin is changed then it needs to be manually rebuilt. + // Note: The crate of the mock is built when spl-governance is built + // but we also need spl_governance_addin_mock.so. + // And we can't use build.rs script because cargo build-sbf hangs when + // executed from the script. ensure_addin_mock_is_built(); Self::start_impl(use_voter_weight_addin, use_max_voter_weight_addin).await @@ -2782,8 +2784,9 @@ impl GovernanceProgramTest { .iter() .map(|a| AccountMeta { pubkey: a.pubkey, - is_signer: false, /* Remove signer since the Governance account PDA will be - * signing the instruction for us */ + // Remove signer since the Governance account PDA will be + // signing the instruction for us + is_signer: false, is_writable: a.is_writable, }) .collect(); diff --git a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs index f36ee61ed56..7e4b7d4039e 100644 --- a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs +++ b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs @@ -212,9 +212,8 @@ async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_vote .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max - // based on cast - // votes + // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); } #[tokio::test] @@ -360,9 +359,8 @@ async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max - // based on cast - // votes + // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); } #[tokio::test] diff --git a/governance/tools/src/account.rs b/governance/tools/src/account.rs index 347cbb5d07c..192060ea95c 100644 --- a/governance/tools/src/account.rs +++ b/governance/tools/src/account.rs @@ -152,8 +152,9 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac let total_lamports = rent_exempt_lamports.checked_add(extra_lamports).unwrap(); // If the account has some lamports already it can't be created using - // create_account instruction Anybody can send lamports to a PDA and by - // doing so create the account and perform DoS attack by blocking create_account + // create_account instruction. + // Anybody can send lamports to a PDA and by doing so create the account + // and perform DoS attack by blocking create_account if account_info.lamports() > 0 { let top_up_lamports = total_lamports.saturating_sub(account_info.lamports());