use crate::account::*; use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{self, Mint, Token, TokenAccount}; use std::mem::size_of; pub const VOTER_WEIGHT_RECORD: [u8; 19] = *b"voter-weight-record"; #[derive(Accounts)] #[instruction(warmup_secs: i64, registrar_bump: u8)] pub struct CreateRegistrar<'info> { #[account( init, seeds = [realm.key().as_ref()], bump = registrar_bump, payer = payer, space = 8 + size_of::() )] pub registrar: AccountLoader<'info, Registrar>, // Unsafe and untrusted. This instruction needs to be invoked immediatley // after the realm is created. pub realm: UncheckedAccount<'info>, pub realm_community_mint: Account<'info, Mint>, pub authority: UncheckedAccount<'info>, pub payer: Signer<'info>, pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, pub rent: Sysvar<'info, Rent>, } #[derive(Accounts)] #[instruction(voter_bump: u8, voter_weight_record_bump: u8)] pub struct CreateVoter<'info> { #[account( init, seeds = [registrar.key().as_ref(), authority.key().as_ref()], bump = voter_bump, payer = authority, space = 8 + size_of::(), )] pub voter: AccountLoader<'info, Voter>, #[account( init , seeds = [VOTER_WEIGHT_RECORD.as_ref(), registrar.key().as_ref(), authority.key().as_ref()], bump = voter_weight_record_bump, payer = payer, space = 150, )] pub voter_weight_record: Account<'info, VoterWeightRecord>, pub registrar: AccountLoader<'info, Registrar>, pub authority: Signer<'info>, pub payer: Signer<'info>, pub token_program: Program<'info, Token>, pub associated_token_program: Program<'info, AssociatedToken>, pub system_program: Program<'info, System>, pub rent: Sysvar<'info, Rent>, } #[derive(Accounts)] #[instruction(idx: u16, rate: ExchangeRateEntry)] pub struct CreateExchangeRate<'info> { #[account( init, payer = authority, associated_token::authority = registrar, associated_token::mint = deposit_mint, )] pub exchange_vault: Account<'info, TokenAccount>, #[account( init, seeds = [registrar.key().as_ref(), deposit_mint.key().as_ref()], bump, payer = authority, mint::authority = registrar, mint::freeze_authority = registrar, mint::decimals = deposit_mint.decimals, )] pub voting_mint: Account<'info, Mint>, pub deposit_mint: Account<'info, Mint>, #[account(mut, has_one = authority)] pub registrar: AccountLoader<'info, Registrar>, #[account(mut)] pub authority: Signer<'info>, pub rent: Sysvar<'info, Rent>, pub token_program: Program<'info, Token>, pub associated_token_program: Program<'info, AssociatedToken>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct CreateDeposit<'info> { pub deposit: UpdateDeposit<'info>, } #[derive(Accounts)] pub struct UpdateDeposit<'info> { pub registrar: AccountLoader<'info, Registrar>, #[account(mut, has_one = authority, has_one = registrar)] pub voter: AccountLoader<'info, Voter>, #[account( mut, associated_token::authority = registrar, associated_token::mint = deposit_mint, )] pub exchange_vault: Account<'info, TokenAccount>, #[account( mut, constraint = deposit_token.mint == deposit_mint.key(), )] pub deposit_token: Account<'info, TokenAccount>, #[account( init_if_needed, payer = authority, associated_token::authority = authority, associated_token::mint = voting_mint, )] pub voting_token: Account<'info, TokenAccount>, pub authority: Signer<'info>, pub deposit_mint: Account<'info, Mint>, #[account( mut, seeds = [registrar.key().as_ref(), deposit_token.mint.as_ref()], bump, )] pub voting_mint: Account<'info, Mint>, pub token_program: Program<'info, Token>, pub associated_token_program: Program<'info, AssociatedToken>, pub system_program: Program<'info, System>, pub rent: Sysvar<'info, Rent>, } impl<'info> UpdateDeposit<'info> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { let program = self.token_program.to_account_info(); let accounts = token::Transfer { from: self.deposit_token.to_account_info(), to: self.exchange_vault.to_account_info(), authority: self.authority.to_account_info(), }; CpiContext::new(program, accounts) } pub fn thaw_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::ThawAccount<'info>> { let program = self.token_program.to_account_info(); let accounts = token::ThawAccount { account: self.voting_token.to_account_info(), mint: self.voting_mint.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } pub fn mint_to_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::MintTo<'info>> { let program = self.token_program.to_account_info(); let accounts = token::MintTo { mint: self.voting_mint.to_account_info(), to: self.voting_token.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } pub fn freeze_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::FreezeAccount<'info>> { let program = self.token_program.to_account_info(); let accounts = token::FreezeAccount { account: self.voting_token.to_account_info(), mint: self.voting_mint.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } } #[derive(Accounts)] pub struct Withdraw<'info> { pub registrar: AccountLoader<'info, Registrar>, #[account(mut, has_one = registrar, has_one = authority)] pub voter: AccountLoader<'info, Voter>, #[account( mut, associated_token::authority = registrar, associated_token::mint = withdraw_mint, )] pub exchange_vault: Account<'info, TokenAccount>, pub withdraw_mint: Account<'info, Mint>, #[account( mut, associated_token::authority = authority, associated_token::mint = voting_mint, )] pub voting_token: Account<'info, TokenAccount>, #[account( mut, seeds = [registrar.load()?.realm.as_ref(), voting_token.mint.as_ref()], bump, )] pub voting_mint: Account<'info, Mint>, #[account(mut)] pub destination: Account<'info, TokenAccount>, pub authority: Signer<'info>, pub token_program: Program<'info, Token>, } impl<'info> Withdraw<'info> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { let program = self.token_program.to_account_info(); let accounts = token::Transfer { from: self.exchange_vault.to_account_info(), to: self.destination.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } pub fn thaw_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::ThawAccount<'info>> { let program = self.token_program.to_account_info(); let accounts = token::ThawAccount { account: self.voting_token.to_account_info(), mint: self.voting_mint.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } pub fn burn_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Burn<'info>> { let program = self.token_program.to_account_info(); let accounts = token::Burn { mint: self.voting_mint.to_account_info(), to: self.voting_token.to_account_info(), authority: self.authority.to_account_info(), }; CpiContext::new(program, accounts) } pub fn freeze_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::FreezeAccount<'info>> { let program = self.token_program.to_account_info(); let accounts = token::FreezeAccount { account: self.voting_token.to_account_info(), mint: self.voting_mint.to_account_info(), authority: self.registrar.to_account_info(), }; CpiContext::new(program, accounts) } } #[derive(Accounts)] pub struct UpdateSchedule<'info> { #[account(mut, has_one = authority)] pub voter: AccountLoader<'info, Voter>, pub authority: Signer<'info>, } #[derive(Accounts)] pub struct UpdateVoterWeightRecord<'info> { #[account( seeds = [voter_weight_record.realm.as_ref()], bump = registrar.load()?.bump, )] pub registrar: AccountLoader<'info, Registrar>, #[account( has_one = registrar, has_one = authority, )] pub voter: AccountLoader<'info, Voter>, #[account( mut, seeds = [VOTER_WEIGHT_RECORD.as_ref(), registrar.key().as_ref(), authority.key().as_ref()], bump = voter.load()?.voter_weight_record_bump, constraint = voter_weight_record.realm == registrar.load()?.realm, constraint = voter_weight_record.governing_token_owner == voter.load()?.authority, )] pub voter_weight_record: Account<'info, VoterWeightRecord>, pub authority: Signer<'info>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct CloseVoter<'info> { #[account(mut, has_one = authority, close = sol_destination)] pub voter: AccountLoader<'info, Voter>, pub authority: Signer<'info>, pub voting_token: Account<'info, TokenAccount>, pub sol_destination: UncheckedAccount<'info>, }