Просмотр исходного кода

util: refactored util.rs into util directory

lunar-mining 4 лет назад
Родитель
Сommit
7e43272995
7 измененных файлов с 290 добавлено и 4 удалено
  1. 8 4
      src/bin/darkfid.rs
  2. 9 0
      src/util/mod.rs
  3. 52 0
      src/util/net_name.rs
  4. 144 0
      src/util/parse.rs
  5. 32 0
      src/util/path.rs
  6. 45 0
      src/util/token_list.rs
  7. 0 0
      src/util/util

+ 8 - 4
src/bin/darkfid.rs

@@ -17,7 +17,7 @@ use drk::{
         rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
     },
     serial::{deserialize, serialize},
-    util::{expand_path, join_config_path, parse_network, parse_wrapped_token, search_id},
+    util::{expand_path, join_config_path, parse_network, parse_wrapped_token, TokenList},
     wallet::WalletDb,
     Result,
 };
@@ -27,6 +27,7 @@ struct Darkfid {
     config: DarkfidConfig,
     wallet: Arc<WalletDb>,
     client: Arc<Mutex<Client>>,
+    tokenlist: TokenList,
 }
 
 #[async_trait]
@@ -81,10 +82,13 @@ impl Darkfid {
 
         let client = Arc::new(Mutex::new(client));
 
+        let tokenlist = TokenList::new()?;
+
         Ok(Self {
             config,
             wallet,
             client,
+            tokenlist,
         })
     }
 
