From c1260796330053571d18b05b14a9baf22fea19b3 Mon Sep 17 00:00:00 2001 From: Sun Date: Thu, 9 Dec 2021 14:08:32 +0800 Subject: [PATCH] Wallet: main token balance fetch and show --- assets/logo/logo_erc20.png | Bin 942 -> 0 bytes lib/apps/wallet/models.dart | 51 ++++++++++++++ lib/apps/wallet/page.dart | 23 +++++-- pubspec.yaml | 1 - src/apps/wallet/mod.rs | 2 - src/apps/wallet/models.rs | 129 ++++++++++++++++++++++++++++++++++-- src/apps/wallet/rpc.rs | 91 +++++++++++++++---------- src/migrate/wallet.rs | 9 ++- 8 files changed, 253 insertions(+), 53 deletions(-) delete mode 100644 assets/logo/logo_erc20.png diff --git a/assets/logo/logo_erc20.png b/assets/logo/logo_erc20.png deleted file mode 100644 index b49d2a9635f2bd5b36a35efefdb054b98aa8df94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 942 zcmV;f15x~mP)7^O7q zn*cUx18V^Z3s)|P3Bez6#Rhh+g{8*W2D%~vT9?*DT8IH07w1g-Xz9$IX^r3HX5O6p zJ>PflefOSo-mB>hd+|Po^Ll&QmvIks_zCwr)Gxvy&f*U0h3z)ZVE0xIWCt!`DR1%z zu3!xN(O2R2rELsXv6wzfxQPDE4(1~)r06U@MNb?4JvbpAT^$cF+Ua1X@l4Ea0xxwc zgkDUEJ@yon?FwA9I->&x{Fk$}!U*P5`+VtOrqkhP3>EOZ@msd;0{&2H*A=YPs94h9 z@mhg6d}j4joi6kl6083VM>Znu5X-rQgN4F__%r?H^Lnt*_Z_jP9(ewwuHcfGEDcx(9L$ z=irC@Q?k6*le=LstKdj-uNQC!lKVZ}5GSM6sW_ZYGs;p#cXI3apar)k!o`hk1;P!~ z^LJm~=x7t}(d3kDgLUZSku}y@i@1h=@C09Fdy=+m z$$6YUt+2AGw~2xr-Y#&wi!ZTLq=`fLRph^kygrnDJCl32K(}%4Ie0xsceTKg^?|X5 zkF(Wu78t)(35-Ns`M**}uP9q)s>U-Za-vXVE0b#@N>5ddyG8kNKSx}Gttvm}@E2ZL z+u2AVQ)@e#V6z3cYdOS&v(($%g&1zoB4NTio$ z#a&a3ij7_ub@y@YeQf9zab_+x?uqY8n?j#Rzz 8) { + right = right.substring(0, 8); + } + final amount_s = left + '.' + right; + this.amount = double.parse(amount_s); + } +} diff --git a/lib/apps/wallet/page.dart b/lib/apps/wallet/page.dart index 82dc924..8466675 100644 --- a/lib/apps/wallet/page.dart +++ b/lib/apps/wallet/page.dart @@ -31,11 +31,13 @@ class _WalletDetailState extends State with SingleTickerProviderSt List _networks = []; Network? _selectedNetwork; + Token _mainToken = Token(); + List _tokens = []; + List tokens = [ - ['ETH', '100', '1000', 'assets/logo/logo_eth.png'], ['USDT', '2000', '2000', 'assets/logo/logo_tether.png'], - ['XXX', '100', '1000', 'assets/logo/logo_erc20.png'], - ['FFF', '100', '1000', 'assets/logo/logo_erc20.png'], + ['XXX', '100', '1000', 'assets/logo/logo_eth.png'], + ['FFF', '100', '1000', 'assets/logo/logo_eth.png'], ]; @override @@ -62,8 +64,17 @@ class _WalletDetailState extends State with SingleTickerProviderSt } _walletBalance(List params) { - // TODO print(params); + final address = params[0]; + final network = NetworkExtension.fromInt(params[1]); + final contract = params[2]; + final balance = params[3]; + + // TODO check token. + + this._mainToken = Token.eth(network); + this._mainToken.balance(balance); + setState(() {}); } _load() async { @@ -249,7 +260,7 @@ class _WalletDetailState extends State with SingleTickerProviderSt height: 36.0, decoration: BoxDecoration( image: DecorationImage( - image: AssetImage(tokens[0][3]), + image: AssetImage(this._mainToken.logo), fit: BoxFit.cover, ), ), @@ -258,7 +269,7 @@ class _WalletDetailState extends State with SingleTickerProviderSt height: 60.0, alignment: Alignment.center, child: Text( - '100 ETH', + "${this._mainToken.amount} ${this._mainToken.name}", style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold)), ), Text('\$1000', style: TextStyle(color: Color(0xFFADB0BB))), diff --git a/pubspec.yaml b/pubspec.yaml index 3202aa1..746db7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,7 +86,6 @@ flutter: - assets/logo/logo_wallet.png - assets/logo/logo_eth.png - assets/logo/logo_tether.png - - assets/logo/logo_erc20.png - assets/images/background_light.jpg - assets/images/background_dark.jpg - assets/images/image_missing.png diff --git a/src/apps/wallet/mod.rs b/src/apps/wallet/mod.rs index 6f2598b..3a9db84 100644 --- a/src/apps/wallet/mod.rs +++ b/src/apps/wallet/mod.rs @@ -1,6 +1,4 @@ mod models; mod rpc; -pub const ETH_NODE: &'static str = "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; - pub(crate) use rpc::new_rpc_handler; diff --git a/src/apps/wallet/models.rs b/src/apps/wallet/models.rs index a9f1379..97c193a 100644 --- a/src/apps/wallet/models.rs +++ b/src/apps/wallet/models.rs @@ -5,6 +5,22 @@ use tdn::types::{ use tdn_storage::local::{DStorage, DsValue}; +#[rustfmt::skip] +pub const ETH_NODE: &'static str = + "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; +#[rustfmt::skip] +pub const ETH_ROPSTEN: &'static str = + "https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; +#[rustfmt::skip] +pub const ETH_RINKEBY: &'static str = + "https://rinkeby.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; +#[rustfmt::skip] +pub const ETH_KOVAN: &'static str = + "https://kovan.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; +#[rustfmt::skip] +pub const ETH_LOCAL: &'static str = + "http://localhost:8545"; + pub(crate) enum ChainToken { ETH, ERC20, @@ -44,6 +60,30 @@ pub(crate) enum Network { } impl Network { + pub fn node<'a>(&self) -> &'a str { + // TODO more. + match self { + Network::EthMain => ETH_NODE, + Network::EthTestRopsten => ETH_ROPSTEN, + Network::EthTestRinkeby => ETH_RINKEBY, + Network::EthTestKovan => ETH_KOVAN, + Network::EthLocal => ETH_LOCAL, + Network::BtcMain => ETH_NODE, + Network::BtcLocal => ETH_NODE, + } + } + + pub fn chain(&self) -> ChainToken { + match self { + Network::EthMain + | Network::EthTestRopsten + | Network::EthTestRinkeby + | Network::EthTestKovan + | Network::EthLocal => ChainToken::ETH, + Network::BtcMain | Network::BtcLocal => ChainToken::BTC, + } + } + pub fn to_i64(&self) -> i64 { match self { Network::EthMain => 1, @@ -70,13 +110,6 @@ impl Network { } } -pub(crate) struct Token { - pub id: i64, - pub chain: ChainToken, - pub contract: String, - pub decimal: i64, -} - pub(crate) struct Address { pub id: i64, pub chain: ChainToken, @@ -172,3 +205,85 @@ impl Address { Ok(()) } } + +pub(crate) struct Token { + pub id: i64, + pub chain: ChainToken, + pub network: Network, + pub name: String, + pub contract: String, + pub decimal: i64, +} + +impl Token { + pub fn new( + chain: ChainToken, + network: Network, + name: String, + contract: String, + decimal: i64, + ) -> Self { + Self { + chain, + network, + name, + contract, + decimal, + id: 0, + } + } + + pub fn to_rpc(&self) -> RpcParam { + json!([ + self.id, + self.chain.to_i64(), + self.network.to_i64(), + self.name, + self.contract, + self.decimal, + ]) + } + + fn from_values(mut v: Vec) -> Self { + Self { + decimal: v.pop().unwrap().as_i64(), + contract: v.pop().unwrap().as_string(), + name: v.pop().unwrap().as_string(), + network: Network::from_i64(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 tokens (chain, network, name, contract, decimal) VALUES ({}, {}, '{}', '{}', {})", + self.chain.to_i64(), + self.network.to_i64(), + self.name, + self.contract, + self.decimal, + ); + let id = db.insert(&sql)?; + self.id = id; + Ok(()) + } + + pub fn list(db: &DStorage, network: &Network) -> Result> { + let matrix = db.query(&format!( + "SELECT id, chain, network, name, contract, decimal FROM tokens where network = {}", + network.to_i64() + ))?; + let mut tokens = vec![]; + for values in matrix { + tokens.push(Self::from_values(values)); + } + Ok(tokens) + } + + pub fn _delete(db: &DStorage, id: &i64) -> Result<()> { + let sql = format!("DELETE FROM tokens WHERE id = {}", id); + db.delete(&sql)?; + Ok(()) + } +} diff --git a/src/apps/wallet/rpc.rs b/src/apps/wallet/rpc.rs index 653c98a..23ee8a3 100644 --- a/src/apps/wallet/rpc.rs +++ b/src/apps/wallet/rpc.rs @@ -2,20 +2,17 @@ use std::sync::Arc; use tdn::types::{ group::GroupId, message::SendMessage, - primitive::HandleResult, + primitive::{HandleResult, Result}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; use tdn_did::{generate_btc_account, generate_eth_account}; use tdn_storage::local::DStorage; -use tokio::sync::mpsc::{error::SendError, Sender}; +use tokio::sync::mpsc::Sender; use web3::signing::Key; use crate::{rpc::RpcState, storage::wallet_db}; -use super::{ - models::{Address, ChainToken, Network}, - ETH_NODE, -}; +use super::models::{Address, ChainToken, Network, Token}; #[inline] fn wallet_list(devices: Vec
) -> RpcParam { @@ -26,45 +23,67 @@ fn wallet_list(devices: Vec
) -> RpcParam { json!(results) } +#[inline] +fn res_balance( + gid: GroupId, + address: &str, + network: &Network, + contract: &str, + balance: &str, +) -> RpcParam { + rpc_response( + 0, + "wallet-balance", + json!([address, network.to_i64(), contract, balance]), + gid, + ) +} + async fn loop_token( sender: Sender, - _db: DStorage, + db: DStorage, gid: GroupId, network: Network, address: String, -) -> std::result::Result<(), SendError> { +) -> Result<()> { // loop get balance of all tokens. - - match network { - Network::EthMain => { - // + let node = network.node(); + let chain = network.chain(); + let tokens = Token::list(&db, &network)?; + + match chain { + ChainToken::ETH => { + let transport = web3::transports::Http::new(node).unwrap(); + let web3 = web3::Web3::new(transport); + let balance = web3 + .eth() + .balance(address.parse().unwrap(), None) + .await + .unwrap(); + let balance = balance.to_string(); + let res = res_balance(gid, &address, &network, "", &balance); + sender.send(SendMessage::Rpc(0, res, true)).await?; + + for token in tokens { + match token.chain { + ChainToken::ERC20 => { + // + } + ChainToken::ERC721 => { + // + } + _ => { + // + } + } + } + } + ChainToken::BTC => { + // TODO } - Network::EthTestRopsten => {} - Network::EthTestRinkeby => {} - Network::EthTestKovan => {} - Network::EthLocal => {} - Network::BtcMain => {} - Network::BtcLocal => {} + _ => panic!("nerver here!"), } - let transport = web3::transports::Http::new(ETH_NODE).unwrap(); - let web3 = web3::Web3::new(transport); - - let balance = web3 - .eth() - .balance(address.parse().unwrap(), None) - .await - .unwrap(); - println!("Balance of {:?}: {}", address, balance); - - let res = rpc_response( - 0, - "wallet-balance", - json!([address, network.to_i64(), balance]), - gid, - ); - sender.send(SendMessage::Rpc(0, res, true)).await?; - Ok(()) } diff --git a/src/migrate/wallet.rs b/src/migrate/wallet.rs index bc01a98..870616d 100644 --- a/src/migrate/wallet.rs +++ b/src/migrate/wallet.rs @@ -1,5 +1,5 @@ #[rustfmt::skip] -pub(super) const WALLET_VERSIONS: [&str; 1] = [ +pub(super) const WALLET_VERSIONS: [&str; 2] = [ "CREATE TABLE IF NOT EXISTS addresses( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, chain INTEGER NOT NULL, @@ -7,4 +7,11 @@ pub(super) const WALLET_VERSIONS: [&str; 1] = [ name TEXT NOT NULL, address TEXT NOT NULL, secret TEXT NOT NULL);", + "CREATE TABLE IF NOT EXISTS tokens( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + chain INTEGER NOT NULL, + network INTEGER NOT NULL, + name TEXT NOT NULL, + contract TEXT NOT NULL, + decimal INTEGER NOT NULL);", ];