Răsfoiți Sursa

initial implementation of drk wallet, includes user and swap keypair

elizabeth 2 ani în urmă
părinte
comite
7828fd94bd
7 a modificat fișierele cu 923 adăugiri și 12 ștergeri
  1. 711 12
      Cargo.lock
  2. 16 0
      Cargo.toml
  3. 25 0
      src/darkfi/error.rs
  4. 4 0
      src/darkfi/mod.rs
  5. 158 0
      src/darkfi/wallet.rs
  6. 8 0
      src/error.rs
  7. 1 0
      src/lib.rs

Fișier diff suprimat deoarece este prea mare
+ 711 - 12
Cargo.lock


+ 16 - 0
Cargo.toml

@@ -11,6 +11,8 @@ edition = "2021"
 [dependencies]
 darkfi = { git = "https://github.com/darkrenaissance/darkfi", features = ["async-daemonize", "async-serial", "system", "util", "net", "rpc", "sled"] }
 darkfi-serial = { git = "https://github.com/darkrenaissance/darkfi", features = ["async"] }
+darkfi-sdk = { git = "https://github.com/darkrenaissance/darkfi" }
+drk = { git = "https://github.com/darkrenaissance/darkfi" }
 
 # Misc
 log = "0.4.21"
@@ -44,3 +46,17 @@ async-std = {version = "1.12.0", features = ["attributes", "tokio1"]}
 [features]
 default = []
 test-utils = []
+
+[patch.crates-io]
+halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v4"}
+halo2_gadgets = {git="https://github.com/parazyd/halo2", branch="v4"}
+
+[patch."https://github.com/darkrenaissance/darkfi"]
+darkfi = { path = "/home/e/darkfi" }
+darkfi-serial = { path = "/home/e/darkfi/src/serial" }
+darkfi-sdk = { path = "/home/e/darkfi/src/sdk" }
+drk = { path = "/home/e/darkfi/bin/drk" }
+
+#darkfi = { git = "https://github.com/noot/darkfi", branch = "fix-include-bytes" }
+#darkfi-serial = { git = "https://github.com/noot/darkfi", branch = "fix-include-bytes" }
+#drk = { git = "https://github.com/noot/darkfi", branch = "fix-include-bytes" }

+ 25 - 0
src/darkfi/error.rs

