use {
crate::{
error::GovernanceError,
state::{
enums::ProposalState,
governance::get_governance_data_for_realm,
proposal::get_proposal_data_for_governance,
realm::get_realm_data_for_governing_token_mint,
token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint,
vote_record::{get_vote_record_data_for_proposal_and_token_owner_record, Vote},
},
},
solana_program::{
account_info::{next_account_info, AccountInfo},
clock::Clock,
entrypoint::ProgramResult,
pubkey::Pubkey,
sysvar::Sysvar,
},
spl_governance_tools::account::dispose_account,
};
pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let realm_info = next_account_info(account_info_iter)?; let governance_info = next_account_info(account_info_iter)?; let proposal_info = next_account_info(account_info_iter)?; let token_owner_record_info = next_account_info(account_info_iter)?;
let vote_record_info = next_account_info(account_info_iter)?; let vote_governing_token_mint_info = next_account_info(account_info_iter)?;
let realm_data = get_realm_data_for_governing_token_mint(
program_id,
realm_info,
vote_governing_token_mint_info.key,
)?;
let governance_data =
get_governance_data_for_realm(program_id, governance_info, realm_info.key)?;
let mut proposal_data =
get_proposal_data_for_governance(program_id, proposal_info, governance_info.key)?;
let mut token_owner_record_data = get_token_owner_record_data_for_realm_and_governing_mint(
program_id,
token_owner_record_info,
&governance_data.realm,
vote_governing_token_mint_info.key,
)?;
let mut vote_record_data = get_vote_record_data_for_proposal_and_token_owner_record(
program_id,
vote_record_info,
&realm_data,
proposal_info.key,
&proposal_data,
&token_owner_record_data,
)?;
vote_record_data.assert_can_relinquish_vote()?;
let clock = Clock::get()?;
if proposal_data.state == ProposalState::Voting
&& !proposal_data.has_voting_max_time_ended(&governance_data.config, clock.unix_timestamp)
{
let governance_authority_info = next_account_info(account_info_iter)?; let beneficiary_info = next_account_info(account_info_iter)?;
token_owner_record_data
.assert_token_owner_or_delegate_is_signer(governance_authority_info)?;
match vote_record_data.vote {
Vote::Approve(choices) => {
for (option, choice) in proposal_data.options.iter_mut().zip(choices) {
option.vote_weight = option
.vote_weight
.checked_sub(choice.get_choice_weight(vote_record_data.voter_weight)?)
.unwrap();
}
}
Vote::Deny => {
proposal_data.deny_vote_weight = Some(
proposal_data
.deny_vote_weight
.unwrap()
.checked_sub(vote_record_data.voter_weight)
.unwrap(),
)
}
Vote::Veto => {
proposal_data.veto_vote_weight = proposal_data
.veto_vote_weight
.checked_sub(vote_record_data.voter_weight)
.unwrap();
}
Vote::Abstain => {
return Err(GovernanceError::NotSupportedVoteType.into());
}
}
proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?;
dispose_account(vote_record_info, beneficiary_info)?;
} else {
if proposal_data.state == ProposalState::Voting {
return Err(GovernanceError::CannotRelinquishInFinalizingState.into());
}
vote_record_data.is_relinquished = true;
vote_record_data.serialize(&mut vote_record_info.data.borrow_mut()[..])?;
}
token_owner_record_data.unrelinquished_votes_count = token_owner_record_data
.unrelinquished_votes_count
.checked_sub(1)
.unwrap();
token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?;
Ok(())
}