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

Commit 103e801

Browse files
authored
Governance: Proposal deposit (#135)
* feat: Add active_proposal_count to Governance * feat: Reallocate GovernanceV1 to GovernanceV2 * chore: test_create_proposal_and_migrate_v1_governance_to_v2 * chore: Cleanup code * chore: Update comments * chore: Use assert_is_valid_realm instead of deserializing the account * chore: Update comments * chore: Update comments * chore: Check for empty account first * feat: Add extra_lamports to create_and_serialize_account * chore: Make Clippy happy * feat: Implement Proposal security deposit * chore: Make Clippy happy * chore: Add proposal deposit amount tests * feat: Implement RefundProposalDeposit * chore: test_refund_proposal_deposit * chore: Make Clippy happy * chore: test_refund_proposal_deposit_with_cannot_refund_draft_proposal_error * chore: test_refund_proposal_deposit_with_invalid_proposal_owner_record_error * chore: test_refund_proposal_deposit_with_invalid_proposal_owner_error * fix: Return deposit to deposit payer * chore: Cleanup * chore: test_refund_proposal_deposit_with_invalid_proposal_deposit_account_error * fix: Remove unnecessary max(1) for account lamports
1 parent 2c50e98 commit 103e801

30 files changed

+761
-26
lines changed

governance/chat/program/tests/program_test/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use spl_governance::{
1111
},
1212
state::{
1313
enums::{MintMaxVoterWeightSource, VoteThreshold},
14-
governance::{get_governance_address, GovernanceConfig},
14+
governance::{
15+
get_governance_address, GovernanceConfig, DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT,
16+
},
1517
proposal::{get_proposal_address, VoteType},
1618
realm::{get_realm_address, GoverningTokenConfigAccountArgs},
1719
realm_config::GoverningTokenType,
@@ -197,7 +199,7 @@ impl GovernanceChatProgramTest {
197199
council_vote_tipping: spl_governance::state::enums::VoteTipping::Strict,
198200
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(55),
199201
voting_cool_off_time: 1,
200-
reserved: 0,
202+
deposit_exempt_proposal_count: DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT,
201203
};
202204

203205
let token_owner_record_address = get_token_owner_record_address(

governance/program/src/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ pub enum GovernanceError {
442442
/// Vote not allowed in cool off time
443443
#[error("Vote not allowed in cool off time")]
444444
VoteNotAllowedInCoolOffTime, // 606
445+
446+
/// Cannot refund ProposalDeposit
447+
#[error("Cannot refund ProposalDeposit")]
448+
CannotRefundProposalDeposit, // 607
449+
450+
/// Invalid ProposalDeposit account address
451+
#[error("Invalid ProposalDeposit account address")]
452+
InvalidProposalDepositAccountAddress, // 608
445453
}
446454

447455
impl PrintProgramError for GovernanceError {

governance/program/src/instruction.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
native_treasury::get_native_treasury_address,
1111
program_metadata::get_program_metadata_address,
1212
proposal::{get_proposal_address, VoteType},
13+
proposal_deposit::get_proposal_deposit_address,
1314
proposal_transaction::{get_proposal_transaction_address, InstructionData},
1415
realm::{
1516
get_governing_token_holding_address, get_realm_address,
@@ -174,6 +175,9 @@ pub enum GovernanceInstruction {
174175
/// 7. `[]` System program
175176
/// 8. `[]` RealmConfig account. PDA seeds: ['realm-config', realm]
176177
/// 9. `[]` Optional Voter Weight Record
178+
/// 10.`[writable]` Optional ProposalDeposit account. PDA seeds: ['proposal-deposit', proposal, deposit payer]
179+
/// Proposal deposit is required when there are more active proposals than the configured deposit exempt amount
180+
/// The deposit is paid by the Payer of the transaction and can be reclaimed using RefundProposalDeposit once the Proposal is no longer active
177181
CreateProposal {
178182
#[allow(dead_code)]
179183
/// UTF-8 encoded name of the proposal
@@ -509,6 +513,14 @@ pub enum GovernanceInstruction {
509513
#[allow(dead_code)]
510514
amount: u64,
511515
},
516+
517+
/// Refunds ProposalDeposit once the given proposal is no longer active (Draft, SigningOff, Voting)
518+
/// Once the condition is met the instruction is permissionless and returns the deposit amount to the deposit payer
519+
///
520+
/// 0. `[]` Proposal account
521+
/// 1. `[writable]` ProposalDeposit account. PDA seeds: ['proposal-deposit', proposal, deposit payer]
522+
/// 2. `[writable]` Proposal deposit payer (beneficiary) account
523+
RefundProposalDeposit {},
512524
}
513525

514526
/// Creates CreateRealm instruction
@@ -919,6 +931,12 @@ pub fn create_proposal(
919931

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

934+
// Deposit is only required when there are more active proposal then the configured exempt amount
935+
// Note: We always pass the account because the actual value is not known here without passing Governance account data
936+
let proposal_deposit_address =
937+
get_proposal_deposit_address(program_id, &proposal_address, payer);
938+
accounts.push(AccountMeta::new(proposal_deposit_address, false));
939+
922940
let instruction = GovernanceInstruction::CreateProposal {
923941
name,
924942
description_link,
@@ -1613,3 +1631,30 @@ pub fn with_governing_token_config_args(
16131631
token_type: governing_token_config_args.token_type,
16141632
}
16151633
}
1634+
1635+
/// Creates RefundProposalDeposit instruction
1636+
#[allow(clippy::too_many_arguments)]
1637+
pub fn refund_proposal_deposit(
1638+
program_id: &Pubkey,
1639+
// Accounts
1640+
proposal: &Pubkey,
1641+
proposal_deposit_payer: &Pubkey,
1642+
// Args
1643+
) -> Instruction {
1644+
let proposal_deposit_address =
1645+
get_proposal_deposit_address(program_id, proposal, proposal_deposit_payer);
1646+
1647+
let accounts = vec![
1648+
AccountMeta::new_readonly(*proposal, false),
1649+
AccountMeta::new(proposal_deposit_address, false),
1650+
AccountMeta::new(*proposal_deposit_payer, false),
1651+
];
1652+
1653+
let instruction = GovernanceInstruction::RefundProposalDeposit {};
1654+
1655+
Instruction {
1656+
program_id: *program_id,
1657+
accounts,
1658+
data: instruction.try_to_vec().unwrap(),
1659+
}
1660+
}

governance/program/src/processor/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod process_execute_transaction;
1616
mod process_finalize_vote;
1717
mod process_flag_transaction_error;
1818
mod process_insert_transaction;
19+
mod process_refund_proposal_deposit;
1920
mod process_relinquish_vote;
2021
mod process_remove_signatory;
2122
mod process_remove_transaction;
@@ -46,6 +47,7 @@ use process_execute_transaction::*;
4647
use process_finalize_vote::*;
4748
use process_flag_transaction_error::*;
4849
use process_insert_transaction::*;
50+
use process_refund_proposal_deposit::*;
4951
use process_relinquish_vote::*;
5052
use process_remove_signatory::*;
5153
use process_remove_transaction::*;
@@ -221,5 +223,9 @@ pub fn process_instruction(
221223
GovernanceInstruction::RevokeGoverningTokens { amount } => {
222224
process_revoke_governing_tokens(program_id, accounts, amount)
223225
}
226+
227+
GovernanceInstruction::RefundProposalDeposit {} => {
228+
process_refund_proposal_deposit(program_id, accounts)
229+
}
224230
}
225231
}

governance/program/src/processor/process_add_signatory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub fn process_add_signatory(
6262
program_id,
6363
system_info,
6464
&rent,
65+
None,
6566
)?;
6667

6768
proposal_data.signatories_count = proposal_data.signatories_count.checked_add(1).unwrap();

governance/program/src/processor/process_cast_vote.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ pub fn process_cast_vote(
214214
program_id,
215215
system_info,
216216
&rent,
217+
None,
217218
)?;
218219

219220
Ok(())

governance/program/src/processor/process_create_governance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub fn process_create_governance(
7272
program_id,
7373
system_info,
7474
&rent,
75+
None,
7576
)?;
7677

7778
Ok(())

governance/program/src/processor/process_create_mint_governance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub fn process_create_mint_governance(
8282
program_id,
8383
system_info,
8484
&rent,
85+
None,
8586
)?;
8687

8788
if transfer_mint_authorities {

governance/program/src/processor/process_create_native_treasury.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn process_create_native_treasury(
4242
&system_program::id(), // System program as the PDA owner
4343
system_info,
4444
&rent,
45+
None,
4546
)?;
4647

4748
Ok(())

governance/program/src/processor/process_create_program_governance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub fn process_create_program_governance(
8484
program_id,
8585
system_info,
8686
&rent,
87+
None,
8788
)?;
8889

8990
if transfer_upgrade_authority {

0 commit comments

Comments
 (0)