use super::super::asset_nonces::AssetNoncesRequest;
use super::super::dh_fill_pool::DhFillPoolRequest;
use super::super::list_markets::ListMarketsRequest;
use super::super::sign_all_states::SignAllStates;
use super::super::{
serializable_to_json, try_response_from_json, NashProtocol, ResponseOrError, State,
};
use super::super::{NashProtocolRequest, ProtocolHook};
use crate::errors::Result;
use crate::graphql::place_limit_order;
use crate::graphql::place_market_order;
use crate::types::{
AssetAmount, AssetofPrecision, Blockchain, BuyOrSell, Market, Nonce, OrderCancellationPolicy,
OrderStatus, OrderType, Rate,
};
use crate::utils::current_time_as_i64;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use tokio::sync::RwLock;
use std::sync::Arc;
use tracing::trace;
#[derive(Clone, Debug)]
pub struct LimitOrderRequest {
pub market: String,
pub buy_or_sell: BuyOrSell,
pub amount: String,
pub price: String,
pub cancellation_policy: OrderCancellationPolicy,
pub allow_taker: bool,
}
#[derive(Clone, Debug)]
pub struct MarketOrderRequest {
pub market: String,
pub amount: String
}
impl LimitOrderRequest {
pub fn new(
market: String,
buy_or_sell: BuyOrSell,
amount_a: &str,
price_b: &str,
cancellation_policy: OrderCancellationPolicy,
allow_taker: bool,
) -> Result<Self> {
Ok(Self {
market,
buy_or_sell,
amount: amount_a.to_string(),
price: price_b.to_string(),
cancellation_policy,
allow_taker,
})
}
}
impl MarketOrderRequest {
pub fn new(
market: String,
amount_a: &str,
) -> Result<Self> {
Ok(Self {
market,
amount: amount_a.to_string(),
})
}
}
pub struct LimitOrderConstructor {
pub buy_or_sell: BuyOrSell,
pub market: Market,
pub me_amount: AssetAmount,
pub me_rate: Rate,
pub cancellation_policy: OrderCancellationPolicy,
pub allow_taker: bool,
pub source: AssetAmount,
pub destination: AssetofPrecision,
pub rate: Rate,
}
pub struct MarketOrderConstructor {
pub market: Market,
pub me_amount: AssetAmount,
pub source: AssetAmount,
pub destination: AssetofPrecision,
}
#[derive(Clone, Debug, Copy)]
pub struct PayloadNonces {
pub nonce_from: Nonce,
pub nonce_to: Nonce,
pub order_nonce: Nonce,
}
#[derive(Clone, Debug)]
pub struct PlaceOrderResponse {
pub remaining_orders: u64,
pub order_id: String,
pub status: OrderStatus,
pub placed_at: DateTime<Utc>,
pub order_type: OrderType,
pub buy_or_sell: BuyOrSell,
pub market_name: String,
}
fn get_required_hooks(state: &State) -> Result<Vec<ProtocolHook>> {
let mut hooks = Vec::new();
match (&state.assets, &state.markets) {
(None, _) | (_, None) => {
hooks.push(ProtocolHook::Protocol(NashProtocolRequest::ListMarkets(
ListMarketsRequest,
)));
}
_ => {}
}
for chain in Blockchain::all() {
if state.signer()?.remaining_r_vals(chain) <= 10 {
trace!("Triggering FillPool (place_order) for {:?}", chain);
hooks.push(ProtocolHook::Protocol(NashProtocolRequest::DhFill(
DhFillPoolRequest::new(chain)?,
)));
}
}
match (state.asset_nonces.as_ref(), state.assets_nonces_refresh) {
(None, _) | (_, true) => {
hooks.push(ProtocolHook::Protocol(NashProtocolRequest::AssetNonces(
AssetNoncesRequest::new(),
)));
}
_ => {}
}
if !state.dont_sign_states && state.remaining_orders < 20 {
hooks.push(ProtocolHook::SignAllState(SignAllStates::new()));
hooks.push(ProtocolHook::Protocol(NashProtocolRequest::AssetNonces(
AssetNoncesRequest::new(),
)));
}
Ok(hooks)
}
#[async_trait]
impl NashProtocol for LimitOrderRequest {
type Response = PlaceOrderResponse;
async fn get_semaphore(&self, state: Arc<RwLock<State>>) -> Option<Arc<tokio::sync::Semaphore>> {
Some(state.read().await.place_order_semaphore.clone())
}
async fn graphql(&self, state: Arc<RwLock<State>>) -> Result<serde_json::Value> {
let builder = self.make_constructor(state.clone()).await?;
let time = current_time_as_i64();
let nonces = builder.make_payload_nonces(state.clone(), time).await?;
let mut state = state.write().await;
if state.remaining_orders > 0 {
state.remaining_orders -= 1;
}
let affiliate = state.affiliate_code.clone();
let signer = state.signer_mut()?;
let query = builder.signed_graphql_request(nonces, time, affiliate, signer)?;
serializable_to_json(&query)
}
async fn response_from_json(
&self,
response: serde_json::Value,
_state: Arc<RwLock<State>>
) -> Result<ResponseOrError<Self::Response>> {
try_response_from_json::<PlaceOrderResponse, place_limit_order::ResponseData>(response)
}
async fn process_response(
&self,
response: &Self::Response,
state: Arc<RwLock<State>>,
) -> Result<()> {
let mut state = state.write().await;
state.remaining_orders = response.remaining_orders;
Ok(())
}
async fn run_before(&self, state: Arc<RwLock<State>>) -> Result<Option<Vec<ProtocolHook>>> {
let state = state.read().await;
get_required_hooks(&state).map(Some)
}
}
#[async_trait]
impl NashProtocol for MarketOrderRequest {
type Response = PlaceOrderResponse;
async fn get_semaphore(&self, state: Arc<RwLock<State>>) -> Option<Arc<tokio::sync::Semaphore>> {
Some(state.read().await.place_order_semaphore.clone())
}
async fn graphql(&self, state: Arc<RwLock<State>>) -> Result<serde_json::Value> {
let builder = self.make_constructor(state.clone()).await?;
let time = current_time_as_i64();
let nonces = builder.make_payload_nonces(state.clone(), time).await?;
let mut state = state.write().await;
if state.remaining_orders > 0 {
state.remaining_orders -= 1;
}
let affiliate = state.affiliate_code.clone();
let signer = state.signer_mut()?;
let query = builder.signed_graphql_request(nonces, time, affiliate, signer)?;
serializable_to_json(&query)
}
async fn response_from_json(
&self,
response: serde_json::Value,
_state: Arc<RwLock<State>>
) -> Result<ResponseOrError<Self::Response>> {
try_response_from_json::<PlaceOrderResponse, place_market_order::ResponseData>(response)
}
async fn process_response(
&self,
response: &Self::Response,
state: Arc<RwLock<State>>,
) -> Result<()> {
let mut state = state.write().await;
state.remaining_orders = response.remaining_orders;
Ok(())
}
async fn run_before(&self, state: Arc<RwLock<State>>) -> Result<Option<Vec<ProtocolHook>>> {
let state = state.read().await;
get_required_hooks(&state).map(Some)
}
}