use anchor_lang::prelude::*;
use gmsol_utils::InitSpace;
use crate::{
constants::MARKET_DECIMALS,
internal,
states::{
market::virtual_inventory::{
VirtualInventory, VIRTUAL_INVENTORY_FOR_POSITIONS_SEED,
VIRTUAL_INVENTORY_FOR_SWAPS_SEED,
},
Market, Store, TokenMapHeader, TokenMapLoader,
},
CoreError,
};
#[derive(Accounts)]
pub struct CloseVirtualInventory<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(mut, seeds = [Store::WALLET_SEED, store.key().as_ref()], bump)]
pub store_wallet: SystemAccount<'info>,
#[account(
mut,
close = store_wallet,
has_one = store,
constraint = virtual_inventory.load()?.ref_count() == 0,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
}
impl CloseVirtualInventory<'_> {
pub(crate) fn invoke_unchecked(_ctx: Context<Self>) -> Result<()> {
Ok(())
}
}
impl<'info> internal::Authentication<'info> for CloseVirtualInventory<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct DisableVirtualInventory<'info> {
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(
mut,
has_one = store,
constraint = !virtual_inventory.load()?.is_disabled() @ CoreError::PreconditionsAreNotMet,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
}
impl<'info> internal::Authentication<'info> for DisableVirtualInventory<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
impl DisableVirtualInventory<'_> {
pub(crate) fn invoke_unchecked(ctx: Context<Self>) -> Result<()> {
ctx.accounts.virtual_inventory.load_mut()?.disable()?;
Ok(())
}
}
#[derive(Accounts)]
pub struct LeaveDisabledVirtualInventory<'info> {
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(
mut,
has_one = store,
constraint = virtual_inventory.load()?.is_disabled() @ CoreError::PreconditionsAreNotMet,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
#[account(mut, has_one = store)]
pub market: AccountLoader<'info, Market>,
}
impl<'info> internal::Authentication<'info> for LeaveDisabledVirtualInventory<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
impl LeaveDisabledVirtualInventory<'_> {
pub(crate) fn invoke_unchecked(ctx: Context<Self>) -> Result<()> {
let address = ctx.accounts.virtual_inventory.key();
let mut market = ctx.accounts.market.load_mut()?;
let mut virtual_inventory = ctx.accounts.virtual_inventory.load_mut()?;
market.leave_disabled_virtual_inventory_unchecked(&address, &mut virtual_inventory)?;
Ok(())
}
}
#[derive(Accounts)]
#[instruction(index: u32)]
pub struct CreateVirtualInventoryForSwaps<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(
init,
payer = authority,
space = 8 + VirtualInventory::INIT_SPACE,
seeds = [VIRTUAL_INVENTORY_FOR_SWAPS_SEED, store.key().as_ref(), &index.to_le_bytes()],
bump,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
pub system_program: Program<'info, System>,
}
impl CreateVirtualInventoryForSwaps<'_> {
pub(crate) fn invoke_unchecked(
ctx: Context<Self>,
index: u32,
long_amount_decimals: u8,
short_amount_decimals: u8,
) -> Result<()> {
ctx.accounts.virtual_inventory.load_init()?.init(
ctx.bumps.virtual_inventory,
index,
ctx.accounts.store.key(),
long_amount_decimals,
short_amount_decimals,
);
Ok(())
}
}
impl<'info> internal::Authentication<'info> for CreateVirtualInventoryForSwaps<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct JoinVirtualInventoryForSwaps<'info> {
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(has_one = store)]
pub token_map: AccountLoader<'info, TokenMapHeader>,
#[account(
mut,
seeds = [VIRTUAL_INVENTORY_FOR_SWAPS_SEED, store.key().as_ref(), &virtual_inventory.load()?.index.to_le_bytes()],
bump = virtual_inventory.load()?.bump,
has_one = store,
constraint = !virtual_inventory.load()?.is_disabled() @ CoreError::PreconditionsAreNotMet,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
#[account(mut, has_one = store, constraint = !market.load()?.is_pure())]
pub market: AccountLoader<'info, Market>,
}
impl JoinVirtualInventoryForSwaps<'_> {
pub(crate) fn invoke_unchecked(ctx: Context<Self>) -> Result<()> {
let address = ctx.accounts.virtual_inventory.key();
let mut virtual_inventory = ctx.accounts.virtual_inventory.load_mut()?;
let token_map = ctx.accounts.token_map.load_token_map()?;
ctx.accounts
.market
.load_mut()?
.join_virtual_inventory_for_swaps_unchecked(
&address,
&mut virtual_inventory,
&token_map,
)?;
Ok(())
}
}
impl<'info> internal::Authentication<'info> for JoinVirtualInventoryForSwaps<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct LeaveVirtualInventoryForSwaps<'info> {
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(
mut,
seeds = [VIRTUAL_INVENTORY_FOR_SWAPS_SEED, store.key().as_ref(), &virtual_inventory.load()?.index.to_le_bytes()],
bump = virtual_inventory.load()?.bump,
has_one = store,
constraint = !virtual_inventory.load()?.is_disabled() @ CoreError::PreconditionsAreNotMet,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
#[account(mut, has_one = store, constraint = !market.load()?.is_pure())]
pub market: AccountLoader<'info, Market>,
}
impl LeaveVirtualInventoryForSwaps<'_> {
pub(crate) fn invoke_unchecked(ctx: Context<Self>) -> Result<()> {
let address = ctx.accounts.virtual_inventory.key();
let mut market = ctx.accounts.market.load_mut()?;
let virtual_inventory_for_swaps = market
.virtual_inventory_for_swaps()
.ok_or_else(|| error!(CoreError::PreconditionsAreNotMet))?;
require_keys_eq!(*virtual_inventory_for_swaps, address);
let mut virtual_inventory = ctx.accounts.virtual_inventory.load_mut()?;
market.leave_virtual_inventory_for_swaps_unchecked(&mut virtual_inventory)?;
Ok(())
}
}
impl<'info> internal::Authentication<'info> for LeaveVirtualInventoryForSwaps<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct CreateVirtualInventoryForPositions<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
pub index_token: UncheckedAccount<'info>,
#[account(
init,
payer = authority,
space = 8 + VirtualInventory::INIT_SPACE,
seeds = [
VIRTUAL_INVENTORY_FOR_POSITIONS_SEED,
store.key().as_ref(),
index_token.key.as_ref(),
],
bump,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
pub system_program: Program<'info, System>,
}
impl CreateVirtualInventoryForPositions<'_> {
pub(crate) fn invoke_unchecked(ctx: Context<Self>) -> Result<()> {
ctx.accounts.virtual_inventory.load_init()?.init(
ctx.bumps.virtual_inventory,
0,
ctx.accounts.store.key(),
MARKET_DECIMALS,
MARKET_DECIMALS,
);
Ok(())
}
}
impl<'info> internal::Authentication<'info> for CreateVirtualInventoryForPositions<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct JoinOrLeaveVirtualInventoryForPositions<'info> {
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
#[account(
mut,
seeds = [VIRTUAL_INVENTORY_FOR_POSITIONS_SEED, store.key().as_ref(), market.load()?.meta().index_token_mint.as_ref()],
bump = virtual_inventory.load()?.bump,
has_one = store,
constraint = !virtual_inventory.load()?.is_disabled() @ CoreError::PreconditionsAreNotMet,
)]
pub virtual_inventory: AccountLoader<'info, VirtualInventory>,
#[account(mut, has_one = store)]
pub market: AccountLoader<'info, Market>,
}
impl JoinOrLeaveVirtualInventoryForPositions<'_> {
pub(crate) fn invoke_join_unchecked(ctx: Context<Self>) -> Result<()> {
let address = ctx.accounts.virtual_inventory.key();
let mut virtual_inventory = ctx.accounts.virtual_inventory.load_mut()?;
ctx.accounts
.market
.load_mut()?
.join_virtual_inventory_for_positions_unchecked(&address, &mut virtual_inventory)?;
Ok(())
}
pub(crate) fn invoke_leave_unchecked(ctx: Context<Self>) -> Result<()> {
let address = ctx.accounts.virtual_inventory.key();
let mut market = ctx.accounts.market.load_mut()?;
let virtual_inventory_for_positions = market
.virtual_inventory_for_positions()
.ok_or_else(|| error!(CoreError::PreconditionsAreNotMet))?;
require_keys_eq!(*virtual_inventory_for_positions, address);
let mut virtual_inventory = ctx.accounts.virtual_inventory.load_mut()?;
market.leave_virtual_inventory_for_positions_unchecked(&mut virtual_inventory)?;
Ok(())
}
}
impl<'info> internal::Authentication<'info> for JoinOrLeaveVirtualInventoryForPositions<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}