1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use solana_program::{
account_info::AccountInfo,
clock::{Clock, Slot},
program_error::ProgramError,
program_pack::IsInitialized,
pubkey::Pubkey,
sysvar::Sysvar,
};
use spl_governance_tools::account::{get_account_data, AccountMaxSize};
use crate::{error::GovernanceError, state::token_owner_record::TokenOwnerRecord};
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
pub enum VoterWeightAccountType {
Uninitialized,
VoterWeightRecord,
}
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
pub struct VoterWeightRecord {
pub account_type: VoterWeightAccountType,
pub realm: Pubkey,
pub governing_token_mint: Pubkey,
pub governing_token_owner: Pubkey,
pub voter_weight: u64,
pub voter_weight_expiry: Option<Slot>,
}
impl AccountMaxSize for VoterWeightRecord {}
impl IsInitialized for VoterWeightRecord {
fn is_initialized(&self) -> bool {
self.account_type == VoterWeightAccountType::VoterWeightRecord
}
}
impl VoterWeightRecord {
pub fn assert_is_up_to_date(&self) -> Result<(), ProgramError> {
if let Some(voter_weight_expiry) = self.voter_weight_expiry {
let slot = Clock::get().unwrap().slot;
if slot > voter_weight_expiry {
return Err(GovernanceError::VoterWeightRecordExpired.into());
}
}
Ok(())
}
}
pub fn get_voter_weight_record_data(
program_id: &Pubkey,
voter_weight_record_info: &AccountInfo,
) -> Result<VoterWeightRecord, ProgramError> {
get_account_data::<VoterWeightRecord>(program_id, voter_weight_record_info)
}
pub fn get_voter_weight_record_data_for_token_owner_record(
program_id: &Pubkey,
voter_weight_record_info: &AccountInfo,
token_owner_record: &TokenOwnerRecord,
) -> Result<VoterWeightRecord, ProgramError> {
let voter_weight_record_data =
get_voter_weight_record_data(program_id, voter_weight_record_info)?;
if voter_weight_record_data.realm != token_owner_record.realm {
return Err(GovernanceError::InvalidVoterWeightRecordForRealm.into());
}
if voter_weight_record_data.governing_token_mint != token_owner_record.governing_token_mint {
return Err(GovernanceError::InvalidVoterWeightRecordForGoverningTokenMint.into());
}
if voter_weight_record_data.governing_token_owner != token_owner_record.governing_token_owner {
return Err(GovernanceError::InvalidVoterWeightRecordForTokenOwner.into());
}
Ok(voter_weight_record_data)
}