@@ -149,7 +153,7 @@ impl Darkfid {
         let symbol = symbol.unwrap();
 
         let result: Result<Value> = async {
-            let token_id = search_id(symbol)?;
+            let token_id = self.tokenlist.clone().search_id(symbol)?;
             Ok(json!(token_id))
         }
         .await;
@@ -211,7 +215,7 @@ impl Darkfid {
 
         let network = network.as_str().unwrap();
 
-        let token_id = match parse_network(&network, &token) {
+        let token_id = match parse_network(&network, &token, self.tokenlist.clone()) {
             Ok(t) => t,
             Err(_e) => {
                 debug!(target: "DARKFID", "TOKEN ID IS ERR");
@@ -330,7 +334,7 @@ impl Darkfid {
         let amount = amount.as_f64().unwrap();
 
         let result: Result<()> = async {
-            let token_id = parse_wrapped_token(token)?;
+            let token_id = parse_wrapped_token(token, self.tokenlist.clone())?;
             let address = bs58::decode(&address).into_vec()?;
             let address: jubjub::SubgroupPoint = deserialize(&address)?;
             // TODO FIX THE AMOUNT

+ 9 - 0
src/util/mod.rs

@@ -0,0 +1,9 @@
+pub mod net_name;
+pub mod parse;
+pub mod path;
+pub mod token_list;
+
+pub use net_name::NetworkName;
+pub use parse::{generate_id, parse_network, parse_params, parse_wrapped_token};
+pub use path::{expand_path, join_config_path};
+pub use token_list::TokenList;

+ 52 - 0
src/util/net_name.rs

@@ -0,0 +1,52 @@
+use crate::{
+    serial::{Decodable, Encodable},
+    Result,
+};
+use std::str::FromStr;
+
+#[derive(Debug, PartialEq, Eq, Hash, Clone)]
+pub enum NetworkName {
+    Solana,
+    Bitcoin,
+}
+
+impl std::fmt::Display for NetworkName {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Solana => {
+                write!(f, "Solana")
+            }
+            Self::Bitcoin => {
+                write!(f, "Bitcoin")
+            }
+        }
+    }
+}
+
+impl FromStr for NetworkName {
+    type Err = crate::Error;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        match s.to_lowercase().as_str() {
+            "sol" | "solana" => Ok(NetworkName::Solana),
+            "btc" | "bitcoin" => Ok(NetworkName::Bitcoin),
+            _ => Err(crate::Error::NotSupportedNetwork),
+        }
+    }
+}
+
+impl Encodable for NetworkName {
+    fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
+        let name = self.to_string();
+        let len = name.encode(s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for NetworkName {
+    fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
+        let name: String = Decodable::decode(&mut d)?;
+        let name = NetworkName::from_str(&name)?;
+        Ok(name)
+    }
+}

+ 144 - 0
src/util/parse.rs

@@ -0,0 +1,144 @@
+use crate::{
+    serial::{deserialize, serialize},
+    util::{NetworkName, TokenList},
+    Error, Result,
+};
+
+use log::debug;
+use sha2::{Digest, Sha256};
+use std::str::FromStr;
+
+//1. deposit(network, asset)
+//internal ID = hash(externalID, NetworkName)
+//deposit(internalID)
+
+//2. withdraw(network, asset, amount)
+//internal ID = hash(externalID, NetworkName)
+//amountu64 = amount.to_u64()
+//withdraw(internalID, amount)
+
+//3. transfer(asset, amount, address)
+//asset = { match [SOL, BTC, TOKEN]
+//        return token-id from wallet.db }
+//amountu64 = amount.to_u64()
+//address = jubjub::SubgroupPoint
+//transfer(token_id, amountu64, address)
+//
+//
+
+// here we hash the alphanumeric token ID. if it fails, we change the last 4 bytes and hash it
+// again, and keep repeating until it works.
+pub fn generate_id(tkn_str: &str) -> Result<jubjub::Fr> {
+    if bs58::decode(tkn_str).into_vec().is_err() {
+        // TODO: make this an error
+        debug!(target: "PARSE ID", "COULD NOT DECODE STR");
+    }
+    let mut data = bs58::decode(tkn_str).into_vec().unwrap();
+
+    let token_id = match deserialize::<jubjub::Fr>(&data) {
+        Ok(v) => v,
+        Err(_) => {
+            let mut counter = 0;
+            loop {
+                data.truncate(28);
+                let serialized_counter = serialize(&counter);
+                data.extend(serialized_counter.iter());
+                let mut hasher = Sha256::new();
+                hasher.update(&data);
+                let hash = hasher.finalize();
+                let token_id = deserialize::<jubjub::Fr>(&hash);
+                if token_id.is_err() {
+                    counter += 1;
+                    continue;
+                }
+                debug!(target: "CASHIER", "DESERIALIZATION SUCCESSFUL");
+                return Ok(token_id.unwrap());
+            }
+        }
+    };
+
+    Ok(token_id)
+}
+
+pub fn parse_wrapped_token(token: &str, tokenlist: TokenList) -> Result<jubjub::Fr> {
+    match token.to_lowercase().as_str() {
+        "sol" => {
+            let id = "So11111111111111111111111111111111111111112";
+            let token_id = generate_id(id)?;
+            Ok(token_id)
+        }
+        "btc" => Err(Error::TokenParseError),
+        tkn => {
+            // (== 44) can represent a Solana base58 token mint address
+            let id = if token.len() == 44 {
+                token.to_string()
+            } else {
+                symbol_to_id(tkn, tokenlist)?
+            };
+
+            let token_id = generate_id(&id)?;
+            Ok(token_id)
+        }
+    }
+}
+
+pub fn parse_network(network: &str, token: &str, tokenlist: TokenList) -> Result<String> {
+    match NetworkName::from_str(network)? {
+        NetworkName::Solana => match token.to_lowercase().as_str() {
+            "solana" | "sol" => {
+                let token_id = "So11111111111111111111111111111111111111112";
+                Ok(token_id.to_string())
+            }
+            tkn => {
+                // (== 44) can represent a Solana base58 token mint address
+                let id = if token.len() == 44 {
+                    token.to_string()
+                } else {
+                    symbol_to_id(tkn, tokenlist)?
+                };
+                Ok(id)
+            }
+        },
+        NetworkName::Bitcoin => Err(Error::NetworkParseError),
+    }
+}
+
+pub fn parse_params(
+    network: &str,
+    token: &str,
+    amount: u64,
+    tokenlist: TokenList,
+) -> Result<(String, u64)> {
+    match NetworkName::from_str(network)? {
+        NetworkName::Solana => match token {
+            "solana" | "sol" => {
+                let token_id = "So11111111111111111111111111111111111111112";
+                let decimals = 9;
+                let amount_in_apo = amount * u64::pow(10, decimals as u32);
+                Ok((token_id.to_string(), amount_in_apo))
+            }
+            tkn => {
+                let token_id = symbol_to_id(tkn, tokenlist.clone())?;
+                let decimals = tokenlist.search_decimal(tkn)?;
+                let amount_in_apo = amount * u64::pow(10, decimals as u32);
+                Ok((token_id, amount_in_apo))
+            }
+        },
+        NetworkName::Bitcoin => Err(Error::NetworkParseError),
+    }
+}
+
+pub fn symbol_to_id(token: &str, tokenlist: TokenList) -> Result<String> {
+    let vec: Vec<char> = token.chars().collect();
+    let mut counter = 0;
+    for c in vec {
+        if c.is_alphabetic() {
+            counter += 1;
+        }
+    }
+    if counter == token.len() {
+        tokenlist.search_id(token)
+    } else {
+        Ok(token.to_string())
+    }
+}

+ 32 - 0
src/util/path.rs

@@ -0,0 +1,32 @@
+use crate::Result;
+use std::path::{Path, PathBuf};
+
+pub fn expand_path(path: &str) -> Result<PathBuf> {
+    let ret: PathBuf;
+
+    if path.starts_with("~/") {
+        let homedir = dirs::home_dir().unwrap();
+        let remains = PathBuf::from(path.strip_prefix("~/").unwrap());
+        ret = [homedir, remains].iter().collect();
+    } else if path.starts_with('~') {
+        ret = dirs::home_dir().unwrap();
+    } else {
+        ret = PathBuf::from(path);
+    }
+
+    Ok(ret)
+}
+
+pub fn join_config_path(file: &Path) -> Result<PathBuf> {
+    let mut path = PathBuf::new();
+    let dfi_path = Path::new("darkfi");
+
+    if let Some(v) = dirs::config_dir() {
+        path.push(v);
+    }
+
+    path.push(dfi_path);
+    path.push(file);
+
+    Ok(path)
+}

+ 45 - 0
src/util/token_list.rs

@@ -0,0 +1,45 @@
+use crate::{Error, Result};
+use serde_json::Value;
+
+#[derive(Debug, Clone)]
+pub struct TokenList {
+    tokenlist: Value,
+}
+
+impl TokenList {
+    pub fn new() -> Result<Self> {
+        // TODO: FIXME
+        let file_contents = std::fs::read_to_string("token/solanatokenlist.json")?;
+        let tokenlist: Value = serde_json::from_str(&file_contents)?;
+
+        Ok(Self { tokenlist })
+    }
+
+    pub fn search_id(self, symbol: &str) -> Result<String> {
+        let tokens = self.tokenlist["tokens"]
+            .as_array()
+            .ok_or(Error::TokenParseError)?;
+        for item in tokens {
+            if item["symbol"] == symbol.to_uppercase() {
+                let address = item["address"].clone();
+                let address = address.as_str().ok_or(Error::TokenParseError)?;
+                return Ok(address.to_string());
+            }
+        }
+        unreachable!();
+    }
+
+    pub fn search_decimal(self, symbol: &str) -> Result<u64> {
+        let tokens = self.tokenlist["tokens"]
+            .as_array()
+            .ok_or(Error::TokenParseError)?;
+        for item in tokens {
+            if item["symbol"] == symbol.to_uppercase() {
+                let decimals = item["decimals"].clone();
+                let decimals = decimals.as_u64().ok_or(Error::TokenParseError)?;
+                return Ok(decimals);
+            }
+        }
+        unreachable!();
+    }
+}

+ 0 - 0
src/util.rs → src/util/util