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 =
85            market.get_config_by_key(MarketConfigKey::MinTokensForFirstDeposit);
86
87        // Skip first deposit check if the amount is zero.
88        if *min_tokens_for_first_deposit == 0 {
89            return Ok(());
90        }
91
92        require_keys_eq!(
93            *receiver,
94            Self::first_deposit_receiver(),
95            CoreError::InvalidReceiverForFirstDeposit
96        );
97
98        require_gte!(
99            min_amount as u128,
100            *min_tokens_for_first_deposit,
101            CoreError::NotEnoughMarketTokenAmountForFirstDeposit
102        );
103
104        Ok(())
105    }
106}
107
108impl Seed for Deposit {
109    /// Seed.
110    const SEED: &'static [u8] = b"deposit";
111}
112
113impl Action for Deposit {
114    const MIN_EXECUTION_LAMPORTS: u64 = 200_000;
115
116    fn header(&self) -> &ActionHeader {
117        &self.header
118    }
119}
120
121/// Token Accounts.
122#[zero_copy]
123#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
124#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
125pub struct DepositTokenAccounts {
126    /// Initial long token accounts.
127    pub initial_long_token: TokenAndAccount,
128    /// Initial short token accounts.
129    pub initial_short_token: TokenAndAccount,
130    /// Market token account.
131    pub(crate) market_token: TokenAndAccount,
132    #[cfg_attr(feature = "debug", debug(skip))]
133    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
134    reserved: [u8; 128],
135}
136
137impl DepositTokenAccounts {
138    /// Get market token.
139    pub fn market_token(&self) -> Pubkey {
140        self.market_token.token().expect("must exist")
141    }
142
143    /// Get market token account.
144    pub fn market_token_account(&self) -> Pubkey {
145        self.market_token.account().expect("must exist")
146    }
147}
148
149/// Deposit Params.
150#[zero_copy]
151#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
152#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
153pub struct DepositActionParams {
154    /// The amount of initial long tokens to deposit.
155    pub(crate) initial_long_token_amount: u64,
156    /// The amount of initial short tokens to deposit.
157    pub(crate) initial_short_token_amount: u64,
158    /// The minimum acceptable amount of market tokens to receive.
159    pub(crate) min_market_token_amount: u64,
160    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
161    #[cfg_attr(feature = "debug", debug(skip))]
162    reserved: [u8; 64],
163}
164
165impl Default for DepositActionParams {
166    fn default() -> Self {
167        Self {
168            initial_long_token_amount: 0,
169            initial_short_token_amount: 0,
170            min_market_token_amount: 0,
171            reserved: [0; 64],
172        }
173    }
174}
175
176impl DepositActionParams {
177    pub(crate) fn validate_market_token_amount(&self, minted: u64) -> Result<()> {
178        require_gte!(
179            minted,
180            self.min_market_token_amount,
181            CoreError::InsufficientOutputAmount
182        );
183        Ok(())
184    }
185}