diff --git a/Cargo.lock b/Cargo.lock index 0e721e6f..ff1887cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -845,6 +845,7 @@ dependencies = [ name = "coin-ethereum" version = "0.1.0" dependencies = [ + "base64 0.13.1", "bitcoin", "bitcoin_hashes", "bytes", @@ -880,6 +881,7 @@ dependencies = [ "base32", "base64 0.13.1", "bech32 0.9.1", + "bitcoin", "bitcoin_hashes", "blake2b-rs", "bytes", @@ -944,6 +946,7 @@ name = "coin-tron" version = "0.1.0" dependencies = [ "bitcoin", + "byteorder 1.4.3", "failure", "hex", "ikc-common", @@ -2847,6 +2850,7 @@ dependencies = [ "aes-soft", "bitcoin", "block-modes", + "byteorder 1.4.3", "bytes", "failure", "hex", diff --git a/imkey-core/ikc-common/Cargo.toml b/imkey-core/ikc-common/Cargo.toml index 0123a982..f9958caa 100644 --- a/imkey-core/ikc-common/Cargo.toml +++ b/imkey-core/ikc-common/Cargo.toml @@ -32,3 +32,4 @@ aes-soft = "=0.6.4" block-modes = "=0.7.0" parking_lot = "=0.12.1" bitcoin = "=0.29.2" +byteorder = "=1.4.3" diff --git a/imkey-core/ikc-common/src/path.rs b/imkey-core/ikc-common/src/path.rs index c0d6db1a..1d1d9cf6 100644 --- a/imkey-core/ikc-common/src/path.rs +++ b/imkey-core/ikc-common/src/path.rs @@ -1,12 +1,13 @@ use crate::error::CommonError; use crate::Result; use regex::Regex; +use std::str::FromStr; pub fn check_path_validity(path: &str) -> Result<()> { //check depth and length let strings: Vec<&str> = path.split("/").collect(); let depth = strings.len(); - if depth < 2 || depth > 10 || path.len() > 100 { + if !(2..=10).contains(&depth) || path.len() > 100 { return Err(CommonError::ImkeyPathIllegal.into()); } //regx check @@ -17,6 +18,50 @@ pub fn check_path_validity(path: &str) -> Result<()> { Ok(()) } +pub fn check_path_max_five_depth(path: &str) -> Result<()> { + //check depth and length + let strings: Vec<&str> = path.split("/").collect(); + let depth = strings.len(); + if !(2..=6).contains(&depth) || path.len() > 100 { + return Err(CommonError::ImkeyPathIllegal.into()); + } + //regx check + let re = Regex::new(r"^m/[0-9'/]+$").unwrap(); + if !re.is_match(path) { + return Err(CommonError::ImkeyPathIllegal.into()); + } + Ok(()) +} + +pub fn get_account_path(path: &str) -> Result { + // example: m/44'/60'/0'/0/0 + let _ = bitcoin::util::bip32::DerivationPath::from_str(path)?; + let mut children: Vec<&str> = path.split('/').collect(); + + ensure!(children.len() >= 4, format!("{} path is too short", path)); + + while children.len() > 4 { + children.remove(children.len() - 1); + } + Ok(children.join("/")) +} + +/** +get parent public key path + */ +pub fn get_parent_path(path: &str) -> Result<&str> { + if path.is_empty() { + return Err(CommonError::ImkeyPathIllegal.into()); + } + + let mut end_flg = path.rfind("/").unwrap(); + if path.ends_with("/") { + let path = &path[..path.len() - 1]; + end_flg = path.rfind("/").unwrap(); + } + Ok(&path[..end_flg]) +} + #[cfg(test)] mod test { use crate::path::check_path_validity; @@ -25,5 +70,7 @@ mod test { fn check_path_validity_test() { assert!(check_path_validity("m/44'/0'/0'").is_ok()); assert!(check_path_validity("m/44a'/0'/0'").is_err()); + assert!(check_path_validity("m/44'/0'/0'/0'/0'").is_ok()); + assert!(check_path_validity("m/44'/0'/0'/0'/0'/0'").is_err()); } } diff --git a/imkey-core/ikc-common/src/utility.rs b/imkey-core/ikc-common/src/utility.rs index 0ca7ca2d..85af2e5a 100644 --- a/imkey-core/ikc-common/src/utility.rs +++ b/imkey-core/ikc-common/src/utility.rs @@ -1,4 +1,7 @@ use crate::Result; +use bitcoin::util::base58; +use bitcoin::util::bip32::ExtendedPubKey; +use byteorder::{BigEndian, ByteOrder}; use num_bigint::BigInt; use num_integer::Integer; use num_traits::{FromPrimitive, Num, Zero}; @@ -118,17 +121,41 @@ pub fn retrieve_recid(msg: &[u8], sign_compact: &[u8], pubkey: &Vec) -> Resu Ok(rec_id) } -pub fn get_account_path(path: &str) -> Result { - // example: m/44'/60'/0'/0/0 - let _ = bitcoin::util::bip32::DerivationPath::from_str(path)?; - let mut children: Vec<&str> = path.split('/').collect(); +pub fn to_ss58check_with_version(extended_key: ExtendedPubKey, version: &[u8]) -> String { + let mut ret = [0; 78]; + // let extended_key = self.0; + ret[0..4].copy_from_slice(version); + ret[4] = extended_key.depth; + ret[5..9].copy_from_slice(&extended_key.parent_fingerprint[..]); - ensure!(children.len() >= 4, format!("{} path is too short", path)); + BigEndian::write_u32(&mut ret[9..13], u32::from(extended_key.child_number)); - while children.len() > 4 { - children.remove(children.len() - 1); - } - Ok(children.join("/")) + ret[13..45].copy_from_slice(&extended_key.chain_code[..]); + ret[45..78].copy_from_slice(&extended_key.public_key.serialize()[..]); + base58::check_encode_slice(&ret[..]) +} + +pub fn get_ext_version(network: &str, derivation_path: &str) -> Result> { + let ret = if derivation_path.starts_with("m/49'") { + if network == "MAINNET" { + hex_to_bytes("049d7cb2")? + } else { + hex_to_bytes("044a5262")? + } + } else if derivation_path.starts_with("m/84'") { + if network == "MAINNET" { + hex_to_bytes("04b24746")? + } else { + hex_to_bytes("045f1cf6")? + } + } else { + if network == "MAINNET" { + hex_to_bytes("0488b21e").unwrap() + } else { + hex_to_bytes("043587cf").unwrap() + } + }; + Ok(ret) } #[cfg(test)] diff --git a/imkey-core/ikc-device/src/device_binding.rs b/imkey-core/ikc-device/src/device_binding.rs index bd77e879..e88cc7ab 100644 --- a/imkey-core/ikc-device/src/device_binding.rs +++ b/imkey-core/ikc-device/src/device_binding.rs @@ -243,7 +243,7 @@ pub fn bind_test() { // pub const TEST_KEY_PATH: &str = "/tmp/"; // pub const TEST_BIND_CODE: &str = "MCYNK5AH"; pub const TEST_KEY_PATH: &str = "/tmp/"; -pub const TEST_BIND_CODE: &str = "DJKP4NUR"; +pub const TEST_BIND_CODE: &str = "7FVRAJJ7"; #[cfg(test)] mod test { diff --git a/imkey-core/ikc-proto/build.rs b/imkey-core/ikc-proto/build.rs index 409c7e62..ca162fca 100644 --- a/imkey-core/ikc-proto/build.rs +++ b/imkey-core/ikc-proto/build.rs @@ -4,7 +4,7 @@ extern crate prost_build; fn main() { // tcx-api env::set_var("OUT_DIR", "../ikc/src"); - prost_build::compile_protos(&["src/ikc.proto"], &["src/"]).unwrap(); + prost_build::compile_protos(&["src/api.proto"], &["src/"]).unwrap(); // common env::set_var("OUT_DIR", "../ikc-common/src"); diff --git a/imkey-core/ikc-proto/src/ikc.proto b/imkey-core/ikc-proto/src/api.proto similarity index 77% rename from imkey-core/ikc-proto/src/ikc.proto rename to imkey-core/ikc-proto/src/api.proto index e4852cf0..8fb7e8e9 100644 --- a/imkey-core/ikc-proto/src/ikc.proto +++ b/imkey-core/ikc-proto/src/api.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package ikc; +package api; import "google/protobuf/any.proto"; @@ -100,4 +100,31 @@ message BtcForkWallet { string chainType = 2; string address = 3; string encXPub = 4; +} + +message DeriveAccountsParam { + message Derivation { + string chainType = 1; + string path = 2; + string network = 3; + string segWit = 4; + string chainId = 5; + string curve = 6; + string bech32Prefix = 7; + } + repeated Derivation derivations= 3; +} + +message AccountResponse { + string chainType = 1; + string address = 2; + string path = 3; + string curve = 4; + string publicKey = 5; + string extendedPublicKey = 6; + string encryptedExtendedPublicKey = 7; +} + +message DeriveAccountsResult { + repeated AccountResponse accounts = 1; } \ No newline at end of file diff --git a/imkey-core/ikc-wallet/coin-bitcoin/src/address.rs b/imkey-core/ikc-wallet/coin-bitcoin/src/address.rs index 5c3dbbf1..dcb091f0 100644 --- a/imkey-core/ikc-wallet/coin-bitcoin/src/address.rs +++ b/imkey-core/ikc-wallet/coin-bitcoin/src/address.rs @@ -101,6 +101,17 @@ impl BtcAddress { Ok(Address::p2shwpkh(&pub_key_obj, network)?.to_string()) } + pub fn get_pub_key(path: &str) -> Result { + //path check + check_path_validity(path)?; + + //get xpub + let xpub_data = get_xpub_data(path, true)?; + let pub_key = &xpub_data[..130]; + + Ok(pub_key.to_string()) + } + /** get parent public key path */ diff --git a/imkey-core/ikc-wallet/coin-btc-fork/src/address.rs b/imkey-core/ikc-wallet/coin-btc-fork/src/address.rs index 94589ff0..9c926365 100644 --- a/imkey-core/ikc-wallet/coin-btc-fork/src/address.rs +++ b/imkey-core/ikc-wallet/coin-btc-fork/src/address.rs @@ -16,6 +16,7 @@ use ikc_common::error::{CoinError, CommonError}; use ikc_common::path::check_path_validity; use bech32::{u5, ToBase32, Variant}; +use ikc_common::utility::uncompress_pubkey_2_compress; use std::fmt::{Display, Formatter}; use std::str::FromStr; @@ -172,6 +173,19 @@ impl BtcForkAddress { addr.network.network == coin.network } } + + pub fn get_pub_key(path: &str) -> Result { + check_path_validity(path)?; + + let xpub_data = get_xpub_data(path, true)?; + let pub_key = uncompress_pubkey_2_compress(&xpub_data[..130]); + + if pub_key.starts_with("0x") { + Ok(pub_key) + } else { + Ok(format!("0x{}", pub_key)) + } + } } impl FromStr for BtcForkAddress { diff --git a/imkey-core/ikc-wallet/coin-ckb/src/address.rs b/imkey-core/ikc-wallet/coin-ckb/src/address.rs index 862b7aa5..a968b5d2 100644 --- a/imkey-core/ikc-wallet/coin-ckb/src/address.rs +++ b/imkey-core/ikc-wallet/coin-ckb/src/address.rs @@ -32,7 +32,7 @@ impl CkbAddress { } pub fn get_public_key(path: &str) -> Result { - check_path_validity(path).expect("check path error"); + check_path_validity(path)?; let select_apdu = Apdu::select_applet(NERVOS_AID); let select_response = send_apdu(select_apdu)?; diff --git a/imkey-core/ikc-wallet/coin-cosmos/src/address.rs b/imkey-core/ikc-wallet/coin-cosmos/src/address.rs index c04cc726..6252fbcd 100644 --- a/imkey-core/ikc-wallet/coin-cosmos/src/address.rs +++ b/imkey-core/ikc-wallet/coin-cosmos/src/address.rs @@ -1,14 +1,19 @@ use crate::Result; use bech32::{encode, ToBase32, Variant}; +use bitcoin::util::bip32::{ChainCode, ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint}; +use bitcoin::Network; use bitcoin_hashes::hex::{FromHex, ToHex}; use bitcoin_hashes::{hash160, Hash}; use hex; use ikc_common::apdu::{ApduCheck, CoinCommonApdu, CosmosApdu}; use ikc_common::error::CoinError; use ikc_common::path; +use ikc_common::path::{check_path_validity, get_parent_path}; use ikc_common::utility; use ikc_device::device_binding::KEY_MANAGER; use ikc_transport::message; +use secp256k1::PublicKey; +use std::str::FromStr; #[derive(Debug)] pub struct CosmosAddress {} @@ -40,17 +45,13 @@ impl CosmosAddress { return Err(CoinError::ImkeySignatureVerifyFail.into()); } - let uncomprs_pubkey: String = res_msg_pubkey - .chars() - .take(res_msg_pubkey.len() - 4) - .collect(); - let comprs_pubkey = utility::uncompress_pubkey_2_compress(&uncomprs_pubkey); - - Ok(comprs_pubkey) + Ok(sign_source_val.to_string()) } pub fn get_address(path: &str) -> Result { - let comprs_pubkey = CosmosAddress::get_pub_key(path).unwrap(); + // let comprs_pubkey = CosmosAddress::get_pub_key(path)?; + let comprs_pubkey = + utility::uncompress_pubkey_2_compress(&CosmosAddress::get_pub_key(path)?); //hash160 let pub_key_bytes = hex::decode(comprs_pubkey).unwrap(); let pub_key_hash = hash160::Hash::hash(&pub_key_bytes).to_hex(); @@ -66,6 +67,54 @@ impl CosmosAddress { ApduCheck::check_response(&res_reg)?; Ok(address) } + + pub fn get_xpub(path: &str) -> Result { + //path check + check_path_validity(path)?; + + //get xpub data + let xpub_data = Self::get_pub_key(path)?; + let xpub_data = &xpub_data[..194]; + + //get public key and chain code + let pub_key = &xpub_data[..130]; + let sub_chain_code = &xpub_data[130..]; + let pub_key_obj = PublicKey::from_str(pub_key)?; + + //build parent public key obj + let parent_xpub_data = Self::get_pub_key(get_parent_path(path)?)?; + let parent_xpub_data = &parent_xpub_data[..194]; + let parent_pub_key = &parent_xpub_data[..130]; + let parent_chain_code = &parent_xpub_data[130..]; + let parent_pub_key_obj = PublicKey::from_str(parent_pub_key)?; + + //get parent public key fingerprint + let parent_chain_code = ChainCode::from(hex::decode(parent_chain_code)?.as_slice()); + let parent_ext_pub_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: 0 as u8, + parent_fingerprint: Fingerprint::default(), + child_number: ChildNumber::from_normal_idx(0).unwrap(), + public_key: parent_pub_key_obj, + chain_code: parent_chain_code, + }; + let fingerprint_obj = parent_ext_pub_key.fingerprint(); + + //build extend public key obj + let sub_chain_code_obj = ChainCode::from(hex::decode(sub_chain_code)?.as_slice()); + + let chain_number_vec: Vec = DerivationPath::from_str(path)?.into(); + let extend_public_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: chain_number_vec.len() as u8, + parent_fingerprint: fingerprint_obj, + child_number: *chain_number_vec.get(chain_number_vec.len() - 1).unwrap(), + public_key: pub_key_obj, + chain_code: sub_chain_code_obj, + }; + //get and return xpub + Ok(extend_public_key.to_string()) + } } #[cfg(test)] @@ -82,7 +131,7 @@ mod tests { let comprs_pubkey = CosmosAddress::get_pub_key(constants::COSMOS_PATH).unwrap(); assert_eq!( &comprs_pubkey, - "0232C1EF21D73C19531B0AA4E863CF397C2B982B2F958F60CDB62969824C096D65" + "0432C1EF21D73C19531B0AA4E863CF397C2B982B2F958F60CDB62969824C096D658AEDE012F4A4B2E3A893B71A787617FEB04F19D2E3BAC5CEE989AA55E8057458CCAAB803B2556DC264D2EE7836AC20B3E2FADB725DA9167F87BD10013D9E48F3" ); } diff --git a/imkey-core/ikc-wallet/coin-eos/src/pubkey.rs b/imkey-core/ikc-wallet/coin-eos/src/pubkey.rs index 6e745686..8fa0377f 100644 --- a/imkey-core/ikc-wallet/coin-eos/src/pubkey.rs +++ b/imkey-core/ikc-wallet/coin-eos/src/pubkey.rs @@ -1,10 +1,15 @@ use crate::Result; +use bitcoin::secp256k1::PublicKey; use bitcoin::util::base58; +use bitcoin::util::bip32::{ChainCode, ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint}; +use bitcoin::Network; use bitcoin_hashes::{ripemd160, Hash}; use ikc_common::apdu::{ApduCheck, CoinCommonApdu, EosApdu}; +use ikc_common::path::{check_path_validity, get_parent_path}; use ikc_common::{path, utility}; use ikc_device::device_binding::KEY_MANAGER; use ikc_transport::message; +use std::str::FromStr; #[derive(Debug)] pub struct EosPubkey {} @@ -54,6 +59,83 @@ impl EosPubkey { Ok(eos_pk) } + pub fn get_sub_pubkey(path: &str) -> Result { + path::check_path_validity(path)?; + + let select_apdu = EosApdu::select_applet(); + let select_response = message::send_apdu(select_apdu)?; + ApduCheck::check_response(&select_response)?; + + //get public key + let msg_pubkey = EosApdu::get_xpub(&path, true); + let res_msg_pubkey = message::send_apdu(msg_pubkey)?; + ApduCheck::check_response(&res_msg_pubkey)?; + + let sign_source_val = &res_msg_pubkey[..194]; + let sign_result = &res_msg_pubkey[194..res_msg_pubkey.len() - 4]; + + let key_manager_obj = KEY_MANAGER.lock(); + + //use se public key verify sign + let sign_verify_result = utility::secp256k1_sign_verify( + &key_manager_obj.se_pub_key, + hex::decode(sign_result).unwrap().as_slice(), + hex::decode(sign_source_val).unwrap().as_slice(), + )?; + if !sign_verify_result { + return Err(format_err!("imkey_signature_verify_fail")); + } + + Ok(sign_source_val.to_string()) + } + + pub fn get_xpub(path: &str) -> Result { + //path check + check_path_validity(path)?; + + //get xpub data + let xpub_data = Self::get_sub_pubkey(path)?; + + //get public key and chain code + let pub_key = &xpub_data[..130]; + let sub_chain_code = &xpub_data[130..]; + let pub_key_obj = PublicKey::from_str(pub_key)?; + + //build parent public key obj + let parent_xpub_data = Self::get_sub_pubkey(get_parent_path(path)?)?; + let parent_xpub_data = &parent_xpub_data[..194]; + let parent_pub_key = &parent_xpub_data[..130]; + let parent_chain_code = &parent_xpub_data[130..]; + let parent_pub_key_obj = PublicKey::from_str(parent_pub_key)?; + + //get parent public key fingerprint + let parent_chain_code = ChainCode::from(hex::decode(parent_chain_code)?.as_slice()); + let parent_ext_pub_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: 0 as u8, + parent_fingerprint: Fingerprint::default(), + child_number: ChildNumber::from_normal_idx(0).unwrap(), + public_key: parent_pub_key_obj, + chain_code: parent_chain_code, + }; + let fingerprint_obj = parent_ext_pub_key.fingerprint(); + + //build extend public key obj + let sub_chain_code_obj = ChainCode::from(hex::decode(sub_chain_code)?.as_slice()); + + let chain_number_vec: Vec = DerivationPath::from_str(path)?.into(); + let extend_public_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: chain_number_vec.len() as u8, + parent_fingerprint: fingerprint_obj, + child_number: *chain_number_vec.get(chain_number_vec.len() - 1).unwrap(), + public_key: pub_key_obj, + chain_code: sub_chain_code_obj, + }; + //get and return xpub + Ok(extend_public_key.to_string()) + } + pub fn pubkey_from_response(response: &str) -> Result { //compressed key let uncomprs_pubkey: String = response.chars().take(response.len() - 4).collect(); diff --git a/imkey-core/ikc-wallet/coin-ethereum/Cargo.toml b/imkey-core/ikc-wallet/coin-ethereum/Cargo.toml index 876d9389..d3ece8d8 100644 --- a/imkey-core/ikc-wallet/coin-ethereum/Cargo.toml +++ b/imkey-core/ikc-wallet/coin-ethereum/Cargo.toml @@ -32,4 +32,5 @@ num-traits = "=0.2.15" num-integer = "=0.1.45" bytes = "=1.4.0" prost = "=0.11.2" -prost-types = "=0.11.2" \ No newline at end of file +prost-types = "=0.11.2" +base64 = "=0.13.1" \ No newline at end of file diff --git a/imkey-core/ikc-wallet/coin-ethereum/src/address.rs b/imkey-core/ikc-wallet/coin-ethereum/src/address.rs index 37c49ead..180ff240 100644 --- a/imkey-core/ikc-wallet/coin-ethereum/src/address.rs +++ b/imkey-core/ikc-wallet/coin-ethereum/src/address.rs @@ -1,11 +1,15 @@ use crate::Result; +use bitcoin::util::bip32::{ChainCode, ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint}; +use bitcoin::Network; use hex; use ikc_common::apdu::{ApduCheck, CoinCommonApdu, EthApdu}; -use ikc_common::path::check_path_validity; +use ikc_common::path::{check_path_validity, get_parent_path}; use ikc_common::utility::hex_to_bytes; use ikc_transport::message::send_apdu; use keccak_hash::keccak; use regex::Regex; +use secp256k1::PublicKey; +use std::str::FromStr; #[derive(Debug)] pub struct EthAddress {} @@ -68,6 +72,69 @@ impl EthAddress { ApduCheck::check_response(&res_reg)?; Ok(address) } + + pub fn get_pub_key(path: &str) -> Result { + check_path_validity(path)?; + + let select_apdu = EthApdu::select_applet(); + let select_response = send_apdu(select_apdu)?; + ApduCheck::check_response(&select_response)?; + + //get public + let msg_pubkey = EthApdu::get_xpub(&path, false); + let res_msg_pubkey = send_apdu(msg_pubkey)?; + ApduCheck::check_response(&res_msg_pubkey)?; + + Ok(res_msg_pubkey[..194].to_string()) + } + + pub fn get_xpub(path: &str) -> Result { + //path check + check_path_validity(path)?; + + //get xpub data + let xpub_data = Self::get_pub_key(path)?; + let xpub_data = &xpub_data[..194]; + + //get public key and chain code + let pub_key = &xpub_data[..130]; + let sub_chain_code = &xpub_data[130..]; + let pub_key_obj = PublicKey::from_str(pub_key)?; + + //build parent public key obj + let parent_xpub_data = Self::get_pub_key(get_parent_path(path)?)?; + let parent_xpub_data = &parent_xpub_data[..194]; + let parent_pub_key = &parent_xpub_data[..130]; + let parent_chain_code = &parent_xpub_data[130..]; + let parent_pub_key_obj = PublicKey::from_str(parent_pub_key)?; + + //get parent public key fingerprint + let parent_chain_code = ChainCode::from(hex::decode(parent_chain_code)?.as_slice()); + let parent_ext_pub_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: 0 as u8, + parent_fingerprint: Fingerprint::default(), + child_number: ChildNumber::from_normal_idx(0).unwrap(), + public_key: parent_pub_key_obj, + chain_code: parent_chain_code, + }; + let fingerprint_obj = parent_ext_pub_key.fingerprint(); + + //build extend public key obj + let sub_chain_code_obj = ChainCode::from(hex::decode(sub_chain_code)?.as_slice()); + + let chain_number_vec: Vec = DerivationPath::from_str(path)?.into(); + let extend_public_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: chain_number_vec.len() as u8, + parent_fingerprint: fingerprint_obj, + child_number: *chain_number_vec.get(chain_number_vec.len() - 1).unwrap(), + public_key: pub_key_obj, + chain_code: sub_chain_code_obj, + }; + //get and return xpub + Ok(extend_public_key.to_string()) + } } #[cfg(test)] diff --git a/imkey-core/ikc-wallet/coin-filecoin/Cargo.toml b/imkey-core/ikc-wallet/coin-filecoin/Cargo.toml index 6c282085..94249ece 100644 --- a/imkey-core/ikc-wallet/coin-filecoin/Cargo.toml +++ b/imkey-core/ikc-wallet/coin-filecoin/Cargo.toml @@ -40,4 +40,5 @@ forest_encoding = "=0.2.2" forest_cid = "=0.3.0" forest_crypto = "=0.5.3" num_bigint_chainsafe = { package = "forest_bigint", version = "=0.1.4"} +bitcoin = "=0.29.2" diff --git a/imkey-core/ikc-wallet/coin-filecoin/src/address.rs b/imkey-core/ikc-wallet/coin-filecoin/src/address.rs index 931d0ddb..34f1e3ee 100644 --- a/imkey-core/ikc-wallet/coin-filecoin/src/address.rs +++ b/imkey-core/ikc-wallet/coin-filecoin/src/address.rs @@ -1,15 +1,20 @@ use crate::utils::{digest, HashSize}; use crate::Result; +use std::str::FromStr; use base32::Alphabet; +use bitcoin::util::bip32::{ChainCode, ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint}; +use bitcoin::Network; use hex; use ikc_common::apdu::{Apdu, ApduCheck, Secp256k1Apdu}; use ikc_common::constants::FILECOIN_AID; use ikc_common::error::CoinError; use ikc_common::path; +use ikc_common::path::{check_path_validity, get_parent_path}; use ikc_common::utility; use ikc_device::device_binding::KEY_MANAGER; use ikc_transport::message; +use secp256k1::PublicKey; const MAINNET_PREFIX: &'static str = "f"; const TESTNET_PREFIX: &'static str = "t"; @@ -59,7 +64,7 @@ impl FilecoinAddress { return Err(CoinError::ImkeySignatureVerifyFail.into()); } - let uncomprs_pubkey: String = res_msg_pubkey.chars().take(130).collect(); + let uncomprs_pubkey: String = res_msg_pubkey.chars().take(194).collect(); Ok(uncomprs_pubkey) } @@ -78,7 +83,7 @@ impl FilecoinAddress { }; let uncomprs_pubkey = Self::get_pub_key(path).unwrap(); - let pub_key_bytes = hex::decode(uncomprs_pubkey).unwrap(); + let pub_key_bytes = hex::decode(&uncomprs_pubkey[..130]).unwrap(); let protocol = Protocol::Secp256k1; let payload = Self::address_hash(&pub_key_bytes); @@ -104,6 +109,54 @@ impl FilecoinAddress { ApduCheck::check_response(&res_reg)?; Ok(address) } + + pub fn get_xpub(network: Network, path: &str) -> Result { + //path check + check_path_validity(path)?; + + //get xpub data + let xpub_data = Self::get_pub_key(path)?; + let xpub_data = &xpub_data[..194]; + + //get public key and chain code + let pub_key = &xpub_data[..130]; + let sub_chain_code = &xpub_data[130..]; + let pub_key_obj = PublicKey::from_str(pub_key)?; + + //build parent public key obj + let parent_xpub_data = Self::get_pub_key(get_parent_path(path)?)?; + let parent_xpub_data = &parent_xpub_data[..194]; + let parent_pub_key = &parent_xpub_data[..130]; + let parent_chain_code = &parent_xpub_data[130..]; + let parent_pub_key_obj = PublicKey::from_str(parent_pub_key)?; + + //get parent public key fingerprint + let parent_chain_code = ChainCode::from(hex::decode(parent_chain_code)?.as_slice()); + let parent_ext_pub_key = ExtendedPubKey { + network, + depth: 0 as u8, + parent_fingerprint: Fingerprint::default(), + child_number: ChildNumber::from_normal_idx(0).unwrap(), + public_key: parent_pub_key_obj, + chain_code: parent_chain_code, + }; + let fingerprint_obj = parent_ext_pub_key.fingerprint(); + + //build extend public key obj + let sub_chain_code_obj = ChainCode::from(hex::decode(sub_chain_code)?.as_slice()); + + let chain_number_vec: Vec = DerivationPath::from_str(path)?.into(); + let extend_public_key = ExtendedPubKey { + network, + depth: chain_number_vec.len() as u8, + parent_fingerprint: fingerprint_obj, + child_number: *chain_number_vec.get(chain_number_vec.len() - 1).unwrap(), + public_key: pub_key_obj, + chain_code: sub_chain_code_obj, + }; + //get and return xpub + Ok(extend_public_key.to_string()) + } } #[cfg(test)] @@ -119,7 +172,7 @@ mod test { let uncomprs_pubkey = FilecoinAddress::get_pub_key(constants::FILECOIN_PATH).unwrap(); assert_eq!( &uncomprs_pubkey, - "044B9C3C0E1CEFD90897798E7CE471FEFF0D1BE4C6BA24061D7D9F68CFDB19A0EC0192392A94B121743ADB91C7029C6F3C80FD18B6E34E8B8F9EA87E559C68FDC4" + "044B9C3C0E1CEFD90897798E7CE471FEFF0D1BE4C6BA24061D7D9F68CFDB19A0EC0192392A94B121743ADB91C7029C6F3C80FD18B6E34E8B8F9EA87E559C68FDC41F7C8E9139DB9850A4E4AD3B91713D9ABD0C887141EBE0EBBD3B607FBC91B017" ); } diff --git a/imkey-core/ikc-wallet/coin-substrate/src/address.rs b/imkey-core/ikc-wallet/coin-substrate/src/address.rs index 43c42b40..9835586b 100644 --- a/imkey-core/ikc-wallet/coin-substrate/src/address.rs +++ b/imkey-core/ikc-wallet/coin-substrate/src/address.rs @@ -2,13 +2,14 @@ use crate::Result; use ikc_common::apdu::{Apdu, ApduCheck, Ed25519Apdu}; use ikc_common::constants::{KUSAMA_AID, POLKADOT_AID}; use ikc_common::error::CoinError; -use ikc_common::path::check_path_validity; +use ikc_common::path::check_path_max_five_depth; use ikc_common::utility::{secp256k1_sign, secp256k1_sign_verify}; use ikc_device::device_binding::KEY_MANAGER; use ikc_transport::message::send_apdu; use sp_core::crypto::{Ss58AddressFormat, Ss58Codec}; use sp_core::ed25519::Public; use sp_core::ByteArray; +use std::str::FromStr; pub struct SubstrateAddress(); impl SubstrateAddress { @@ -27,7 +28,7 @@ impl SubstrateAddress { } pub fn get_public_key(path: &str, address_type: &AddressType) -> Result { - check_path_validity(path).expect("check path error"); + // check_path_max_five_depth(path)?; let aid = match address_type { AddressType::Polkadot => POLKADOT_AID, @@ -94,6 +95,17 @@ pub enum AddressType { Kusama, } +impl FromStr for AddressType { + type Err = failure::Error; + fn from_str(s: &str) -> Result { + match s { + "POLKADOT" => Ok(AddressType::Polkadot), + "KUSAMA" => Ok(AddressType::Kusama), + _ => Err(CoinError::AddressTypeMismatch.into()), + } + } +} + #[cfg(test)] mod test { use crate::address::{AddressType, SubstrateAddress}; diff --git a/imkey-core/ikc-wallet/coin-tezos/src/address.rs b/imkey-core/ikc-wallet/coin-tezos/src/address.rs index 8249eb7b..442d4791 100644 --- a/imkey-core/ikc-wallet/coin-tezos/src/address.rs +++ b/imkey-core/ikc-wallet/coin-tezos/src/address.rs @@ -32,7 +32,7 @@ impl TezosAddress { Ok(address) } - fn get_pub_key(path: &str) -> Result { + pub fn get_pub_key(path: &str) -> Result { //path check check_path_validity(path)?; diff --git a/imkey-core/ikc-wallet/coin-tron/Cargo.toml b/imkey-core/ikc-wallet/coin-tron/Cargo.toml index 57c798bb..0fc644c7 100644 --- a/imkey-core/ikc-wallet/coin-tron/Cargo.toml +++ b/imkey-core/ikc-wallet/coin-tron/Cargo.toml @@ -16,4 +16,5 @@ ikc-device = {path = "../../ikc-device"} ikc-transport = {path = "../../ikc-transport"} prost = "=0.11.2" secp256k1 = {version ="=0.24.3", features = ["rand", "recovery"] } -tiny-keccak = { version = "=2.0.2", features = ["keccak"] } \ No newline at end of file +tiny-keccak = { version = "=2.0.2", features = ["keccak"] } +byteorder = "=1.4.3" \ No newline at end of file diff --git a/imkey-core/ikc-wallet/coin-tron/src/address.rs b/imkey-core/ikc-wallet/coin-tron/src/address.rs index f6ba76e2..34124717 100644 --- a/imkey-core/ikc-wallet/coin-tron/src/address.rs +++ b/imkey-core/ikc-wallet/coin-tron/src/address.rs @@ -1,14 +1,20 @@ use crate::Result; use bitcoin::util::base58; +use bitcoin::util::bip32::{ChainCode, ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint}; +use bitcoin::Network; +use byteorder::{BigEndian, ByteOrder}; use ikc_common::apdu::{Apdu, ApduCheck, Secp256k1Apdu}; use ikc_common::constants::TRON_AID; use ikc_common::error::CoinError; -use ikc_common::path::check_path_validity; +use ikc_common::path::{check_path_validity, get_parent_path}; use ikc_common::utility; use ikc_common::utility::secp256k1_sign; use ikc_device::device_binding::KEY_MANAGER; use ikc_transport::message::send_apdu; use keccak_hash::keccak; +use secp256k1::PublicKey; +use std::convert::TryFrom; +use std::str::FromStr; pub struct TronAddress {} @@ -21,7 +27,25 @@ impl TronAddress { } pub fn get_address(path: &str) -> Result { - check_path_validity(path).unwrap(); + check_path_validity(path)?; + + let pubkey_raw = TronAddress::get_pub_key(path)?; + + let address = TronAddress::address_from_pubkey(&pubkey_raw[..65])?; + Ok(address) + } + + pub fn display_address(path: &str) -> Result { + let address = TronAddress::get_address(path).unwrap(); + let tron_menu_name = "TRX".as_bytes(); + let reg_apdu = Secp256k1Apdu::register_address(tron_menu_name, address.as_bytes()); + let res_reg = send_apdu(reg_apdu)?; + ApduCheck::check_response(&res_reg)?; + Ok(address) + } + + pub fn get_pub_key(path: &str) -> Result> { + check_path_validity(path)?; let select_apdu = Apdu::select_applet(TRON_AID); let select_response = send_apdu(select_apdu)?; @@ -56,27 +80,66 @@ impl TronAddress { return Err(CoinError::ImkeySignatureVerifyFail.into()); } - let pubkey_raw = hex::decode(&res_msg_pubkey[..130]).unwrap(); + // Ok(hex::decode(&res_msg_pubkey[..130])?) + Ok(hex::decode(sign_source_val)?) + } - let address = TronAddress::address_from_pubkey(pubkey_raw.as_slice())?; - Ok(address) + pub fn get_xpub(path: &str) -> Result { + //path check + check_path_validity(path)?; + + let pub_key = hex::encode(Self::get_pub_key(get_parent_path(path)?)?); + let sub_pub_Key = PublicKey::from_str(&pub_key[..130])?; + let chain_code_obj = ChainCode::try_from(hex::decode(&pub_key[130..])?.as_slice())?; + let ext_pub_key = ExtendedPubKey { + network: Network::Testnet, + depth: 0u8, + parent_fingerprint: Fingerprint::default(), + child_number: ChildNumber::from_normal_idx(0).unwrap(), + public_key: sub_pub_Key, + chain_code: chain_code_obj, + }; + let fingerprint_obj = ext_pub_key.fingerprint(); + + let pub_key = hex::encode(Self::get_pub_key(path)?); + let sub_pub_Key = PublicKey::from_str(&pub_key[..130])?; + let chain_code_obj = ChainCode::try_from(hex::decode(&pub_key[130..])?.as_slice())?; + let chain_number_vec: Vec = DerivationPath::from_str(path)?.into(); + let ext_pub_key = ExtendedPubKey { + network: Network::Bitcoin, + depth: chain_number_vec.len() as u8, + parent_fingerprint: fingerprint_obj, + child_number: *chain_number_vec.get(chain_number_vec.len() - 1).unwrap(), + public_key: sub_pub_Key, + chain_code: chain_code_obj, + }; + + Ok(ext_pub_key.to_string()) } - pub fn display_address(path: &str) -> Result { - let address = TronAddress::get_address(path).unwrap(); - let tron_menu_name = "TRX".as_bytes(); - let reg_apdu = Secp256k1Apdu::register_address(tron_menu_name, address.as_bytes()); - let res_reg = send_apdu(reg_apdu)?; - ApduCheck::check_response(&res_reg)?; - Ok(address) + fn to_ss58check_with_version(extended_key: ExtendedPubKey, version: &[u8]) -> String { + let mut ret = [0; 78]; + // let extended_key = self.0; + ret[0..4].copy_from_slice(version); + ret[4] = extended_key.depth; + ret[5..9].copy_from_slice(&extended_key.parent_fingerprint[..]); + + BigEndian::write_u32(&mut ret[9..13], u32::from(extended_key.child_number)); + + ret[13..45].copy_from_slice(&extended_key.chain_code[..]); + ret[45..78].copy_from_slice(&extended_key.public_key.serialize()[..]); + base58::check_encode_slice(&ret[..]) } } #[cfg(test)] mod tests { use crate::address::TronAddress; + use bitcoin::util::bip32::ExtendedPubKey; use ikc_common::constants; + use ikc_common::path::get_account_path; use ikc_device::device_binding::bind_test; + use std::str::FromStr; #[test] fn tron_address() { @@ -102,4 +165,17 @@ mod tests { println!("address:{}", &address); assert_eq!(&address, "TY2uroBeZ5trA9QT96aEWj32XLkAAhQ9R2"); } + + #[test] + fn test_get_xpub() { + bind_test(); + let xpub = TronAddress::get_xpub(&get_account_path("m/44'/195'/0'/0/0").unwrap()).unwrap(); + println!("xpub:{}", &xpub); + let extended_pub_key = ExtendedPubKey::from_str(&xpub).unwrap(); + let res = TronAddress::to_ss58check_with_version( + extended_pub_key, + &hex::decode("043587cf").unwrap(), + ); + println!("res-->:{}", &res); + } } diff --git a/imkey-core/ikc/src/api.rs b/imkey-core/ikc/src/api.rs index acb88fbf..978d4007 100644 --- a/imkey-core/ikc/src/api.rs +++ b/imkey-core/ikc/src/api.rs @@ -3,145 +3,211 @@ /// the real action and param field is the real param of that method. /// When an error occurred, the `call_imkey_api` will return a `Response` which isSuccess field be false and error field is the reason /// which cause the error. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ImkeyAction { #[prost(string, tag = "1")] - pub method: std::string::String, + pub method: ::prost::alloc::string::String, #[prost(message, optional, tag = "2")] - pub param: ::std::option::Option<::prost_types::Any>, + pub param: ::core::option::Option<::prost_types::Any>, } /// A common response when error occurred. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ErrorResponse { #[prost(bool, tag = "1")] pub is_success: bool, #[prost(string, tag = "2")] - pub error: std::string::String, + pub error: ::prost::alloc::string::String, } -///A commonresponse when successfully ended. +/// A commonresponse when successfully ended. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CommonResponse { #[prost(string, tag = "1")] - pub result: std::string::String, + pub result: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AddressParam { #[prost(string, tag = "1")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub network: std::string::String, + pub network: ::prost::alloc::string::String, #[prost(bool, tag = "4")] pub is_seg_wit: bool, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AddressResult { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub address: std::string::String, + pub address: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PubKeyParam { #[prost(string, tag = "1")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub network: std::string::String, + pub network: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub is_seg_wit: std::string::String, + pub is_seg_wit: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PubKeyResult { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub pub_key: std::string::String, + pub pub_key: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub derived_mode: std::string::String, + pub derived_mode: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExternalAddress { #[prost(string, tag = "1")] - pub address: std::string::String, + pub address: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub derived_path: std::string::String, + pub derived_path: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub r#type: std::string::String, + pub r#type: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BitcoinWallet { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub address: std::string::String, + pub address: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub enc_x_pub: std::string::String, + pub enc_x_pub: ::prost::alloc::string::String, #[prost(message, optional, tag = "5")] - pub external_address: ::std::option::Option, + pub external_address: ::core::option::Option, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EosWallet { #[prost(string, tag = "1")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub address: std::string::String, + pub address: ::prost::alloc::string::String, #[prost(message, repeated, tag = "3")] - pub public_keys: ::std::vec::Vec, + pub public_keys: ::prost::alloc::vec::Vec, } +/// Nested message and enum types in `EosWallet`. pub mod eos_wallet { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PubKeyInfo { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub derived_mode: std::string::String, + pub derived_mode: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub public_key: std::string::String, + pub public_key: ::prost::alloc::string::String, } } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExternalAddressParam { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub network: std::string::String, + pub network: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub seg_wit: std::string::String, + pub seg_wit: ::prost::alloc::string::String, #[prost(int32, tag = "5")] pub external_idx: i32, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct InitImKeyCoreXParam { #[prost(string, tag = "1")] - pub file_dir: std::string::String, + pub file_dir: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub xpub_common_key: std::string::String, + pub xpub_common_key: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub xpub_common_iv: std::string::String, + pub xpub_common_iv: ::prost::alloc::string::String, #[prost(bool, tag = "4")] pub is_debug: bool, #[prost(string, tag = "5")] - pub system: std::string::String, + pub system: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BtcForkWallet { #[prost(string, tag = "1")] - pub path: std::string::String, + pub path: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub chain_type: std::string::String, + pub chain_type: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub address: std::string::String, + pub address: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub enc_x_pub: std::string::String, + pub enc_x_pub: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeriveAccountsParam { + #[prost(message, repeated, tag = "3")] + pub derivations: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `DeriveAccountsParam`. +pub mod derive_accounts_param { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Derivation { + #[prost(string, tag = "1")] + pub chain_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub path: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub network: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub seg_wit: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub chain_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub curve: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub bech32_prefix: ::prost::alloc::string::String, + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountResponse { + #[prost(string, tag = "1")] + pub chain_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub address: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub path: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub curve: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub public_key: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub extended_public_key: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub encrypted_extended_public_key: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeriveAccountsResult { + #[prost(message, repeated, tag = "1")] + pub accounts: ::prost::alloc::vec::Vec, } diff --git a/imkey-core/ikc/src/bch_address.rs b/imkey-core/ikc/src/bch_address.rs index 844863c0..75831450 100644 --- a/imkey-core/ikc/src/bch_address.rs +++ b/imkey-core/ikc/src/bch_address.rs @@ -4,6 +4,7 @@ use crate::message_handler::encode_message; use bitcoin::Network; use coin_bch::address::BchAddress; use coin_btc_fork::address::BtcForkAddress; +use ikc_common::path::get_account_path; pub fn get_address(param: &AddressParam) -> Result> { let network = match param.network.as_ref() { @@ -13,7 +14,7 @@ pub fn get_address(param: &AddressParam) -> Result> { }; let address = BchAddress::get_address(network, ¶m.path)?; - let account_path = ikc_common::utility::get_account_path(¶m.path)?; + let account_path = get_account_path(¶m.path)?; let enc_xpub = BtcForkAddress::get_enc_xpub(network, &account_path)?; let address_message = BtcForkWallet { diff --git a/imkey-core/ikc/src/btc_address.rs b/imkey-core/ikc/src/btc_address.rs index 4e442fee..df17202b 100644 --- a/imkey-core/ikc/src/btc_address.rs +++ b/imkey-core/ikc/src/btc_address.rs @@ -142,3 +142,21 @@ pub fn display_segwit_address(param: &AddressParam) -> Result> { }; encode_message(address_message) } + +pub fn derive_account(param: &AddressParam) -> Result> { + let network = match param.network.as_ref() { + "MAINNET" => Network::Bitcoin, + "TESTNET" => Network::Testnet, + _ => Network::Testnet, + }; + + let path = format!("{}/0/0", param.path); + let address = BtcAddress::display_segwit_address(network, &path)?; + + let address_message = AddressResult { + path: param.path.to_string(), + chain_type: param.chain_type.to_string(), + address, + }; + encode_message(address_message) +} diff --git a/imkey-core/ikc/src/btc_fork_address.rs b/imkey-core/ikc/src/btc_fork_address.rs index 3f81abb5..b77962ba 100644 --- a/imkey-core/ikc/src/btc_fork_address.rs +++ b/imkey-core/ikc/src/btc_fork_address.rs @@ -4,6 +4,7 @@ use crate::message_handler::encode_message; use bitcoin::Network; use coin_btc_fork::address::BtcForkAddress; use coin_btc_fork::btc_fork_network::network_from_param; +use ikc_common::path::get_account_path; pub fn get_address(param: &AddressParam) -> Result> { let address: String; @@ -23,7 +24,7 @@ pub fn get_address(param: &AddressParam) -> Result> { "TESTNET" => Network::Testnet, _ => Network::Testnet, }; - let account_path = ikc_common::utility::get_account_path(¶m.path)?; + let account_path = get_account_path(¶m.path)?; let enc_xpub = BtcForkAddress::get_enc_xpub(network, &account_path)?; let address_message = BtcForkWallet { diff --git a/imkey-core/ikc/src/handler.rs b/imkey-core/ikc/src/handler.rs new file mode 100644 index 00000000..5abf6252 --- /dev/null +++ b/imkey-core/ikc/src/handler.rs @@ -0,0 +1,162 @@ +use crate::api::{AccountResponse, DeriveAccountsParam, DeriveAccountsResult}; +use crate::message_handler::encode_message; +use crate::Result; +use bitcoin::util::bip32::ExtendedPubKey; +use bitcoin::Network; +use coin_bch::address::BchAddress; +use coin_bitcoin::address::BtcAddress; +use coin_btc_fork::address::BtcForkAddress; +use coin_btc_fork::btc_fork_network::network_from_param; +use coin_ckb::address::CkbAddress; +use coin_cosmos::address::CosmosAddress; +use coin_eos::pubkey::EosPubkey; +use coin_ethereum::address::EthAddress; +use coin_filecoin::address::FilecoinAddress; +use coin_substrate::address::{AddressType, SubstrateAddress}; +use coin_tron::address::TronAddress; +use ikc_common::aes::cbc::encrypt_pkcs7; +use ikc_common::path::get_account_path; +use ikc_common::utility::{ + get_ext_version, to_ss58check_with_version, uncompress_pubkey_2_compress, +}; +use prost::Message; +use std::str::FromStr; +pub(crate) fn derive_accounts(data: &[u8]) -> Result> { + let param: DeriveAccountsParam = + DeriveAccountsParam::decode(data).expect("derive_accounts param"); + let mut account_responses = vec![]; + for derivation in param.derivations { + let account_path = if "secp256k1".eq(&derivation.curve.to_lowercase()) { + get_account_path(&derivation.path)? + } else { + "".to_string() + }; + + let mut account_rsp = AccountResponse { + chain_type: derivation.chain_type.to_owned(), + path: derivation.path.to_owned(), + curve: derivation.curve, + ..Default::default() + }; + + let ext_public_key = match derivation.chain_type.as_str() { + "BITCOIN" | "LITECOIN" => { + let network = match derivation.network.as_str() { + "MAINNET" => Network::Bitcoin, + "TESTNET" => Network::Testnet, + _ => Network::Testnet, + }; + + let public_key = BtcAddress::get_pub_key(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + let btc_fork_network = network_from_param( + &derivation.chain_type, + &derivation.network, + &derivation.seg_wit, + ) + .unwrap(); + let address = match derivation.seg_wit.as_str() { + "P2WPKH" => BtcForkAddress::p2shwpkh(&btc_fork_network, &derivation.path)?, + _ => BtcForkAddress::p2pkh(&btc_fork_network, &derivation.path)?, + }; + account_rsp.address = address; + BtcAddress::get_xpub(network, &account_path)? + } + "ETHEREUM" => { + let public_key = EthAddress::get_pub_key(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key[..130]).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = EthAddress::get_address(&derivation.path)?; + CosmosAddress::get_xpub(&account_path)? + } + "COSMOS" => { + let public_key = CosmosAddress::get_pub_key(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key[..130]).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = CosmosAddress::get_address(&derivation.path)?; + CosmosAddress::get_xpub(&account_path)? + } + "FILECOIN" => { + let public_key = FilecoinAddress::get_pub_key(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key[..130]); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = + FilecoinAddress::get_address(&derivation.path, &derivation.network)?; + + let network = Network::from_str(&derivation.network.to_lowercase())?; + FilecoinAddress::get_xpub(network, &account_path)? + } + "POLKADOT" | "KUSAMA" => { + let public_key = SubstrateAddress::get_public_key( + &derivation.path, + &AddressType::from_str(&derivation.chain_type)?, + )?; + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = SubstrateAddress::get_address( + &derivation.path, + &AddressType::from_str(&derivation.chain_type)?, + )?; + "".to_string() + } + "TRON" => { + let public_key = hex::encode(TronAddress::get_pub_key(&derivation.path)?); + let public_key = uncompress_pubkey_2_compress(&public_key[..130]).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = TronAddress::get_address(&derivation.path)?; + TronAddress::get_xpub(&account_path)? + } + "NERVOS" => { + let public_key = CkbAddress::get_public_key(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = + CkbAddress::get_address(&derivation.network, &derivation.path)?; + let network = Network::from_str(&derivation.network.to_lowercase())?; + CkbAddress::get_xpub(network, &account_path)? + } + "EOS" => { + let public_key = EosPubkey::get_sub_pubkey(&derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key[..130]).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = EosPubkey::get_pubkey(&derivation.path)?; + EosPubkey::get_xpub(&account_path)? + } + "BITCOINCASH" => { + let network = match derivation.network.as_str() { + "MAINNET" => Network::Bitcoin, + "TESTNET" => Network::Testnet, + _ => Network::Testnet, + }; + let public_key = BchAddress::get_pub_key(network, &derivation.path)?; + let public_key = uncompress_pubkey_2_compress(&public_key).to_uppercase(); + account_rsp.public_key = format!("0x{}", public_key); + account_rsp.address = BchAddress::get_address(network, &derivation.path)?; + BtcAddress::get_xpub(network, &account_path)? + } + _ => return Err(format_err!("unsupported_chain_type")), + }; + + if !ext_public_key.is_empty() { + let extended_pub_key = ExtendedPubKey::from_str(&ext_public_key)?; + let ext_version = get_ext_version(&derivation.network, &account_path)?; + let ext_public_key = to_ss58check_with_version(extended_pub_key, &ext_version); + account_rsp.extended_public_key = ext_public_key.clone(); + account_rsp.encrypted_extended_public_key = encrypt_xpub(&ext_public_key)?; + } + account_responses.push(account_rsp); + } + + encode_message(DeriveAccountsResult { + accounts: account_responses, + }) +} + +fn encrypt_xpub(xpub: &str) -> Result { + let key = ikc_common::XPUB_COMMON_KEY_128.read(); + let iv = ikc_common::XPUB_COMMON_IV.read(); + let key_bytes = hex::decode(&*key)?; + let iv_bytes = hex::decode(&*iv)?; + let encrypted = encrypt_pkcs7(xpub.as_bytes(), &key_bytes, &iv_bytes)?; + Ok(base64::encode(encrypted)) +} diff --git a/imkey-core/ikc/src/ikc.rs b/imkey-core/ikc/src/ikc.rs deleted file mode 100644 index cd385493..00000000 --- a/imkey-core/ikc/src/ikc.rs +++ /dev/null @@ -1,162 +0,0 @@ -/// Action Wrapper -/// There is a `call_imkey_api` method in tcx which act as a endpoint like RPC. It accepts a `ImkeyAction` param which method field is -/// the real action and param field is the real param of that method. -/// When an error occurred, the `call_imkey_api` will return a `Response` which isSuccess field be false and error field is the reason -/// which cause the error. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ImkeyAction { - #[prost(string, tag = "1")] - pub method: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub param: ::core::option::Option<::prost_types::Any>, -} -/// A common response when error occurred. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ErrorResponse { - #[prost(bool, tag = "1")] - pub is_success: bool, - #[prost(string, tag = "2")] - pub error: ::prost::alloc::string::String, -} -/// A commonresponse when successfully ended. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CommonResponse { - #[prost(string, tag = "1")] - pub result: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddressParam { - #[prost(string, tag = "1")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub network: ::prost::alloc::string::String, - #[prost(bool, tag = "4")] - pub is_seg_wit: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddressResult { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PubKeyParam { - #[prost(string, tag = "1")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub network: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub is_seg_wit: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PubKeyResult { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub pub_key: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub derived_mode: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ExternalAddress { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub derived_path: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub r#type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BitcoinWallet { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub address: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub enc_x_pub: ::prost::alloc::string::String, - #[prost(message, optional, tag = "5")] - pub external_address: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EosWallet { - #[prost(string, tag = "1")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "3")] - pub public_keys: ::prost::alloc::vec::Vec, -} -/// Nested message and enum types in `EosWallet`. -pub mod eos_wallet { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct PubKeyInfo { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub derived_mode: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub public_key: ::prost::alloc::string::String, - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ExternalAddressParam { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub network: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub seg_wit: ::prost::alloc::string::String, - #[prost(int32, tag = "5")] - pub external_idx: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InitImKeyCoreXParam { - #[prost(string, tag = "1")] - pub file_dir: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub xpub_common_key: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub xpub_common_iv: ::prost::alloc::string::String, - #[prost(bool, tag = "4")] - pub is_debug: bool, - #[prost(string, tag = "5")] - pub system: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BtcForkWallet { - #[prost(string, tag = "1")] - pub path: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub address: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub enc_x_pub: ::prost::alloc::string::String, -} diff --git a/imkey-core/ikc/src/lib.rs b/imkey-core/ikc/src/lib.rs index dcefe0b3..1c77fc93 100644 --- a/imkey-core/ikc/src/lib.rs +++ b/imkey-core/ikc/src/lib.rs @@ -1,4 +1,7 @@ -use crate::api::{AddressParam, ErrorResponse, ExternalAddressParam, ImkeyAction, PubKeyParam}; +use crate::api::{ + AddressParam, DeriveAccountsParam, ErrorResponse, ExternalAddressParam, ImkeyAction, + PubKeyParam, +}; use failure::Error; use ikc_common::SignParam; use prost::Message; @@ -32,6 +35,7 @@ pub mod tron_address; pub mod tron_signer; use parking_lot::Mutex; +mod handler; pub mod tezos_address; pub mod tezos_signer; @@ -41,6 +45,7 @@ extern crate lazy_static; #[macro_use] extern crate failure; use crate::error_handling::{landingpad, LAST_BACKTRACE, LAST_ERROR}; +use crate::handler::derive_accounts; use crate::message_handler::encode_message; use ikc_transport::message; @@ -147,7 +152,7 @@ pub unsafe extern "C" fn call_imkey_api(hex_str: *const c_char) -> *const c_char _ => Err(format_err!("get_address unsupported_chain")), } }), - + "derive_accounts" => landingpad(|| derive_accounts(&action.param.unwrap().value)), "get_pub_key" => landingpad(|| { let param: PubKeyParam = PubKeyParam::decode(action.param.unwrap().value.as_slice()) .expect("imkey_illegal_param"); @@ -307,8 +312,10 @@ pub unsafe extern "C" fn imkey_get_last_err_message() -> *const c_char { #[cfg(test)] mod tests { use super::*; - use crate::api::CommonResponse; + use crate::api::derive_accounts_param::Derivation; + use crate::api::{CommonResponse, DeriveAccountsResult}; use ikc_device::device_binding::DeviceManage; + use ikc_device::deviceapi::{BindAcquireReq, BindCheckRes}; use ikc_transport::hid_api::hid_connect; use prost::Message; use std::ffi::{CStr, CString}; @@ -383,4 +390,336 @@ mod tests { assert_eq!("ret", ret.result) } } + + #[test] + fn get_register_address() { + hid_connect("imKey Pro").is_ok(); + let action: ImkeyAction = ImkeyAction { + method: "bind_check".to_string(), + param: None, + }; + let action = hex::encode(encode_message(action).unwrap()); + let ret_hex = unsafe { _to_str(call_imkey_api(_to_c_char(action.as_str()))) }; + let ret_bytes = hex::decode(ret_hex).unwrap(); + let bind_result: BindCheckRes = BindCheckRes::decode(ret_bytes.as_slice()).unwrap(); + if "bound_other".eq(&bind_result.bind_status) { + let param = BindAcquireReq { + bind_code: "7FVRAJJ7".to_string(), + }; + let action: ImkeyAction = ImkeyAction { + method: "bind_acquire".to_string(), + param: Some(::prost_types::Any { + type_url: "deviceapi.bind_acquire".to_string(), + value: encode_message(param).unwrap(), + }), + }; + let action = hex::encode(encode_message(action).unwrap()); + let ret_hex = unsafe { _to_str(call_imkey_api(_to_c_char(action.as_str()))) }; + let ret_bytes = hex::decode(ret_hex).unwrap(); + let bind_result: BindCheckRes = BindCheckRes::decode(ret_bytes.as_slice()).unwrap(); + assert_eq!("success", bind_result.bind_status); + } + + let derivations = vec![ + Derivation { + chain_type: "LITECOIN".to_string(), + path: "m/44'/2'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "NONE".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "LITECOIN".to_string(), + path: "m/49'/2'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "P2WPKH".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "LITECOIN".to_string(), + path: "m/49'/1'/0'/0/0".to_string(), + network: "TESTNET".to_string(), + seg_wit: "NONE".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "TRON".to_string(), + path: "m/44'/195'/0'/0/0".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "NERVOS".to_string(), + path: "m/44'/309'/0'/0/0".to_string(), + network: "TESTNET".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "FILECOIN".to_string(), + path: "m/44'/461'/0'/0/0".to_string(), + network: "TESTNET".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "COSMOS".to_string(), + path: "m/44'/118'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "EOS".to_string(), + path: "m/44'/194'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "ETHEREUM".to_string(), + path: "m/44'/60'/0'/0/0".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "BITCOIN".to_string(), + path: "m/44'/0'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "NONE".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "BITCOIN".to_string(), + path: "m/49'/0'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "P2WPKH".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "KUSAMA".to_string(), + path: "m/44'/434'/0'/0'/0'".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "ed25519".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "POLKADOT".to_string(), + path: "m/44'/354'/0'/0'/0'".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "ed25519".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "BITCOINCASH".to_string(), + path: "m/44'/145'/0'/0/0".to_string(), + network: "MAINNET".to_string(), + seg_wit: "NONE".to_string(), + chain_id: "".to_string(), + curve: "secp256k1".to_string(), + bech32_prefix: "".to_string(), + }, + ]; + let param = DeriveAccountsParam { derivations }; + let action: ImkeyAction = ImkeyAction { + method: "derive_accounts".to_string(), + param: Some(::prost_types::Any { + type_url: "deviceapi.derive_accounts".to_string(), + value: encode_message(param).unwrap(), + }), + }; + let action = hex::encode(encode_message(action).unwrap()); + let ret_hex = unsafe { _to_str(call_imkey_api(_to_c_char(action.as_str()))) }; + let ret_bytes = hex::decode(ret_hex).unwrap(); + let derived_accounts: DeriveAccountsResult = + DeriveAccountsResult::decode(ret_bytes.as_slice()).unwrap(); + + assert_eq!( + "Ldfdegx3hJygDuFDUA7Rkzjjx8gfFhP9DP", + derived_accounts.accounts[0].address + ); + assert_eq!( + "0x0289CA41680EDBC5594EE6378EBD937E42CD6B4B969E40DD82C20EF2A8AA5BAD7B", + derived_accounts.accounts[0].public_key + ); + assert_eq!("xpub6D3MqTwuLWB5veAfhDjPu1oHfS6L1imVbf22zQFWJW9EtnSmYYqiGMGkW1MCsT2HmkW872tefMY9deewW6DGd8zE7RcXVv8wKhZnbJeidjT", derived_accounts.accounts[0].extended_public_key); + assert_eq!("MwDMFXVWDEuWvBogeW1v/MOMFDnGnnflm2JAPvJaJZO4HXp8fCsWETA7u8MzOW3KaPksglpUHLN3xkDr2QWMEQq0TewFZoZ3KsjmLW0KGMRN7XQKqo/omkSEsPfalVnp9Zxm2lpxVmIacqvlernVSg==", derived_accounts.accounts[0].encrypted_extended_public_key); + + assert_eq!( + "MQHaFwU3DiWQoz48TqZHtZ4jF7tFDj9yQF", + derived_accounts.accounts[1].address + ); + assert_eq!( + "0x03ACE3B0DA84C9944A077D62FC839C95324C2BDAA01786353F5538F89FBC24F428", + derived_accounts.accounts[1].public_key + ); + assert_eq!("ypub6Y37Xmn4afXWyQduPKYWPXSbX6YUCewxo4qKJqqtKsGJzPnS95QNT261uvzfQJH95CeuGn3xEysWHau3knBKxy1tNs21HipL9cpG1LJy4Wc", derived_accounts.accounts[1].extended_public_key); + assert_eq!("ypB3aQxsFPVl6EJAnDGiGh6UaUrh1bXsGFG7teh1fOJdkdcjq8vNCNh1f4MDYrjt71xA9cZ9y2iTRuSGdU0doLJkqdQ/VkRaGOlN4fsO2L+oBqUwxKQc0iHxsjrrNEBcge//2RglytnelFnGJHmzVw==", derived_accounts.accounts[1].encrypted_extended_public_key); + + assert_eq!( + "mpke4CzhBTV2dFZpnABT9EN1kPc4vDWZxw", + derived_accounts.accounts[2].address + ); + assert_eq!( + "0x031AEE5E20399D68CF0035D1A21564868F22BC448AB205292B4279136B15ECAEBC", + derived_accounts.accounts[2].public_key + ); + assert_eq!("upub5E4woDJohDBJ2trk6HqhsvEeZXtjjWMAbHV4LWRhfR9thcpfkjJbBRnvBS21L2JjsZAGC6LhkqAoYgD5VHSXBRNW7gszbiGJP7B6CR35QhD", derived_accounts.accounts[2].extended_public_key); + assert_eq!("ZDxvs7NEiNuUO/iXWvB2WvWmxXmQ+eP2qrEZe165dWLBm0PJpeRncYu+mZVUJJe0o6QUbnVop5TRqUBmRUzcxPioSmOVlzRpxOeUBZmaUi48hIwid1ouBZZ1zakxGLLnK4DyJN9NkyNDllKqxVhpdg==", derived_accounts.accounts[2].encrypted_extended_public_key); + + assert_eq!( + "TY2uroBeZ5trA9QT96aEWj32XLkAAhQ9R2", + derived_accounts.accounts[3].address + ); + assert_eq!( + "0x037B5253C24CE2A293566F9E066051366CDA5073E4A43B25F07C990D7C9AC0AAB5", + derived_accounts.accounts[3].public_key + ); + assert_eq!("tpubDCxD6k9PreNhSacpfSZ3iErESZnncY1n7qU7e3stZXLPh84xVVt5ERMAqKeefUU8jswx2GpCkQpeYow4xH3PGx2iim6ftPa32GNvTKAtknz", derived_accounts.accounts[3].extended_public_key); + assert_eq!("A6SCjz/iYksc/3pnVnMIzXimsQAm2p4EUJ1T6fRYkeHSqtSuBcF7O2Fyt3lYbiD4RoL1wf6VfknDiLdS1mcJyD09kXl5s+fuBaklKAZ2Dh6YuGlPGJqaGnrQ/rsTJ+Adb0ZRO3F3xGadXjiGb3hTSA==", derived_accounts.accounts[3].encrypted_extended_public_key); + + assert_eq!( + "ckt1qyqtr684u76tu7r8efkd24hw8922xfvhnazskzdzy6", + derived_accounts.accounts[4].address + ); + assert_eq!( + "0x03554851980004FF256888612BF0D64D9B1002BF82331450FD5A7405D1B23CC5BD", + derived_accounts.accounts[4].public_key + ); + assert_eq!("tpubDDMZ3uNczagkRgAQBT6vmHFwM6Tc8RwYKU4ufqywmZEUNVfYNNyrVyXgmSpDTVsthVEbEzH5QjhxQPExpjBtVXVWZinpdRjiRGtpXuALuND", derived_accounts.accounts[4].extended_public_key); + assert_eq!("VXhh0t5/x2aZJI0mKfkYREXX/VWw7PVEz4Gyf1bj9DS9ETRShdPA519gJMrbw8XJVk/p8X+ixbYras39ITKtl7KOSaE+E2T126r2NAR0gXRWOLIp2rrpnVWerlBkzjkoJ1KOKIPIIYhZYP7kn+tbSQ==", derived_accounts.accounts[4].encrypted_extended_public_key); + + assert_eq!( + "t12i3bop43tprlnymx2c75u6uvlq7iur2rcd7qsey", + derived_accounts.accounts[5].address + ); + assert_eq!( + "0x03BD460186D29FD9AC68EE88B110C3ACC4A4443648A1EC7607AF9CE306AD76F785", + derived_accounts.accounts[5].public_key + ); + assert_eq!("tpubDDaEZaaDDmwnZTP6u7m3yTKFgnbSx2uTaxp1hKM5oiVZo6iBB46rWnWpdkpbPxtfdYiyLbyhqgbXRXYff3LfW4rCpYyfpb5pC67CPZdKkZB", derived_accounts.accounts[5].extended_public_key); + assert_eq!("PRImz4qL7pDJsEtqNVzVG9llzx+DN1XFbucDahOvyQ9g9yc5HWMdH6jAx4Mc/syseMWHLj9Y17Mfqib3sl88Ddgs3tTXhJq6vWToyXlQ6t9yg/LX1qKzLKcXLD+W0872G5m1urk//YOLIyhPkaLV2g==", derived_accounts.accounts[5].encrypted_extended_public_key); + + assert_eq!( + "cosmos1ajz9y0x3wekez7tz2td2j6l2dftn28v26dd992", + derived_accounts.accounts[6].address + ); + assert_eq!( + "0x0232C1EF21D73C19531B0AA4E863CF397C2B982B2F958F60CDB62969824C096D65", + derived_accounts.accounts[6].public_key + ); + assert_eq!("xpub6CrWRZY39gj49G1ipdmcVunEnb5RoTGf9o6QnJQp8c4b84V2piN1Rdy1xWVJ4P7VXNx5Ckg6rZcvSNvJtvWz8zs3RkPayHn9vMMuK9ERrFr", derived_accounts.accounts[6].extended_public_key); + assert_eq!("rJQ+jO02Yn+Rdfjn5QbStU/2aS0T5zW5HU83JoHLBZHafsr8FSdG7lPV59XAw1LwuUCMCtRBueG1iJ2AsA76PP1zyVzj0LxDIq3iHAOxBdwIZDP5C1sY+RMGwXk+6a2OwmYN/zF/q2SL8D6aeGyD9g==", derived_accounts.accounts[6].encrypted_extended_public_key); + + assert_eq!( + "EOS88XhiiP7Cu5TmAUJqHbyuhyYgd6sei68AU266PyetDDAtjmYWF", + derived_accounts.accounts[7].address + ); + assert_eq!( + "0x03AAF80E479AAC0813B17950C390A16438B307AEE9A814689D6706BE4FB4A4E30A", + derived_accounts.accounts[7].public_key + ); + assert_eq!("xpub6CUtvjXi3yjmhjaC2GxjiWE9FbQs1TrtqAgRDhB2gmDBsPzTfwqZ7MvGGYScKiVx8PBNFSmHm4mCnFDCaX23c1nJS4p8ynR2wnGne4qEEX9", derived_accounts.accounts[7].extended_public_key); + assert_eq!("jSPl9msMWjfMrj/09dRJ/epEWFnjjNHoOfro8xVrvcmhTnTC0iK+RDXXJ7iI2UpIa3ckFw7g2QGaVgODFQVLrEboEysXX5YMsPczdAUrdKh27vx5A3KMFylw2kVrUmSdoMDID8wlVfqkteyIHED0iQ==", derived_accounts.accounts[7].encrypted_extended_public_key); + + assert_eq!( + "0x6031564e7b2F5cc33737807b2E58DaFF870B590b", + derived_accounts.accounts[8].address + ); + assert_eq!( + "0x0280C98B8EA7CAB630DEFB0C09A4295C2193CDEE016C1D5B9B0CB18572B9C370FE", + derived_accounts.accounts[8].public_key + ); + assert_eq!("tpubDCvte6zYB6DKMaEy4fwyoXpuExA4ery3Hu6dVSBZeY9Rg57VKFLwNPMfywWtqRFM1Df5gQJTu42RaaNCgVEyngdVfnYRh9Kb1UCoEYojURc", derived_accounts.accounts[8].extended_public_key); + assert_eq!("w6s0ZvUoPPSiEi1xDMKy5X9+qwhcX4u3e3LOBosJaOSro2ny9jppDxcczZfrhe29n9H3UkmgNoecq/85xfXkGDtH8PMR9iclK5WrcUtkgjXsBcrR6JF0j58i4W9x3y539vXOsLMifCmUr2RcqknDgw==", derived_accounts.accounts[8].encrypted_extended_public_key); + + assert_eq!( + "12z6UzsA3tjpaeuvA2Zr9jwx19Azz74D6g", + derived_accounts.accounts[9].address + ); + assert_eq!( + "0x026B5B6A9D041BC5187E0B34F9E496436C7BFF261C6C1B5F3C06B433C61394B868", + derived_accounts.accounts[9].public_key + ); + assert_eq!("xpub6CqzLtyKdJN53jPY13W6GdyB8ZGWuFZuBPU4Xh9DXm6Q1cULVLtsyfXSjx4G77rNdCRBgi83LByaWxjtDaZfLAKT6vFUq3EhPtNwTpJigx8", derived_accounts.accounts[9].extended_public_key); + assert_eq!("BdgvWHN/Uh/K526q/+CdpGwEPZ41SvZHHGSgiSqhFesjErdbo6UnJMIoDOHV94qW8fd2KBW18UG3nTzDwS7a5oArqPtv+2aE9+1bNvCdtYoAx3979N3vbX4Xxn/najTABykXrJDjgpoaXxSo/xTktQ==", derived_accounts.accounts[9].encrypted_extended_public_key); + + assert_eq!( + "3JmreiUEKn8P3SyLYmZ7C1YCd4r2nFy3Dp", + derived_accounts.accounts[10].address + ); + assert_eq!( + "0x03036695C5F3DE2E2792B170F59679D4DB88A8516728012EAA42A22CE6F8BF593B", + derived_accounts.accounts[10].public_key + ); + assert_eq!("ypub6Wdz1gzMKLnPxXti2GbSjQGXSqrA5NMKNP3C5JS2ZJKRDEecuZH8AhSvYQs4dZHi7b6Yind7bLekuTH9fNbJcH1MXMy9meoifu2wST55sav", derived_accounts.accounts[10].extended_public_key); + assert_eq!("8mPByX5qAwVJ2bVNqDrm6Jx19osoWZwplnAESPaN//Gx3Q9Gp2Q2bqkaDsxlYaYsUKN6FRzwrJHaSKD2A9aWJ3RoTWJ9zY9g21zW4ttsXFl1CAZNIlFCC9CnXd2b89vDgqCQC/foz50TV4PUikR+/g==", derived_accounts.accounts[10].encrypted_extended_public_key); + + assert_eq!( + "Fde6T2hDvbvuQrRizcjPoQNZTxuVSbTp78zwFcxzUb86xXS", + derived_accounts.accounts[11].address + ); + assert_eq!( + "0x873CF8E52A7B93A55197EF2846E9627A6F105B0A06C86659C813F1A50438B479", + derived_accounts.accounts[11].public_key + ); + assert_eq!("", derived_accounts.accounts[11].extended_public_key); + assert_eq!( + "", + derived_accounts.accounts[11].encrypted_extended_public_key + ); + + assert_eq!( + "16NhUkUTkYsYRjMD22Sop2DF8MAXUsjPcYtgHF3t1ccmohx1", + derived_accounts.accounts[12].address + ); + assert_eq!( + "0xEDB9955556C8E07287DF95AD77FAD826168F8A50488CCE0D738DF3769E24613A", + derived_accounts.accounts[12].public_key + ); + assert_eq!("", derived_accounts.accounts[12].extended_public_key); + assert_eq!( + "", + derived_accounts.accounts[12].encrypted_extended_public_key + ); + + assert_eq!( + "qzld7dav7d2sfjdl6x9snkvf6raj8lfxjcj5fa8y2r", + derived_accounts.accounts[13].address + ); + assert_eq!( + "0x0251492DFB299F21E426307180B577F927696B6DF0B61883215F88EB9685D3D449", + derived_accounts.accounts[13].public_key + ); + assert_eq!("xpub6Bmkv3mmRZZWoFSBdj9vDMqR2PCPSP6DEj8u3bBuv44g3Ncnro6cPVqZAw6wTEcxHQuodkuJG4EmAinqrrRXGsN3HHnRRMtAvzfYTiBATV1", derived_accounts.accounts[13].extended_public_key); + assert_eq!("MwDMFXVWDEuWvBogeW1v/MOMFDnGnnflm2JAPvJaJZO4HXp8fCsWETA7u8MzOW3KaPksglpUHLN3xkDr2QWMEQq0TewFZoZ3KsjmLW0KGMRN7XQKqo/omkSEsPfalVnp9Zxm2lpxVmIacqvlernVSg==", derived_accounts.accounts[0].encrypted_extended_public_key); + } } diff --git a/imkey-core/ikc/src/nervos_address.rs b/imkey-core/ikc/src/nervos_address.rs index 44fb3592..eb9ffa88 100644 --- a/imkey-core/ikc/src/nervos_address.rs +++ b/imkey-core/ikc/src/nervos_address.rs @@ -3,6 +3,7 @@ use crate::error_handling::Result; use crate::message_handler::encode_message; use bitcoin::Network; use coin_ckb::address::CkbAddress; +use ikc_common::path::get_account_path; pub fn get_address(param: &AddressParam) -> Result> { let network = match param.network.as_ref() { @@ -12,7 +13,7 @@ pub fn get_address(param: &AddressParam) -> Result> { }; let address = CkbAddress::get_address(param.network.as_ref(), param.path.as_ref())?; - let account_path = ikc_common::utility::get_account_path(¶m.path)?; + let account_path = get_account_path(¶m.path)?; let enc_xpub = CkbAddress::get_enc_xpub(network, &account_path)?; let address_message = BtcForkWallet { diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 8a5db988..43ced2d0 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -211,7 +211,7 @@ mod tests { use tcx_tron::transaction::{TronMessageInput, TronMessageOutput, TronTxInput, TronTxOutput}; static OTHER_MNEMONIC: &'static str = - "calm release clay imitate top extend close draw quiz refuse shuffle injury"; + "inject kidney empty canal shadow pact comfort wife crush horse wife sketch"; fn _to_c_char(str: &str) -> *const c_char { CString::new(str).unwrap().into_raw() @@ -4056,4 +4056,309 @@ mod tests { assert_eq!(keystore.id(), "4b07b86f-cc3f-4bdd-b156-a69d5cbd4bca"); fs::remove_dir_all("../test-data/walletsV2").unwrap(); } + + #[test] + #[serial] + pub fn test_derive_accounts2() { + run_test(|| { + let param = ImportMnemonicParam { + mnemonic: OTHER_MNEMONIC.to_string(), + password: TEST_PASSWORD.to_string(), + network: "TESTNET".to_string(), + name: "test-wallet".to_string(), + password_hint: "imtoken".to_string(), + overwrite: true, + }; + let ret = call_api("import_mnemonic", param).unwrap(); + let import_result: KeystoreResult = KeystoreResult::decode(ret.as_slice()).unwrap(); + + let derivations = vec![ + // Derivation { + // chain_type: "LITECOIN".to_string(), + // path: "m/44'/2'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "NONE".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "LITECOIN".to_string(), + // path: "m/49'/2'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "P2WPKH".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "LITECOIN".to_string(), + // path: "m/49'/1'/0'/0/0".to_string(), + // network: "TESTNET".to_string(), + // seg_wit: "NONE".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "TRON".to_string(), + // path: "m/44'/195'/0'/0/0".to_string(), + // network: "".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "NERVOS".to_string(), + // path: "m/44'/309'/0'/0/0".to_string(), + // network: "TESTNET".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "FILECOIN".to_string(), + // path: "m/44'/461'/0'/0/0".to_string(), + // network: "TESTNET".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "FILECOIN".to_string(), + // path: "m/12381/461/0/0".to_string(), + // network: "TESTNET".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "bls12-381".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "COSMOS".to_string(), + // path: "m/44'/118'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "EOS".to_string(), + // path: "m/44'/194'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "ETHEREUM".to_string(), + // path: "m/44'/60'/0'/0/0".to_string(), + // network: "".to_string(), + // seg_wit: "".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "BITCOIN".to_string(), + // path: "m/44'/0'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "NONE".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + // Derivation { + // chain_type: "BITCOIN".to_string(), + // path: "m/49'/0'/0'/0/0".to_string(), + // network: "MAINNET".to_string(), + // seg_wit: "P2WPKH".to_string(), + // chain_id: "".to_string(), + // curve: "secp256k1".to_string(), + // bech32_prefix: "".to_string(), + // }, + Derivation { + chain_type: "KUSAMA".to_string(), + path: "m/44'/434'/0'/0'/0'".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "sr25519".to_string(), + bech32_prefix: "".to_string(), + }, + Derivation { + chain_type: "POLKADOT".to_string(), + path: "//polkadot//imToken/0".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + chain_id: "".to_string(), + curve: "sr25519".to_string(), + bech32_prefix: "".to_string(), + }, + ]; + + let param = DeriveAccountsParam { + id: import_result.id.to_string(), + key: Some(crate::api::derive_accounts_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + derivations, + }; + let derived_accounts_bytes = call_api("derive_accounts", param).unwrap(); + let derived_accounts: DeriveAccountsResult = + DeriveAccountsResult::decode(derived_accounts_bytes.as_slice()).unwrap(); + // assert_eq!( + // "Ldfdegx3hJygDuFDUA7Rkzjjx8gfFhP9DP", + // derived_accounts.accounts[0].address + // ); + // assert_eq!( + // "0x0289ca41680edbc5594ee6378ebd937e42cd6b4b969e40dd82c20ef2a8aa5bad7b", + // derived_accounts.accounts[0].public_key + // ); + // assert_eq!("xpub6D3MqTwuLWB5veAfhDjPu1oHfS6L1imVbf22zQFWJW9EtnSmYYqiGMGkW1MCsT2HmkW872tefMY9deewW6DGd8zE7RcXVv8wKhZnbJeidjT", derived_accounts.accounts[0].extended_public_key); + // assert_eq!("MwDMFXVWDEuWvBogeW1v/MOMFDnGnnflm2JAPvJaJZO4HXp8fCsWETA7u8MzOW3KaPksglpUHLN3xkDr2QWMEQq0TewFZoZ3KsjmLW0KGMRN7XQKqo/omkSEsPfalVnp9Zxm2lpxVmIacqvlernVSg==", derived_accounts.accounts[0].encrypted_extended_public_key); + + // assert_eq!( + // "MQHaFwU3DiWQoz48TqZHtZ4jF7tFDj9yQF", + // derived_accounts.accounts[1].address + // ); + // assert_eq!( + // "0x03ace3b0da84c9944a077d62fc839c95324c2bdaa01786353f5538f89fbc24f428", + // derived_accounts.accounts[1].public_key + // ); + // assert_eq!("ypub6Y37Xmn4afXWyQduPKYWPXSbX6YUCewxo4qKJqqtKsGJzPnS95QNT261uvzfQJH95CeuGn3xEysWHau3knBKxy1tNs21HipL9cpG1LJy4Wc", derived_accounts.accounts[1].extended_public_key); + // assert_eq!("ypB3aQxsFPVl6EJAnDGiGh6UaUrh1bXsGFG7teh1fOJdkdcjq8vNCNh1f4MDYrjt71xA9cZ9y2iTRuSGdU0doLJkqdQ/VkRaGOlN4fsO2L+oBqUwxKQc0iHxsjrrNEBcge//2RglytnelFnGJHmzVw==", derived_accounts.accounts[1].encrypted_extended_public_key); + + // assert_eq!( + // "mpke4CzhBTV2dFZpnABT9EN1kPc4vDWZxw", + // derived_accounts.accounts[2].address + // ); + // assert_eq!( + // "0x031aee5e20399d68cf0035d1a21564868f22bc448ab205292b4279136b15ecaebc", + // derived_accounts.accounts[2].public_key + // ); + // assert_eq!("upub5E4woDJohDBJ2trk6HqhsvEeZXtjjWMAbHV4LWRhfR9thcpfkjJbBRnvBS21L2JjsZAGC6LhkqAoYgD5VHSXBRNW7gszbiGJP7B6CR35QhD", derived_accounts.accounts[2].extended_public_key); + // assert_eq!("ZDxvs7NEiNuUO/iXWvB2WvWmxXmQ+eP2qrEZe165dWLBm0PJpeRncYu+mZVUJJe0o6QUbnVop5TRqUBmRUzcxPioSmOVlzRpxOeUBZmaUi48hIwid1ouBZZ1zakxGLLnK4DyJN9NkyNDllKqxVhpdg==", derived_accounts.accounts[2].encrypted_extended_public_key); + + // assert_eq!( + // "TY2uroBeZ5trA9QT96aEWj32XLkAAhQ9R2", + // derived_accounts.accounts[3].address + // ); + // assert_eq!( + // "0x037b5253c24ce2a293566f9e066051366cda5073e4a43b25f07c990d7c9ac0aab5", + // derived_accounts.accounts[3].public_key + // ); + // assert_eq!("tpubDCxD6k9PreNhSacpfSZ3iErESZnncY1n7qU7e3stZXLPh84xVVt5ERMAqKeefUU8jswx2GpCkQpeYow4xH3PGx2iim6ftPa32GNvTKAtknz", derived_accounts.accounts[3].extended_public_key); + // assert_eq!("A6SCjz/iYksc/3pnVnMIzXimsQAm2p4EUJ1T6fRYkeHSqtSuBcF7O2Fyt3lYbiD4RoL1wf6VfknDiLdS1mcJyD09kXl5s+fuBaklKAZ2Dh6YuGlPGJqaGnrQ/rsTJ+Adb0ZRO3F3xGadXjiGb3hTSA==", derived_accounts.accounts[3].encrypted_extended_public_key); + + // assert_eq!( + // "ckt1qyqtr684u76tu7r8efkd24hw8922xfvhnazskzdzy6", + // derived_accounts.accounts[4].address + // ); + // assert_eq!( + // "0x03554851980004ff256888612bf0d64d9b1002bf82331450fd5a7405d1b23cc5bd", + // derived_accounts.accounts[4].public_key + // ); + // assert_eq!("tpubDDMZ3uNczagkRgAQBT6vmHFwM6Tc8RwYKU4ufqywmZEUNVfYNNyrVyXgmSpDTVsthVEbEzH5QjhxQPExpjBtVXVWZinpdRjiRGtpXuALuND", derived_accounts.accounts[4].extended_public_key); + // assert_eq!("VXhh0t5/x2aZJI0mKfkYREXX/VWw7PVEz4Gyf1bj9DS9ETRShdPA519gJMrbw8XJVk/p8X+ixbYras39ITKtl7KOSaE+E2T126r2NAR0gXRWOLIp2rrpnVWerlBkzjkoJ1KOKIPIIYhZYP7kn+tbSQ==", derived_accounts.accounts[4].encrypted_extended_public_key); + + // assert_eq!( + // "FqivQE5wEmrFDURJfkjcegQcqBuTGrxuSH5ugSVjNtNmmFF", + // derived_accounts.accounts[5].address + // ); + + // assert_eq!( + // "12wobevw8droBMpe5avXvEPPY6pUopJKEcyfHe8tmU9vVgxC", + // derived_accounts.accounts[6].address + // ); + + // assert_eq!( + // "t12i3bop43tprlnymx2c75u6uvlq7iur2rcd7qsey", + // derived_accounts.accounts[7].address + // ); + // assert_eq!( + // "0x03bd460186d29fd9ac68ee88b110c3acc4a4443648a1ec7607af9ce306ad76f785", + // derived_accounts.accounts[7].public_key + // ); + // assert_eq!("tpubDDaEZaaDDmwnZTP6u7m3yTKFgnbSx2uTaxp1hKM5oiVZo6iBB46rWnWpdkpbPxtfdYiyLbyhqgbXRXYff3LfW4rCpYyfpb5pC67CPZdKkZB", derived_accounts.accounts[7].extended_public_key); + // assert_eq!("PRImz4qL7pDJsEtqNVzVG9llzx+DN1XFbucDahOvyQ9g9yc5HWMdH6jAx4Mc/syseMWHLj9Y17Mfqib3sl88Ddgs3tTXhJq6vWToyXlQ6t9yg/LX1qKzLKcXLD+W0872G5m1urk//YOLIyhPkaLV2g==", derived_accounts.accounts[7].encrypted_extended_public_key); + + // assert_eq!( + // "cosmos1ajz9y0x3wekez7tz2td2j6l2dftn28v26dd992", + // derived_accounts.accounts[9].address + // ); + // assert_eq!( + // "0x0232c1ef21d73c19531b0aa4e863cf397c2b982b2f958f60cdb62969824c096d65", + // derived_accounts.accounts[9].public_key + // ); + // assert_eq!("xpub6CrWRZY39gj49G1ipdmcVunEnb5RoTGf9o6QnJQp8c4b84V2piN1Rdy1xWVJ4P7VXNx5Ckg6rZcvSNvJtvWz8zs3RkPayHn9vMMuK9ERrFr", derived_accounts.accounts[9].extended_public_key); + // assert_eq!("rJQ+jO02Yn+Rdfjn5QbStU/2aS0T5zW5HU83JoHLBZHafsr8FSdG7lPV59XAw1LwuUCMCtRBueG1iJ2AsA76PP1zyVzj0LxDIq3iHAOxBdwIZDP5C1sY+RMGwXk+6a2OwmYN/zF/q2SL8D6aeGyD9g==", derived_accounts.accounts[9].encrypted_extended_public_key); + + // assert_eq!("", derived_accounts.accounts[10].address); + // assert_eq!( + // "EOS88XhiiP7Cu5TmAUJqHbyuhyYgd6sei68AU266PyetDDAtjmYWF", + // derived_accounts.accounts[10].public_key + // ); + // assert_eq!("xpub6CUtvjXi3yjmhjaC2GxjiWE9FbQs1TrtqAgRDhB2gmDBsPzTfwqZ7MvGGYScKiVx8PBNFSmHm4mCnFDCaX23c1nJS4p8ynR2wnGne4qEEX9", derived_accounts.accounts[10].extended_public_key); + // assert_eq!("jSPl9msMWjfMrj/09dRJ/epEWFnjjNHoOfro8xVrvcmhTnTC0iK+RDXXJ7iI2UpIa3ckFw7g2QGaVgODFQVLrEboEysXX5YMsPczdAUrdKh27vx5A3KMFylw2kVrUmSdoMDID8wlVfqkteyIHED0iQ==", derived_accounts.accounts[10].encrypted_extended_public_key); + + // assert_eq!( + // "0x6031564e7b2F5cc33737807b2E58DaFF870B590b", + // derived_accounts.accounts[11].address + // ); + // assert_eq!( + // "0x0280c98b8ea7cab630defb0c09a4295c2193cdee016c1d5b9b0cb18572b9c370fe", + // derived_accounts.accounts[11].public_key + // ); + // assert_eq!("tpubDCvte6zYB6DKMaEy4fwyoXpuExA4ery3Hu6dVSBZeY9Rg57VKFLwNPMfywWtqRFM1Df5gQJTu42RaaNCgVEyngdVfnYRh9Kb1UCoEYojURc", derived_accounts.accounts[11].extended_public_key); + // assert_eq!("w6s0ZvUoPPSiEi1xDMKy5X9+qwhcX4u3e3LOBosJaOSro2ny9jppDxcczZfrhe29n9H3UkmgNoecq/85xfXkGDtH8PMR9iclK5WrcUtkgjXsBcrR6JF0j58i4W9x3y539vXOsLMifCmUr2RcqknDgw==", derived_accounts.accounts[11].encrypted_extended_public_key); + + // assert_eq!( + // "12z6UzsA3tjpaeuvA2Zr9jwx19Azz74D6g", + // derived_accounts.accounts[12].address + // ); + // assert_eq!( + // "0x026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", + // derived_accounts.accounts[12].public_key + // ); + // assert_eq!("xpub6CqzLtyKdJN53jPY13W6GdyB8ZGWuFZuBPU4Xh9DXm6Q1cULVLtsyfXSjx4G77rNdCRBgi83LByaWxjtDaZfLAKT6vFUq3EhPtNwTpJigx8", derived_accounts.accounts[12].extended_public_key); + // assert_eq!("BdgvWHN/Uh/K526q/+CdpGwEPZ41SvZHHGSgiSqhFesjErdbo6UnJMIoDOHV94qW8fd2KBW18UG3nTzDwS7a5oArqPtv+2aE9+1bNvCdtYoAx3979N3vbX4Xxn/najTABykXrJDjgpoaXxSo/xTktQ==", derived_accounts.accounts[12].encrypted_extended_public_key); + + // assert_eq!( + // "3JmreiUEKn8P3SyLYmZ7C1YCd4r2nFy3Dp", + // derived_accounts.accounts[13].address + // ); + // assert_eq!( + // "0x03036695c5f3de2e2792b170f59679d4db88a8516728012eaa42a22ce6f8bf593b", + // derived_accounts.accounts[13].public_key + // ); + // assert_eq!("ypub6Wdz1gzMKLnPxXti2GbSjQGXSqrA5NMKNP3C5JS2ZJKRDEecuZH8AhSvYQs4dZHi7b6Yind7bLekuTH9fNbJcH1MXMy9meoifu2wST55sav", derived_accounts.accounts[13].extended_public_key); + // assert_eq!("8mPByX5qAwVJ2bVNqDrm6Jx19osoWZwplnAESPaN//Gx3Q9Gp2Q2bqkaDsxlYaYsUKN6FRzwrJHaSKD2A9aWJ3RoTWJ9zY9g21zW4ttsXFl1CAZNIlFCC9CnXd2b89vDgqCQC/foz50TV4PUikR+/g==", derived_accounts.accounts[13].encrypted_extended_public_key); + + assert_eq!( + "FqivQE5wEmrFDURJfkjcegQcqBuTGrxuSH5ugSVjNtNmmFF", + derived_accounts.accounts[0].address + ); + assert_eq!( + "0x90742a577c8515391a46b7881c98c80ec92fe04255bb5b5fec862c7d633ada21", + derived_accounts.accounts[0].public_key + ); + assert_eq!("", derived_accounts.accounts[0].extended_public_key); + assert_eq!( + "", + derived_accounts.accounts[0].encrypted_extended_public_key + ); + + assert_eq!( + "12wobevw8droBMpe5avXvEPPY6pUopJKEcyfHe8tmU9vVgxC", + derived_accounts.accounts[1].address + ); + + remove_created_wallet(&import_result.id); + }) + } }