1use std::str::FromStr;
4
5use bdk::{
6 bitcoin::{
7 secp256k1::Secp256k1,
8 util::bip32::{DerivationPath, ExtendedPrivKey},
9 Address as BitcoinAddress, AddressType as BitcoinAddressType,
10 Network as BitcoinNetwork,
11 },
12 keys::bip39::Mnemonic,
13};
14use rand::random;
15use serde::{Deserialize, Serialize};
16
17use crate::{
18 address::{AddressVersion, StacksAddress},
19 crypto::{wif::WIF, PrivateKey, PublicKey},
20 Network, StacksError, StacksResult,
21};
22
23pub fn stacks_derivation_path(index: u32) -> StacksResult<DerivationPath> {
25 Ok(DerivationPath::from_str(&format!(
26 "m/44'/5757'/0'/0/{}",
27 index
28 ))?)
29}
30
31pub fn bitcoin_derivation_path(
33 network: BitcoinNetwork,
34 kind: BitcoinAddressType,
35 index: u32,
36) -> StacksResult<DerivationPath> {
37 let mut path = "m/".to_string();
38
39 match kind {
40 BitcoinAddressType::P2pkh => path.push_str("44'/"),
41 BitcoinAddressType::P2wpkh => path.push_str("84'/"),
42 BitcoinAddressType::P2tr => path.push_str("86'/"),
43 _ => {
44 return Err(StacksError::InvalidArguments(
45 "Invalid Bitcoin addres type",
46 ))
47 }
48 };
49
50 match network {
51 BitcoinNetwork::Bitcoin => path.push_str("0'/"),
52 _ => path.push_str("1'/"),
53 }
54
55 path.push_str(&format!("{}'/0/0", index));
56
57 Ok(DerivationPath::from_str(&path)?)
58}
59
60pub fn derive_key(
62 master_key: ExtendedPrivKey,
63 path: DerivationPath,
64) -> ExtendedPrivKey {
65 master_key.derive_priv(&Secp256k1::new(), &path).unwrap()
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Wallet {
71 master_key: ExtendedPrivKey,
72 mnemonic: Mnemonic,
73}
74
75impl Wallet {
76 pub fn new(mnemonic: impl AsRef<str>) -> StacksResult<Self> {
78 let mnemonic = Mnemonic::from_str(mnemonic.as_ref())?;
79
80 let master_key = ExtendedPrivKey::new_master(
82 BitcoinNetwork::Bitcoin,
83 &mnemonic.to_seed(""),
84 )?;
85
86 Ok(Self {
87 master_key,
88 mnemonic,
89 })
90 }
91
92 pub fn random() -> StacksResult<Self> {
94 let entropy: [u8; 32] = random();
95 let mnemonic = Mnemonic::from_entropy(&entropy)?;
96
97 Self::new(mnemonic.to_string())
98 }
99
100 pub fn mnemonic(&self) -> Mnemonic {
102 self.mnemonic.clone()
103 }
104
105 pub fn master_key(&self) -> PrivateKey {
107 self.master_key.private_key
108 }
109
110 pub fn wif(&self, network: Network) -> WIF {
112 WIF::new(network, self.master_key())
113 }
114
115 pub fn credentials(
117 &self,
118 network: Network,
119 index: u32,
120 ) -> StacksResult<Credentials> {
121 Credentials::new(network, self.master_key, index)
122 }
123
124 pub fn bitcoin_credentials(
126 &self,
127 network: BitcoinNetwork,
128 index: u32,
129 ) -> StacksResult<BitcoinCredentials> {
130 BitcoinCredentials::new(network, self.master_key, index)
131 }
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct Credentials {
137 network: Network,
138 private_key: PrivateKey,
139}
140
141impl Credentials {
142 pub fn new(
144 network: Network,
145 master_key: ExtendedPrivKey,
146 index: u32,
147 ) -> StacksResult<Self> {
148 let private_key =
149 derive_key(master_key, stacks_derivation_path(index)?)
150 .to_priv()
151 .inner;
152
153 Ok(Self {
154 network,
155 private_key,
156 })
157 }
158
159 pub fn network(&self) -> Network {
161 self.network
162 }
163
164 pub fn private_key(&self) -> PrivateKey {
166 self.private_key
167 }
168
169 pub fn public_key(&self) -> PublicKey {
171 self.private_key.public_key(&Secp256k1::new())
172 }
173
174 pub fn address(&self) -> StacksAddress {
176 let version = match self.network {
177 Network::Mainnet => AddressVersion::MainnetSingleSig,
178 Network::Testnet => AddressVersion::TestnetSingleSig,
179 };
180
181 StacksAddress::p2pkh(version, &self.public_key())
182 }
183
184 pub fn wif(&self) -> WIF {
186 WIF::new(self.network(), self.private_key())
187 }
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct BitcoinCredentials {
193 network: BitcoinNetwork,
194 private_key_p2pkh: PrivateKey,
195 private_key_p2wpkh: PrivateKey,
196 private_key_p2tr: PrivateKey,
197}
198
199impl BitcoinCredentials {
200 pub fn new(
202 network: BitcoinNetwork,
203 master_key: ExtendedPrivKey,
204 index: u32,
205 ) -> StacksResult<Self> {
206 let private_key_p2pkh = derive_key(
207 master_key,
208 bitcoin_derivation_path(network, BitcoinAddressType::P2pkh, index)?,
209 )
210 .to_priv()
211 .inner;
212
213 let private_key_p2wpkh = derive_key(
214 master_key,
215 bitcoin_derivation_path(
216 network,
217 BitcoinAddressType::P2wpkh,
218 index,
219 )?,
220 )
221 .to_priv()
222 .inner;
223
224 let private_key_p2tr = derive_key(
225 master_key,
226 bitcoin_derivation_path(network, BitcoinAddressType::P2tr, index)?,
227 )
228 .to_priv()
229 .inner;
230
231 Ok(Self {
232 network,
233 private_key_p2pkh,
234 private_key_p2wpkh,
235 private_key_p2tr,
236 })
237 }
238
239 pub fn network(&self) -> BitcoinNetwork {
241 self.network
242 }
243
244 pub fn private_key_p2pkh(&self) -> PrivateKey {
246 self.private_key_p2pkh
247 }
248
249 pub fn private_key_p2wpkh(&self) -> PrivateKey {
251 self.private_key_p2wpkh
252 }
253
254 pub fn private_key_p2tr(&self) -> PrivateKey {
256 self.private_key_p2tr
257 }
258
259 pub fn public_key_p2pkh(&self) -> PublicKey {
261 self.private_key_p2pkh.public_key(&Secp256k1::new())
262 }
263
264 pub fn public_key_p2wpkh(&self) -> PublicKey {
266 self.private_key_p2wpkh.public_key(&Secp256k1::new())
267 }
268
269 pub fn public_key_p2tr(&self) -> PublicKey {
271 self.private_key_p2tr.public_key(&Secp256k1::new())
272 }
273
274 pub fn address_p2pkh(&self) -> BitcoinAddress {
276 BitcoinAddress::p2pkh(
277 &bdk::bitcoin::PublicKey::new(self.public_key_p2pkh()),
278 self.network(),
279 )
280 }
281
282 pub fn address_p2wpkh(&self) -> BitcoinAddress {
284 BitcoinAddress::p2wpkh(
285 &bdk::bitcoin::PublicKey::new(self.public_key_p2wpkh()),
286 self.network(),
287 )
288 .unwrap()
289 }
290
291 pub fn address_p2tr(&self) -> BitcoinAddress {
293 BitcoinAddress::p2tr(
294 &Secp256k1::new(),
295 self.public_key_p2tr().x_only_public_key().0,
296 None,
297 self.network(),
298 )
299 }
300
301 pub fn wif_p2pkh(&self) -> WIF {
303 WIF::new(self.network().into(), self.private_key_p2pkh())
304 }
305
306 pub fn wif_p2wpkh(&self) -> WIF {
308 WIF::new(self.network().into(), self.private_key_p2wpkh())
309 }
310
311 pub fn wif_p2tr(&self) -> WIF {
313 WIF::new(self.network().into(), self.private_key_p2tr())
314 }
315}