use anchor_lang::prelude::*;
use crate::{events::WithdrawalRemoved, CoreError};
use super::{
common::{
action::{Action, ActionHeader, Closable},
swap::SwapActionParams,
token::TokenAndAccount,
},
Seed,
};
#[account(zero_copy)]
#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Withdrawal {
pub(crate) header: ActionHeader,
pub(crate) tokens: WithdrawalTokenAccounts,
pub(crate) params: WithdrawalActionParams,
pub(crate) swap: SwapActionParams,
#[cfg_attr(feature = "debug", debug(skip))]
padding_1: [u8; 4],
#[cfg_attr(feature = "debug", debug(skip))]
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
reserved: [u8; 128],
}
impl Withdrawal {
pub fn tokens(&self) -> &WithdrawalTokenAccounts {
&self.tokens
}
pub fn swap(&self) -> &SwapActionParams {
&self.swap
}
}
impl Seed for Withdrawal {
const SEED: &'static [u8] = b"withdrawal";
}
impl gmsol_utils::InitSpace for Withdrawal {
const INIT_SPACE: usize = std::mem::size_of::<Self>();
}
impl Action for Withdrawal {
const MIN_EXECUTION_LAMPORTS: u64 = 200_000;
fn header(&self) -> &ActionHeader {
&self.header
}
}
impl Closable for Withdrawal {
type ClosedEvent = WithdrawalRemoved;
fn to_closed_event(&self, address: &Pubkey, reason: &str) -> Result<Self::ClosedEvent> {
WithdrawalRemoved::new(
self.header.id,
self.header.store,
*address,
self.tokens.market_token(),
self.header.owner,
self.header.action_state()?,
reason,
)
}
}
#[zero_copy]
#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WithdrawalTokenAccounts {
pub(crate) final_long_token: TokenAndAccount,
pub(crate) final_short_token: TokenAndAccount,
pub(crate) market_token: TokenAndAccount,
#[cfg_attr(feature = "debug", debug(skip))]
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
reserved: [u8; 128],
}
impl WithdrawalTokenAccounts {
pub fn market_token(&self) -> Pubkey {
self.market_token.token().expect("must exist")
}
pub fn market_token_account(&self) -> Pubkey {
self.market_token.account().expect("must exist")
}
pub fn final_long_token(&self) -> Pubkey {
self.final_long_token.token().expect("must exist")
}
pub fn final_long_token_account(&self) -> Pubkey {
self.final_long_token.account().expect("must exist")
}
pub fn final_short_token(&self) -> Pubkey {
self.final_short_token.token().expect("must exist")
}
pub fn final_short_token_account(&self) -> Pubkey {
self.final_short_token.account().expect("must exist")
}
}
#[zero_copy]
#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WithdrawalActionParams {
pub market_token_amount: u64,
pub min_long_token_amount: u64,
pub min_short_token_amount: u64,
#[cfg_attr(feature = "debug", debug(skip))]
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
reserved: [u8; 64],
}
impl Default for WithdrawalActionParams {
fn default() -> Self {
Self {
reserved: [0; 64],
market_token_amount: 0,
min_long_token_amount: 0,
min_short_token_amount: 0,
}
}
}
impl WithdrawalActionParams {
pub(crate) fn validate_output_amounts(
&self,
long_amount: u64,
short_amount: u64,
) -> Result<()> {
require_gte!(
long_amount,
self.min_long_token_amount,
CoreError::InsufficientOutputAmount
);
require_gte!(
short_amount,
self.min_short_token_amount,
CoreError::InsufficientOutputAmount
);
Ok(())
}
}