1use std::sync::Arc;
2
3use gmsol_model::PositionState;
4use gmsol_programs::{gmsol_store::accounts::Position, model::PositionModel};
5use wasm_bindgen::prelude::*;
6
7use crate::{
8 js::events::JsTradeEvent,
9 position::{status::PositionStatus, CalculatePositionStatusOptions, PositionCalculations},
10 utils::zero_copy::{
11 try_deserialize_zero_copy, try_deserialize_zero_copy_from_base64_with_options,
12 },
13};
14
15use super::{market::JsMarketModel, price::Prices};
16
17#[wasm_bindgen(js_name = Position)]
19#[derive(Clone)]
20pub struct JsPosition {
21 pub(crate) position: Arc<Position>,
22}
23
24#[wasm_bindgen(js_class = Position)]
25impl JsPosition {
26 pub fn decode_from_base64_with_options(
28 data: &str,
29 no_discriminator: Option<bool>,
30 ) -> crate::Result<Self> {
31 let position = try_deserialize_zero_copy_from_base64_with_options(
32 data,
33 no_discriminator.unwrap_or(false),
34 )?;
35
36 Ok(Self {
37 position: Arc::new(position.0),
38 })
39 }
40
41 pub fn decode_from_base64(data: &str) -> crate::Result<Self> {
43 Self::decode_from_base64_with_options(data, None)
44 }
45
46 pub fn decode(data: &[u8]) -> crate::Result<Self> {
48 let position = try_deserialize_zero_copy(data)?;
49
50 Ok(Self {
51 position: Arc::new(position.0),
52 })
53 }
54
55 pub fn to_model(&self, market: &JsMarketModel) -> crate::Result<JsPositionModel> {
57 let mut market_model = market.model.clone();
58 Ok(JsPositionModel {
59 model: market_model.with_vis_disabled(|market| {
60 PositionModel::new(market.clone(), self.position.clone())
61 })?,
62 })
63 }
64
65 #[wasm_bindgen(js_name = clone)]
67 pub fn js_clone(&self) -> Self {
68 self.clone()
69 }
70}
71
72#[wasm_bindgen(js_name = PositionModel)]
74#[derive(Clone)]
75pub struct JsPositionModel {
76 model: PositionModel,
77}
78
79#[wasm_bindgen(js_class = PositionModel)]
80impl JsPositionModel {
81 pub fn status(&self, prices: Prices) -> crate::Result<PositionStatus> {
83 self.status_with_options(prices, None)
84 }
85
86 pub fn status_with_options(
88 &self,
89 prices: Prices,
90 include_virtual_inventory_impact: Option<bool>,
91 ) -> crate::Result<PositionStatus> {
92 let prices = prices.into();
93 self.model.status_with_options(
94 &prices,
95 CalculatePositionStatusOptions {
96 include_virtual_inventory_impact: include_virtual_inventory_impact
97 .unwrap_or_default(),
98 },
99 )
100 }
101
102 pub fn size(&self) -> u128 {
104 *self.model.size_in_usd()
105 }
106
107 pub fn size_in_tokens(&self) -> u128 {
109 *self.model.size_in_tokens()
110 }
111
112 pub fn collateral_amount(&self) -> u128 {
114 *self.model.collateral_amount()
115 }
116
117 pub fn position(&self) -> JsPosition {
119 JsPosition {
120 position: self.model.position_arc().clone(),
121 }
122 }
123
124 pub fn update_with_trade_event(
126 &mut self,
127 event: &JsTradeEvent,
128 force_update: Option<bool>,
129 ) -> crate::Result<bool> {
130 let updated = self
131 .model
132 .update(&event.event.after.into(), force_update.unwrap_or_default());
133
134 Ok(updated)
135 }
136
137 #[wasm_bindgen(js_name = clone)]
139 pub fn js_clone(&self) -> Self {
140 self.clone()
141 }
142}
143
144impl From<PositionModel> for JsPositionModel {
145 fn from(model: PositionModel) -> Self {
146 Self { model }
147 }
148}