@@ -0,0 +1,25 @@
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("failed to create drk struct: {0}")]
+    DrkInitializationFailed(#[source] darkfi::Error),
+    #[error("failed to initialize wallet: {0}")]
+    InitializeWallet(#[source] darkfi::Error),
+    #[error("failed to initialize money: {0}")]
+    InitializeMoney(#[source] drk::WalletDbError),
+    #[error("failed to initialize dao: {0}")]
+    InitializeDao(#[source] drk::WalletDbError),
+    #[error("failed to get default secret: {0}")]
+    DefaultSecret(#[source] darkfi::Error),
+    #[error("failed to generate keypair: {0}")]
+    Keygen(#[source] drk::WalletDbError),
+    #[error("failed to get money balance: {0}")]
+    MoneyBalance(#[source] darkfi::Error),
+    #[error("failed to get aliases mapped by token: {0}")]
+    GetAliasesMappedByToken(#[source] darkfi::Error),
+    #[error("failed to build transfer: {0}")]
+    BuildTransfer(#[source] darkfi::Error),
+    #[error("failed to submit transaction: {0}")]
+    SubmitTransaction(#[source] darkfi::Error),
+    #[error("swap keypair does not exist; generate one first")]
+    SwapKeypairDoesNotExist,
+}

+ 4 - 0
src/darkfi/mod.rs

@@ -0,0 +1,4 @@
+mod error;
+pub(crate) mod wallet;
+
+pub(crate) use error::Error;

+ 158 - 0
src/darkfi/wallet.rs

@@ -0,0 +1,158 @@
+use drk::Drk;
+use url::Url;
+
+use crate::darkfi::Error;
+use darkfi::tx::Transaction;
+use darkfi_sdk::crypto::{Keypair, PublicKey, SecretKey};
+use std::sync::Arc;
+
+/// Darkfi wallet implementation.
+///
+/// Interacts with a running darkfid node.
+pub(crate) struct Wallet {
+    drk: Drk,
+
+    // user keypair; the default when the wallet is made
+    user_keypair: Keypair,
+
+    // swap keypair
+    swap_keypair: Option<Keypair>,
+}
+
+impl Wallet {
+    pub(crate) async fn new(
+        wallet_path: String,
+        wallet_pass: String,
+        endpoint: Url,
+        ex: Arc<smol::Executor<'static>>,
+    ) -> Result<Self, crate::Error> {
+        let drk = Drk::new(wallet_path, wallet_pass, endpoint, ex)
+            .await
+            .map_err(|e| crate::Error::from(Error::DrkInitializationFailed(e)))?;
+        drk.initialize_wallet()
+            .await
+            .map_err(|e| crate::Error::from(Error::InitializeWallet(e)))?;
+        drk.initialize_money().await.map_err(|e| crate::Error::from(Error::InitializeMoney(e)))?;
+        drk.initialize_dao().await.map_err(|e| crate::Error::from(Error::InitializeDao(e)))?;
+
+        let user_keypair = Keypair::new(
+            drk.default_secret().await.map_err(|e| crate::Error::from(Error::DefaultSecret(e)))?,
+        );
+
+        Ok(Self { drk, user_keypair, swap_keypair: None })
+    }
+
+    pub(crate) async fn generate_swap_keypair(&mut self) -> Result<(), crate::Error> {
+        self.swap_keypair =
+            Some(self.drk.money_keygen().await.map_err(|e| crate::Error::from(Error::Keygen(e)))?);
+        Ok(())
+    }
+
+    // get the user's DRK balance
+    pub(crate) async fn get_user_balance(&self) -> Result<u64, crate::Error> {
+        get_balance(&self.drk, self.user_keypair.secret).await
+    }
+
+    // get the swap account's DRK balance
+    pub(crate) async fn get_swap_balance(&self) -> Result<u64, crate::Error> {
+        let swap_keypair =
+            self.swap_keypair.ok_or(crate::Error::from(Error::SwapKeypairDoesNotExist))?;
+
+        get_balance(&self.drk, swap_keypair.secret).await
+    }
+
+    // build a transfer of DRK from the user account to the given recipient
+    pub(crate) async fn build_user_transfer(
+        &self,
+        amount: u128,
+        recipient: PublicKey,
+    ) -> Result<Transaction, crate::Error> {
+        let token_id =
+            self.drk.get_token("DRK".to_string()).await.expect("token id must exist for DRK");
+        self.drk
+            .transfer_with_signer(&amount.to_string(), token_id, recipient, self.user_keypair)
+            .await
+            .map_err(|e| crate::Error::from(Error::BuildTransfer(e)))
+    }
+
+    // build a transfer of DRK from the swap account to the given recipient
+    pub(crate) async fn build_swap_transfer(
+        &self,
+        amount: u128,
+        recipient: PublicKey,
+    ) -> Result<Transaction, crate::Error> {
+        let swap_keypair =
+            self.swap_keypair.ok_or(crate::Error::from(Error::SwapKeypairDoesNotExist))?;
+        let token_id =
+            self.drk.get_token("DRK".to_string()).await.expect("token id must exist for DRK");
+        self.drk
+            .transfer_with_signer(&amount.to_string(), token_id, recipient, swap_keypair)
+            .await
+            .map_err(|e| crate::Error::from(Error::BuildTransfer(e)))
+    }
+
+    // submit a transaction to the network
+    pub(crate) async fn submit_transaction(
+        &self,
+        tx: &Transaction,
+    ) -> Result<String, crate::Error> {
+        self.drk.broadcast_tx(tx).await.map_err(|e| crate::Error::from(Error::SubmitTransaction(e)))
+    }
+}
+
+async fn get_balance(drk: &Drk, secret: SecretKey) -> Result<u64, crate::Error> {
+    use std::collections::HashMap;
+
+    let mut coins =
+        drk.get_coins(false).await.map_err(|e| crate::Error::from(Error::MoneyBalance(e)))?;
+    coins.retain(|x| x.0.note.spend_hook == darkfi_sdk::crypto::FuncId::none());
+    coins.retain(|x| x.0.secret == secret);
+
+    let mut balmap: HashMap<String, u64> = HashMap::new();
+
+    for coin in coins {
+        let mut value = coin.0.note.value;
+
+        if let Some(prev) = balmap.get(&coin.0.note.token_id.to_string()) {
+            value += prev;
+        }
+
+        balmap.insert(coin.0.note.token_id.to_string(), value);
+    }
+
+    let aliases_map = drk
+        .get_aliases_mapped_by_token()
+        .await
+        .map_err(|e| crate::Error::from(Error::GetAliasesMappedByToken(e)))?;
+    for (token_id, balance) in balmap.iter() {
+        let alias = match aliases_map.get(token_id) {
+            Some(a) => a,
+            None => "-", // TODO: should every token have an alias?
+        };
+
+        if alias == "DRK" {
+            return Ok(*balance);
+        }
+    }
+
+    return Ok(0);
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::str::FromStr;
+
+    #[ignore = "requires a running darkfid node"]
+    #[async_std::test]
+    async fn test_get_balance() {
+        let drk = Wallet::new(
+            "~/darkfi/contrib/localnet/darkfid-single-node/drk/wallet.db".to_string(),
+            "testing".to_string(),
+            Url::from_str("tcp://127.0.0.1:48340").unwrap(),
+            Arc::new(smol::Executor::new()),
+        )
+        .await
+        .unwrap();
+    }
+}

+ 8 - 0
src/error.rs

@@ -2,12 +2,20 @@ use crate::{ethereum, protocol};
 
 #[derive(Debug, thiserror::Error)]
 pub enum Error {
+    #[error("darkfi error: {0}")]
+    DarkfiError(#[source] crate::darkfi::Error),
     #[error("protocol error: {0}")]
     ProtocolError(#[source] protocol::Error),
     #[error("ethereum error: {0}")]
     EthereumError(#[source] ethereum::Error),
 }
 
+impl From<crate::darkfi::Error> for Error {
+    fn from(e: crate::darkfi::Error) -> Self {
+        Error::DarkfiError(e)
+    }
+}
+
 impl From<protocol::Error> for Error {
     fn from(e: protocol::Error) -> Self {
         Error::ProtocolError(e)

+ 1 - 0
src/lib.rs

@@ -1,3 +1,4 @@
+mod darkfi;
 pub(crate) mod error;
 mod ethereum;
 pub(crate) mod protocol;

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff