gmsol_store/states/
deposit.rs

1use anchor_lang::prelude::*;
2use gmsol_utils::InitSpace;
3
4use crate::{events::DepositRemoved, states::MarketConfigKey, CoreError};
5
6use super::{
7    common::{
8        action::{Action, ActionHeader, Closable},
9        swap::SwapActionParams,
10        token::TokenAndAccount,
11    },
12    Market, Seed,
13};
14
15/// Deposit.
16#[account(zero_copy)]
17#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct Deposit {
20    /// Header.
21    pub(crate) header: ActionHeader,
22    /// Token accounts.
23    pub(crate) tokens: DepositTokenAccounts,
24    /// Deposit params.
25    pub(crate) params: DepositActionParams,
26    /// Swap params.
27    pub(crate) swap: SwapActionParams,
28    #[cfg_attr(feature = "debug", debug(skip))]
29    padding_0: [u8; 4],
30    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
31    #[cfg_attr(feature = "debug", debug(skip))]
32    reserved: [u8; 128],
33}
34
35/// PDA for first deposit owner.
36pub fn find_first_deposit_receiver_pda(store_program_id: &Pubkey) -> (Pubkey, u8) {
37    Pubkey::find_program_address(&[Deposit::FIRST_DEPOSIT_RECEIVER_SEED], store_program_id)
38}
39
40impl InitSpace for Deposit {
41    const INIT_SPACE: usize = std::mem::size_of::<Self>();
42}
43
44impl Closable for Deposit {
45    type ClosedEvent = DepositRemoved;
46
47    fn to_closed_event(&self, address: &Pubkey, reason: &str) -> Result<Self::ClosedEvent> {
48        DepositRemoved::new(
49            self.header.id,
50            self.header.store,
51            *address,
52            self.tokens.market_token(),
53            self.header.owner,
54            self.header.action_state()?,
55            reason,
56        )
57    }
58}
59
60impl Deposit {
61    /// Fisrt Deposit Receiver Seed.
62    pub const FIRST_DEPOSIT_RECEIVER_SEED: &'static [u8] = b"first_deposit_receiver";
63
64    /// Get first deposit receiver.
65    pub fn first_deposit_receiver() -> Pubkey {
66        find_first_deposit_receiver_pda(&crate::ID).0
67    }
68
69    /// Get tokens.
70    pub fn tokens(&self) -> &DepositTokenAccounts {
71        &self.tokens
72    }
73
74    /// Get swap params.
75    pub fn swap(&self) -> &SwapActionParams {
76        &self.swap
77    }
78
79    pub(crate) fn validate_first_deposit(
80        receiver: &Pubkey,
81        min_amount: u64,
82        market: &Market,
83    ) -> Result<()> {
84        let min_tokens_for_first_deposit = market
85            .get_config_by_key(MarketConfigKey::MinTokensForFirstDeposit)
86            .ok_or_else(|| error!(CoreError::Unimplemented))?;
87
88        // Skip first deposit check if the amount is zero.
89        if *min_tokens_for_first_deposit == 0 {
90            return Ok(());
91        }
92
93        require_keys_eq!(
94            *receiver,
95            Self::first_deposit_receiver(),
96            CoreError::InvalidReceiverForFirstDeposit
97        );
98
99        require_gte!(
100            min_amount as u128,
101            *min_tokens_for_first_deposit,
102            CoreError::NotEnoughMarketTokenAmountForFirstDeposit
103        );
104
105        Ok(())
106    }
107}
108
109impl Seed for Deposit {
110    /// Seed.
111    const SEED: &'static [u8] = b"deposit";
112}
113
114impl Action for Deposit {
115    const MIN_EXECUTION_LAMPORTS: u64 = 200_000;
116
117    fn header(&self) -> &ActionHeader {
118        &self.header
119    }
120}
121
122/// Token Accounts.
123#[zero_copy]
124#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126pub struct DepositTokenAccounts {
127    /// Initial long token accounts.
128    pub initial_long_token: TokenAndAccount,
129    /// Initial short token accounts.
130    pub initial_short_token: TokenAndAccount,
131    /// Market token account.
132    pub(crate) market_token: TokenAndAccount,
133    #[cfg_attr(feature = "debug", debug(skip))]
134    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
135    reserved: [u8; 128],
136}
137
138impl DepositTokenAccounts {
139    /// Get market token.
140    pub fn market_token(&self) -> Pubkey {
141        self.market_token.token().expect("must exist")
142    }
143
144    /// Get market token account.
145    pub fn market_token_account(&self) -> Pubkey {
146        self.market_token.account().expect("must exist")
147    }
148}
149
150/// Deposit Params.
151#[zero_copy]
152#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
154pub struct DepositActionParams {
155    /// The amount of initial long tokens to deposit.
156    pub(crate) initial_long_token_amount: u64,
157    /// The amount of initial short tokens to deposit.
158    pub(crate) initial_short_token_amount: u64,
159    /// The minimum acceptable amount of market tokens to receive.
160    pub(crate) min_market_token_amount: u64,
161    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
162    #[cfg_attr(feature = "debug", debug(skip))]
163    reserved: [u8; 64],
164}
165
166impl Default for DepositActionParams {
167    fn default() -> Self {
168        Self {
169            initial_long_token_amount: 0,
170            initial_short_token_amount: 0,
171            min_market_token_amount: 0,
172            reserved: [0; 64],
173        }
174    }
175}
176
177impl DepositActionParams {
178    pub(crate) fn validate_market_token_amount(&self, minted: u64) -> Result<()> {
179        require_gte!(
180            minted,
181            self.min_market_token_amount,
182            CoreError::InsufficientOutputAmount
183        );
184        Ok(())
185    }
186}