mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
util: refactored util.rs into util directory
This commit is contained in:
@@ -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
src/util/mod.rs
Normal file
9
src/util/mod.rs
Normal file
@@ -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
src/util/net_name.rs
Normal file
52
src/util/net_name.rs
Normal file
@@ -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
src/util/parse.rs
Normal file
144
src/util/parse.rs
Normal file
@@ -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
src/util/path.rs
Normal file
32
src/util/path.rs
Normal file
@@ -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
src/util/token_list.rs
Normal file
45
src/util/token_list.rs
Normal file
@@ -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!();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user