cpchain_rust_sdk/
accounts.rs

1use bip39::Mnemonic;
2use secp256k1::{rand, PublicKey, Secp256k1, SecretKey};
3use web3::{signing, types::Address as Web3Address};
4
5use crate::{address::Address, hd::HDNode, utils, keystore::Keystore};
6
7/// Account
8///
9/// Example
10/// ```rust
11/// // Default derived path is "m/44'/337'/0'/0/0"
12/// let account = Account::new(None);
13/// // Get addres
14/// println!("{}", account.address.to_checksum());
15/// ```
16#[derive(Debug, Clone)]
17pub struct Account {
18    pub secret_key: SecretKey,
19    #[allow(dead_code)]
20    public_key: PublicKey,
21    pub address: Address,
22    pub mnemonic: Option<Mnemonic>,
23}
24
25fn generate_address(public_key: &PublicKey) -> Address {
26    let public_key = public_key.serialize_uncompressed();
27    debug_assert_eq!(public_key[0], 0x04);
28    let hash = signing::keccak256(&public_key[1..]);
29    let h160 = Web3Address::from_slice(&hash[12..]);
30    Address::new(h160)
31}
32
33impl Account {
34    pub fn new(derive_path: Option<String>) -> Result<Self, Box<dyn std::error::Error>> {
35        let hd_node = HDNode::new()?;
36        Account::_new(derive_path, &hd_node)
37    }
38
39    fn _new(derive_path: Option<String>, hd_node: &HDNode) -> Result<Account, Box<dyn std::error::Error>> {
40        let hd_node = hd_node.derive_path(
41            derive_path
42                .unwrap_or("m/44'/337'/0'/0/0".to_string())
43                .as_str(),
44        )?;
45        let secret_key = SecretKey::from_slice(&hd_node.private_key.unwrap())?;
46        let secp = Secp256k1::new();
47        let public_key = PublicKey::from_secret_key(&secp, &secret_key);
48        let address = generate_address(&public_key);
49        Ok(Self {
50            secret_key,
51            public_key,
52            address,
53            mnemonic: hd_node.mnemonic,
54        })
55    }
56
57    pub fn from_phrase(phrase: &str, derive_path: Option<String>) -> Result<Account, Box<dyn std::error::Error>> {
58        let hd_node = HDNode::from_phrase(phrase)?;
59        Account::_new(derive_path, &hd_node)
60    }
61
62    pub fn from_keystore(json: &str, password: &str) -> Result<Account, Box<dyn std::error::Error + Send + Sync>> {
63        let ks = Keystore::from(json.to_string());
64        ks.decrypt(password)
65    }
66
67    fn from_secert_key(secret_key: SecretKey) -> Self {
68        let secp = Secp256k1::new();
69        let public_key = PublicKey::from_secret_key(&secp, &secret_key);
70        let address = generate_address(&public_key);
71        Self {
72            secret_key,
73            public_key,
74            address,
75            mnemonic: None,
76        }
77    }
78
79    pub fn from_private_key(private_key: &str) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
80        let bytes = utils::hex_to_bytes(private_key)?;
81        let secret_key = SecretKey::from_slice(&bytes)?;
82        Ok(Account::from_secert_key(secret_key))
83    }
84
85    pub fn random() -> Account {
86        let secret_key = SecretKey::new(&mut rand::thread_rng());
87        Account::from_secert_key(secret_key)
88    }
89
90    pub fn private_key_bytes(&self) -> [u8; 32] {
91        self.secret_key.serialize_secret()
92    }
93
94    pub fn private_key(&self) -> String {
95        let bytes = self.secret_key.serialize_secret().to_vec();
96        format!("0x{}", hex::encode(&bytes))
97    }
98
99    /// sign_tx 给交易签名
100    pub fn sign_tx(&self) {
101
102    }
103
104}
105
106#[cfg(test)]
107mod tests {
108    use bip39::{Language, Mnemonic, MnemonicType};
109
110    use crate::address::Address;
111
112    use super::Account;
113
114    #[test]
115    fn test_create_account() {
116        let account = Account::random();
117        assert!(account.private_key().len() == 66);
118        let account = Account::new(None).unwrap();
119        println!("{} {}", account.mnemonic.unwrap().phrase(), account.address)
120    }
121
122    #[test]
123    fn test_from_phrase() {
124        let account = Account::from_phrase("length much pull abstract almost spin hair chest ankle harbor dizzy life", None).unwrap();
125        assert_eq!(account.address.to_checksum(), "0x7D491C482eBa270700b584888f864177205c5159");
126    }
127
128    #[test]
129    fn test_from_private_key() {
130        let account = Account::from_private_key(
131            "0x6c0296556144bf09864f0583886867e5cb2eea02206ca7187d998529ff8ef069",
132        )
133        .unwrap();
134        assert!(
135            account.address
136                == Address::from_str("0x7de6c6E04Ea0CDc76fD51c6F441C25a7DCA236A0").unwrap()
137        )
138    }
139
140    #[test]
141    fn test_bip39() {
142        let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
143        println!("{}", mnemonic.phrase());
144        println!("{:?}", mnemonic.entropy().len())
145    }
146
147    #[test]
148    fn test_mnemonic_of_account() {
149        let addr = "0xd7998FD7F5454722a16Cd67E881CedF9896CE396";
150        let private_key = "0xf07ab943a5cd880d273ec38878bfa914bbfa1fe46dc6deb78590f8ef137a0690";
151        // let mnemonic = "lyrics mean wisdom census merit sample always escape spread tone pipe current";
152        let account = Account::from_private_key(private_key).unwrap();
153        assert!(account.address == Address::from_str(addr).unwrap());
154        assert_eq!(account.mnemonic.is_none(), true);
155    }
156}