use crate::errors::{ProtocolError, Result};
use crate::graphql::place_limit_order;
use crate::graphql::place_market_order;
use crate::types::eth::Address;
use crate::types::{Amount, AssetOrCrosschain, Blockchain, Nonce, Prefix, Rate};
use crate::utils::{bigint_to_nash_r, bigint_to_nash_sig, hash_eth_message};
use nash_mpc::rust_bigint::BigInt;
use std::convert::TryInto;
use super::super::super::signer::Signer;
#[derive(Clone, Debug, PartialEq)]
pub struct FillOrder {
pub prefix: Prefix, pub address: Address, pub asset_from: AssetOrCrosschain, pub asset_to: AssetOrCrosschain, pub nonce_from: Nonce, pub nonce_to: Nonce, pub amount: Amount, pub min_order: Rate, pub max_order: Rate, pub fee_rate: Rate, pub order_nonce: Nonce, }
impl FillOrder {
pub fn new(
address: Address,
asset_from: AssetOrCrosschain,
asset_to: AssetOrCrosschain,
nonce_from: Nonce,
nonce_to: Nonce,
amount: Amount,
min_order: Rate,
max_order: Rate,
fee_rate: Rate,
order_nonce: Nonce,
) -> Self {
Self {
prefix: Prefix::FillOrder,
address,
asset_from,
asset_to,
nonce_from,
nonce_to,
amount,
min_order,
max_order,
fee_rate,
order_nonce,
}
}
pub fn to_bytes(&self, order_precision: u32, fee_precision: u32) -> Result<Vec<u8>> {
Ok([
&self.prefix.to_bytes()[..],
&self.address.to_bytes()[..],
&self.asset_from.to_eth_bytes()[..],
&self.asset_to.to_eth_bytes()[..],
&self.nonce_from.to_be_bytes()[..],
&self.nonce_to.to_be_bytes()[..],
&self.amount.to_be_bytes()?[..],
&self.min_order.to_be_bytes(order_precision, fee_precision)?[..],
&self.max_order.to_be_bytes(order_precision, fee_precision)?[..],
&self.fee_rate.to_be_bytes(order_precision, fee_precision)?[..],
&self.order_nonce.to_be_bytes()[..],
]
.concat())
}
pub fn to_hex(&self, order_precision: u32, fee_precision: u32) -> Result<String> {
Ok(hex::encode(self.to_bytes(order_precision, fee_precision)?).to_uppercase())
}
pub fn from_hex(hex_str: &str) -> Result<Self> {
let bytes = hex::decode(hex_str)
.map_err(|_| ProtocolError("Could not decode FillOrder hex to bytes"))?;
let prefix = Prefix::from_bytes(bytes[..1].try_into()?)?;
let address = Address::from_bytes(bytes[1..21].try_into()?)?;
let asset_from = AssetOrCrosschain::from_eth_bytes(bytes[21..23].try_into()?)?;
let asset_to = AssetOrCrosschain::from_eth_bytes(bytes[23..25].try_into()?)?;
let nonce_from = Nonce::from_be_bytes(bytes[25..29].try_into()?)?;
let nonce_to = Nonce::from_be_bytes(bytes[29..33].try_into()?)?;
let amount = Amount::from_bytes(bytes[33..41].try_into()?, 8)?;
let min_order = Rate::from_be_bytes(bytes[41..49].try_into()?)?;
let max_order = Rate::from_be_bytes(bytes[49..57].try_into()?)?;
let fee_rate = Rate::from_be_bytes(bytes[57..65].try_into()?)?;
let order_nonce = Nonce::from_be_bytes(bytes[65..69].try_into()?)?;
Ok(Self {
prefix,
address,
asset_from,
asset_to,
nonce_from,
nonce_to,
amount,
min_order,
max_order,
fee_rate,
order_nonce,
})
}
pub fn hash(&self, order_precision: u32, fee_precision: u32) -> Result<BigInt> {
let bytes = self.to_bytes(order_precision, fee_precision)?;
Ok(hash_eth_message(&bytes))
}
pub fn to_blockchain_signature(
&self,
signer: &Signer,
order_precision: u32,
fee_precision: u32
) -> Result<place_limit_order::BlockchainSignature> {
let payload_hash = self.hash(order_precision, fee_precision)?;
let (sig, r, pub_key) = signer.sign_child_key(payload_hash, Blockchain::Ethereum)?;
let graphql_output = place_limit_order::BlockchainSignature {
blockchain: place_limit_order::Blockchain::ETH,
nonce_from: Some(self.nonce_from.into()),
nonce_to: Some(self.nonce_to.into()),
public_key: Some(pub_key),
signature: bigint_to_nash_sig(sig),
r: Some(bigint_to_nash_r(r)),
};
Ok(graphql_output)
}
pub fn to_market_blockchain_signature(
&self,
signer: &Signer,
order_precision: u32,
fee_precision: u32
) -> Result<place_market_order::BlockchainSignature> {
let payload_hash = self.hash(order_precision, fee_precision)?;
let (sig, r, pub_key) = signer.sign_child_key(payload_hash, Blockchain::Ethereum)?;
let graphql_output = place_market_order::BlockchainSignature {
blockchain: place_market_order::Blockchain::ETH,
nonce_from: Some(self.nonce_from.into()),
nonce_to: Some(self.nonce_to.into()),
public_key: Some(pub_key),
signature: bigint_to_nash_sig(sig),
r: Some(bigint_to_nash_r(r)),
};
Ok(graphql_output)
}
}
#[cfg(test)]
mod tests {
use super::{Address, Amount, FillOrder, Nonce, Rate};
use crate::types::Asset;
#[test]
fn fillorder_generate_and_parse() {
let order = FillOrder::new(
Address::new("D58547F100B67BB99BBE8E94523B6BB4FDA76954").unwrap(),
Asset::USDC.into(),
Asset::ETH.into(),
Nonce::Value(0),
Nonce::Value(1),
Amount::new("100.0", 8).unwrap(),
Rate::MinOrderRate,
Rate::MaxOrderRate,
Rate::MaxFeeRate,
Nonce::Value(23),
);
let order_hex = order.to_hex(8, 8).unwrap();
let parsed_order = FillOrder::from_hex(&order_hex).unwrap();
let to_hex_again = parsed_order.to_hex(8, 8).unwrap();
println!("{:?}", order);
println!("{:?}", parsed_order);
assert_eq!(order_hex, to_hex_again);
}
#[test]
fn decode_fillorder(){
let x = FillOrder::from_hex("0136c8b049a6a32421f8a2e16c1f3c4e5efea1706000030000000000010000000100000000077359400000000af2066ba0ffffffffffffffff000000000003d09057b78d6c").unwrap();
println!("{:#?}", x);
}
}