whisky_wallet/wallet/
mod.rs

1pub mod derivation_indices;
2pub mod mnemonic;
3pub mod root_key;
4use bip39::{Language, Mnemonic};
5use derivation_indices::DerivationIndices;
6pub use mnemonic::MnemonicWallet;
7pub use root_key::RootKeyWallet;
8use whisky_common::WError;
9use whisky_csl::{
10    csl::{Bip32PrivateKey, FixedTransaction, PrivateKey, PublicKey},
11    sign_transaction,
12};
13
14pub enum WalletType {
15    MnemonicWallet(MnemonicWallet),
16    RootKeyWallet(RootKeyWallet),
17    Cli(String),
18}
19
20pub struct Wallet {
21    pub wallet_type: WalletType,
22    pub account: Account,
23}
24
25pub struct Account {
26    pub private_key: PrivateKey,
27    pub public_key: PublicKey,
28}
29
30impl Account {
31    pub fn sign_transaction(&self, tx_hex: &str) -> Result<String, WError> {
32        let mut tx = FixedTransaction::from_hex(tx_hex)
33            .map_err(WError::from_err("Account - failed to deserialize tx hex"))?;
34        tx.sign_and_add_vkey_signature(&self.private_key)
35            .map_err(WError::from_err("Account - failed to sign transaction"))?;
36        Ok(tx.to_hex())
37    }
38}
39
40impl Wallet {
41    pub fn new(wallet_type: WalletType) -> Result<Self, WError> {
42        let account =
43            Wallet::get_account(&wallet_type).map_err(WError::from_err("Wallet - new"))?;
44        Ok(Self {
45            wallet_type: wallet_type,
46            account,
47        })
48    }
49
50    pub fn new_cli(cli_skey: &str) -> Result<Self, WError> {
51        let wallet_type = WalletType::Cli(cli_skey.to_string());
52        let account =
53            Wallet::get_account(&wallet_type).map_err(WError::from_err("Wallet - new"))?;
54        Ok(Self {
55            wallet_type,
56            account,
57        })
58    }
59
60    pub fn new_mnemonic(mnemonic_phrase: &str) -> Result<Self, WError> {
61        let wallet_type = WalletType::MnemonicWallet(MnemonicWallet {
62            mnemonic_phrase: mnemonic_phrase.to_string(),
63            derivation_indices: DerivationIndices::default(),
64        });
65        let account =
66            Wallet::get_account(&wallet_type).map_err(WError::from_err("Wallet - new_mnemonic"))?;
67        Ok(Self {
68            wallet_type,
69            account,
70        })
71    }
72
73    pub fn new_root_key(root_key: &str) -> Result<Self, WError> {
74        let wallet_type = WalletType::RootKeyWallet(RootKeyWallet {
75            root_key: root_key.to_string(),
76            derivation_indices: DerivationIndices::default(),
77        });
78        let account = Wallet::get_account(&wallet_type).map_err(WError::from_err(
79            "Wallet - new_root_key - failed to get account",
80        ))?;
81        Ok(Self {
82            wallet_type,
83            account,
84        })
85    }
86
87    pub fn payment_account(
88        &mut self,
89        account_index: u32,
90        key_index: u32,
91    ) -> Result<&mut Self, WError> {
92        match &mut self.wallet_type {
93            WalletType::MnemonicWallet(mnemonic_wallet) => {
94                mnemonic_wallet.payment_account(account_index, key_index);
95            }
96            WalletType::RootKeyWallet(root_key_wallet) => {
97                root_key_wallet.payment_account(account_index, key_index);
98            }
99            _ => {}
100        }
101        self.account = Wallet::get_account(&self.wallet_type).map_err(WError::from_err(
102            "Wallet - payment_account - failed to get account",
103        ))?;
104        Ok(self)
105    }
106
107    pub fn stake_account(
108        &mut self,
109        account_index: u32,
110        key_index: u32,
111    ) -> Result<&mut Self, WError> {
112        match &mut self.wallet_type {
113            WalletType::MnemonicWallet(mnemonic_wallet) => {
114                mnemonic_wallet.stake_account(account_index, key_index);
115            }
116            WalletType::RootKeyWallet(root_key_wallet) => {
117                root_key_wallet.stake_account(account_index, key_index);
118            }
119            _ => {}
120        }
121        self.account = Wallet::get_account(&self.wallet_type).map_err(WError::from_err(
122            "Wallet - stake_account - failed to get account",
123        ))?;
124        Ok(self)
125    }
126
127    pub fn drep_account(
128        &mut self,
129        account_index: u32,
130        key_index: u32,
131    ) -> Result<&mut Self, WError> {
132        match &mut self.wallet_type {
133            WalletType::MnemonicWallet(mnemonic_wallet) => {
134                mnemonic_wallet.drep_account(account_index, key_index);
135            }
136            WalletType::RootKeyWallet(root_key_wallet) => {
137                root_key_wallet.drep_account(account_index, key_index);
138            }
139            _ => {}
140        }
141        self.account = Wallet::get_account(&self.wallet_type).map_err(WError::from_err(
142            "Wallet - drep_account - failed to get account",
143        ))?;
144        Ok(self)
145    }
146
147    pub fn sign_tx(&self, tx_hex: &str) -> Result<String, WError> {
148        match &self.wallet_type {
149            WalletType::Cli(cli_skey) => {
150                let signed_tx = sign_transaction(tx_hex, &[cli_skey])
151                    .map_err(WError::from_err("Wallet - sign_tx"))?;
152                Ok(signed_tx)
153            }
154            _ => {
155                let signed_tx = self
156                    .account
157                    .sign_transaction(tx_hex)
158                    .map_err(WError::from_err("Wallet - sign_tx"))?;
159                Ok(signed_tx.to_string())
160            }
161        }
162    }
163
164    pub fn get_account(wallet_type: &WalletType) -> Result<Account, WError> {
165        let private_key: PrivateKey = match wallet_type {
166            WalletType::MnemonicWallet(mnemonic_wallet) => {
167                let mnemonic =
168                    Mnemonic::from_phrase(&mnemonic_wallet.mnemonic_phrase, Language::English)
169                        .map_err(WError::from_err(
170                            "Wallet - get_account - failed to create mnemonic",
171                        ))?;
172                let entropy = mnemonic.entropy();
173                let mut root_key = Bip32PrivateKey::from_bip39_entropy(entropy, &[]);
174                for index in &mnemonic_wallet.derivation_indices.0 {
175                    root_key = root_key.derive(index.clone());
176                }
177                root_key.to_raw_key()
178            }
179            WalletType::RootKeyWallet(root_key_wallet) => {
180                let mut root_key = Bip32PrivateKey::from_bech32(&root_key_wallet.root_key)
181                    .map_err(WError::from_err(
182                        "Wallet - get_account - invalid root key hex",
183                    ))?;
184                for index in &root_key_wallet.derivation_indices.0 {
185                    root_key = root_key.derive(index.clone());
186                }
187                root_key.to_raw_key()
188            }
189            WalletType::Cli(private_key) => PrivateKey::from_hex(&private_key).map_err(
190                WError::from_err("Wallet - get_account - invalid private key hex"),
191            )?,
192        };
193        let public_key = private_key.to_public();
194        Ok(Account {
195            private_key,
196            public_key,
197        })
198    }
199}