parse.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. use crate::{
  2. serial::{deserialize, serialize},
  3. util::{NetworkName, TokenList},
  4. Error, Result,
  5. };
  6. use log::debug;
  7. use sha2::{Digest, Sha256};
  8. use std::str::FromStr;
  9. // hash the external token ID and NetworkName param.
  10. // if fails, change the last 4 bytes and hash it again. keep repeating until it works.
  11. pub fn generate_id(tkn_str: &str, network: &NetworkName) -> Result<jubjub::Fr> {
  12. let mut id_string = network.to_string();
  13. id_string.push_str(tkn_str);
  14. if bs58::decode(id_string.clone()).into_vec().is_err() {
  15. // TODO: make this an error
  16. debug!(target: "PARSE ID", "COULD NOT DECODE STR");
  17. }
  18. let mut data = bs58::decode(id_string).into_vec().unwrap();
  19. let token_id = match deserialize::<jubjub::Fr>(&data) {
  20. Ok(v) => v,
  21. Err(_) => {
  22. let mut counter = 0;
  23. loop {
  24. data.truncate(28);
  25. let serialized_counter = serialize(&counter);
  26. data.extend(serialized_counter.iter());
  27. let mut hasher = Sha256::new();
  28. hasher.update(&data);
  29. let hash = hasher.finalize();
  30. let token_id = deserialize::<jubjub::Fr>(&hash);
  31. if token_id.is_err() {
  32. counter += 1;
  33. continue;
  34. }
  35. debug!(target: "CASHIER", "DESERIALIZATION SUCCESSFUL");
  36. return Ok(token_id.unwrap());
  37. }
  38. }
  39. };
  40. Ok(token_id)
  41. }
  42. pub fn assign_id(network: &str, token: &str, tokenlist: TokenList) -> Result<String> {
  43. match NetworkName::from_str(network)? {
  44. NetworkName::Solana => match token.to_lowercase().as_str() {
  45. "solana" | "sol" => {
  46. let token_id = "So11111111111111111111111111111111111111112";
  47. Ok(token_id.to_string())
  48. }
  49. tkn => {
  50. // (== 44) can represent a Solana base58 token mint address
  51. let id = if token.len() == 44 {
  52. token.to_string()
  53. } else {
  54. symbol_to_id(tkn, tokenlist)?
  55. };
  56. Ok(id)
  57. }
  58. },
  59. NetworkName::Bitcoin => Err(Error::NetworkParseError),
  60. }
  61. }
  62. pub fn decimals(network: &str, token: &str, tokenlist: TokenList) -> Result<usize> {
  63. match NetworkName::from_str(network)? {
  64. NetworkName::Solana => match token {
  65. "solana" | "sol" => {
  66. let decimals = 9;
  67. Ok(decimals)
  68. }
  69. tkn => {
  70. let decimals = tokenlist.search_decimal(tkn)?;
  71. Ok(decimals)
  72. }
  73. },
  74. NetworkName::Bitcoin => Err(Error::NetworkParseError),
  75. }
  76. }
  77. pub fn to_apo(amount: f64, decimals: u32) -> Result<u64> {
  78. let apo = amount as u64 * u64::pow(10, decimals as u32);
  79. Ok(apo)
  80. }
  81. pub fn symbol_to_id(token: &str, tokenlist: TokenList) -> Result<String> {
  82. let vec: Vec<char> = token.chars().collect();
  83. let mut counter = 0;
  84. for c in vec {
  85. if c.is_alphabetic() {
  86. counter += 1;
  87. }
  88. }
  89. if counter == token.len() {
  90. tokenlist.search_id(token)
  91. } else {
  92. Ok(token.to_string())
  93. }
  94. }
  95. //pub fn decode_base10(amount: &str, decimals: usize) -> Result<u64> {
  96. // const RADIX: u32 = 10;
  97. //
  98. // let mut input_str = amount.to_string();
  99. //
  100. // // remove the decimal point
  101. // let mut amount: String = match input_str.find(".") {
  102. // Some(v) => {
  103. // input_str.remove(v);
  104. // input_str
  105. // }
  106. // None => input_str,
  107. // };
  108. //
  109. // // only digits should remain:
  110. // for c in amount.chars() {
  111. // if c.is_digit(RADIX) == false {
  112. // // TODO: Make this an error
  113. // println!("Amount is not valid digits!")
  114. // }
  115. // }
  116. //
  117. // // add digits to the end if there are too few
  118. // if amount.len() < decimals {
  119. // loop {
  120. // amount.push('0');
  121. //
  122. // if amount.len() == decimals {
  123. // break;
  124. // }
  125. // continue;
  126. // }
  127. // }
  128. //
  129. // // remove digits from the end if there are too many
  130. // if amount.len() > decimals {
  131. // loop {
  132. // amount.pop();
  133. //
  134. // if amount.len() == decimals {
  135. // break;
  136. // }
  137. // continue;
  138. // }
  139. // }
  140. //
  141. // println!("Resized amount: {}", amount);
  142. //
  143. // let amount_vec: Vec<u32> = vec![0; decimals];
  144. //
  145. // // convert to an integer
  146. // for i in amount.chars() {
  147. // let digit = i.to_digit(RADIX).unwrap();
  148. // amount_vec.push(digit);
  149. // }
  150. //
  151. // let amount: u64 = amount_vec.drain();
  152. // Ok(amount)
  153. //}
  154. mod tests {
  155. #[test]
  156. fn decode_base10() {
  157. const RADIX: u32 = 10;
  158. // TODO: this number varies per token
  159. let decimal_places = 10;
  160. let input = "2.5";
  161. println!("Initial input: {}", input);
  162. let mut input_str = input.to_string();
  163. // remove the decimal point
  164. let mut amount: String = match input_str.find(".") {
  165. Some(v) => {
  166. input_str.remove(v);
  167. input_str
  168. }
  169. None => {
  170. print!("Number isn't a float");
  171. input_str
  172. }
  173. };
  174. println!("Removed decimal point: {}", amount);
  175. // only digits should remain:
  176. for c in amount.chars() {
  177. if c.is_digit(RADIX) == false {
  178. println!("Amount is not valid digits!")
  179. }
  180. }
  181. // add digits to the end if there are too few
  182. if amount.len() < decimal_places {
  183. loop {
  184. amount.push('0');
  185. if amount.len() == decimal_places {
  186. break;
  187. }
  188. continue;
  189. }
  190. }
  191. // remove digits from the end if there are too many
  192. if amount.len() > decimal_places {
  193. loop {
  194. amount.pop();
  195. if amount.len() == decimal_places {
  196. break;
  197. }
  198. continue;
  199. }
  200. }
  201. println!("Resized amount: {}", amount);
  202. // convert to an integer
  203. for i in amount.chars() {
  204. let digit = i.to_digit(RADIX).unwrap();
  205. println!("Converted to integer: {}", digit);
  206. let u = u64::from(digit);
  207. }
  208. }
  209. #[test]
  210. fn encode_base10() {
  211. let input = 100000000;
  212. println!("Original input: {}", input);
  213. let mut input_str = input.to_string();
  214. input_str.insert(1, '.');
  215. let amount = input_str.trim_end_matches('0');
  216. let amount = if amount.ends_with('.') == true {
  217. let amount = amount.trim_end_matches('.');
  218. amount
  219. } else {
  220. amount
  221. };
  222. println!("Encoded output: {}", amount);
  223. }
  224. }