use anchor_lang::prelude::*;
use anchor_spl::token_interface::Mint;
use std::ops::{BitAnd, BitOr, BitXor};
use crate::curve::AMM;
pub const POOL_SEED: &str = "pool";
pub const POOL_LP_MINT_SEED: &str = "pool_lp_mint";
pub const POOL_VAULT_SEED: &str = "pool_vault";
pub const Q32: u128 = (u32::MAX as u128) + 1;
pub enum PoolStatusBitIndex {
Deposit,
Withdraw,
Swap,
}
#[derive(PartialEq, Eq)]
pub enum PoolStatusBitFlag {
Enable,
Disable,
}
#[account(zero_copy(unsafe))]
#[repr(packed)]
#[derive(Default, Debug)]
pub struct PoolState {
pub amm_config: Pubkey,
pub pool_creator: Pubkey,
pub token_0_vault: Pubkey,
pub token_1_vault: Pubkey,
pub lp_mint: Pubkey,
pub token_0_mint: Pubkey,
pub token_1_mint: Pubkey,
pub token_0_program: Pubkey,
pub token_1_program: Pubkey,
pub observation_key: Pubkey,
pub auth_bump: u8,
pub status: u8,
pub lp_mint_decimals: u8,
pub mint_0_decimals: u8,
pub mint_1_decimals: u8,
pub lp_supply: u64,
pub protocol_fees_token_0: u64,
pub protocol_fees_token_1: u64,
pub fund_fees_token_0: u64,
pub fund_fees_token_1: u64,
pub open_time: u64,
pub recent_epoch: u64,
pub amm: AMM,
pub padding: [u64; 31 ],
}
impl PoolState {
pub const LEN: usize =8 + std::mem::size_of::<PoolState>();
pub fn initialize(
&mut self,
auth_bump: u8,
lp_supply: u64,
open_time: u64,
pool_creator: Pubkey,
amm_config: Pubkey,
token_0_vault: Pubkey,
token_1_vault: Pubkey,
token_0_mint: &InterfaceAccount<Mint>,
token_1_mint: &InterfaceAccount<Mint>,
lp_mint: &InterfaceAccount<Mint>,
observation_key: Pubkey,
) {
self.amm_config = amm_config.key();
self.pool_creator = pool_creator.key();
self.token_0_vault = token_0_vault;
self.token_1_vault = token_1_vault;
self.lp_mint = lp_mint.key();
self.token_0_mint = token_0_mint.key();
self.token_1_mint = token_1_mint.key();
self.token_0_program = *token_0_mint.to_account_info().owner;
self.token_1_program = *token_1_mint.to_account_info().owner;
self.observation_key = observation_key;
self.auth_bump = auth_bump;
self.lp_mint_decimals = lp_mint.decimals;
self.mint_0_decimals = token_0_mint.decimals;
self.mint_1_decimals = token_1_mint.decimals;
self.lp_supply = lp_supply;
self.protocol_fees_token_0 = 0;
self.protocol_fees_token_1 = 0;
self.fund_fees_token_0 = 0;
self.fund_fees_token_1 = 0;
self.open_time = open_time;
self.recent_epoch = Clock::get().unwrap().epoch;
self.padding = [0u64; 31];
}
pub fn set_status(&mut self, status: u8) {
self.status = status
}
pub fn set_status_by_bit(&mut self, bit: PoolStatusBitIndex, flag: PoolStatusBitFlag) {
let s = u8::from(1) << (bit as u8);
if flag == PoolStatusBitFlag::Disable {
self.status = self.status.bitor(s);
} else {
let m = u8::from(255).bitxor(s);
self.status = self.status.bitand(m);
}
}
pub fn get_status_by_bit(&self, bit: PoolStatusBitIndex) -> bool {
let status = u8::from(1) << (bit as u8);
self.status.bitand(status) == 0
}
pub fn vault_amount_without_fee(&self, vault_0: u64, vault_1: u64) -> (u64, u64) {
(
vault_0
.checked_sub(self.protocol_fees_token_0 + self.fund_fees_token_0)
.unwrap(),
vault_1
.checked_sub(self.protocol_fees_token_1 + self.fund_fees_token_1)
.unwrap(),
)
}
pub fn token_price_x32(&self, vault_0: u64, vault_1: u64) -> (u128, u128) {
let (token_0_amount, token_1_amount) = self.vault_amount_without_fee(vault_0, vault_1);
(
token_1_amount as u128 * Q32 as u128 / token_0_amount as u128,
token_0_amount as u128 * Q32 as u128 / token_1_amount as u128,
)
}
}
#[cfg(test)]
pub mod pool_test {
use super::*;
mod pool_status_test {
use super::*;
#[test]
fn get_set_status_by_bit() {
let mut pool_state = PoolState::default();
pool_state.set_status(4); assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Swap),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit),
true
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw),
true
);
pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Disable);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Swap),
false
);
pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Enable);
assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true);
pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Enable);
assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true);
pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Disable);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Swap),
false
);
pool_state.set_status(5); assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Swap),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw),
true
);
pool_state.set_status(7); assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Swap),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw),
false
);
pool_state.set_status(3); assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit),
false
);
assert_eq!(
pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw),
false
);
}
}
}