1use crate::errors::{ProtocolError, Result};
4use bigdecimal::BigDecimal;
5use nash_mpc::rust_bigint::traits::Converter;
6use nash_mpc::rust_bigint::BigInt;
7use sha3::{Digest, Keccak256};
8use std::str::FromStr;
9use std::time::{SystemTime, UNIX_EPOCH};
10
11#[cfg(feature = "num_bigint")]
12use num_traits::Num;
13
14pub fn bigint_to_nash_sig(num: BigInt) -> String {
16 format!("{:0>1024}", num.to_hex())
17}
18
19pub fn bigint_to_nash_r(r: BigInt) -> String {
21 format!("{:0>66}", r.to_hex())
22}
23
24pub fn hash_eth_message(msg: &[u8]) -> BigInt {
26 const ETH_PREFIX: &[u8] = b"\x19Ethereum Signed Message:\n32";
29 let msg_hash =
31 Keccak256::digest(&[Ð_PREFIX[..], &Keccak256::digest(&msg).to_vec()].concat());
32 BigInt::from_bytes(&msg_hash)
33}
34
35pub fn hash_neo_message(msg: &[u8]) -> BigInt {
37 let msg_hash_once = sha2::Sha256::digest(msg);
38 let msg_hash_twice = sha2::Sha256::digest(&msg_hash_once[..]);
39 BigInt::from_str_radix(&hex::encode(msg_hash_twice), 16).unwrap()
40}
41
42pub fn hash_message(message: &str) -> BigInt {
44 let hash = sha2::Sha256::digest(message.as_bytes());
45 BigInt::from_str_radix(&hex::encode(hash), 16).unwrap()
46}
47
48pub fn der_encode_sig(r: &BigInt, s: &BigInt) -> Vec<u8> {
50 let r_bytes = der_encode_sig_value(r);
51 let s_bytes = der_encode_sig_value(s);
52 let mut der_bytes = Vec::new();
53 der_bytes.push(0x30);
55 der_bytes.push((r_bytes.len() + s_bytes.len()) as u8);
57 for byte in r_bytes {
59 der_bytes.push(byte);
60 }
61 for byte in s_bytes {
62 der_bytes.push(byte)
63 }
64 der_bytes
65}
66
67fn der_encode_sig_value(r_or_s: &BigInt) -> Vec<u8> {
68 let mut bytes = r_or_s.to_bytes();
69 if bytes[0] >= 0b1000_0000 {
71 bytes.insert(0, 0x00);
72 }
73 bytes.insert(0, bytes.len() as u8);
75 bytes.insert(0, 0x02);
77 bytes
78}
79
80pub fn current_time_as_i64() -> i64 {
82 SystemTime::now()
83 .duration_since(UNIX_EPOCH)
84 .unwrap()
85 .as_millis() as i64
86}
87
88pub fn decode_hexstr(hex_str: &str) -> Result<Vec<u8>> {
89 Ok(hex::decode(hex_str).map_err(|_| ProtocolError("Could not decode hex string"))?)
90}
91
92pub fn pad_zeros(str_num: &str, precision: u32) -> Result<String> {
95 let components: Vec<&str> = str_num.split('.').collect();
96 match components.len() {
97 1 => {
98 let mut zeros = ".".to_string();
99 for _ in 0..precision {
100 zeros += "0"
101 }
102 Ok(str_num.to_string() + &zeros)
103 }
104 2 => {
105 let mut zeros = "".to_string();
106 let existing_count = components[1].len();
107 if existing_count as u32 > precision {
108 let num_zeros_to_subtract = existing_count as u32 - precision;
110 let reduced_prec = &str_num[..(str_num.len() - (num_zeros_to_subtract as usize))];
111 Ok(reduced_prec.to_string())
112 } else {
113 for _ in 0..(precision - existing_count as u32) {
114 zeros += "0"
115 }
116 Ok(str_num.to_string() + &zeros)
117 }
118 }
119 _ => Err(ProtocolError(
120 "String was not a valid number for zero padding",
121 )),
122 }
123}
124
125pub fn convert_at_price(amount: &str, price: &str) -> Result<String> {
126 let amount_bd = BigDecimal::from_str(amount)
127 .map_err(|_| ProtocolError("Could not convert amount to bigdecimal"))?;
128 let price_bd = BigDecimal::from_str(price)
129 .map_err(|_| ProtocolError("Could not convert price to bigdecimal"))?;
130 let convert = amount_bd * price_bd.inverse();
131 Ok(convert.to_string())
132}