#![deny(rustdoc::all)]
#![allow(rustdoc::missing_doc_code_examples)]
mod account_validators;
mod events;
mod instructions;
mod state;
use anchor_lang::prelude::*;
use anchor_spl::token::Mint;
use vipers::prelude::*;
pub use events::*;
use instructions::*;
pub use state::*;
pub const CASH_DECIMALS: u8 = 6;
declare_id!("BANKhiCgEYd7QmcWwPLkqvTuuLN6qEwXDZgTe6HEbwv1");
#[program]
pub mod bankman {
use super::*;
#[access_control(ctx.accounts.validate())]
pub fn new_bank(ctx: Context<NewBank>, _bank_bump: u8, crate_bump: u8) -> Result<()> {
crate_token::cpi::new_crate(
CpiContext::new(
ctx.accounts.crate_token_program.to_account_info(),
crate_token::cpi::accounts::NewCrate {
crate_mint: ctx.accounts.crate_mint.to_account_info(),
crate_token: ctx.accounts.crate_token.to_account_info(),
fee_to_setter: ctx.accounts.bank.to_account_info(),
fee_setter_authority: ctx.accounts.bank.to_account_info(),
author_fee_to: ctx.accounts.bank.to_account_info(),
issue_authority: ctx.accounts.brrr_issue_authority.to_account_info(),
withdraw_authority: ctx.accounts.burn_withdraw_authority.to_account_info(),
payer: ctx.accounts.payer.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
},
),
crate_bump,
)?;
let bank_bump = unwrap_bump!(ctx, "bank");
let signer_seeds: &[&[&[u8]]] = &[&[
b"Bank".as_ref(),
&ctx.accounts.crate_token.key().to_bytes(),
&[bank_bump],
]];
crate_token::cpi::set_withdraw_fee(
CpiContext::new(
ctx.accounts.crate_token_program.to_account_info(),
crate_token::cpi::accounts::SetFees {
crate_token: ctx.accounts.crate_token.to_account_info(),
fee_setter: ctx.accounts.bank.to_account_info(),
},
)
.with_signer(signer_seeds),
50,
)?;
let bank = &mut ctx.accounts.bank;
bank.crate_token = ctx.accounts.crate_token.key();
bank.bump = bank_bump;
bank.crate_mint = ctx.accounts.crate_mint.key();
bank.curator = ctx.accounts.admin.key();
bank.bankman = ctx.accounts.admin.key();
emit!(NewBankEvent {
bank: bank.key(),
curator: bank.curator,
timestamp: Clock::get()?.unix_timestamp
});
Ok(())
}
#[access_control(ctx.accounts.validate())]
pub fn authorize_collateral(ctx: Context<AuthorizeCollateral>, _bump: u8) -> Result<()> {
let bank = &ctx.accounts.bank;
let collateral = &mut ctx.accounts.collateral;
collateral.bank = bank.key();
collateral.mint = ctx.accounts.mint.key();
collateral.bump = unwrap_bump!(ctx, "collateral");
emit!(AddCollateralEvent {
bank: bank.key(),
collateral: collateral.key(),
curator: bank.curator,
mint: collateral.mint,
timestamp: Clock::get()?.unix_timestamp
});
Ok(())
}
#[access_control(ctx.accounts.validate())]
pub fn set_collateral_hard_cap(
ctx: Context<SetCollateralHardCap>,
hard_cap: u64,
) -> Result<()> {
let collateral = &mut ctx.accounts.collateral;
collateral.hard_cap = hard_cap;
emit!(SetCollateralHardCapEvent {
bank: ctx.accounts.bank.key(),
collateral: collateral.key(),
hard_cap,
timestamp: Clock::get()?.unix_timestamp
});
Ok(())
}
#[access_control(ctx.accounts.validate())]
pub fn set_curator(ctx: Context<SetCurator>) -> Result<()> {
let bank = &mut ctx.accounts.bank;
let previous_curator = bank.curator;
bank.curator = ctx.accounts.next_curator.key();
emit!(SetCuratorEvent {
bank: bank.key(),
previous_curator,
curator: bank.curator,
bankman: bank.bankman,
timestamp: Clock::get()?.unix_timestamp
});
Ok(())
}
#[access_control(ctx.accounts.validate())]
pub fn set_bankman(ctx: Context<SetBankman>) -> Result<()> {
let bank = &mut ctx.accounts.bank;
let previous_bankman = bank.bankman;
bank.bankman = ctx.accounts.next_bankman.key();
emit!(SetBankmanEvent {
bank: bank.key(),
previous_bankman,
bankman: bank.bankman,
timestamp: Clock::get()?.unix_timestamp
});
Ok(())
}
#[access_control(ctx.accounts.validate())]
pub fn withdraw_author_fee(ctx: Context<WithdrawAuthorFee>, amount: u64) -> Result<()> {
instructions::withdraw_author_fee::handler(ctx, amount)
}
}
#[derive(Accounts)]
pub struct NewBank<'info> {
#[account(
init,
seeds = [
b"Bank".as_ref(),
crate_token.key().to_bytes().as_ref()
],
bump,
space = 8 + Bank::BYTES,
payer = payer
)]
pub bank: Account<'info, Bank>,
pub crate_mint: Account<'info, Mint>,
#[account(mut)]
pub crate_token: SystemAccount<'info>,
pub brrr_issue_authority: UncheckedAccount<'info>,
pub burn_withdraw_authority: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub admin: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
pub crate_token_program: Program<'info, crate_token::program::CrateToken>,
}
#[derive(Accounts)]
pub struct AuthorizeCollateral<'info> {
pub bank: Account<'info, Bank>,
#[account(
init,
seeds = [
b"Collateral".as_ref(),
bank.key().to_bytes().as_ref(),
mint.key().to_bytes().as_ref()
],
bump,
space = 8 + Collateral::BYTES,
payer = payer
)]
pub collateral: Account<'info, Collateral>,
pub mint: Box<Account<'info, Mint>>,
pub curator: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct SetCollateralHardCap<'info> {
pub bank: Account<'info, Bank>,
#[account(mut)]
pub collateral: Account<'info, Collateral>,
pub curator: Signer<'info>,
}
#[derive(Accounts)]
pub struct SetCurator<'info> {
#[account(mut)]
pub bank: Account<'info, Bank>,
pub bankman: Signer<'info>,
pub next_curator: UncheckedAccount<'info>,
}
#[derive(Accounts)]
pub struct SetBankman<'info> {
#[account(mut)]
pub bank: Account<'info, Bank>,
pub bankman: Signer<'info>,
pub next_bankman: UncheckedAccount<'info>,
}
#[error_code]
pub enum ErrorCode {
#[msg("Must be curator.")]
UnauthorizedNotCurator,
#[msg("Must be the bankman.")]
UnauthorizedNotBankman,
#[msg("Pool not found in snapshot.", offset = 10)]
PoolNotFoundInSnapshot,
#[msg("Cannot add a pool that has already been added.")]
PoolAlreadyAdded,
#[msg("new_bank: supply must be zero", offset = 20)]
NewBankSupplyMustBeZero,
#[msg("new_bank: cash must have 6 decimals")]
NewBankWrongDecimals,
#[msg("new_bank: crate already initialized")]
NewBankAlreadyInitialized,
}