2021-12-02 07:28:12 -08:00
|
|
|
use crate::error::*;
|
2021-12-03 00:52:48 -08:00
|
|
|
use crate::state::*;
|
2021-12-02 07:28:12 -08:00
|
|
|
use anchor_lang::prelude::*;
|
2022-01-25 05:56:15 -08:00
|
|
|
use anchor_spl::token::{self, CloseAccount, Token, TokenAccount};
|
2021-12-02 07:28:12 -08:00
|
|
|
|
2022-01-25 05:56:15 -08:00
|
|
|
// Remaining accounts must be all the token token accounts owned by voter, he wants to close,
|
|
|
|
// they should be writable so that they can be closed and sol required for rent
|
|
|
|
// can then be sent back to the sol_destination
|
2021-12-02 07:28:12 -08:00
|
|
|
#[derive(Accounts)]
|
|
|
|
pub struct CloseVoter<'info> {
|
2022-01-25 05:56:15 -08:00
|
|
|
pub registrar: AccountLoader<'info, Registrar>,
|
|
|
|
|
2021-12-04 00:02:20 -08:00
|
|
|
// checking the PDA address it just an extra precaution,
|
|
|
|
// the other constraints must be exhaustive
|
|
|
|
#[account(
|
|
|
|
mut,
|
|
|
|
seeds = [voter.load()?.registrar.key().as_ref(), b"voter".as_ref(), voter_authority.key().as_ref()],
|
|
|
|
bump = voter.load()?.voter_bump,
|
|
|
|
has_one = voter_authority,
|
|
|
|
close = sol_destination)]
|
2021-12-02 07:28:12 -08:00
|
|
|
pub voter: AccountLoader<'info, Voter>,
|
2022-01-25 05:56:15 -08:00
|
|
|
|
2021-12-02 07:28:12 -08:00
|
|
|
pub voter_authority: Signer<'info>,
|
2022-01-25 05:56:15 -08:00
|
|
|
|
|
|
|
#[account(mut)]
|
2021-12-02 07:28:12 -08:00
|
|
|
pub sol_destination: UncheckedAccount<'info>,
|
2022-01-25 05:56:15 -08:00
|
|
|
|
|
|
|
pub token_program: Program<'info, Token>,
|
2021-12-02 07:28:12 -08:00
|
|
|
}
|
|
|
|
|
2022-01-25 05:56:15 -08:00
|
|
|
/// Closes the voter account (Optionally, also token vaults, as part of remaining_accounts),
|
|
|
|
/// allowing one to retrieve rent exemption SOL.
|
2021-12-02 07:28:12 -08:00
|
|
|
/// Only accounts with no remaining deposits can be closed.
|
2022-01-25 05:56:15 -08:00
|
|
|
pub fn close_voter<'key, 'accounts, 'remaining, 'info>(
|
|
|
|
ctx: Context<'key, 'accounts, 'remaining, 'info, CloseVoter<'info>>,
|
|
|
|
) -> Result<()> {
|
2021-12-02 07:28:12 -08:00
|
|
|
let voter = &ctx.accounts.voter.load()?;
|
|
|
|
let amount = voter.deposits.iter().fold(0u64, |sum, d| {
|
|
|
|
sum.checked_add(d.amount_deposited_native).unwrap()
|
|
|
|
});
|
|
|
|
require!(amount == 0, VotingTokenNonZero);
|
2022-01-25 05:56:15 -08:00
|
|
|
|
|
|
|
let voter_seeds = voter_seeds!(voter);
|
|
|
|
for account in &mut ctx.remaining_accounts.iter() {
|
|
|
|
let token = Account::<TokenAccount>::try_from(&account.clone()).unwrap();
|
|
|
|
require!(token.owner == ctx.accounts.voter.key(), InvalidAuthority);
|
|
|
|
require!(token.amount == 0, VaultTokenNonZero);
|
|
|
|
|
|
|
|
let cpi_accounts = CloseAccount {
|
|
|
|
account: account.to_account_info(),
|
|
|
|
destination: ctx.accounts.sol_destination.to_account_info(),
|
|
|
|
authority: ctx.accounts.voter.to_account_info(),
|
|
|
|
};
|
|
|
|
let cpi_program = ctx.accounts.token_program.to_account_info();
|
|
|
|
token::close_account(CpiContext::new_with_signer(
|
|
|
|
cpi_program,
|
|
|
|
cpi_accounts,
|
|
|
|
&[voter_seeds],
|
|
|
|
))?;
|
|
|
|
|
|
|
|
account.exit(ctx.program_id)?;
|
|
|
|
}
|
|
|
|
|
2021-12-02 07:28:12 -08:00
|
|
|
Ok(())
|
|
|
|
}
|