1use std::sync::Arc;
2
3use gmsol_model::{LiquidityMarketExt, PnlFactorKind};
4use gmsol_programs::{
5 gmsol_store::accounts::Market,
6 model::{MarketModel, PositionOptions},
7};
8use serde::{Deserialize, Serialize};
9use tsify_next::Tsify;
10use wasm_bindgen::prelude::*;
11
12use crate::{
13 js::position::JsPositionModel,
14 market::{MarketCalculations, MarketStatus},
15 serde::StringPubkey,
16 utils::zero_copy::{
17 try_deserialize_zero_copy, try_deserialize_zero_copy_from_base64_with_options,
18 },
19};
20
21use super::price::Prices;
22
23#[wasm_bindgen(js_name = Market)]
25#[derive(Clone)]
26pub struct JsMarket {
27 market: Arc<Market>,
28}
29
30#[wasm_bindgen(js_class = Market)]
31impl JsMarket {
32 pub fn decode_from_base64_with_options(
34 data: &str,
35 no_discriminator: Option<bool>,
36 ) -> crate::Result<Self> {
37 let market = try_deserialize_zero_copy_from_base64_with_options(
38 data,
39 no_discriminator.unwrap_or(false),
40 )?;
41
42 Ok(Self {
43 market: Arc::new(market.0),
44 })
45 }
46
47 pub fn decode_from_base64(data: &str) -> crate::Result<Self> {
49 Self::decode_from_base64_with_options(data, None)
50 }
51
52 pub fn decode(data: &[u8]) -> crate::Result<Self> {
54 let market = try_deserialize_zero_copy(data)?;
55
56 Ok(Self {
57 market: Arc::new(market.0),
58 })
59 }
60
61 pub fn to_model(&self, supply: u64) -> JsMarketModel {
63 JsMarketModel {
64 model: MarketModel::from_parts(self.market.clone(), supply),
65 }
66 }
67
68 pub fn market_token_address(&self) -> String {
70 self.market.meta.market_token_mint.to_string()
71 }
72
73 pub fn index_token_address(&self) -> String {
75 self.market.meta.index_token_mint.to_string()
76 }
77
78 pub fn long_token_address(&self) -> String {
80 self.market.meta.long_token_mint.to_string()
81 }
82
83 pub fn short_token_address(&self) -> String {
85 self.market.meta.short_token_mint.to_string()
86 }
87
88 #[wasm_bindgen(js_name = clone)]
90 pub fn js_clone(&self) -> Self {
91 self.clone()
92 }
93}
94
95#[derive(Debug, Serialize, Deserialize, Tsify)]
97#[tsify(into_wasm_abi, from_wasm_abi)]
98pub struct MarketTokenPriceParams {
99 pub prices: Prices,
101 #[serde(default = "default_pnl_factor")]
103 pub pnl_factor: PnlFactorKind,
104 pub maximize: bool,
106}
107
108fn default_pnl_factor() -> PnlFactorKind {
109 PnlFactorKind::MaxAfterDeposit
110}
111
112#[derive(Debug, Serialize, Deserialize, Tsify)]
114#[tsify(into_wasm_abi, from_wasm_abi)]
115pub struct MarketStatusParams {
116 pub prices: Prices,
118}
119
120#[wasm_bindgen(js_name = MarketModel)]
122#[derive(Clone)]
123pub struct JsMarketModel {
124 pub(super) model: MarketModel,
125}
126
127#[wasm_bindgen(js_class = MarketModel)]
128impl JsMarketModel {
129 pub fn market_token_price(&self, params: MarketTokenPriceParams) -> crate::Result<u128> {
131 Ok(self.model.market_token_price(
132 ¶ms.prices.into(),
133 params.pnl_factor,
134 params.maximize,
135 )?)
136 }
137
138 pub fn status(&self, params: MarketStatusParams) -> crate::Result<MarketStatus> {
140 let prices = params.prices.into();
141 self.model.status(&prices)
142 }
143
144 pub fn create_empty_position(
146 &self,
147 args: CreateEmptyPositionArgs,
148 ) -> crate::Result<JsPositionModel> {
149 let CreateEmptyPositionArgs {
150 is_long,
151 collateral_token,
152 owner,
153 created_at,
154 generate_bump,
155 store_program_id,
156 } = args;
157
158 let mut options = PositionOptions::default();
159
160 if let Some(owner) = owner {
161 options.owner = Some(*owner);
162 }
163
164 if let Some(created_at) = created_at {
165 options.created_at = created_at;
166 }
167
168 if let Some(generate_bump) = generate_bump {
169 options.generate_bump = generate_bump;
170 }
171
172 if let Some(program_id) = store_program_id {
173 options.store_program_id = *program_id;
174 }
175
176 let position =
177 self.model
178 .clone()
179 .into_empty_position_opts(is_long, *collateral_token, options)?;
180
181 Ok(position.into())
182 }
183
184 #[wasm_bindgen(js_name = clone)]
186 pub fn js_clone(&self) -> Self {
187 self.clone()
188 }
189}
190
191impl From<MarketModel> for JsMarketModel {
192 fn from(model: MarketModel) -> Self {
193 Self { model }
194 }
195}
196
197#[derive(Debug, Serialize, Deserialize, Tsify)]
199#[tsify(into_wasm_abi, from_wasm_abi)]
200pub struct CreateEmptyPositionArgs {
201 pub is_long: bool,
203 pub collateral_token: StringPubkey,
205 #[serde(default)]
209 pub owner: Option<StringPubkey>,
210 #[serde(default)]
212 pub created_at: Option<i64>,
213 #[serde(default)]
217 pub generate_bump: Option<bool>,
218 #[serde(default)]
220 pub store_program_id: Option<StringPubkey>,
221}