nash_protocol/protocol/place_order/
types.rs1use std::sync::Arc;
2
3use async_trait::async_trait;
4use chrono::{DateTime, Utc};
5use tokio::sync::{Mutex, RwLock};
6use tracing::error;
7use serde::{Serialize, Deserialize};
8
9use crate::errors::Result;
10use crate::graphql::place_limit_order;
11use crate::graphql::place_market_order;
12use crate::protocol::ErrorResponse;
13use crate::protocol::{
14 asset_nonces::AssetNoncesRequest, list_markets::ListMarketsRequest, serializable_to_json,
15 sign_all_states::SignAllStates, try_response_from_json, NashProtocol, NashProtocolRequest,
16 ProtocolHook, ResponseOrError, State,
17};
18use crate::types::{
19 AssetAmount, AssetofPrecision, BuyOrSell, Market, Nonce, OrderCancellationPolicy, OrderStatus,
20 OrderType, Rate,
21};
22use crate::utils::current_time_as_i64;
23
24#[derive(Clone, Debug)]
27pub struct LimitOrderRequest {
28 pub market: String,
29 pub client_order_id: Option<String>,
30 pub buy_or_sell: BuyOrSell,
31 pub amount: String,
32 pub price: String,
33 pub cancellation_policy: OrderCancellationPolicy,
34 pub allow_taker: bool,
35}
36
37#[derive(Clone, Debug)]
38pub struct MarketOrderRequest {
39 pub client_order_id: Option<String>,
40 pub market: String,
41 pub amount: String,
42}
43
44impl LimitOrderRequest {
45 pub fn new(
46 market: String,
47 buy_or_sell: BuyOrSell,
48 amount_a: &str,
49 price_b: &str,
50 cancellation_policy: OrderCancellationPolicy,
51 allow_taker: bool,
52 client_order_id: Option<String>,
53 ) -> Result<Self> {
54 Ok(Self {
55 market,
56 buy_or_sell,
57 amount: amount_a.to_string(),
58 price: price_b.to_string(),
59 cancellation_policy,
60 allow_taker,
61 client_order_id,
62 })
63 }
64}
65
66impl MarketOrderRequest {
67 pub fn new(market: String, amount_a: &str, client_order_id: Option<String>) -> Result<Self> {
68 Ok(Self {
69 market,
70 amount: amount_a.to_string(),
71 client_order_id,
72 })
73 }
74}
75
76pub struct LimitOrderConstructor {
78 pub buy_or_sell: BuyOrSell,
80 pub client_order_id: Option<String>,
81 pub market: Market,
82 pub me_amount: AssetAmount,
83 pub me_rate: Rate,
84 pub cancellation_policy: OrderCancellationPolicy,
85 pub allow_taker: bool,
86 pub source: AssetAmount,
88 pub destination: AssetofPrecision,
89 pub rate: Rate,
90}
91
92pub struct MarketOrderConstructor {
93 pub market: Market,
95 pub client_order_id: Option<String>,
96 pub me_amount: AssetAmount,
97 pub source: AssetAmount,
99 pub destination: AssetofPrecision,
100}
101
102#[derive(Clone, Debug, Copy)]
105pub struct PayloadNonces {
106 pub nonce_from: Nonce,
107 pub nonce_to: Nonce,
108 pub order_nonce: Nonce,
109}
110
111#[derive(Serialize, Deserialize, Clone, Debug)]
112pub struct MarketName {
113 pub name: String
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug)]
118#[serde(rename_all = "camelCase")]
119pub struct PlaceOrderResponse {
120 #[serde(rename = "ordersTillSignState")]
121 pub remaining_orders: u64,
122 #[serde(rename = "id")]
123 pub order_id: String,
124 pub status: OrderStatus,
125 pub placed_at: DateTime<Utc>,
126 #[serde(rename = "type")]
127 pub order_type: OrderType,
128 pub buy_or_sell: BuyOrSell,
129 pub market: MarketName,
130}
131
132async fn get_required_hooks(state: Arc<RwLock<State>>, market: &str) -> Result<Vec<ProtocolHook>> {
133 let state = state.read().await;
134
135 let mut hooks = Vec::new();
136 match (&state.assets, &state.markets) {
138 (None, _) | (_, None) => {
139 hooks.push(ProtocolHook::Protocol(NashProtocolRequest::ListMarkets(
140 ListMarketsRequest,
141 )));
142 }
143 _ => {}
144 }
145 let chains = state.get_market(market)?.blockchains();
147 let fill_pool_schedules = state
148 .acquire_fill_pool_schedules(Some(&chains), Some(10))
149 .await?;
150 for (request, permit) in fill_pool_schedules {
151 let permit = Some(Arc::new(Mutex::new(Some(permit))));
153 hooks.push(ProtocolHook::Protocol(NashProtocolRequest::DhFill(
154 request, permit,
155 )));
156 }
157 match (state.asset_nonces.as_ref(), state.assets_nonces_refresh) {
159 (None, _) | (_, true) => {
160 hooks.push(ProtocolHook::Protocol(NashProtocolRequest::AssetNonces(
161 AssetNoncesRequest::new(),
162 )));
163 }
164 _ => {}
165 }
166 if !state.dont_sign_states && state.get_remaining_orders() < 10 {
168 hooks.push(ProtocolHook::SignAllState(SignAllStates::new()));
170 hooks.push(ProtocolHook::Protocol(NashProtocolRequest::AssetNonces(
172 AssetNoncesRequest::new(),
173 )));
174 }
175 Ok(hooks)
176}
177
178#[async_trait]
179impl NashProtocol for LimitOrderRequest {
180 type Response = PlaceOrderResponse;
181
182 async fn acquire_permit(
183 &self,
184 state: Arc<RwLock<State>>,
185 ) -> Option<tokio::sync::OwnedSemaphorePermit> {
186 state
187 .read()
188 .await
189 .place_order_semaphore
190 .clone()
191 .acquire_owned()
192 .await
193 .ok()
194 }
195
196 async fn graphql(&self, state: Arc<RwLock<State>>) -> Result<serde_json::Value> {
197 let builder = self.make_constructor(state.clone()).await?;
198 let time = current_time_as_i64();
199 let nonces = builder.make_payload_nonces(state.clone(), time).await?;
200 let state = state.read().await;
201 let affiliate = state.affiliate_code.clone();
202 let market = state.get_market(&self.market)?;
203 let order_precision = 8;
204 let fee_precision = market.min_trade_size_b.asset.precision;
205 let query = builder.signed_graphql_request(nonces, time, affiliate, state.signer()?, order_precision, fee_precision)?;
206 let json = serializable_to_json(&query);
207 json
208 }
209
210 async fn response_from_json(
211 &self,
212 response: serde_json::Value,
213 _state: Arc<RwLock<State>>,
214 ) -> Result<ResponseOrError<Self::Response>> {
215 try_response_from_json::<PlaceOrderResponse, place_limit_order::ResponseData>(response)
216 }
217
218 async fn process_response(
220 &self,
221 response: &Self::Response,
222 state: Arc<RwLock<State>>,
223 ) -> Result<()> {
224 let state = state.read().await;
225 state.set_remaining_orders(response.remaining_orders);
226 Ok(())
227 }
228
229 async fn process_error(
230 &self,
231 response: &ErrorResponse,
232 state: Arc<RwLock<State>>,
233 ) -> Result<()> {
234 state.read().await.decr_remaining_orders();
236 for err in &response.errors {
237 if err.message.find("invalid blockchain signature").is_some() {
238 error!(err = %err.message, request = ?self, "invalid blockchain signature");
239 }
240 }
241 Ok(())
242 }
243
244 async fn run_before(&self, state: Arc<RwLock<State>>) -> Result<Option<Vec<ProtocolHook>>> {
246 get_required_hooks(state, &self.market).await.map(Some)
247 }
248}
249
250#[async_trait]
251impl NashProtocol for MarketOrderRequest {
252 type Response = PlaceOrderResponse;
253
254 async fn acquire_permit(
255 &self,
256 state: Arc<RwLock<State>>,
257 ) -> Option<tokio::sync::OwnedSemaphorePermit> {
258 state
259 .read()
260 .await
261 .place_order_semaphore
262 .clone()
263 .acquire_owned()
264 .await
265 .ok()
266 }
267
268 async fn graphql(&self, state: Arc<RwLock<State>>) -> Result<serde_json::Value> {
269 let builder = self.make_constructor(state.clone()).await?;
270 let time = current_time_as_i64();
271 let nonces = builder.make_payload_nonces(state.clone(), time).await?;
272 let state = state.read().await;
273 let affiliate = state.affiliate_code.clone();
274 let market = state.get_market(&self.market)?;
275 let order_precision = 8;
276 let fee_precision = market.min_trade_size_b.asset.precision;
277 let query = builder.signed_graphql_request(nonces, time, affiliate, state.signer()?, order_precision, fee_precision)?;
278 serializable_to_json(&query)
279 }
280
281 async fn response_from_json(
282 &self,
283 response: serde_json::Value,
284 _state: Arc<RwLock<State>>,
285 ) -> Result<ResponseOrError<Self::Response>> {
286 try_response_from_json::<PlaceOrderResponse, place_market_order::ResponseData>(response)
287 }
288
289 async fn process_response(
291 &self,
292 response: &Self::Response,
293 state: Arc<RwLock<State>>,
294 ) -> Result<()> {
295 let state = state.read().await;
296 state.set_remaining_orders(response.remaining_orders);
298 Ok(())
299 }
300
301 async fn process_error(
302 &self,
303 _response: &ErrorResponse,
304 state: Arc<RwLock<State>>,
305 ) -> Result<()> {
306 state.read().await.decr_remaining_orders();
308 Ok(())
309 }
310
311 async fn run_before(&self, state: Arc<RwLock<State>>) -> Result<Option<Vec<ProtocolHook>>> {
313 get_required_hooks(state, &self.market).await.map(Some)
314 }
315}