From c0ac3585809b36b8f71431a51bcaec00d912b6d9 Mon Sep 17 00:00:00 2001 From: XuNeal Date: Fri, 15 Dec 2023 15:01:21 +0800 Subject: [PATCH] feat: add import private key and key hash --- token-core/tcx-btc-kin/src/signer.rs | 8 +- token-core/tcx-ckb/src/signer.rs | 3 +- token-core/tcx-common/src/util.rs | 2 +- token-core/tcx-eth/src/signer.rs | 2 +- token-core/tcx-filecoin/src/key_info.rs | 4 +- token-core/tcx-filecoin/src/signer.rs | 8 +- token-core/tcx-keystore/src/identity.rs | 60 ++-- token-core/tcx-keystore/src/keystore/guard.rs | 2 +- token-core/tcx-keystore/src/keystore/hd.rs | 48 +-- token-core/tcx-keystore/src/keystore/mod.rs | 18 +- .../tcx-keystore/src/keystore/private.rs | 56 +++- token-core/tcx-migration/src/migration.rs | 2 +- token-core/tcx-primitive/src/bip32.rs | 6 + token-core/tcx-primitive/src/ecc.rs | 7 + token-core/tcx-primitive/src/secp256k1.rs | 2 + token-core/tcx-proto/src/params.proto | 17 +- token-core/tcx-proto/src/substrate.proto | 1 - token-core/tcx-substrate/src/transaction.rs | 2 - token-core/tcx-tezos/src/lib.rs | 6 +- token-core/tcx/src/api.rs | 32 +- token-core/tcx/src/handler.rs | 315 ++++++++++++++---- token-core/tcx/src/lib.rs | 261 ++++----------- token-core/tcx/src/macros.rs | 2 +- 23 files changed, 497 insertions(+), 367 deletions(-) diff --git a/token-core/tcx-btc-kin/src/signer.rs b/token-core/tcx-btc-kin/src/signer.rs index cdb462dd..37f9a0c2 100644 --- a/token-core/tcx-btc-kin/src/signer.rs +++ b/token-core/tcx-btc-kin/src/signer.rs @@ -447,7 +447,8 @@ mod tests { use super::*; fn hex_keystore(hex: &str) -> Keystore { - let mut keystore = Keystore::from_private_key(hex, TEST_PASSWORD, Metadata::default()); + let mut keystore = + Keystore::from_private_key(hex, TEST_PASSWORD, Metadata::default()).unwrap(); keystore.unlock_by_password(TEST_PASSWORD).unwrap(); keystore } @@ -616,7 +617,8 @@ mod tests { "b0dabbf9ffed224fbca3b41a9e446b3d0b6240c6d2957197a8ab75bbf2e1a5d4", TEST_PASSWORD, Metadata::default(), - ); + ) + .unwrap(); ks.unlock_by_password(TEST_PASSWORD).unwrap(); let params = SignatureParameters { @@ -1384,7 +1386,7 @@ mod tests { .to_hex(); let mut keystore = - Keystore::from_private_key(&prv_key, TEST_PASSWORD, Metadata::default()); + Keystore::from_private_key(&prv_key, TEST_PASSWORD, Metadata::default()).unwrap(); let _coin_info = coin_info_from_param("LITECOIN", "TESTNET", "NONE", "").unwrap(); let _ = keystore.unlock_by_password(TEST_PASSWORD).unwrap(); let params = SignatureParameters { diff --git a/token-core/tcx-ckb/src/signer.rs b/token-core/tcx-ckb/src/signer.rs index 476d5b22..6d8dafb5 100644 --- a/token-core/tcx-ckb/src/signer.rs +++ b/token-core/tcx-ckb/src/signer.rs @@ -418,7 +418,8 @@ mod tests { "dcec27d0d975b0378471183a03f7071dea8532aaf968be796719ecd20af6988f", "Password", Metadata::default(), - ); + ) + .unwrap(); ks.unlock_by_password("Password").unwrap(); let coin_info = CoinInfo { diff --git a/token-core/tcx-common/src/util.rs b/token-core/tcx-common/src/util.rs index f102c79e..87844c7d 100644 --- a/token-core/tcx-common/src/util.rs +++ b/token-core/tcx-common/src/util.rs @@ -3,7 +3,7 @@ use crate::Result; pub fn utf8_or_hex_to_bytes(value: &str) -> Result> { if value.to_lowercase().starts_with("0x") { - FromHex::from_hex_auto(value) + FromHex::from_0x_hex(value) } else { Ok(value.as_bytes().to_vec()) } diff --git a/token-core/tcx-eth/src/signer.rs b/token-core/tcx-eth/src/signer.rs index 7637d9d6..fb35e9dc 100644 --- a/token-core/tcx-eth/src/signer.rs +++ b/token-core/tcx-eth/src/signer.rs @@ -172,7 +172,7 @@ mod test { use tcx_keystore::{Keystore, MessageSigner, Metadata, SignatureParameters, TransactionSigner}; fn private_key_store(key: &str) -> Keystore { - let mut ks = Keystore::from_private_key(key, "imToken1", Metadata::default()); + let mut ks = Keystore::from_private_key(key, "imToken1", Metadata::default()).unwrap(); ks.unlock_by_password("imToken1").unwrap(); ks } diff --git a/token-core/tcx-filecoin/src/key_info.rs b/token-core/tcx-filecoin/src/key_info.rs index 4a2dafd7..58abfeeb 100644 --- a/token-core/tcx-filecoin/src/key_info.rs +++ b/token-core/tcx-filecoin/src/key_info.rs @@ -7,10 +7,10 @@ use super::Error; #[derive(Deserialize, Serialize, Debug)] pub struct KeyInfo { #[serde(rename = "Type")] - r#type: String, + pub r#type: String, #[serde(rename = "PrivateKey")] - private_key: String, + pub private_key: String, } impl KeyInfo { diff --git a/token-core/tcx-filecoin/src/signer.rs b/token-core/tcx-filecoin/src/signer.rs index 9fc55c9b..9d5b5c2a 100644 --- a/token-core/tcx-filecoin/src/signer.rs +++ b/token-core/tcx-filecoin/src/signer.rs @@ -122,7 +122,8 @@ mod tests { &Vec::from_hex("7b2254797065223a22736563703235366b31222c22507269766174654b6579223a222f5059574777574e577a58614d5675437a613958502b314b4a695a4474696f4c76777863754268783041553d227d").unwrap()).unwrap(); let private_key = key_info.decode_private_key().unwrap(); let mut ks = - Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()); + Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()) + .unwrap(); ks.unlock_by_password("Password").unwrap(); let sign_context = SignatureParameters { @@ -163,7 +164,8 @@ mod tests { &Vec::from_hex("7b2254797065223a22626c73222c22507269766174654b6579223a2269376b4f2b7a78633651532b7637597967636d555968374d55595352657336616e6967694c684b463830383d227d").unwrap()).unwrap(); let private_key = key_info.decode_private_key().unwrap(); let mut ks = - Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()); + Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()) + .unwrap(); ks.unlock_by_password("Password").unwrap(); let sign_context = SignatureParameters { @@ -205,7 +207,7 @@ mod tests { &Vec::from_hex("7b2254797065223a22626c73222c22507269766174654b6579223a2269376b4f2b7a78633651532b7637597967636d555968374d55595352657336616e6967694c684b463830383d227d").unwrap()).unwrap(); let private_key = key_info.decode_private_key().unwrap(); let mut ks = - Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()); + Keystore::from_private_key(&private_key.to_hex(), "Password", Metadata::default()).unwrap(); ks.unlock_by_password("Password").unwrap(); let sign_context = SignatureParameters { diff --git a/token-core/tcx-keystore/src/identity.rs b/token-core/tcx-keystore/src/identity.rs index d4f18292..f1ac4be6 100644 --- a/token-core/tcx-keystore/src/identity.rs +++ b/token-core/tcx-keystore/src/identity.rs @@ -32,23 +32,20 @@ pub struct Identity { } impl Identity { - pub fn new(seed: &Seed, unlocker: &Unlocker, network: &IdentityNetwork) -> Result { - let network_type = if network == &IdentityNetwork::Mainnet { - Network::Bitcoin + pub fn new( + master_private_key: &[u8], + unlocker: &Unlocker, + network: &IdentityNetwork, + ) -> Result { + let (network_type, network_salt) = if network == &IdentityNetwork::Mainnet { + (Network::Bitcoin, "Mainnet") } else { - Network::Testnet + (Network::Testnet, "Testnet") }; - let master_key = ExtendedPrivKey::new_master(network_type, seed.as_ref())?; - - let network_salt = if network == &IdentityNetwork::Mainnet { - "Mainnet" - } else { - "Testnet" - }; let salt = format!("Automatic Backup Key {}", network_salt); - let backup_key = HMAC::mac(salt.as_bytes(), master_key.private_key.secret_bytes()); + let backup_key = HMAC::mac(salt.as_bytes(), master_private_key); let authentication_key = HMAC::mac("Authentication Key".as_bytes(), backup_key); @@ -101,7 +98,15 @@ impl Identity { } let mnemonic = Mnemonic::from_phrase(mnemonic_phrase, Language::English).unwrap(); let seed = Seed::new(&mnemonic, ""); - return Self::new(&seed, unlocker, network); + + let network_type = if network == &IdentityNetwork::Mainnet { + Network::Bitcoin + } else { + Network::Testnet + }; + + let master_key = ExtendedPrivKey::new_master(network_type, seed.as_ref())?; + return Self::new(&master_key.private_key.secret_bytes(), unlocker, network); } pub fn from_private_key( @@ -109,10 +114,8 @@ impl Identity { unlocker: &Unlocker, network: &IdentityNetwork, ) -> Result { - let entropy = Vec::from_hex_auto(private_key)?; - let mnemonic = Mnemonic::from_entropy(&entropy, Language::English).unwrap(); - let seed = Seed::new(&mnemonic, ""); - return Self::new(&seed, unlocker, network); + let private_key_bytes = Vec::::from_hex_auto(private_key)?; + return Self::new(&private_key_bytes, unlocker, network); } pub fn calculate_ipfs_id(pub_key: &PublicKey) -> String { @@ -392,15 +395,32 @@ mod test { #[test] fn test_create_identity_from_private_key() { let meta = Metadata::default(); - let keystore = PrivateKeystore::from_private_key(&PRIVATE_KEY, &PASSWORD, meta); + let keystore = PrivateKeystore::from_private_key(&PRIVATE_KEY, &PASSWORD, meta).unwrap(); + let identity = &keystore.store().identity; + + assert_eq!( + "im14x5GLbjpSGz4Y2ebqcP2aN2R1qY54qKsX6bj", + identity.identifier + ); + assert_eq!( + "QmYS86Nzo9mi7ccBH7iZc11ModqXahbUxtTDNaZHU6EHqV", + identity.ipfs_id + ); + } + + #[test] + fn test_create_identity_from_private_key_testnet() { + let mut meta = Metadata::default(); + meta.network = IdentityNetwork::Testnet; + let keystore = PrivateKeystore::from_private_key(&PRIVATE_KEY, &PASSWORD, meta).unwrap(); let identity = &keystore.store().identity; assert_eq!( - "im14x5Ka4SC7WkwL1PzPtHvB1jdzLyaJ3tru511", + "im18MD7LnJJa6vkDd9jZmjqXw2N7K9KZuk2bGjW", identity.identifier ); assert_eq!( - "QmRYFQbmD37D4fvodcFvQtaSFo3mcAPJmYLPUHrr8w1teZ", + "QmYtS45NgsQBqZdJbJGn33DYPWGsSbmUbuuVoR2rdfaJWV", identity.ipfs_id ); } diff --git a/token-core/tcx-keystore/src/keystore/guard.rs b/token-core/tcx-keystore/src/keystore/guard.rs index c2c0cd3f..c621ca53 100644 --- a/token-core/tcx-keystore/src/keystore/guard.rs +++ b/token-core/tcx-keystore/src/keystore/guard.rs @@ -70,7 +70,7 @@ mod tests { assert!(ks.is_locked()); - let mut ks = Keystore::from_private_key(PRIVATE_KEY, TEST_PASSWORD, Metadata::default()); + let mut ks = Keystore::from_private_key(PRIVATE_KEY, TEST_PASSWORD, Metadata::default()).unwrap(); let derived_key = ks.get_derived_key(&TEST_PASSWORD).unwrap(); { diff --git a/token-core/tcx-keystore/src/keystore/hd.rs b/token-core/tcx-keystore/src/keystore/hd.rs index c2fbb04c..768ee547 100644 --- a/token-core/tcx-keystore/src/keystore/hd.rs +++ b/token-core/tcx-keystore/src/keystore/hd.rs @@ -58,13 +58,10 @@ pub struct HdKeystore { } pub fn key_hash_from_mnemonic(mnemonic: &str) -> Result { - let mn = - Mnemonic::from_phrase(mnemonic, Language::English).map_err(transform_mnemonic_error)?; - - let seed = Seed::new(&mn, ""); - - let bytes = sha256d(seed.as_bytes())[..20].to_vec(); - Ok(bytes.to_hex()) + let xprv = TypedDeterministicPrivateKey::from_mnemonic(CurveType::SECP256k1, mnemonic)?; + let xpub = xprv.deterministic_public_key(); + let fingerprint = xpub.fingerprint()?; + Ok(fingerprint.to_0x_hex()) } impl HdKeystore { @@ -261,13 +258,6 @@ mod tests { assert_eq!(meta.source, expected.source); } - #[test] - fn test_key_hash_from_mnemonic() { - let mnemonic = "inject kidney empty canal shadow pact comfort wife crush horse wife sketch"; - let key_hash = key_hash_from_mnemonic(mnemonic).unwrap(); - assert_eq!(key_hash, "512115eca3ae86646aeb06861d551e403b543509"); - } - #[test] fn test_new_keystore() { let keystore = HdKeystore::new(TEST_PASSWORD, Metadata::default()); @@ -403,24 +393,6 @@ mod tests { assert_eq!(format!("{}", wrong_password_err), "password_incorrect"); } - // #[test] - // pub fn generate_seed() { - // let mnemonic = Mnemonic::from_phrase( - // "favorite liar zebra assume hurt cage any damp inherit rescue delay panic", - // Language::English, - // ) - // .unwrap(); - // - // // let entropy = mnemonic.entropy(); - // - // let seed = bip39::Seed::new(&mnemonic, &"").as_bytes().to_vec(); - // - // assert_eq!( - // "235c69907d33b85f27bd78e73ff5d0c67bd4894515cc30c77f4391859bc1a3f2", - // hex::encode(seed) - // ); - // } - #[test] fn test_get_private_key() { let mut keystore = @@ -489,4 +461,16 @@ mod tests { assert_eq!(acc, expected); } + + #[test] + fn test_key_hash_from_mnemonic() { + let key_hash = key_hash_from_mnemonic(&TEST_MNEMONIC).unwrap(); + assert_eq!("0x1468dba9", key_hash); + + let key_hash = key_hash_from_mnemonic( + "risk outer wing rent aerobic hamster island skin mistake high boost swear", + ) + .unwrap(); + assert_eq!("0xf6f23259", key_hash); + } } diff --git a/token-core/tcx-keystore/src/keystore/mod.rs b/token-core/tcx-keystore/src/keystore/mod.rs index 60481cc7..19808b72 100644 --- a/token-core/tcx-keystore/src/keystore/mod.rs +++ b/token-core/tcx-keystore/src/keystore/mod.rs @@ -120,6 +120,7 @@ pub enum Source { Wif, Private, KeystoreV3, + SubstrateKeystore, Mnemonic, NewMnemonic, /*NewIdentity, @@ -135,6 +136,7 @@ impl FromStr for Source { "WIF" => Ok(Source::Wif), "PRIVATE" => Ok(Source::Private), "KEYSTORE_V3" => Ok(Source::KeystoreV3), + "SUBSTRATE_KEYSTORE" => Ok(Source::SubstrateKeystore), "MNEMONIC" => Ok(Source::Mnemonic), "NEW_MNEMONIC" => Ok(Source::NewMnemonic), _ => Err(format_err!("unknown_source")), @@ -147,6 +149,7 @@ impl fmt::Display for Source { Source::Wif => write!(f, "WIF"), Source::Private => write!(f, "PRIVATE"), Source::KeystoreV3 => write!(f, "KEYSTORE_V3"), + Source::SubstrateKeystore => write!(f, "SUBSTRATE_KEYSTORE"), Source::Mnemonic => write!(f, "MNEMONIC"), Source::NewMnemonic => write!(f, "NEW_MNEMONIC"), } @@ -231,12 +234,12 @@ pub enum Keystore { } impl Keystore { - pub fn from_private_key(private_key: &str, password: &str, meta: Metadata) -> Keystore { - Keystore::PrivateKey(PrivateKeystore::from_private_key( + pub fn from_private_key(private_key: &str, password: &str, meta: Metadata) -> Result { + Ok(Keystore::PrivateKey(PrivateKeystore::from_private_key( private_key, password, meta, - )) + )?)) } pub fn from_mnemonic(mnemonic: &str, password: &str, metadata: Metadata) -> Result { @@ -529,8 +532,8 @@ impl ChainSigner for Keystore { pub(crate) mod tests { use crate::keystore::Keystore::{Hd, PrivateKey}; use crate::{ - Address, ChainSigner, HdKeystore, Keystore, Metadata, PrivateKeystore, SignatureParameters, - Signer, Source, + Address, HdKeystore, Keystore, Metadata, PrivateKeystore, SignatureParameters, Signer, + Source, }; use serde_json::Value; use std::str::FromStr; @@ -832,7 +835,8 @@ pub(crate) mod tests { "a392604efc2fad9c0b3da43b5f698a2e3f270f170d859912be0d54742275c5f6", TEST_PASSWORD, meta, - ); + ) + .unwrap(); let keystore = PrivateKey(pk_store); assert!(!keystore.derivable()); @@ -872,7 +876,7 @@ pub(crate) mod tests { #[test] fn test_private_keystore() { let mut keystore = - Keystore::from_private_key(TEST_PRIVATE_KEY, TEST_PASSWORD, Metadata::default()); + Keystore::from_private_key(TEST_PRIVATE_KEY, TEST_PASSWORD, Metadata::default()).unwrap(); assert!(keystore .unlock(&Key::Password(TEST_PASSWORD.to_owned())) diff --git a/token-core/tcx-keystore/src/keystore/private.rs b/token-core/tcx-keystore/src/keystore/private.rs index 187246ec..e222da83 100644 --- a/token-core/tcx-keystore/src/keystore/private.rs +++ b/token-core/tcx-keystore/src/keystore/private.rs @@ -8,12 +8,15 @@ use super::Result; use crate::identity::Identity; use crate::keystore::Store; -use tcx_common::{sha256d, FromHex, ToHex}; -use tcx_primitive::TypedPrivateKey; +use tcx_common::{ripemd160, sha256, FromHex, ToHex}; +use tcx_primitive::{PrivateKey, Secp256k1PrivateKey, TypedPrivateKey}; use uuid::Uuid; -pub fn key_hash_from_private_key(data: &[u8]) -> String { - sha256d(data)[..20].to_hex() +pub fn key_hash_from_private_key(data: &[u8]) -> Result { + let private_key = Secp256k1PrivateKey::from_slice(data)?; + let public_key_data = private_key.public_key().to_compressed(); + let hashed = ripemd160(&sha256(&public_key_data)); + Ok(hashed[0..4].to_0x_hex()) } #[derive(Clone)] @@ -76,15 +79,16 @@ impl PrivateKeystore { self.store.crypto.verify_password(password) } - pub fn from_private_key(private_key: &str, password: &str, meta: Metadata) -> PrivateKeystore { - let key_data: Vec = Vec::from_hex_auto(private_key).expect("hex can't decode"); - let key_hash = key_hash_from_private_key(&key_data); + pub fn from_private_key( + private_key: &str, + password: &str, + meta: Metadata, + ) -> Result { + let key_data: Vec = Vec::from_hex_auto(private_key)?; + let key_hash = key_hash_from_private_key(&key_data)?; let crypto: Crypto = Crypto::new(password, &key_data); - let unlocker = crypto - .use_key(&Key::Password(password.to_string())) - .expect("create private keystore to get unlocker"); - let identity = Identity::from_private_key(private_key, &unlocker, &meta.network) - .expect("identity from private key"); + let unlocker = crypto.use_key(&Key::Password(password.to_string()))?; + let identity = Identity::from_private_key(private_key, &unlocker, &meta.network)?; let store = Store { key_hash, @@ -95,10 +99,10 @@ impl PrivateKeystore { identity, }; - PrivateKeystore { + Ok(PrivateKeystore { store, private_key: None, - } + }) } pub(crate) fn private_key_to_account( @@ -136,9 +140,10 @@ impl PrivateKeystore { #[cfg(test)] mod tests { - use crate::{HdKeystore, Metadata, PrivateKeystore, Source}; + use crate::{HdKeystore, Metadata, PrivateKeystore, Source, key_hash_from_private_key}; use tcx_constants::{TEST_MNEMONIC, TEST_PASSWORD, TEST_PRIVATE_KEY}; use tcx_crypto::Key; + use bitcoin_hashes::hex::FromHex; #[test] fn test_from_private_key() { @@ -151,7 +156,7 @@ mod tests { "a392604efc2fad9c0b3da43b5f698a2e3f270f170d859912be0d54742275c5f6", TEST_PASSWORD, meta, - ); + ).unwrap(); keystore .unlock(&Key::Password(TEST_PASSWORD.to_owned())) @@ -168,9 +173,26 @@ mod tests { #[test] fn test_verify_password() { let mut keystore = - PrivateKeystore::from_private_key(TEST_PRIVATE_KEY, TEST_PASSWORD, Metadata::default()); + PrivateKeystore::from_private_key(TEST_PRIVATE_KEY, TEST_PASSWORD, Metadata::default()).unwrap(); assert!(keystore.verify_password(TEST_PASSWORD)); assert!(!keystore.verify_password("WrongPassword")); } + + #[test] + pub fn test_key_hash_from_private_key() { + let pk_data = &Vec::::from_hex( + "ad87a08796efbdd9276e2ca5a10f938937cb5d2b7d5f698c06a94d8eeed3f6ae", + ) + .unwrap(); + let fingerprint = key_hash_from_private_key(&pk_data).unwrap(); + assert_eq!(fingerprint, "0x1468dba9"); + + let pk_data = &Vec::::from_hex( + "257cd2f8eb13f6930ecb95ac7736dd25e65d231ce1a3b1669e51f6737350b43e", + ) + .unwrap(); + let fingerprint = key_hash_from_private_key(&pk_data).unwrap(); + assert_eq!(fingerprint, "0xf6f23259"); + } } diff --git a/token-core/tcx-migration/src/migration.rs b/token-core/tcx-migration/src/migration.rs index 8072df60..223448e8 100644 --- a/token-core/tcx-migration/src/migration.rs +++ b/token-core/tcx-migration/src/migration.rs @@ -278,7 +278,7 @@ impl LegacyKeystore { Secp256k1PrivateKey::from_wif(&String::from_utf8_lossy(&private_key))?.to_bytes() } - let key_hash = key_hash_from_private_key(&private_key); + let key_hash = key_hash_from_private_key(&private_key)?; let unlocker = self.crypto.use_key(key)?; let im_token_meta = self .im_token_meta diff --git a/token-core/tcx-primitive/src/bip32.rs b/token-core/tcx-primitive/src/bip32.rs index 5480d899..f89562b6 100644 --- a/token-core/tcx-primitive/src/bip32.rs +++ b/token-core/tcx-primitive/src/bip32.rs @@ -73,6 +73,12 @@ impl Derive for Bip32DeterministicPrivateKey { } } +impl Bip32DeterministicPublicKey { + pub fn fingerprint(&self) -> Vec { + self.0.fingerprint().to_bytes().to_vec() + } +} + impl Derive for Bip32DeterministicPublicKey { fn derive(&self, path: &str) -> Result { let extended_key = self.0.clone(); diff --git a/token-core/tcx-primitive/src/ecc.rs b/token-core/tcx-primitive/src/ecc.rs index 7c4e8a8c..1ecd9dac 100644 --- a/token-core/tcx-primitive/src/ecc.rs +++ b/token-core/tcx-primitive/src/ecc.rs @@ -263,6 +263,13 @@ impl TypedDeterministicPublicKey { } } + pub fn fingerprint(&self) -> Result> { + match self { + TypedDeterministicPublicKey::Bip32Sepc256k1(epk) => Ok(epk.fingerprint()), + _ => Err(format_err!("bls or ed25519 not support fingerprint")), + } + } + pub fn public_key(&self) -> TypedPublicKey { match self { TypedDeterministicPublicKey::Bip32Sepc256k1(epk) => { diff --git a/token-core/tcx-primitive/src/secp256k1.rs b/token-core/tcx-primitive/src/secp256k1.rs index 56bf4280..e145665c 100644 --- a/token-core/tcx-primitive/src/secp256k1.rs +++ b/token-core/tcx-primitive/src/secp256k1.rs @@ -118,6 +118,8 @@ impl TraitPublicKey for Secp256k1PublicKey { impl Ss58Codec for Secp256k1PrivateKey { fn from_ss58check_with_version(wif: &str) -> Result<(Self, Vec)> { + let data_with_check = base58::from(wif)?; + dbg!(data_with_check.to_0x_hex()); let data = base58::from_check(wif)?; let compressed = match data.len() { diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index fce03aa2..04bbb9ca 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -41,6 +41,18 @@ message ImportMnemonicParam { bool overwrite = 6; } +message ImportPrivateKeyResult { + string id = 1; + string name = 2; + string identifier = 3; + string ipfsId = 4; + string source = 5; + int64 createdAt = 6; + repeated string suggestChainTypes = 7; + string suggestNetwork = 8; + string suggestCurve = 9; +} + // // derive new accounts from a hd keystore message DeriveAccountsParam { @@ -98,7 +110,6 @@ message ImportPrivateKeyParam { string name = 3; string passwordHint = 4; bool overwrite = 5; - string encoding = 6; } // FUNCTION: private_key_store_export(PrivateKeyStoreExportParam): ExportResult @@ -126,7 +137,6 @@ message ExistsMnemonicParam { message ExistsPrivateKeyParam { string private_key = 1; - string encoding = 2; } message ExistsKeystoreResult { @@ -230,9 +240,6 @@ message SignAuthenticationMessageResult { string signature = 2; } -message GenerateMnemonicResult { - string mnemonic = 1; -} message MnemonicToPublicKeyParam { string mnemonic = 1; diff --git a/token-core/tcx-proto/src/substrate.proto b/token-core/tcx-proto/src/substrate.proto index 51831ad0..6c41d13e 100644 --- a/token-core/tcx-proto/src/substrate.proto +++ b/token-core/tcx-proto/src/substrate.proto @@ -5,7 +5,6 @@ package transaction; message ImportJsonParam { string keystore = 1; string password = 2; - string chainType = 3; bool overwrite = 4; } diff --git a/token-core/tcx-substrate/src/transaction.rs b/token-core/tcx-substrate/src/transaction.rs index bbd37d86..cbc75158 100644 --- a/token-core/tcx-substrate/src/transaction.rs +++ b/token-core/tcx-substrate/src/transaction.rs @@ -5,8 +5,6 @@ pub struct ImportJsonParam { pub keystore: ::prost::alloc::string::String, #[prost(string, tag = "2")] pub password: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub chain_type: ::prost::alloc::string::String, #[prost(bool, tag = "4")] pub overwrite: bool, } diff --git a/token-core/tcx-tezos/src/lib.rs b/token-core/tcx-tezos/src/lib.rs index a5200d7c..580d6fd9 100644 --- a/token-core/tcx-tezos/src/lib.rs +++ b/token-core/tcx-tezos/src/lib.rs @@ -21,7 +21,7 @@ pub fn build_tezos_base58_private_key(sk: &str) -> Result { Ok(base58::check_encode_slice(prefixed_sec_key_vec.as_slice())) } -pub fn pars_tezos_private_key(private_key: &str) -> Result> { +pub fn parse_tezos_private_key(private_key: &str) -> Result> { let data = base58::from_check(private_key)?; let pk = Ed25519PrivateKey::from_slice(&data[4..36])?; Ok(pk.to_bytes()) @@ -39,7 +39,7 @@ pub mod tezos { #[cfg(test)] mod tests { - use crate::{build_tezos_base58_private_key, pars_tezos_private_key}; + use crate::{build_tezos_base58_private_key, parse_tezos_private_key}; use tcx_common::ToHex; #[test] @@ -54,7 +54,7 @@ mod tests { #[test] fn test_pars_tezos_private_key() { let tezos_base58_sk = "edskRoRrqsGXLTjMwAtzLSx8G7s9ipibZQh6ponFhZYSReSwxwPo7qJCkPJoRjdUhz8Hj7uZhZaFp7F5yftHUYBpJwF2ZY6vAc"; - let parsing_result = pars_tezos_private_key(tezos_base58_sk).unwrap(); + let parsing_result = parse_tezos_private_key(tezos_base58_sk).unwrap(); assert_eq!( parsing_result.to_hex(), "5740dedadb610333de66ef2db2d91fd648fcbe419dff766f921ae97d536f94ce".to_string() diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index 705d87b4..3c2f1c99 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -250,6 +250,28 @@ pub struct ImportMnemonicParam { #[prost(bool, tag = "6")] pub overwrite: bool, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ImportPrivateKeyResult { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub identifier: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub ipfs_id: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub source: ::prost::alloc::string::String, + #[prost(int64, tag = "6")] + pub created_at: i64, + #[prost(string, repeated, tag = "7")] + pub suggest_chain_types: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(string, tag = "8")] + pub suggest_network: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub suggest_curve: ::prost::alloc::string::String, +} /// /// derive new accounts from a hd keystore #[allow(clippy::derive_partial_eq_without_eq)] @@ -336,8 +358,6 @@ pub struct ImportPrivateKeyParam { pub password_hint: ::prost::alloc::string::String, #[prost(bool, tag = "5")] pub overwrite: bool, - #[prost(string, tag = "6")] - pub encoding: ::prost::alloc::string::String, } /// FUNCTION: private_key_store_export(PrivateKeyStoreExportParam): ExportResult /// @@ -378,8 +398,6 @@ pub struct ExistsMnemonicParam { pub struct ExistsPrivateKeyParam { #[prost(string, tag = "1")] pub private_key: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub encoding: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -547,12 +565,6 @@ pub struct SignAuthenticationMessageResult { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct GenerateMnemonicResult { - #[prost(string, tag = "1")] - pub mnemonic: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct MnemonicToPublicKeyParam { #[prost(string, tag = "1")] pub mnemonic: ::prost::alloc::string::String, diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index 7728f250..5d7d102d 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -9,7 +9,7 @@ use tcx_eos::address::EosAddress; use tcx_keystore::keystore::IdentityNetwork; use tcx_common::{FromHex, ToHex}; -use tcx_primitive::{private_key_without_version, TypedPrivateKey}; +use tcx_primitive::{private_key_without_version, Secp256k1PrivateKey, TypedPrivateKey}; use tcx_btc_kin::WIFDisplay; use tcx_keystore::{ @@ -28,9 +28,9 @@ use crate::api::{ DeriveAccountsParam, DeriveAccountsResult, DeriveSubAccountsParam, DeriveSubAccountsResult, DerivedKeyResult, EncryptDataToIpfsParam, EncryptDataToIpfsResult, ExistsKeystoreResult, ExistsMnemonicParam, ExistsPrivateKeyParam, ExportPrivateKeyParam, ExportResult, GeneralResult, - GenerateMnemonicResult, GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, - GetPublicKeysParam, GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, KeyType, - KeystoreCommonExistsParam, KeystoreMigrationParam, KeystoreResult, MnemonicToPublicKeyParam, + GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, GetPublicKeysParam, + GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, ImportPrivateKeyResult, + KeyType, KeystoreMigrationParam, KeystoreResult, MnemonicToPublicKeyParam, MnemonicToPublicKeyResult, RemoveWalletParam, RemoveWalletResult, SignAuthenticationMessageParam, SignAuthenticationMessageResult, SignHashesParam, SignHashesResult, WalletKeyParam, ZksyncPrivateKeyFromSeedParam, @@ -47,6 +47,7 @@ use crate::filemanager::{delete_keystore_file, KEYSTORE_MAP}; use crate::IS_DEBUG; +use base58::FromBase58; use tcx_keystore::tcx_ensure; use tcx_constants::coin_info::coin_info_from_param; @@ -65,7 +66,7 @@ use tcx_substrate::{ use tcx_migration::migration::LegacyKeystore; use tcx_primitive::TypedDeterministicPublicKey; -use tcx_tezos::{build_tezos_base58_private_key, pars_tezos_private_key}; +use tcx_tezos::{build_tezos_base58_private_key, parse_tezos_private_key}; use zksync_crypto::{private_key_from_seed, private_key_to_pubkey_hash, sign_musig}; use crate::macros::use_chains; @@ -175,8 +176,7 @@ pub(crate) fn create_keystore(data: &[u8]) -> Result> { let mut meta = Metadata::default(); meta.name = param.name.to_owned(); meta.password_hint = param.password_hint.to_owned(); - // TODO: change source to NEW_MNEMONIC - meta.source = Source::Mnemonic; + meta.source = Source::NewMnemonic; meta.network = IdentityNetwork::from_str(¶m.network)?; let ks = HdKeystore::new(¶m.password, meta); @@ -190,8 +190,7 @@ pub(crate) fn create_keystore(data: &[u8]) -> Result> { let wallet = KeystoreResult { id: keystore.id(), name: meta.name.to_owned(), - // TODO: change source to NEW_MNEMONIC - source: Source::Mnemonic.to_string(), + source: Source::NewMnemonic.to_string(), created_at: meta.timestamp.clone(), identifier: identity.identifier.to_string(), ipfs_id: identity.ipfs_id.to_string(), @@ -365,22 +364,23 @@ fn key_data_from_any_format_pk(pk: &str) -> Result> { fn key_hash_from_any_format_pk(pk: &str) -> Result { let key_data = key_data_from_any_format_pk(pk)?; - Ok(key_hash_from_private_key(&key_data)) + key_hash_from_private_key(&key_data) } fn key_hash_from_tezos_format_pk(pk: &str) -> Result { - let key_data = pars_tezos_private_key(pk)?; - Ok(key_hash_from_private_key(&key_data)) + let key_data = parse_tezos_private_key(pk)?; + key_hash_from_private_key(&key_data) } -pub(crate) fn import_private_key(data: &[u8]) -> Result> { - let param: ImportPrivateKeyParam = - ImportPrivateKeyParam::decode(data).expect("import_private_key"); - +pub(crate) fn import_private_key_internal( + param: &ImportPrivateKeyParam, + source: Option, +) -> Result { let mut founded_id: Option = None; { let key_hash: String; - if param.encoding.eq("TEZOS") { + // TODO: make sure the prefix of tezoos + if param.private_key.starts_with("edsk") { key_hash = key_hash_from_tezos_format_pk(¶m.private_key)?; } else { key_hash = key_hash_from_any_format_pk(¶m.private_key)?; @@ -399,20 +399,20 @@ pub(crate) fn import_private_key(data: &[u8]) -> Result> { return Err(format_err!("{}", "address_already_exist")); } - let pk_bytes: Vec; - if param.encoding.eq("TEZOS") { - pk_bytes = pars_tezos_private_key(¶m.private_key)?; + let decoded_ret = decode_private_key(¶m.private_key)?; + let private_key = decoded_ret.bytes.to_hex(); + let meta_source = if let Some(source) = source { + source } else { - pk_bytes = key_data_from_any_format_pk(¶m.private_key)?; - } - let private_key = pk_bytes.to_hex(); + decoded_ret.source + }; let meta = Metadata { - name: param.name, - password_hint: param.password_hint, - source: Source::Private, + name: param.name.to_string(), + password_hint: param.password_hint.to_string(), + source: meta_source, ..Metadata::default() }; - let pk_store = PrivateKeystore::from_private_key(&private_key, ¶m.password, meta); + let pk_store = PrivateKeystore::from_private_key(&private_key, ¶m.password, meta)?; let mut keystore = Keystore::PrivateKey(pk_store); @@ -424,16 +424,113 @@ pub(crate) fn import_private_key(data: &[u8]) -> Result> { let meta = keystore.meta(); let identity = keystore.identity(); - let wallet = KeystoreResult { + let wallet = ImportPrivateKeyResult { id: keystore.id(), name: meta.name.to_owned(), - source: "PRIVATE".to_owned(), + source: meta_source.to_string(), created_at: meta.timestamp.clone(), identifier: identity.identifier.to_string(), ipfs_id: identity.ipfs_id.to_string(), + suggest_chain_types: decoded_ret.chain_types.to_owned(), + suggest_network: decoded_ret.network.to_string(), + suggest_curve: decoded_ret.curve.as_str().to_string(), }; - let ret = encode_message(wallet)?; cache_keystore(keystore); + Ok(wallet) +} + +struct DecodedPrivateKey { + bytes: Vec, + network: String, + curve: CurveType, + chain_types: Vec, + source: Source, +} + +fn decode_private_key(private_key: &str) -> Result { + let private_key_bytes: Vec; + let mut network = "".to_string(); + let mut chain_types: Vec = vec![]; + let mut curve: CurveType = CurveType::SECP256k1; + let mut source: Source = Source::Private; + if private_key.starts_with("edsk") { + private_key_bytes = parse_tezos_private_key(&private_key)?; + chain_types.push("TEZOS".to_string()); + } else { + let decoded = Vec::from_0x_hex(private_key.to_string()); + if decoded.is_ok() { + let decoded_data = decoded.unwrap(); + if decoded_data.len() <= 64 { + private_key_bytes = decoded_data; + chain_types.push("ETHEREUM".to_string()); + chain_types.push("TRON".to_string()); + } else { + let key_info = KeyInfo::from_lotus(&decoded_data)?; + private_key_bytes = key_info.decode_private_key()?; + chain_types.push("FILECOIN".to_string()); + if key_info.r#type != "secp256k1" { + curve = CurveType::BLS; + } + } + } else { + let data_len = private_key + .from_base58() + .map_err(|_| format_err!("decode private from base58 error"))? + .len(); + let (k1_pk, ver) = Secp256k1PrivateKey::from_ss58check_with_version(&private_key)?; + private_key_bytes = k1_pk.0.to_bytes(); + + source = Source::Wif; + match ver[0] { + 0xef => { + network = "TESTNET".to_string(); + chain_types.push("BITCOIN".to_string()); + chain_types.push("BITCOINCASH".to_string()); + chain_types.push("LITECOIN".to_string()); + } + 0x80 => { + if data_len == 37 { + // EOS 1byte network + 32bytes private key + 4byte checksum = 37bytes + // EOS not use compressed suffix https://developers.eos.io/manuals/eos/v2.2/keosd/wallet-specification + network = "".to_string(); + chain_types.push("EOS".to_string()); + } else { + // EOS 1byte network + 32bytes private key + 1byte compressed suffix + 4byte checksum = 38bytes + network = "MAINNET".to_string(); + chain_types.push("BITCOIN".to_string()); + chain_types.push("BITCOINCASH".to_string()); + } + } + 0xb0 => { + network = "MAINNET".to_string(); + chain_types.push("LITECOIN".to_string()); + } + _ => { + return Err(format_err!( + "unknow ver header when parse wif, ver: {}", + ver[0] + )) + } + } + } + } + + Ok(DecodedPrivateKey { + bytes: private_key_bytes, + network, + curve, + chain_types, + source, + }) +} + +pub(crate) fn import_private_key(data: &[u8]) -> Result> { + let param: ImportPrivateKeyParam = + ImportPrivateKeyParam::decode(data).expect("import_private_key"); + + let rsp = import_private_key_internal(¶m, None)?; + + let ret = encode_message(rsp)?; Ok(ret) } @@ -529,7 +626,7 @@ pub(crate) fn delete_keystore(data: &[u8]) -> Result> { pub(crate) fn exists_private_key(data: &[u8]) -> Result> { let param: ExistsPrivateKeyParam = ExistsPrivateKeyParam::decode(data).expect("ExistsPrivateKeyParam"); - let key_hash = if param.encoding.eq("TEZOS") { + let key_hash = if param.private_key.starts_with("edsk") { key_hash_from_tezos_format_pk(¶m.private_key)? } else { key_hash_from_any_format_pk(¶m.private_key)? @@ -752,21 +849,39 @@ pub(crate) fn get_derived_key(data: &[u8]) -> Result> { pub(crate) fn import_json(data: &[u8]) -> Result> { let param: ImportJsonParam = ImportJsonParam::decode(data)?; - let (sec_key_bytes, name) = match param.chain_type.as_str() { - "ETHEREUM" => key_info_from_v3(¶m), - "POLKADOT" | "KUSAMA" => key_info_from_substrate_keystore(¶m), - _ => Err(format_err!("unsupported_chain")), - }?; - let pk_import_param = ImportPrivateKeyParam { - private_key: sec_key_bytes.to_hex(), - password: param.password.to_string(), - name, - password_hint: "".to_string(), - overwrite: param.overwrite, - encoding: "".to_string(), - }; - let param_bytes = encode_message(pk_import_param)?; - import_private_key(¶m_bytes) + // let parse_v3_result = key_info_from_v3(¶m); + if let Ok(parse_v3_result) = key_info_from_v3(¶m) { + let (sec_key_bytes, name) = parse_v3_result; + let pk_import_param = ImportPrivateKeyParam { + private_key: sec_key_bytes.to_hex(), + password: param.password.to_string(), + name, + password_hint: "".to_string(), + overwrite: param.overwrite, + }; + let mut ret = import_private_key_internal(&pk_import_param, Some(Source::KeystoreV3))?; + ret.suggest_chain_types = vec!["ETHEREUM".to_string()]; + ret.suggest_curve = CurveType::SECP256k1.as_str().to_string(); + ret.suggest_network = "".to_string(); + return encode_message(ret); + } else if let Ok(parse_substrate_result) = key_info_from_substrate_keystore(¶m) { + let (sec_key_bytes, name) = parse_substrate_result; + let pk_import_param = ImportPrivateKeyParam { + private_key: sec_key_bytes.to_hex(), + password: param.password.to_string(), + name, + password_hint: "".to_string(), + overwrite: param.overwrite, + }; + let mut ret = + import_private_key_internal(&pk_import_param, Some(Source::SubstrateKeystore))?; + ret.suggest_chain_types = vec!["KUSAMA".to_string(), "POLKADOT".to_string()]; + ret.suggest_curve = CurveType::SubSr25519.as_str().to_string(); + ret.suggest_network = "".to_string(); + return encode_message(ret); + } else { + return Err(format_err!("unsupport_chain")); + } } fn key_info_from_v3(param: &ImportJsonParam) -> Result<(Vec, String)> { @@ -830,16 +945,19 @@ pub(crate) fn export_json(data: &[u8]) -> Result> { pub(crate) fn exists_json(data: &[u8]) -> Result> { let param: ImportJsonParam = ImportJsonParam::decode(data)?; - let (pk_bytes, _) = match param.chain_type.as_str() { - "ETHEREUM" => key_info_from_v3(¶m), - "KUSAMA" | "POLKADOT" => key_info_from_substrate_keystore(¶m), - _ => Err(format_err!("unsupported_chain")), - }?; - let pk_hex = pk_bytes.to_hex(); + let sec_key_hex = if let Ok(parse_v3_result) = key_info_from_v3(¶m) { + let (sec_key_bytes, _) = parse_v3_result; + sec_key_bytes.to_hex() + } else if let Ok(parse_substrate_result) = key_info_from_substrate_keystore(¶m) { + let (sec_key_bytes, _) = parse_substrate_result; + sec_key_bytes.to_hex() + } else { + return Err(format_err!("decrypt_json_error")); + }; + let exists_param = ExistsPrivateKeyParam { - encoding: "".to_string(), - private_key: pk_hex, + private_key: sec_key_hex, }; let exists_param_bytes = encode_message(exists_param)?; exists_private_key(&exists_param_bytes) @@ -893,12 +1011,6 @@ pub(crate) fn zksync_private_key_to_pubkey_hash(data: &[u8]) -> Result> encode_message(ret) } -pub(crate) fn generate_mnemonic() -> Result> { - let mnemonic = tcx_primitive::generate_mnemonic(); - let result = GenerateMnemonicResult { mnemonic }; - encode_message(result) -} - pub(crate) fn remove_wallet(data: &[u8]) -> Result> { let param: RemoveWalletParam = RemoveWalletParam::decode(data)?; let map = KEYSTORE_MAP.read(); @@ -970,7 +1082,8 @@ pub(crate) fn sign_authentication_message(data: &[u8]) -> Result> { }; let key = tcx_crypto::Key::Password(param.password); - let unlocker = identity_ks.use_key(&key)?; + // TODO: hide crypto object + let unlocker = identity_ks.store().crypto.use_key(&key)?; let signature = identity_ks.identity().sign_authentication_message( param.access_time, @@ -1090,3 +1203,83 @@ pub(crate) fn mnemonic_to_public(data: &[u8]) -> Result> { public_key: public_key_str, }) } + +#[cfg(test)] +mod tests { + use tcx_constants::CurveType; + use tcx_keystore::Source; + + use super::decode_private_key; + + #[test] + fn test_decode_private_key() { + let private_key = "cPrsVCDgzf7FLG2NyCrfudbAav4DQt2vs1ZcAqcjZWQ6wi1kp3Uc"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!( + decoded.chain_types, + vec![ + "BITCOIN".to_string(), + "BITCOINCASH".to_string(), + "LITECOIN".to_string() + ] + ); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "TESTNET".to_string()); + assert_eq!(decoded.source, Source::Wif); + + let private_key = "KyVt2HDqZbQzApZ7ao3YYK66xgkokRwEnyR94RAE4Pk6gxtMdsrA"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!( + decoded.chain_types, + vec!["BITCOIN".to_string(), "BITCOINCASH".to_string()] + ); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "MAINNET".to_string()); + assert_eq!(decoded.source, Source::Wif); + + let private_key = "T5L9U2X1xyPawfBz8RzQkfdUuYQ7pWx8cBKPvDnmdMvGCrR7TZEw"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!(decoded.chain_types, vec!["LITECOIN".to_string()]); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "MAINNET".to_string()); + assert_eq!(decoded.source, Source::Wif); + + let private_key = "edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!(decoded.chain_types, vec!["TEZOS".to_string()]); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "".to_string()); + assert_eq!(decoded.source, Source::Private); + + let private_key = "0x43fe394358d14f2e096f4efe80894b4e51a3fdcb73c06b77e937b80deb8c746b"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!( + decoded.chain_types, + vec!["ETHEREUM".to_string(), "TRON".to_string()] + ); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "".to_string()); + assert_eq!(decoded.source, Source::Private); + + let private_key = "0x7b2254797065223a22736563703235366b31222c22507269766174654b6579223a226f354a6754767776725a774c5061513758326d4b4c6a386e4478634e685a6b537667315564434a317866593d227d"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!(decoded.chain_types, vec!["FILECOIN".to_string()]); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "".to_string()); + assert_eq!(decoded.source, Source::Private); + + let private_key = "0x7b2254797065223a22626c73222c22507269766174654b6579223a2269376b4f2b7a78633651532b7637597967636d555968374d55595352657336616e6967694c684b463830383d227d"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!(decoded.chain_types, vec!["FILECOIN".to_string()]); + assert_eq!(decoded.curve, CurveType::BLS); + assert_eq!(decoded.network, "".to_string()); + assert_eq!(decoded.source, Source::Private); + + let private_key = "5JLENb318PJDVxdjGp8pvmRigMLSYbCPA4GSPXPwANvGLZE3ukq"; + let decoded = decode_private_key(&private_key).unwrap(); + assert_eq!(decoded.chain_types, vec!["EOS".to_string()]); + assert_eq!(decoded.curve, CurveType::SECP256k1); + assert_eq!(decoded.network, "".to_string()); + assert_eq!(decoded.source, Source::Wif); + } +} diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 78bcc94f..c5364812 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -17,12 +17,11 @@ use crate::error_handling::{landingpad, LAST_BACKTRACE, LAST_ERROR}; use crate::handler::{ create_keystore, decrypt_data_from_ipfs, delete_keystore, derive_accounts, derive_sub_accounts, encode_message, encrypt_data_to_ipfs, eth_recover_address, exists_json, exists_mnemonic, - exists_private_key, export_json, export_mnemonic, export_private_key, generate_mnemonic, - get_derived_key, get_extended_public_keys, get_public_keys, import_json, import_mnemonic, - import_private_key, migrate_keystore, mnemonic_to_public, remove_wallet, - sign_authentication_message, sign_hashes, sign_message, sign_tx, unlock_then_crash, - verify_password, zksync_private_key_from_seed, zksync_private_key_to_pubkey_hash, - zksync_sign_musig, + exists_private_key, export_json, export_mnemonic, export_private_key, get_derived_key, + get_extended_public_keys, get_public_keys, import_json, import_mnemonic, import_private_key, + migrate_keystore, mnemonic_to_public, remove_wallet, sign_authentication_message, sign_hashes, + sign_message, sign_tx, unlock_then_crash, verify_password, zksync_private_key_from_seed, + zksync_private_key_to_pubkey_hash, zksync_sign_musig, }; mod filemanager; @@ -175,8 +174,8 @@ mod tests { use crate::api::{ sign_param, CreateKeystoreParam, DeriveAccountsParam, DeriveAccountsResult, DeriveSubAccountsParam, DeriveSubAccountsResult, DerivedKeyResult, ExistsKeystoreResult, - ExportPrivateKeyParam, ExportResult, GeneralResult, GenerateMnemonicResult, - GetPublicKeysParam, GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, + ExportPrivateKeyParam, ExportResult, GeneralResult, GetPublicKeysParam, + GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, ImportPrivateKeyResult, InitTokenCoreXParam, KeyType, KeystoreCommonAccountsParam, KeystoreCommonExistsParam, KeystoreResult, MnemonicToPublicKeyParam, MnemonicToPublicKeyResult, PrivateKeyStoreExportParam, PublicKeyDerivation, PublicKeyParam, PublicKeyResult, @@ -199,7 +198,9 @@ mod tests { use sp_runtime::traits::Verify; use tcx_btc_kin::Utxo; use tcx_ckb::{CachedCell, CellInput, CkbTxInput, CkbTxOutput, OutPoint, Script, Witness}; - use tcx_eth::transaction::{AccessList, EthTxInput, EthTxOutput}; + use tcx_eth::transaction::{ + AccessList, EthMessageInput, EthMessageOutput, EthTxInput, EthTxOutput, + }; use tcx_filecoin::{SignedMessage, UnsignedMessage}; use tcx_substrate::{ ExportJsonResult, ImportJsonParam, SubstrateKeystore, SubstrateRawTxIn, SubstrateTxOut, @@ -269,7 +270,6 @@ mod tests { fn import_default_wallet() -> KeystoreResult { let param = ImportMnemonicParam { mnemonic: TEST_MNEMONIC.to_string(), - // mnemonic: TEST_MNEMONIC.to_string(), password: TEST_PASSWORD.to_string(), network: "TESTNET".to_string(), name: "test-wallet".to_string(), @@ -280,18 +280,17 @@ mod tests { KeystoreResult::decode(ret.as_slice()).unwrap() } - fn import_default_pk_store() -> KeystoreResult { + fn import_default_pk_store() -> ImportPrivateKeyResult { let param: ImportPrivateKeyParam = ImportPrivateKeyParam { private_key: "L2hfzPyVC1jWH7n2QLTe7tVTb6btg9smp5UVzhEBxLYaSFF7sCZB".to_string(), password: TEST_PASSWORD.to_string(), name: "import_default_pk_store".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); - KeystoreResult::decode(ret.as_slice()).unwrap() + ImportPrivateKeyResult::decode(ret.as_slice()).unwrap() } fn import_filecoin_pk_store() -> KeystoreResult { @@ -302,7 +301,6 @@ mod tests { name: "import_filecoin_pk_store".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -324,7 +322,9 @@ mod tests { (wallet, accounts) } - fn import_pk_and_derive(derivation: Derivation) -> (KeystoreResult, DeriveAccountsResult) { + fn import_pk_and_derive( + derivation: Derivation, + ) -> (ImportPrivateKeyResult, DeriveAccountsResult) { let wallet = import_default_pk_store(); let param = DeriveAccountsParam { @@ -810,7 +810,7 @@ mod tests { #[test] pub fn test_import_private_key() { run_test(|| { - let import_result: KeystoreResult = import_default_pk_store(); + let import_result = import_default_pk_store(); let derivations = vec![ Derivation { @@ -946,7 +946,6 @@ mod tests { name: "test_tezos_import_private_key_export".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "TEZOS".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -1019,7 +1018,7 @@ mod tests { #[test] pub fn test_tezos_hd_private_key_import_export() { run_test(|| { - let import_result: KeystoreResult = import_default_pk_store(); + let import_result = import_default_pk_store(); let derivations = vec![Derivation { chain_type: "TEZOS".to_string(), @@ -1073,7 +1072,6 @@ mod tests { name: "test_filecoin_import_private_key".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -1134,7 +1132,6 @@ mod tests { name: "test_filecoin_import_private_key".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -1194,7 +1191,6 @@ mod tests { name: "test_64bytes_import_private_key".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -1246,7 +1242,7 @@ mod tests { #[test] pub fn test_private_key_store_export() { run_test(|| { - let import_result: KeystoreResult = import_default_pk_store(); + let import_result = import_default_pk_store(); let param: PrivateKeyStoreExportParam = PrivateKeyStoreExportParam { id: import_result.id.to_string(), password: TEST_PASSWORD.to_string(), @@ -1525,7 +1521,6 @@ mod tests { name: "test_import_to_pk_which_from_hd".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -1560,10 +1555,13 @@ mod tests { #[test] pub fn test_verify_password() { run_test(|| { - let wallets = vec![import_default_pk_store(), import_default_wallet()]; - for wallet in wallets { + let wallet_id = vec![ + import_default_pk_store().id.to_string(), + import_default_wallet().id.to_string(), + ]; + for id in wallet_id { let param: WalletKeyParam = WalletKeyParam { - id: wallet.id.to_string(), + id: id.to_string(), password: TEST_PASSWORD.to_string(), }; @@ -1572,7 +1570,7 @@ mod tests { assert!(result.is_success); let param: WalletKeyParam = WalletKeyParam { - id: wallet.id.to_string(), + id: id.to_string(), password: "WRONG PASSWORD".to_string(), }; @@ -1592,7 +1590,6 @@ mod tests { name: "test_delete_keystore".to_string(), password_hint: "".to_string(), overwrite: true, - encoding: "".to_string(), }; let ret_bytes = import_private_key(&encode_message(param).unwrap()).unwrap(); @@ -2107,7 +2104,6 @@ mod tests { let param = ImportJsonParam { keystore: wrong_keystore_str.to_string(), password: TEST_PASSWORD.to_string(), - chain_type: "KUSAMA".to_string(), overwrite: true, }; // let param_bytes = encode_message(param).unwrap(); @@ -2144,7 +2140,6 @@ mod tests { let param = ImportJsonParam { keystore: keystore_str.to_string(), password: TEST_PASSWORD.to_string(), - chain_type: "KUSAMA".to_string(), overwrite: true, }; // let param_bytes = encode_message(param).unwrap(); @@ -2275,7 +2270,6 @@ mod tests { let param = ImportJsonParam { keystore: keystore_str.to_string(), password: TEST_PASSWORD.to_string(), - chain_type: "KUSAMA".to_string(), overwrite: true, }; // let param_bytes = encode_message(param).unwrap(); @@ -3147,162 +3141,6 @@ mod tests { }) } - #[test] - pub fn test_generate_mnemonic() { - run_test(|| { - let generate_mnemonic_bytes = call_api("generate_mnemonic", ()).unwrap(); - let generate_mnemonic_result: GenerateMnemonicResult = - GenerateMnemonicResult::decode(generate_mnemonic_bytes.as_slice()).unwrap(); - let split_result: Vec<&str> = generate_mnemonic_result - .mnemonic - .split_whitespace() - .collect(); - assert_eq!(split_result.len(), 12); - }) - } - - // #[test] - // pub fn test_identity_wallet_create() { - // run_test(|| { - // let param = CreateIdentityParam { - // name: sample_key::NAME.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: Some(sample_key::PASSWORD_HINT.to_string()), - // network: model::NETWORK_TESTNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("create_identity", param).unwrap(); - // let create_result: CreateIdentityResult = - // CreateIdentityResult::decode(ret.as_slice()).unwrap(); - // assert!(create_result.ipfs_id.len() > 0); - // assert!(create_result.identifier.len() > 0); - - // let param = CreateIdentityParam { - // name: sample_key::NAME.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: None, - // network: model::NETWORK_TESTNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("create_identity", param).unwrap(); - // let create_result: CreateIdentityResult = - // CreateIdentityResult::decode(ret.as_slice()).unwrap(); - // assert!(create_result.ipfs_id.len() > 0); - // assert!(create_result.identifier.len() > 0); - // assert_eq!(create_result.wallets.len(), 1); - // let wallets = create_result.wallets.get(0).unwrap(); - // assert_eq!(wallets.chain_type, "ETHEREUM"); - - // let param = CreateIdentityParam { - // name: sample_key::NAME.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: None, - // network: model::NETWORK_MAINNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("create_identity", param).unwrap(); - // let create_result: CreateIdentityResult = - // CreateIdentityResult::decode(ret.as_slice()).unwrap(); - // assert!(create_result.ipfs_id.len() > 0); - // assert!(create_result.identifier.len() > 0); - - // let ret_bytes = call_api("get_current_identity", ()).unwrap(); - // let ret: GetCurrentIdentityResult = - // GetCurrentIdentityResult::decode(ret_bytes.as_slice()).unwrap(); - // assert_eq!(ret.wallets.len(), 1); - // let wallet = ret.wallets.get(0).unwrap(); - // assert_eq!( - // wallet.metadata.clone().unwrap().chain_type, - // constants::CHAIN_TYPE_ETHEREUM - // ) - // }) - // } - - // #[test] - // pub fn test_recover_identity_on_testnet() { - // run_test(|| { - // let param = RecoverIdentityParam { - // name: sample_key::NAME.to_string(), - // mnemonic: sample_key::MNEMONIC.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: Some(sample_key::PASSWORD_HINT.to_string()), - // network: model::NETWORK_TESTNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("recover_identity", param).unwrap(); - // let recover_result: RecoverIdentityResult = - // RecoverIdentityResult::decode(ret.as_slice()).unwrap(); - // assert_eq!( - // recover_result.ipfs_id, - // "QmSTTidyfa4np9ak9BZP38atuzkCHy4K59oif23f4dNAGU" - // ); - // assert_eq!( - // recover_result.identifier, - // "im18MDKM8hcTykvMmhLnov9m2BaFqsdjoA7cwNg" - // ); - - // let wallet = recover_result.wallets.get(0).unwrap(); - // assert_eq!(wallet.chain_type, constants::CHAIN_TYPE_ETHEREUM); - // assert_eq!(wallet.address, "6031564e7b2f5cc33737807b2e58daff870b590b"); - // }) - // } - - // #[test] - // pub fn test_export_identity() { - // run_test(|| { - // let param = RecoverIdentityParam { - // name: sample_key::NAME.to_string(), - // mnemonic: MNEMONIC.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: Some(sample_key::PASSWORD_HINT.to_string()), - // network: model::NETWORK_TESTNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("recover_identity", param).unwrap(); - // let recover_result: RecoverIdentityResult = - // RecoverIdentityResult::decode(ret.as_slice()).unwrap(); - // assert!(recover_result.ipfs_id.len() > 0); - // assert!(recover_result.identifier.len() > 0); - - // let param = ExportIdentityParam { - // identifier: recover_result.identifier.to_owned(), - // password: sample_key::PASSWORD.to_string(), - // }; - // let ret = call_api("export_identity", param).unwrap(); - // let export_result: ExportIdentityResult = - // ExportIdentityResult::decode(ret.as_slice()).unwrap(); - // assert_eq!(export_result.mnemonic, MNEMONIC); - // assert_eq!(recover_result.identifier, export_result.identifier); - // }) - // } - - // #[test] - // pub fn test_delete_identity() { - // run_test(|| { - // let param = CreateIdentityParam { - // name: sample_key::NAME.to_string(), - // password: sample_key::PASSWORD.to_string(), - // password_hint: Some(sample_key::PASSWORD_HINT.to_string()), - // network: model::NETWORK_TESTNET.to_string(), - // seg_wit: None, - // }; - // let ret = call_api("create_identity", param).unwrap(); - // let create_result: CreateIdentityResult = - // CreateIdentityResult::decode(ret.as_slice()).unwrap(); - // assert!(create_result.ipfs_id.len() > 0); - // assert!(create_result.identifier.len() > 0); - - // let remove_identity_param = RemoveIdentityParam { - // identifier: create_result.identifier.to_owned(), - // password: sample_key::PASSWORD.to_string(), - // }; - // let ret = call_api("remove_identity", remove_identity_param).unwrap(); - // let remove_result: RemoveIdentityResult = - // RemoveIdentityResult::decode(ret.as_slice()).unwrap(); - // assert_eq!(remove_result.identifier, create_result.identifier); - // }) - // } - #[test] pub fn test_sign_ethereum_legacy_tx() { run_test(|| { @@ -3488,6 +3326,47 @@ mod tests { }) } + #[test] + pub fn test_sign_ethereum_sign_message() { + run_test(|| { + let derivation = 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: "".to_string(), + bech32_prefix: "".to_string(), + }; + + let (wallet, _acc_rsp) = import_and_derive(derivation); + + let eth_tx_input = EthMessageInput { + message: "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765" + .to_string(), + signature_type: 0i32, + }; + let input_value = encode_message(eth_tx_input).unwrap(); + let param = SignParam { + id: wallet.id.to_string(), + chain_type: "ETHEREUM".to_string(), + path: "m/44'/60'/0'/0/0".to_string(), + curve: "SECP256k1".to_string(), + network: "".to_string(), + seg_wit: "".to_string(), + input: Some(::prost_types::Any { + type_url: "imtoken".to_string(), + value: input_value, + }), + key: Some(sign_param::Key::Password(sample_key::PASSWORD.to_string())), + }; + let ret = call_api("sign_msg", param).unwrap(); + let output: EthMessageOutput = EthMessageOutput::decode(ret.as_slice()).unwrap(); + + assert_eq!(output.signature, "0x5d595524847790aade63630ba4320854e0ae474b50d4c83eadfea9179185b2d67479cdfa9f59ec8f62575a7c09d4a5c9683aaf9cdb198ee51bdbe1bbf6eed1e91b"); + }) + } + #[test] pub fn test_derive_btc_legacy_sub_accounts() { run_test(|| { @@ -3768,12 +3647,4 @@ mod tests { // fn test_sign_authentication_message() { // todo!() // } - - #[test] - fn test_decode_derive_account() { - let data = Vec::::from_hex("0ab2020a08455448455245554d122a3078456332373437326434314142616464373331373932343737333345423039323761443635316338361a106d2f3434272f3630272f30272f302f302298014c795a4867657356664178796e4e425a6f5463313645536551376d463772685a334b75385152364f6f67584c614e3845387559484139574442335632533977376c333665424a4f38766470636c644e45524264634d482f544c7a6a4e7a32446b314878337939734b6c77527a41464c563931357445714f716641586e796351555770304276556a6e415a54486a764a45354954546b413d3d2a423033313564636233386135383937343832373538616266303564616335616531303465626231326234383131666134343639646433306361653736653133373339303209534543503235366b310aa4020a07424954434f494e1222334e664e354a386933706e6d44526951593550556368764441386e3566364a68556f1a0b6d2f3439272f30272f3027229801336b5a6d5a763378636756615346562b734c675050524a55344f6a6a76306c4630314e4571644e48565655687874427062485378496b4356566d53332f6e726a3743696c4b58505145657063615332575a795772722b53694b4d425859486f3658545772664978314e4f6b4569323935324e4e41736b7470796c496e71494573592f4151313761524d3350686f6f55594d7a6c4c46413d3d2a423032636561386631663766313566396534383739393338623137396636616631343961373664333334663934346137646164636136333464323865343966343964363209534543503235366b310aa9020a084c495445434f494e12224c56337570376a3877637968423347766575524e4b7157464a387864764464474c481a0f6d2f3439272f32272f30272f302f3022980144557873735951594833615878654c735266626b474479676f6972537254496e7a447133614b7178714b4b6f3269427048796e596757474a58776c5968774345334d712f696d2b4e314537504f592f52533375366779694a45614a43364533716a4c32766435396769632f2f3430305a76323675422b3657394c764954767071513357304662506a38656c4d395632655638323870773d3d2a423032653066616466396439386339656263373337643633343565353136376163303439393333396635333233343161393365643461653436613937643861306662373209534543503235366b310ab4020a06434f534d4f53122d636f736d6f7331793039396b75636570636b656a39687539337063706c387635346867303432396775307037641a116d2f3434272f313138272f30272f302f30229801334d45484d6a3263497078664833662b7a52314f6d6b45743169496453704e324670435734634d693230354a4c4f7463386e554c3241365146574e47797465624b45713765796432686754424c4b4d2f3344454d366d3672534b536f67534f3056616d4c6677442b70304375302b304452775335444f7a6c50673874364d733575372b4556763877707a6d75357a627a53326a4854513d3d2a423032333239626232346366373834633765363066376637663236393931383661656430663138656139303932306364613130363039386464303338393765303038383209534543503235366b310ab2020a0846494c45434f494e122966317a7369723576677977636b6e61716a6a653377336179666d327a72797671636c6362376f7436611a116d2f3434272f343631272f30272f302f302298012b78664f452f66342f42347070366f2b62553952433631684863383662664b732f456e78653254337569646136637432396a4738317443427150365a37564845476c33505266713479675152695137624d2f4b4d63505471334739324c67577a796a676a356e742b4e62536a55637a6b4253375879456a6345336e6637425731434c2f574662544f734f516b714e37574546667033513d3d2a423033643434633732356261663934356632356630613961633131396433313064343336333437343936353030623461336133326563633236343339366631336362653209534543503235366b310ab5020a064e4552564f53122e636b62317179717878793577796d616d68736a3076636b6a6c716b6377326e7470346c75366476716d687a6c61661a116d2f3434272f333039272f30272f302f30229801744e38717a484e484e454b5a2f674d443833526b783472304c687777723478636a6e4f646e6b526e395261695569387450336b5a6145366234595a544f4c563074647641444a715378356165675149412f6a527a526e4169774e544963576f50764d6733436e4c2f4b4c61536d374842716662665241673951567936744364306349653969614e6751737a774148536c6d4c366632413d3d2a423032333163663165666661316166396137346334613266306333376166323831643735623464383533636231626331373931353865336564336632643038666638333209534543503235366b310a9c010a064b5553414d41122f485046716e39526b4b42686f41575743765950416a5a51525935624264575775525234584338513657656f6265527a1a132f2f6b7573616d612f2f696d546f6b656e2f302a4064346264313765616138373638666662373437386433326439363039336239366634663663386338323639656437373836666661636436396431623531313234320a537562537232353531390aa1010a08504f4c4b41444f54123031346144413137543570476248366a735157714348395477664d5a41706a5a366e656874654d445843347536653779431a152f2f706f6c6b61646f742f2f696d546f6b656e2f302a4039653038623737653565306539326330643231383966653736326137663061663132386236623438396462316465326432386431333030663163323638303736320a537562537232353531390a8b010a0554455a4f531224747a3159714a584b686f43354e6e78393431794a41456a77464e786252564a7361626d451a116d2f3434272f31373239272f30272f30272a4065613835376561343365316435333164343664336234336438356538383233666165336230373533636639363539383563316164643666316534656365323733320745443235353139").unwrap(); - let rsp: DeriveAccountsResult = DeriveAccountsResult::decode(data.as_slice()).unwrap(); - dbg!(&rsp); - assert_eq!("ex", rsp.accounts.first().unwrap().extended_public_key); - } } diff --git a/token-core/tcx/src/macros.rs b/token-core/tcx/src/macros.rs index 84aaa7e6..b99566aa 100644 --- a/token-core/tcx/src/macros.rs +++ b/token-core/tcx/src/macros.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use tcx_constants::CoinInfo; use tcx_keystore::{Address, Keystore, MessageSigner, SignatureParameters, TransactionSigner}; -use tcx_primitive::TypedDeterministicPublicKey; + use tcx_primitive::TypedPublicKey; #[allow(clippy::derive_partial_eq_without_eq)]