Эх сурвалжийг харах

token_list: integrate erc20 token list for DrkTokenList

ghassmo 4 жил өмнө
parent
commit
b034c09c7f
2 өөрчлөгдсөн 135 нэмэгдсэн , 48 устгасан
  1. 48 20
      src/bin/darkfid.rs
  2. 87 28
      src/util/token_list.rs

+ 48 - 20
src/bin/darkfid.rs

@@ -79,6 +79,7 @@ struct Darkfid {
     client: Arc<Mutex<Client>>,
     state: Arc<Mutex<State>>,
     sol_tokenlist: TokenList,
+    eth_tokenlist: TokenList,
     drk_tokenlist: DrkTokenList,
     cashiers: Vec<Cashier>,
 }
@@ -90,12 +91,14 @@ impl Darkfid {
         cashiers: Vec<Cashier>,
     ) -> Result<Self> {
         let sol_tokenlist = TokenList::new(include_bytes!("../../token/solana_token_list.json"))?;
-        let drk_tokenlist = DrkTokenList::new(sol_tokenlist.clone())?;
+        let eth_tokenlist = TokenList::new(include_bytes!("../../token/erc20_token_list.json"))?;
+        let drk_tokenlist = DrkTokenList::new(&sol_tokenlist, &eth_tokenlist)?;
 
         Ok(Self {
             client,
             state,
             sol_tokenlist,
+            eth_tokenlist,
             drk_tokenlist,
             cashiers,
         })
@@ -184,7 +187,7 @@ impl Darkfid {
                     network = "bitcoin"
                 }
 
-                if let Some(symbol) = self.drk_tokenlist.symbol_from_id(balance.token_id)? {
+                if let Some(symbol) = self.drk_tokenlist.symbol_from_id(&balance.token_id)? {
                     let amount = encode_base10(BigUint::from(balance.value), 8);
                     symbols.insert(symbol, (amount, network.to_string()));
                 } else {
@@ -248,6 +251,13 @@ impl Darkfid {
                     let token_id = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".to_string();
                     Ok(json!(token_id))
                 }
+                #[cfg(feature = "eth")]
+                NetworkName::Ethereum => {
+                    //hardcoded genesis coinbase address
+                    use drk::service::eth::ETH_NATIVE_TOKEN_ID;
+                    let token_id = ETH_NATIVE_TOKEN_ID.to_string();
+                    Ok(json!(token_id))
+                }
                 _ => Err(Error::NotSupportedNetwork),
             }
         }
@@ -295,12 +305,15 @@ impl Darkfid {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
         }
 
-        let network: &str;
+        let network: NetworkName;
         let token: &str;
 
         match (args[0].as_str(), args[1].as_str()) {
             (Some(net), Some(tkn)) => {
-                network = net;
+                if NetworkName::from_str(net).is_err() {
+                    return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
+                }
+                network = NetworkName::from_str(net).unwrap();
                 token = tkn;
             }
             (None, _) => {
@@ -311,7 +324,7 @@ impl Darkfid {
             }
         }
 
-        let token_id = match assign_id(network, token, &self.sol_tokenlist) {
+        let token_id = match assign_id(&network, token, &self.sol_tokenlist, &self.eth_tokenlist) {
             Ok(t) => t,
             Err(e) => {
                 return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
@@ -363,7 +376,7 @@ impl Darkfid {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
         }
 
-        let network: &str;
+        let network: NetworkName;
         let token: &str;
         let address: &str;
         let amount: &str;
@@ -375,7 +388,10 @@ impl Darkfid {
             args[3].as_str(),
         ) {
             (Some(net), Some(tkn), Some(addr), Some(val)) => {
-                network = net;
+                if NetworkName::from_str(net).is_err() {
+                    return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
+                }
+                network = NetworkName::from_str(net).unwrap();
                 token = tkn;
                 address = addr;
                 amount = val;
@@ -401,7 +417,7 @@ impl Darkfid {
             }
         };
 
-        let token_id = match assign_id(network, token, &self.sol_tokenlist) {
+        let token_id = match assign_id(&network, token, &self.sol_tokenlist, &self.eth_tokenlist) {
             Ok(t) => t,
             Err(e) => {
                 return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
@@ -422,11 +438,10 @@ impl Darkfid {
 
         let token_id: &jubjub::Fr;
 
-        // get the id for the token
-        if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
+        if let Some(tk_id) = self.drk_tokenlist.tokens[&network].get(&token.to_uppercase()) {
             token_id = tk_id;
         } else {
-            return JsonResult::Err(jsonerr(InvalidParams, None, id));
+            return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
         }
 
         // send drk to cashier_public
@@ -475,7 +490,7 @@ impl Darkfid {
         }
     }
 
-    // --> {"method": "transfer", [dToken, address, amount]}
+    // --> {"method": "transfer", [network, dToken, address, amount]}
     // <-- {"result": "txID"}
     async fn transfer(&self, id: Value, params: Value) -> JsonResult {
         let args = params.as_array();
@@ -483,27 +498,40 @@ impl Darkfid {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
         }
         let args = args.unwrap();
-        if args.len() != 3 {
+        if args.len() != 4 {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
         }
 
+        let network: NetworkName;
         let token: &str;
         let address: &str;
         let amount: &str;
 
-        match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
-            (Some(tkn), Some(addr), Some(val)) => {
+        match (
+            args[0].as_str(),
+            args[1].as_str(),
+            args[2].as_str(),
+            args[3].as_str(),
+        ) {
+            (Some(net), Some(tkn), Some(addr), Some(val)) => {
+                if NetworkName::from_str(net).is_err() {
+                    return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
+                }
+                network = NetworkName::from_str(net).unwrap();
                 token = tkn;
                 address = addr;
                 amount = val;
             }
-            (None, _, _) => {
+            (None, _, _, _) => {
+                return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
+            }
+            (_, None, _, _) => {
                 return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
             }
-            (_, None, _) => {
+            (_, _, None, _) => {
                 return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
             }
-            (_, _, None) => {
+            (_, _, _, None) => {
                 return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
             }
         }
@@ -511,10 +539,10 @@ impl Darkfid {
         let token_id: &jubjub::Fr;
 
         // get the id for the token
-        if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
+        if let Some(tk_id) = self.drk_tokenlist.tokens[&network].get(&token.to_uppercase()) {
             token_id = tk_id;
         } else {
-            return JsonResult::Err(jsonerr(InvalidParams, None, id));
+            return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
         }
 
         let result: Result<()> = async {

+ 87 - 28
src/util/token_list.rs

@@ -57,46 +57,73 @@ impl TokenList {
 
 #[derive(Debug, Clone)]
 pub struct DrkTokenList {
-    pub tokens: HashMap<String, jubjub::Fr>,
+    pub tokens: HashMap<NetworkName, HashMap<String, jubjub::Fr>>,
 }
 
 impl DrkTokenList {
-    pub fn new(sol_list: TokenList) -> Result<Self> {
+    pub fn new(sol_list: &TokenList, eth_list: &TokenList) -> Result<Self> {
         let sol_symbols = sol_list.get_symbols()?;
+        let eth_symbols = eth_list.get_symbols()?;
 
-        let mut tokens: HashMap<String, jubjub::Fr> = sol_symbols
+        let sol_tokens: HashMap<String, jubjub::Fr> = sol_symbols
             .iter()
-            .filter_map(|symbol| Self::generate_hash_pair(&sol_list, symbol).ok())
+            .filter_map(|symbol| {
+                Self::generate_hash_pair(&sol_list, &NetworkName::Solana, symbol).ok()
+            })
             .collect();
 
-        tokens.insert(
+        let eth_tokens: HashMap<String, jubjub::Fr> = eth_symbols
+            .iter()
+            .filter_map(|symbol| {
+                Self::generate_hash_pair(&eth_list, &NetworkName::Ethereum, symbol).ok()
+            })
+            .collect();
+
+        // FIXME
+        let mut btc_tokens: HashMap<String, jubjub::Fr> = HashMap::new();
+        btc_tokens.insert(
             "BTC".to_string(),
             generate_id("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", &NetworkName::Bitcoin)?,
         );
 
+        let mut tokens: HashMap<NetworkName, HashMap<String, jubjub::Fr>> = HashMap::new();
+
+        tokens.insert(NetworkName::Solana, sol_tokens);
+        tokens.insert(NetworkName::Ethereum, eth_tokens);
+        tokens.insert(NetworkName::Bitcoin, btc_tokens);
+
         Ok(Self { tokens })
     }
 
-    fn generate_hash_pair(sol_list: &TokenList, symbol: &str) -> Result<(String, jubjub::Fr)> {
-        if let Some(token_id) = &sol_list.search_id(symbol)? {
-            Ok((
-                symbol.to_string(),
-                generate_id(token_id, &NetworkName::Solana)?,
-            ))
-        } else {
-            Err(Error::NotSupportedToken)
-        }
+    fn generate_hash_pair(
+        token_list: &TokenList,
+        network_name: &NetworkName,
+        symbol: &str,
+    ) -> Result<(String, jubjub::Fr)> {
+        if let Some(token_id) = &token_list.search_id(symbol)? {
+            return Ok((symbol.to_string(), generate_id(token_id, network_name)?));
+        };
+
+        Err(Error::NotSupportedToken)
     }
 
-    pub fn symbol_from_id(&self, id: jubjub::Fr) -> Result<Option<String>> {
+    pub fn symbol_from_id(
+        &self,
+        id: &jubjub::Fr,
+    ) -> Result<Option<String>> {
         if id.to_string() == "0x01300f9bce0f9ba7168dc001a67bcbda3a5bf4bdb4c56ae900fe4698cee9a7bd" {
             return Ok(Some("BTC".to_string()));
         }
 
-        Ok(self
-            .tokens
-            .iter()
-            .find_map(|(key, &val)| if val == id { Some(key.clone()) } else { None }))
+        for (_, tokens) in self.tokens.iter() {
+            for (key, val) in tokens.iter() {
+                if val == id {
+                    return Ok(Some(key.clone()));
+                }
+            }
+        }
+
+        Ok(None)
     }
 }
 
@@ -106,7 +133,7 @@ mod tests {
     use crate::util::{DrkTokenList, TokenList};
     use crate::Result;
 
-    fn _get_tokens() -> Result<TokenList> {
+    fn _get_sol_tokens() -> Result<TokenList> {
         let file_contents = include_bytes!("../../testdata/solanatokenlisttest.json");
         let sol_tokenlist: Value = serde_json::from_slice(file_contents)?;
 
@@ -119,9 +146,22 @@ mod tests {
         Ok(sol_tokenlist)
     }
 
+    fn _get_eth_tokens() -> Result<TokenList> {
+        let file_contents = include_bytes!("../../testdata/erc20tokenlisttest.json");
+        let sol_tokenlist: Value = serde_json::from_slice(file_contents)?;
+
+        let tokens = sol_tokenlist["tokens"]
+            .as_array()
+            .ok_or(Error::TokenParseError)?
+            .clone();
+
+        let sol_tokenlist = TokenList { tokens };
+        Ok(sol_tokenlist)
+    }
+
     #[test]
     pub fn test_get_symbols() -> Result<()> {
-        let tokens = _get_tokens()?;
+        let tokens = _get_sol_tokens()?;
         let symbols = tokens.get_symbols()?;
         assert_eq!(symbols.len(), 5);
         assert_eq!("MILLI", symbols[0]);
@@ -134,7 +174,7 @@ mod tests {
 
     #[test]
     pub fn test_get_id_from_symbols() -> Result<()> {
-        let tokens = _get_tokens()?;
+        let tokens = _get_sol_tokens()?;
         let symbol = &tokens.get_symbols()?[3];
         let id = tokens.search_id(symbol)?;
         assert!(id.is_some());
@@ -144,14 +184,33 @@ mod tests {
 
     #[test]
     pub fn test_hashmap() -> Result<()> {
-        let tokens = _get_tokens()?;
-        let tokens2 = _get_tokens()?;
-        let drk_token = DrkTokenList::new(tokens)?;
-        //assert_eq!(drk_token.tokens.len(), 5);
+        let sol_tokens = _get_sol_tokens()?;
+        let sol_tokens2 = _get_sol_tokens()?;
+        let eth_tokens = _get_eth_tokens()?;
+        let eth_tokens2 = _get_eth_tokens()?;
+
+        let drk_token = DrkTokenList::new(&sol_tokens, &eth_tokens)?;
+
+        assert_eq!(drk_token.tokens[&NetworkName::Solana].len(), 5);
+        assert_eq!(drk_token.tokens[&NetworkName::Ethereum].len(), 3);
+        assert_eq!(drk_token.tokens[&NetworkName::Bitcoin].len(), 1);
+
         assert_eq!(
-            drk_token.tokens["SOL"],
-            generate_id(&tokens2.search_id("SOL")?.unwrap(), &NetworkName::Solana)?
+            drk_token.tokens[&NetworkName::Solana]["SOL"],
+            generate_id(
+                &sol_tokens2.search_id("SOL")?.unwrap(),
+                &NetworkName::Solana
+            )?
         );
+
+        assert_eq!(
+            drk_token.tokens[&NetworkName::Ethereum]["WBTC"],
+            generate_id(
+                &eth_tokens2.search_id("WBTC")?.unwrap(),
+                &NetworkName::Ethereum
+            )?
+        );
+
         Ok(())
     }
 }