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

drk/interactive: token commands added

skoupidi 1 год назад
Родитель
Сommit
f910402fa0
2 измененных файлов с 285 добавлено и 15 удалено
  1. 274 4
      bin/drk/src/interactive.rs
  2. 11 11
      bin/drk/src/main.rs

+ 274 - 4
bin/drk/src/interactive.rs

@@ -48,7 +48,8 @@ use darkfi_dao_contract::{blockwindow, model::DaoProposalBulla, DaoFunction};
 use darkfi_money_contract::model::{Coin, CoinAttributes, TokenId};
 use darkfi_money_contract::model::{Coin, CoinAttributes, TokenId};
 use darkfi_sdk::{
 use darkfi_sdk::{
     crypto::{
     crypto::{
-        note::AeadEncryptedNote, BaseBlind, FuncId, FuncRef, Keypair, PublicKey, DAO_CONTRACT_ID,
+        note::AeadEncryptedNote, BaseBlind, FuncId, FuncRef, Keypair, PublicKey, SecretKey,
+        DAO_CONTRACT_ID,
     },
     },
     pasta::{group::ff::PrimeField, pallas},
     pasta::{group::ff::PrimeField, pallas},
     tx::TransactionHash,
     tx::TransactionHash,
@@ -102,6 +103,7 @@ fn help(output: &mut Vec<String>) {
     output.push(String::from("\tscan: Scan the blockchain and parse relevant transactions"));
     output.push(String::from("\tscan: Scan the blockchain and parse relevant transactions"));
     output.push(String::from("\texplorer: Explorer related subcommands"));
     output.push(String::from("\texplorer: Explorer related subcommands"));
     output.push(String::from("\talias: Token alias"));
     output.push(String::from("\talias: Token alias"));
+    output.push(String::from("\ttoken: Token functionalities"));
 }
 }
 
 
 /// Auxiliary function to define the interactive shell completions.
 /// Auxiliary function to define the interactive shell completions.
@@ -162,7 +164,7 @@ fn completion(buffer: &str, lc: &mut Vec<String>) {
         return
         return
     }
     }
 
 
-    if last.starts_with("t") {
+    if last.starts_with("tr") {
         lc.push(prefix + "transfer");
         lc.push(prefix + "transfer");
         return
         return
     }
     }
@@ -255,6 +257,16 @@ fn completion(buffer: &str, lc: &mut Vec<String>) {
         return
         return
     }
     }
 
 
+    if last.starts_with("to") {
+        lc.push(prefix.clone() + "token");
+        lc.push(prefix.clone() + "token import");
+        lc.push(prefix.clone() + "token generate-mint");
+        lc.push(prefix.clone() + "token list");
+        lc.push(prefix.clone() + "token mint");
+        lc.push(prefix + "token freeze");
+        return
+    }
+
     // Now the catch alls
     // Now the catch alls
     if last.starts_with("a") {
     if last.starts_with("a") {
         lc.push(prefix.clone() + "attach-fee");
         lc.push(prefix.clone() + "attach-fee");
@@ -274,6 +286,17 @@ fn completion(buffer: &str, lc: &mut Vec<String>) {
         return
         return
     }
     }
 
 
+    if last.starts_with("t") {
+        lc.push(prefix.clone() + "transfer");
+        lc.push(prefix.clone() + "token");
+        lc.push(prefix.clone() + "token import");
+        lc.push(prefix.clone() + "token generate-mint");
+        lc.push(prefix.clone() + "token list");
+        lc.push(prefix.clone() + "token mint");
+        lc.push(prefix + "token freeze");
+        return
+    }
+
     if last.starts_with("u") {
     if last.starts_with("u") {
         lc.push(prefix.clone() + "unspend");
         lc.push(prefix.clone() + "unspend");
         lc.push(prefix.clone() + "unsubscribe");
         lc.push(prefix.clone() + "unsubscribe");
@@ -318,6 +341,10 @@ fn hints(buffer: &str) -> Option<(String, i32, bool)> {
         "alias add " => Some(("<alias> <token>".to_string(), color, bold)),
         "alias add " => Some(("<alias> <token>".to_string(), color, bold)),
         "alias show " => Some(("[-a, --alias <alias>] [-t, --token <token>]".to_string(), color, bold)),
         "alias show " => Some(("[-a, --alias <alias>] [-t, --token <token>]".to_string(), color, bold)),
         "alias remove " => Some(("<alias>".to_string(), color, bold)),
         "alias remove " => Some(("<alias>".to_string(), color, bold)),
+        "token " => Some(("(import|generate-mint|list|mint|freeze)".to_string(), color, bold)),
+        "token import " => Some(("<secret-key> <token-blind>".to_string(), color, bold)),
+        "token mint " => Some(("<token> <amount> <recipient> [spend-hook] [user-data]".to_string(), color, bold)),
+        "token freeze " => Some(("<token>".to_string(), color, bold)),
         _ => None,
         _ => None,
     }
     }
 }
 }
