nash_protocol/types/blockchain/
neo.rs1use super::super::{Amount, Asset, AssetOrCrosschain, Nonce, OrderRate, Rate};
4use super::bigdecimal_to_nash_u64;
5use crate::errors::{ProtocolError, Result};
6use bs58::{decode, encode};
7use nash_mpc::curves::secp256_r1::Secp256r1Point;
8use nash_mpc::curves::traits::ECPoint;
9use nash_mpc::rust_bigint::traits::Converter;
10use nash_mpc::rust_bigint::BigInt;
11use ripemd160::Ripemd160;
12use sha2::{Digest, Sha256};
13
14impl Rate {
15 pub fn to_le_bytes(&self) -> Result<[u8; 8]> {
17 let zero_bytes = (0 as f64).to_le_bytes();
18 let bytes = match self {
19 Self::OrderRate(rate) | Self::FeeRate(rate) => rate.to_le_bytes()?,
20 Self::MinOrderRate | Self::MinFeeRate => zero_bytes,
21 Self::MaxOrderRate => [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
22 Self::MaxFeeRate => [0x90, 0xD0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00],
24 };
25 Ok(bytes)
26 }
27}
28
29impl OrderRate {
30 pub fn to_le_bytes(&self) -> Result<[u8; 8]> {
33 let bytes = bigdecimal_to_nash_u64(&self.to_bigdecimal(), 8)?.to_le_bytes();
34 Ok(bytes)
35 }
36}
37
38impl Asset {
39 pub fn to_neo_bytes(&self) -> Vec<u8> {
42 match self {
43 Self::ETH => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
44 .unwrap()
45 .to_bytes(),
46 Self::BAT => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
47 .unwrap()
48 .to_bytes(),
49 Self::OMG => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
50 .unwrap()
51 .to_bytes(),
52 Self::USDC => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
53 .unwrap()
54 .to_bytes(),
55 Self::USDT => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
56 .unwrap()
57 .to_bytes(),
58 Self::ZRX => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
59 .unwrap()
60 .to_bytes(),
61 Self::LINK => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
62 .unwrap()
63 .to_bytes(),
64 Self::QNT => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
65 .unwrap()
66 .to_bytes(),
67 Self::RLC => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
68 .unwrap()
69 .to_bytes(),
70 Self::ANT => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
71 .unwrap()
72 .to_bytes(),
73 Self::TRAC => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
74 .unwrap()
75 .to_bytes(),
76 Self::GUNTHY => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
77 .unwrap()
78 .to_bytes(),
79 Self::BTC => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
80 .unwrap()
81 .to_bytes(),
82 Self::NOIA => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
83 .unwrap()
84 .to_bytes(),
85 Self::NEO => {
86 BigInt::from_hex("9B7CFFDAA674BEAE0F930EBE6085AF9093E5FE56B34A5C220CCDCF6EFC336FC5")
87 .unwrap()
88 .to_bytes()
89 }
90 Self::GAS => {
91 BigInt::from_hex("E72D286979EE6CB1B7E65DFDDFB2E384100B8D148E7758DE42E4168B71792C60")
92 .unwrap()
93 .to_bytes()
94 }
95 Self::NNN => BigInt::from_hex("045fab3389daf5602fa0953b4d7db3ef7b57b753")
96 .unwrap()
97 .to_bytes(),
98 }
99 }
100
101 pub fn from_neo_bytes(bytes: &[u8; 32]) -> Result<Self> {
103 match bytes {
104 [0x9B, 0x7C, 0xFF, 0xDA, 0xA6, 0x74, 0xBE, 0xAE, 0x0F, 0x93, 0x0E, 0xBE, 0x60, 0x85, 0xAF, 0x90, 0x93, 0xE5, 0xFE, 0x56, 0xB3, 0x4A, 0x5C, 0x22, 0x0C, 0xCD, 0xCF, 0x6E, 0xFC, 0x33, 0x6F, 0xC5] => {
105 Ok(Self::NEO)
106 }
107 [0xE7, 0x2D, 0x28, 0x69, 0x79, 0xEE, 0x6C, 0xB1, 0xB7, 0xE6, 0x5D, 0xFD, 0xDF, 0xB2, 0xE3, 0x84, 0x10, 0x0B, 0x8D, 0x14, 0x8E, 0x77, 0x58, 0xDE, 0x42, 0xE4, 0x16, 0x8B, 0x71, 0x79, 0x2C, 0x60] => {
108 Ok(Self::GAS)
109 }
110 _ => Err(ProtocolError("Invalid Asset ID in bytes")),
111 }
112 }
113}
114
115impl AssetOrCrosschain {
116 pub fn to_neo_bytes(&self) -> Vec<u8> {
119 match self {
120 Self::Crosschain => BigInt::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
121 .unwrap()
122 .to_bytes(),
123 Self::Asset(asset) => asset.to_neo_bytes().to_vec(),
124 }
125 }
126 pub fn from_neo_bytes(bytes: Vec<u8>) -> Result<Self> {
129 if bytes.len() == 20
130 && bytes
131 == [
132 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
133 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
134 ]
135 .to_vec()
136 {
137 Ok(Self::Crosschain)
138 } else if bytes.len() == 32 {
139 let mut arr = [0; 32];
141 let bytes = &bytes[..arr.len()];
142 arr.copy_from_slice(bytes);
143 Ok(Self::Asset(Asset::from_neo_bytes(&arr)?))
144 } else {
145 Err(ProtocolError("Invalid Asset ID in bytes"))
146 }
147 }
148}
149
150impl Amount {
151 pub fn to_le_bytes(&self) -> Result<[u8; 8]> {
153 let bytes = bigdecimal_to_nash_u64(&self.to_bigdecimal(), 8)?.to_le_bytes();
154 Ok(bytes)
155 }
156}
157
158impl Nonce {
159 pub fn to_le_bytes(&self) -> [u8; 8] {
161 match self {
162 Self::Value(value) => u64::from(*value).to_le_bytes(),
163 Self::Crosschain => u64::from(Nonce::crosschain()).to_le_bytes(),
164 }
165 }
166}
167
168#[derive(Clone, Debug, PartialEq)]
170pub struct Address {
171 inner: BigInt,
172}
173
174impl Address {
175 pub fn new(addr: &str) -> Result<Self> {
177 let bytes = decode(addr)
179 .with_check(None)
180 .into_vec()
181 .map_err(|_| ProtocolError("Could not base58check decode NEO address"))?;
182 let hex_str = hex::encode(bytes);
183 Self::from_script_hash(&hex_str[2..42])
185 }
186
187 pub fn from_script_hash(s: &str) -> Result<Self> {
189 Ok(Self {
190 inner: BigInt::from_hex(s)
192 .map_err(|_| ProtocolError("Could not parse NEO script hash as BigInt"))?,
193 })
194 }
195
196 pub fn to_bytes(&self) -> Vec<u8> {
198 self.inner.to_bytes()
199 }
200}
201
202#[derive(Clone, Debug, PartialEq)]
204pub struct PublicKey {
205 pub inner: Secp256r1Point,
207}
208
209impl PublicKey {
210 pub fn new(hex_str: &str) -> Result<Self> {
212 let inner = Secp256r1Point::from_hex(hex_str).map_err(|_| {
213 ProtocolError("Could not create public key (Secp256r1Point) from hex string")
214 })?;
215 Ok(Self { inner })
216 }
217
218 pub fn to_bytes(&self) -> Vec<u8> {
220 self.inner.to_bytes()
221 }
222
223 pub fn to_address(&self) -> Address {
225 let addr_script = [
227 vec![0x21],
228 self.to_bytes(),
229 vec![0xac],
230 ]
231 .concat();
232
233 let hash = Ripemd160::digest(&Sha256::digest(&addr_script));
235
236 let neo_hash = [vec![0x17], hash.to_vec()].concat();
238
239 let address = encode(neo_hash).with_check().into_string();
241 Address::new(&address).unwrap()
242 }
243
244 pub fn to_point(&self) -> Secp256r1Point {
246 self.inner.clone()
247 }
248
249 pub fn to_hex(&self) -> String {
251 self.inner.to_hex()
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::{Address, PublicKey};
258
259 #[test]
260 fn inverse_op() {
261 let pk_string = "029ff76d1287091b34c77bd580c631931307631f5538d7f267ea1d8b2ee1cd5bc2";
262 let pk = PublicKey::new(pk_string).expect("Couldn't create public key.");
263 assert_eq!(pk_string, pk.to_hex());
264 assert_eq!(hex::decode(pk_string).unwrap(), pk.to_bytes());
265 }
266
267 #[test]
268 fn test_pk_to_addr() {
269 assert_eq!(
270 PublicKey::new("035a928f201639204e06b4368b1a93365462a8ebbff0b8818151b74faab3a2b61a")
271 .unwrap()
272 .to_address(),
273 Address::new("AXaXZjZGA3qhQRTCsyG5uFKr9HeShgVhTF").unwrap(),
274 );
275 assert_eq!(
276 PublicKey::new("027973267230b7cba0724589653e667ddea7aa8479c01a82bf8dd398cec93508ef")
277 .unwrap()
278 .to_address(),
279 Address::new("AayaivCAcYnM8q79JCrfpRGXrCEHJRN5bV").unwrap(),
280 );
281 assert_eq!(
282 PublicKey::new("0208035f32c5d0e59f71c55b1e060f6d504c004222c25670ff2b788d76a84af2f2")
283 .unwrap()
284 .to_address(),
285 Address::new("AVSFwsxsedGGip1FgJdjavVBuFHHRXD2Uz").unwrap(),
286 );
287 assert_eq!(
288 PublicKey::new("03a41d39a4209e18eb79245ea368674edf335a4ebeb8ed344b87d3ccaf3a2c730e")
289 .unwrap()
290 .to_address(),
291 Address::new("ANwZ2RFRKrASBvZifGgjqqJNUbfJUW6gbn").unwrap(),
292 );
293 }
294}