use std::sync::Arc;
use gmsol_model::{LiquidityMarket, LiquidityMarketExt, PnlFactorKind};
use gmsol_programs::{
gmsol_store::accounts::Market,
model::{MarketModel, PositionOptions},
};
use serde::{Deserialize, Serialize};
use tsify_next::Tsify;
use wasm_bindgen::prelude::*;
use crate::{
js::position::JsPositionModel,
market::{MarketCalculations, MarketStatus},
serde::StringPubkey,
utils::zero_copy::{
try_deserialize_zero_copy, try_deserialize_zero_copy_from_base64_with_options,
},
};
use super::price::Prices;
#[wasm_bindgen(js_name = Market)]
#[derive(Clone)]
pub struct JsMarket {
market: Arc<Market>,
}
#[wasm_bindgen(js_class = Market)]
impl JsMarket {
pub fn decode_from_base64_with_options(
data: &str,
no_discriminator: Option<bool>,
) -> crate::Result<Self> {
let market = try_deserialize_zero_copy_from_base64_with_options(
data,
no_discriminator.unwrap_or(false),
)?;
Ok(Self {
market: Arc::new(market.0),
})
}
pub fn decode_from_base64(data: &str) -> crate::Result<Self> {
Self::decode_from_base64_with_options(data, None)
}
pub fn decode(data: &[u8]) -> crate::Result<Self> {
let market = try_deserialize_zero_copy(data)?;
Ok(Self {
market: Arc::new(market.0),
})
}
pub fn to_model(&self, supply: u64) -> JsMarketModel {
JsMarketModel {
model: MarketModel::from_parts(self.market.clone(), supply),
}
}
pub fn market_token_address(&self) -> String {
self.market.meta.market_token_mint.to_string()
}
pub fn index_token_address(&self) -> String {
self.market.meta.index_token_mint.to_string()
}
pub fn long_token_address(&self) -> String {
self.market.meta.long_token_mint.to_string()
}
pub fn short_token_address(&self) -> String {
self.market.meta.short_token_mint.to_string()
}
#[wasm_bindgen(js_name = clone)]
pub fn js_clone(&self) -> Self {
self.clone()
}
}
#[derive(Debug, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct MarketTokenPriceParams {
pub prices: Prices,
#[serde(default = "default_pnl_factor")]
pub pnl_factor: PnlFactorKind,
pub maximize: bool,
}
fn default_pnl_factor() -> PnlFactorKind {
PnlFactorKind::MaxAfterDeposit
}
#[derive(Debug, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct MarketStatusParams {
pub prices: Prices,
}
#[derive(Debug, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct MaxSellableValueParams {
pub prices: Prices,
}
#[wasm_bindgen(js_name = MarketModel)]
#[derive(Clone)]
pub struct JsMarketModel {
pub(super) model: MarketModel,
}
#[wasm_bindgen(js_class = MarketModel)]
impl JsMarketModel {
pub fn market_token_price(&self, params: MarketTokenPriceParams) -> crate::Result<u128> {
let mut market_model = self.model.clone();
Ok(market_model.with_vis_disabled(|market| {
market.market_token_price(¶ms.prices.into(), params.pnl_factor, params.maximize)
})?)
}
pub fn max_sellable_value(&self, params: MaxSellableValueParams) -> crate::Result<u128> {
self.model.max_sellable_value(¶ms.prices.into())
}
pub fn status(&self, params: MarketStatusParams) -> crate::Result<MarketStatus> {
let prices = params.prices.into();
let mut market_model = self.model.clone();
market_model.with_vis_disabled(|market| market.status(&prices))
}
pub fn supply(&self) -> u128 {
self.model.total_supply()
}
pub fn create_empty_position(
&self,
args: CreateEmptyPositionArgs,
) -> crate::Result<JsPositionModel> {
let CreateEmptyPositionArgs {
is_long,
collateral_token,
owner,
created_at,
generate_bump,
store_program_id,
} = args;
let mut options = PositionOptions::default();
if let Some(owner) = owner {
options.owner = Some(*owner);
}
if let Some(created_at) = created_at {
options.created_at = created_at;
}
if let Some(generate_bump) = generate_bump {
options.generate_bump = generate_bump;
}
if let Some(program_id) = store_program_id {
options.store_program_id = *program_id;
}
let mut market_model = self.model.clone();
let position = market_model.with_vis_disabled(|market| {
market
.clone()
.into_empty_position_opts(is_long, *collateral_token, options)
})?;
Ok(position.into())
}
#[wasm_bindgen(js_name = clone)]
pub fn js_clone(&self) -> Self {
self.clone()
}
#[wasm_bindgen(js_name = setOrderFeeDiscountFactor)]
pub fn set_order_fee_discount_factor(&mut self, factor: u128) {
self.model.set_order_fee_discount_factor(factor);
}
}
impl From<MarketModel> for JsMarketModel {
fn from(model: MarketModel) -> Self {
Self { model }
}
}
#[derive(Debug, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct CreateEmptyPositionArgs {
pub is_long: bool,
pub collateral_token: StringPubkey,
#[serde(default)]
pub owner: Option<StringPubkey>,
#[serde(default)]
pub created_at: Option<i64>,
#[serde(default)]
pub generate_bump: Option<bool>,
#[serde(default)]
pub store_program_id: Option<StringPubkey>,
}