From 570b20efb5079f91ab5545804ad3be2b29502efb Mon Sep 17 00:00:00 2001 From: Sun Date: Tue, 7 Dec 2021 22:33:30 +0800 Subject: [PATCH] Wallet: add generate & list --- src/apps/wallet/models.rs | 70 ++++++++++++++++++++++++++++++--------- src/apps/wallet/rpc.rs | 49 ++++++++++++++++++++++----- src/migrate.rs | 20 +++++++++++ src/migrate/account.rs | 4 ++- src/migrate/wallet.rs | 9 +++++ src/storage.rs | 10 +++++- 6 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 src/migrate/wallet.rs diff --git a/src/apps/wallet/models.rs b/src/apps/wallet/models.rs index 1926e71..6edab84 100644 --- a/src/apps/wallet/models.rs +++ b/src/apps/wallet/models.rs @@ -35,35 +35,73 @@ impl ChainToken { } } -pub(crate) struct Address { +pub(crate) struct Token { pub id: i64, - pub index: i64, pub chain: ChainToken, - pub address: String, - pub public_key: String, - pub secret_key: String, + pub contract: String, + pub decimal: i64, } -pub(crate) struct Token { +pub(crate) struct Address { pub id: i64, pub chain: ChainToken, - pub contract: String, - pub decimal: i64, + pub index: i64, + pub name: String, + pub address: String, } impl Address { - pub fn generate(index: i64, chain: ChainToken) -> Self { - let address = String::new(); - let public_key = String::new(); - let secret_key = String::new(); - + pub fn new(chain: ChainToken, index: i64, address: String) -> Self { Self { - index, chain, + index, address, - public_key, - secret_key, + name: format!("Account {}", index), id: 0, } } + + pub fn to_rpc(&self) -> RpcParam { + json!([self.id, self.chain.to_i64(), self.index, self.address]) + } + + fn from_values(mut v: Vec) -> Self { + Self { + address: v.pop().unwrap().as_string(), + name: v.pop().unwrap().as_string(), + index: v.pop().unwrap().as_i64(), + chain: ChainToken::from_i64(v.pop().unwrap().as_i64()), + id: v.pop().unwrap().as_i64(), + } + } + + pub fn insert(&mut self, db: &DStorage) -> Result<()> { + let sql = format!( + "INSERT INTO addresses (chain, indx, name, address) VALUES ({}, {}, '{}', '{}')", + self.chain.to_i64(), + self.index, + self.name, + self.address, + ); + let id = db.insert(&sql)?; + self.id = id; + Ok(()) + } + + pub fn list(db: &DStorage) -> Result> { + let matrix = db.query(&format!( + "SELECT id, chain, indx, name, address FROM addresses" + ))?; + let mut addresses = vec![]; + for values in matrix { + addresses.push(Self::from_values(values)); + } + Ok(addresses) + } + + pub fn delete(db: &DStorage, id: &i64) -> Result<()> { + let sql = format!("DELETE FROM addresses WHERE id = {}", id); + db.delete(&sql)?; + Ok(()) + } } diff --git a/src/apps/wallet/rpc.rs b/src/apps/wallet/rpc.rs index 825d481..1a5cad2 100644 --- a/src/apps/wallet/rpc.rs +++ b/src/apps/wallet/rpc.rs @@ -4,22 +4,44 @@ use tdn::types::{ primitive::HandleResult, rpc::{json, RpcError, RpcHandler, RpcParam}, }; -use tdn_did::generate_eth_account; +use tdn_did::{generate_btc_account, generate_eth_account}; use web3::signing::Key; -use crate::rpc::RpcState; +use crate::{rpc::RpcState, storage::wallet_db}; -use super::{models::ChainToken, ETH_NODE}; +use super::{ + models::{Address, ChainToken}, + ETH_NODE, +}; + +#[inline] +fn wallet_list(devices: Vec
) -> RpcParam { + let mut results = vec![]; + for wallet in devices { + results.push(wallet.to_rpc()); + } + json!(results) +} pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method("wallet-echo", |_, params, _| async move { Ok(HandleResult::rpc(json!(params))) }); + handler.add_method( + "wallet-list", + |gid: GroupId, _params: Vec, state: Arc| async move { + let db = wallet_db(state.layer.read().await.base(), &gid)?; + let addresses = Address::list(&db)?; + Ok(HandleResult::rpc(wallet_list(addresses))) + }, + ); + handler.add_method( "wallet-generate", |gid: GroupId, params: Vec, state: Arc| async move { - let lock = params[0].as_str().ok_or(RpcError::ParseError)?; + let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); + let lock = params[1].as_str().ok_or(RpcError::ParseError)?; let group_lock = state.group.read().await; let mnemonic = group_lock.mnemonic(&gid, lock)?; @@ -35,11 +57,22 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { None }; let index = 0; // TOOD - let sk = generate_eth_account(lang, &mnemonic, account_index, index, pass)?; - let address = (&sk).address(); - println!("{:?}", address); + let mut address = match chain { + ChainToken::ETH | ChainToken::ERC20 | ChainToken::ERC721 => { + let sk = generate_eth_account(lang, &mnemonic, account_index, index, pass)?; + let address = (&sk).address().to_string(); + Address::new(chain, index as i64, address) + } + ChainToken::BTC => { + let _sk = generate_btc_account(lang, &mnemonic, account_index, index, pass)?; + todo!(); + } + }; + + let db = wallet_db(state.layer.read().await.base(), &gid)?; + address.insert(&db)?; - Ok(HandleResult::rpc(json!([mnemonic]))) + Ok(HandleResult::rpc(address.to_rpc())) }, ); diff --git a/src/migrate.rs b/src/migrate.rs index bd58d15..5f518d2 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -11,6 +11,7 @@ mod file; mod group_chat; mod service; mod session; +mod wallet; use account::ACCOUNT_VERSIONS; use chat::CHAT_VERSIONS; @@ -20,6 +21,7 @@ use file::FILE_VERSIONS; use group_chat::GROUP_CHAT_VERSIONS; use service::SERVICE_VERSIONS; use session::SESSION_VERSIONS; +use wallet::WALLET_VERSIONS; use crate::apps::assistant::ASSISTANT_VERSIONS; @@ -50,6 +52,9 @@ pub(crate) const GROUP_CHAT_DB: &'static str = "group_chat.db"; /// Account's domain database name pub(crate) const DOMAIN_DB: &'static str = "domain.db"; +/// Account's domain database name +pub(crate) const WALLET_DB: &'static str = "wallet.db"; + pub(crate) fn main_migrate(path: &PathBuf) -> Result<()> { let mut db_path = path.clone(); db_path.push(ACCOUNT_DB); @@ -118,6 +123,7 @@ pub(crate) fn main_migrate(path: &PathBuf) -> Result<()> { GROUP_CHAT_DB => GROUP_CHAT_VERSIONS.as_ref(), CHAT_DB => CHAT_VERSIONS.as_ref(), DOMAIN_DB => DOMAIN_VERSIONS.as_ref(), + WALLET_DB => WALLET_VERSIONS.as_ref(), _ => { continue; } @@ -207,6 +213,12 @@ pub(crate) fn main_migrate(path: &PathBuf) -> Result<()> { DOMAIN_DB, ))?; + db.update(&format!( + "UPDATE migrates SET version = {} where db_name = '{}'", + WALLET_VERSIONS.len(), + WALLET_DB, + ))?; + db.close()?; } @@ -276,5 +288,13 @@ pub(crate) fn account_init_migrate(path: &PathBuf) -> Result<()> { for i in &DOMAIN_VERSIONS { db.execute(i)?; } + db.close()?; + + let mut db_path = path.clone(); + db_path.push(WALLET_DB); + let db = DStorage::open(db_path)?; + for i in &WALLET_VERSIONS { + db.execute(i)?; + } db.close() } diff --git a/src/migrate/account.rs b/src/migrate/account.rs index 8c9595f..dcbd49b 100644 --- a/src/migrate/account.rs +++ b/src/migrate/account.rs @@ -1,5 +1,5 @@ #[rustfmt::skip] -pub(super) const ACCOUNT_VERSIONS: [&str; 9] = [ +pub(super) const ACCOUNT_VERSIONS: [&str; 11] = [ "CREATE TABLE IF NOT EXISTS accounts( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, gid TEXT NOT NULL, @@ -24,4 +24,6 @@ pub(super) const ACCOUNT_VERSIONS: [&str; 9] = [ "INSERT INTO migrates (db_name, version) values ('assistant.db', 0)", "INSERT INTO migrates (db_name, version) values ('group_chat.db', 0)", "INSERT INTO migrates (db_name, version) values ('chat.db', 0)", + "INSERT INTO migrates (db_name, version) values ('domain.db', 0)", + "INSERT INTO migrates (db_name, version) values ('wallet.db', 0)", ]; diff --git a/src/migrate/wallet.rs b/src/migrate/wallet.rs new file mode 100644 index 0000000..0e4b818 --- /dev/null +++ b/src/migrate/wallet.rs @@ -0,0 +1,9 @@ +#[rustfmt::skip] +pub(super) const WALLET_VERSIONS: [&str; 1] = [ + "CREATE TABLE IF NOT EXISTS addresses( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + chain INTEGER NOT NULL, + indx INTEGER NOT NULL, + name TEXT NOT NULL, + address TEXT NOT NULL);", +]; diff --git a/src/storage.rs b/src/storage.rs index 289b37e..5589b0b 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -9,7 +9,7 @@ use tdn_storage::local::DStorage; use crate::migrate::{ account_init_migrate, ACCOUNT_DB, ASSISTANT_DB, CHAT_DB, CONSENSUS_DB, DOMAIN_DB, FILE_DB, - GROUP_CHAT_DB, SERVICE_DB, SESSION_DB, + GROUP_CHAT_DB, SERVICE_DB, SESSION_DB, WALLET_DB, }; const FILES_DIR: &'static str = "files"; @@ -400,6 +400,14 @@ pub(crate) fn domain_db(base: &PathBuf, gid: &GroupId) -> Result { DStorage::open(db_path) } +#[inline] +pub(crate) fn wallet_db(base: &PathBuf, gid: &GroupId) -> Result { + let mut db_path = base.clone(); + db_path.push(gid.to_hex()); + db_path.push(WALLET_DB); + DStorage::open(db_path) +} + /// account independent db and storage directory. pub(crate) async fn account_init(base: &PathBuf, gid: &GroupId) -> Result<()> { let mut db_path = base.clone();