@@ -505,6 +532,7 @@ pub async fn interactive(drk: &DrkPtr, endpoint: &Url, history_path: &str, ex: &
                 }
                 }
                 "explorer" => handle_explorer(drk, &parts, &input, &mut output).await,
                 "explorer" => handle_explorer(drk, &parts, &input, &mut output).await,
                 "alias" => handle_alias(drk, &parts, &mut output).await,
                 "alias" => handle_alias(drk, &parts, &mut output).await,
+                "token" => handle_token(drk, &parts, &mut output).await,
                 _ => output.push(format!("Unreconized command: {}", parts[0])),
                 _ => output.push(format!("Unreconized command: {}", parts[0])),
             }
             }
 
 
@@ -1063,7 +1091,7 @@ async fn handle_transfer(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>)
     let token_id = match lock.get_token(String::from(parts[index])).await {
     let token_id = match lock.get_token(String::from(parts[index])).await {
         Ok(t) => t,
         Ok(t) => t,
         Err(e) => {
         Err(e) => {
-            output.push(format!("Invalid token alias: {e}"));
+            output.push(format!("Invalid token ID: {e}"));
             return
             return
         }
         }
     };
     };
@@ -1653,7 +1681,7 @@ async fn handle_dao_propose_transfer(drk: &DrkPtr, parts: &[&str], output: &mut
     let token_id = match lock.get_token(String::from(parts[5])).await {
     let token_id = match lock.get_token(String::from(parts[5])).await {
         Ok(t) => t,
         Ok(t) => t,
         Err(e) => {
         Err(e) => {
-            output.push(format!("Invalid token alias: {e}"));
+            output.push(format!("Invalid token ID: {e}"));
             return
             return
         }
         }
     };
     };
@@ -2775,3 +2803,245 @@ async fn handle_alias_remove(drk: &DrkPtr, parts: &[&str], output: &mut Vec<Stri
         output.push(format!("Failed to remove alias: {e}"));
         output.push(format!("Failed to remove alias: {e}"));
     }
     }
 }
 }
