|
|
@@ -1,290 +0,0 @@
|
|
|
-use crate::{
|
|
|
- serial::{deserialize, serialize, Decodable, Encodable},
|
|
|
- Error, Result,
|
|
|
-};
|
|
|
-
|
|
|
-use log::debug;
|
|
|
-use sha2::{Digest, Sha256};
|
|
|
-
|
|
|
-use std::path::{Path, PathBuf};
|
|
|
-use std::str::FromStr;
|
|
|
-
|
|
|
-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)
|
|
|
-}
|
|
|
-
|
|
|
-#[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)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 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) -> 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)?
|
|
|
- };
|
|
|
-
|
|
|
- let token_id = generate_id(&id)?;
|
|
|
- Ok(token_id)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub fn parse_network(network: &str, token: &str) -> 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)?
|
|
|
- };
|
|
|
- Ok(id)
|
|
|
- }
|
|
|
- },
|
|
|
- NetworkName::Bitcoin => Err(Error::NetworkParseError),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub fn parse_params(network: &str, token: &str, amount: u64) -> 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)?;
|
|
|
- let decimals = 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) -> 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() {
|
|
|
- search_id(token)
|
|
|
- } else {
|
|
|
- Ok(token.to_string())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub fn search_id(symbol: &str) -> Result<String> {
|
|
|
- // TODO: FIXME
|
|
|
- let file_contents = std::fs::read_to_string("token/solanatokenlist.json")?;
|
|
|
- let tokenlist: serde_json::Value = serde_json::from_str(&file_contents)?;
|
|
|
- let tokens = 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(symbol: &str) -> Result<u64> {
|
|
|
- // TODO: FIXME
|
|
|
- let file_contents = std::fs::read_to_string("token/solanatokenlist.json")?;
|
|
|
- let tokenlist: serde_json::Value = serde_json::from_str(&file_contents)?;
|
|
|
- let tokens = 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!();
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(test)]
|
|
|
-mod tests {
|
|
|
- use crate::serial::{deserialize, serialize};
|
|
|
- use sha2::{Digest, Sha256};
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_jubjub_parsing() {
|
|
|
- // 1. counter = 0
|
|
|
- // 2. serialized_counter = serialize(counter)
|
|
|
- // 3. asset_id_data = hash(data + serialized_counter)
|
|
|
- // 4. asset_id = deserialize(asset_id_data)
|
|
|
- // 5. test parse
|
|
|
- // 6. loop
|
|
|
- let tkn_str = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
|
- println!("{}", tkn_str);
|
|
|
- if bs58::decode(tkn_str).into_vec().is_err() {
|
|
|
- println!("Could not decode str into vec");
|
|
|
- }
|
|
|
- let mut data = bs58::decode(tkn_str).into_vec().unwrap();
|
|
|
- println!("{:?}", data);
|
|
|
- let mut hasher = Sha256::new();
|
|
|
- hasher.update(&data);
|
|
|
- let hash = hasher.finalize();
|
|
|
- let token_id = deserialize::<jubjub::Fr>(&hash);
|
|
|
- println!("{:?}", token_id);
|
|
|
- let mut counter = 0;
|
|
|
- if token_id.is_err() {
|
|
|
- println!("could not deserialize tkn 58");
|
|
|
- loop {
|
|
|
- println!("TOKEN IS NONE. COMMENCING LOOP");
|
|
|
- counter += 1;
|
|
|
- println!("LOOP NUMBER {}", counter);
|
|
|
- println!("{:?}", data.len());
|
|
|
- data.truncate(28);
|
|
|
- let serialized_counter = serialize(&counter);
|
|
|
- println!("{:?}", serialized_counter);
|
|
|
- data.extend(serialized_counter.iter());
|
|
|
- println!("{:?}", data.len());
|
|
|
- let mut hasher = Sha256::new();
|
|
|
- hasher.update(&data);
|
|
|
- let hash = hasher.finalize();
|
|
|
- let token_id = deserialize::<jubjub::Fr>(&hash);
|
|
|
- println!("{:?}", token_id);
|
|
|
- if token_id.is_err() {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if counter > 10 {
|
|
|
- break;
|
|
|
- }
|
|
|
- println!("deserialization successful");
|
|
|
- token_id.unwrap();
|
|
|
- break;
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-}
|