+
+/// Auxiliary function to define the token command handling.
+async fn handle_token(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct command structure
+    if parts.len() < 2 {
+        output.push(String::from("Malformed `token` command"));
+        output.push(String::from("Usage: token (import|generate-mint|list|mint|freeze)"));
+        return
+    }
+
+    // Handle subcommand
+    match parts[1] {
+        "import" => handle_token_import(drk, parts, output).await,
+        "generate-mint" => handle_token_generate_mint(drk, parts, output).await,
+        "list" => handle_token_list(drk, parts, output).await,
+        "mint" => handle_token_mint(drk, parts, output).await,
+        "freeze" => handle_token_freeze(drk, parts, output).await,
+        _ => {
+            output.push(format!("Unreconized token subcommand: {}", parts[1]));
+            output.push(String::from("Usage: token (import|generate-mint|list|mint|freeze)"));
+        }
+    }
+}
+
+/// Auxiliary function to define the token import subcommand handling.
+async fn handle_token_import(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct subcommand structure
+    if parts.len() != 4 {
+        output.push(String::from("Malformed `token import` subcommand"));
+        output.push(String::from("Usage: token import <secret-key> <token-blind>"));
+        return
+    }
+
+    let mint_authority = match SecretKey::from_str(parts[2]) {
+        Ok(ma) => ma,
+        Err(e) => {
+            output.push(format!("Invalid mint authority: {e}"));
+            return
+        }
+    };
+
+    let token_blind = match BaseBlind::from_str(parts[3]) {
+        Ok(tb) => tb,
+        Err(e) => {
+            output.push(format!("Invalid token blind: {e}"));
+            return
+        }
+    };
+
+    match drk.read().await.import_mint_authority(mint_authority, token_blind).await {
+        Ok(token_id) => {
+            output.push(format!("Successfully imported mint authority for token ID: {token_id}"))
+        }
+        Err(e) => output.push(format!("Failed to import mint authority: {e}")),
+    }
+}
+
+/// Auxiliary function to define the token generate mint subcommand handling.
+async fn handle_token_generate_mint(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct subcommand structure
+    if parts.len() != 2 {
+        output.push(String::from("Malformed `token generate-mint` subcommand"));
+        output.push(String::from("Usage: token generate-mint"));
+        return
+    }
+
+    let mint_authority = SecretKey::random(&mut OsRng);
+    let token_blind = BaseBlind::random(&mut OsRng);
+    match drk.read().await.import_mint_authority(mint_authority, token_blind).await {
+        Ok(token_id) => {
+            output.push(format!("Successfully imported mint authority for token ID: {token_id}"))
+        }
+        Err(e) => output.push(format!("Failed to import mint authority: {e}")),
+    }
+}
+
+/// Auxiliary function to define the token list subcommand handling.
+async fn handle_token_list(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct subcommand structure
+    if parts.len() != 2 {
+        output.push(String::from("Malformed `token list` subcommand"));
+        output.push(String::from("Usage: token list"));
+        return
+    }
+
+    let lock = drk.read().await;
+    let tokens = match lock.get_mint_authorities().await {
+        Ok(m) => m,
+        Err(e) => {
+            output.push(format!("Failed to fetch mint autorities: {e:?}"));
+            return
+        }
+    };
+
+    let aliases_map = match lock.get_aliases_mapped_by_token().await {
+        Ok(m) => m,
+        Err(e) => {
+            output.push(format!("Failed to fetch aliases map: {e:?}"));
+            return
+        }
+    };
+
+    let mut table = Table::new();
+    table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
+    table.set_titles(row![
+        "Token ID",
+        "Aliases",
+        "Mint Authority",
+        "Token Blind",
+        "Frozen",
+        "Freeze Height"
+    ]);
+
+    for (token_id, authority, blind, frozen, freeze_height) in tokens {
+        let aliases = match aliases_map.get(&token_id.to_string()) {
+            Some(a) => a,
+            None => "-",
+        };
+
+        let freeze_height = match freeze_height {
+            Some(freeze_height) => freeze_height.to_string(),
+            None => String::from("-"),
+        };
+
+        table.add_row(row![token_id, aliases, authority, blind, frozen, freeze_height]);
+    }
+
+    if table.is_empty() {
+        output.push(String::from("No tokens found"));
+    } else {
+        output.push(format!("{table}"));
+    }
+}
+
+/// Auxiliary function to define the token mint subcommand handling.
+async fn handle_token_mint(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct command structure
+    if parts.len() < 5 || parts.len() > 7 {
+        output.push(String::from("Malformed `token mint` subcommand"));
+        output.push(String::from(
+            "Usage: token mint <token> <amount> <recipient> [spend-hook] [user-data]",
+        ));
+        return
+    }
+
+    let amount = String::from(parts[3]);
+    if let Err(e) = f64::from_str(&amount) {
+        output.push(format!("Invalid amount: {e}"));
+        return
+    }
+
+    let rcpt = match PublicKey::from_str(parts[4]) {
+        Ok(r) => r,
+        Err(e) => {
+            output.push(format!("Invalid recipient: {e}"));
+            return
+        }
+    };
+
+    let lock = drk.read().await;
+    let token_id = match lock.get_token(String::from(parts[2])).await {
+        Ok(t) => t,
+        Err(e) => {
+            output.push(format!("Invalid token ID: {e}"));
+            return
+        }
+    };
+
+    // Parse command
+    let mut index = 4;
+    let spend_hook = if index < parts.len() {
+        match FuncId::from_str(parts[index]) {
+            Ok(s) => Some(s),
+            Err(e) => {
+                output.push(format!("Invalid spend hook: {e}"));
+                return
+            }
+        }
+    } else {
+        None
+    };
+    index += 1;
+
+    let user_data = if index < parts.len() {
+        let bytes = match bs58::decode(&parts[index]).into_vec() {
+            Ok(b) => b,
+            Err(e) => {
+                output.push(format!("Invalid user data: {e}"));
+                return
+            }
+        };
+
+        let bytes: [u8; 32] = match bytes.try_into() {
+            Ok(b) => b,
+            Err(e) => {
+                output.push(format!("Invalid user data: {e:?}"));
+                return
+            }
+        };
+
+        let elem: pallas::Base = match pallas::Base::from_repr(bytes).into() {
+            Some(v) => v,
+            None => {
+                output.push(String::from("Invalid user data"));
+                return
+            }
+        };
+
+        Some(elem)
+    } else {
+        None
+    };
+
+    match lock.mint_token(&amount, rcpt, token_id, spend_hook, user_data).await {
+        Ok(t) => output.push(base64::encode(&serialize_async(&t).await)),
+        Err(e) => output.push(format!("Failed to create token mint transaction: {e}")),
+    }
+}
+
+/// Auxiliary function to define the token freeze subcommand handling.
+async fn handle_token_freeze(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct subcommand structure
+    if parts.len() != 3 {
+        output.push(String::from("Malformed `token freeze` subcommand"));
+        output.push(String::from("Usage: token freeze <token>"));
+        return
+    }
+
+    let lock = drk.read().await;
+    let token_id = match lock.get_token(String::from(parts[2])).await {
+        Ok(t) => t,
+        Err(e) => {
+            output.push(format!("Invalid token ID: {e}"));
+            return
+        }
+    };
+
+    match lock.freeze_token(token_id).await {
+        Ok(t) => output.push(base64::encode(&serialize_async(&t).await)),
+        Err(e) => output.push(format!("Failed to create token freeze transaction: {e}")),
+    }
+}

+ 11 - 11
bin/drk/src/main.rs

@@ -2277,7 +2277,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                     Some(t) => match TokenId::from_str(t.as_str()) {
                     Some(t) => match TokenId::from_str(t.as_str()) {
                         Ok(t) => Some(t),
                         Ok(t) => Some(t),
                         Err(e) => {
                         Err(e) => {
-                            eprintln!("Invalid Token ID: {e:?}");
+                            eprintln!("Invalid Token ID: {e}");
                             exit(2);
                             exit(2);
                         }
                         }
                     },
                     },
@@ -2339,7 +2339,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let mint_authority = match SecretKey::from_str(&secret_key) {
                 let mint_authority = match SecretKey::from_str(&secret_key) {
                     Ok(ma) => ma,
                     Ok(ma) => ma,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Invalid mint authority: {e:?}");
+                        eprintln!("Invalid mint authority: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2347,7 +2347,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let token_blind = match BaseBlind::from_str(&token_blind) {
                 let token_blind = match BaseBlind::from_str(&token_blind) {
                     Ok(tb) => tb,
                     Ok(tb) => tb,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Invalid token blind: {e:?}");
+                        eprintln!("Invalid token blind: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2399,7 +2399,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let aliases_map = match drk.get_aliases_mapped_by_token().await {
                 let aliases_map = match drk.get_aliases_mapped_by_token().await {
                     Ok(map) => map,
                     Ok(map) => map,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Failed to fetch wallet aliases: {e:?}");
+                        eprintln!("Failed to fetch wallet aliases: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2450,14 +2450,14 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 .await;
                 .await;
 
 
                 if let Err(e) = f64::from_str(&amount) {
                 if let Err(e) = f64::from_str(&amount) {
-                    eprintln!("Invalid amount: {e:?}");
+                    eprintln!("Invalid amount: {e}");
                     exit(2);
                     exit(2);
                 }
                 }
 
 
                 let rcpt = match PublicKey::from_str(&recipient) {
                 let rcpt = match PublicKey::from_str(&recipient) {
                     Ok(r) => r,
                     Ok(r) => r,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Invalid recipient: {e:?}");
+                        eprintln!("Invalid recipient: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2465,7 +2465,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let token_id = match drk.get_token(token).await {
                 let token_id = match drk.get_token(token).await {
                     Ok(t) => t,
                     Ok(t) => t,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Invalid Token ID: {e:?}");
+                        eprintln!("Invalid Token ID: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2474,7 +2474,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                     Some(s) => match FuncId::from_str(&s) {
                     Some(s) => match FuncId::from_str(&s) {
                         Ok(s) => Some(s),
                         Ok(s) => Some(s),
                         Err(e) => {
                         Err(e) => {
-                            eprintln!("Invalid spend hook: {e:?}");
+                            eprintln!("Invalid spend hook: {e}");
                             exit(2);
                             exit(2);
                         }
                         }
                     },
                     },
@@ -2506,7 +2506,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 {
                 {
                     Ok(tx) => tx,
                     Ok(tx) => tx,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Failed to create token mint transaction: {e:?}");
+                        eprintln!("Failed to create token mint transaction: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2529,7 +2529,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let token_id = match drk.get_token(token).await {
                 let token_id = match drk.get_token(token).await {
                     Ok(t) => t,
                     Ok(t) => t,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Invalid Token ID: {e:?}");
+                        eprintln!("Invalid Token ID: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };
@@ -2537,7 +2537,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 let tx = match drk.freeze_token(token_id).await {
                 let tx = match drk.freeze_token(token_id).await {
                     Ok(tx) => tx,
                     Ok(tx) => tx,
                     Err(e) => {
                     Err(e) => {
-                        eprintln!("Failed to create token freeze transaction: {e:?}");
+                        eprintln!("Failed to create token freeze transaction: {e}");
                         exit(2);
                         exit(2);
                     }
                     }
                 };
                 };