Skip to content

Commit 44e12a9

Browse files
Merge pull request #85 from DCG-Claude/feat/key-wallet-api-improvements
refactor(key-wallet): improve API with standard FromStr trait and bet…
2 parents b0be986 + bc14806 commit 44e12a9

File tree

5 files changed

+45
-33
lines changed

5 files changed

+45
-33
lines changed

key-wallet/examples/basic_usage.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ fn main() -> core::result::Result<(), Box<dyn std::error::Error>> {
6767
// 8. Address parsing example
6868
println!("\n8. Address parsing...");
6969
let test_address = "XyPvhVmhWKDgvMJLwfFfMwhxpxGgd3TBxq";
70-
match key_wallet::address::Address::from_str(test_address) {
70+
match test_address.parse::<key_wallet::address::Address>() {
7171
Ok(parsed) => {
7272
println!(" Parsed address: {}", parsed);
7373
println!(" Type: {:?}", parsed.address_type);
@@ -84,7 +84,6 @@ fn demonstrate_address_generation() -> core::result::Result<(), Box<dyn std::err
8484
// This demonstrates bulk address generation
8585
let seed = [0u8; 64];
8686
let wallet = HDWallet::from_seed(&seed, Network::Dash)?;
87-
let account = wallet.bip44_account(0)?;
8887
let path = key_wallet::DerivationPath::from(vec![
8988
key_wallet::ChildNumber::from_hardened_idx(44).unwrap(),
9089
key_wallet::ChildNumber::from_hardened_idx(5).unwrap(),

key-wallet/src/address.rs

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use alloc::string::String;
44
use alloc::vec::Vec;
55
use core::fmt;
6+
use core::str::FromStr;
67

78
use bitcoin_hashes::{hash160, Hash};
89
use secp256k1::{PublicKey, Secp256k1};
@@ -97,7 +98,39 @@ impl Address {
9798
}
9899

99100
/// Parse an address from a string (network is inferred from version byte)
100-
pub fn from_str(s: &str) -> Result<Self> {
101+
pub fn from_string(s: &str) -> Result<Self> {
102+
s.parse()
103+
}
104+
105+
/// Get the script pubkey for this address
106+
pub fn script_pubkey(&self) -> Vec<u8> {
107+
match self.address_type {
108+
AddressType::P2PKH => {
109+
let mut script = Vec::with_capacity(25);
110+
script.push(0x76); // OP_DUP
111+
script.push(0xa9); // OP_HASH160
112+
script.push(0x14); // Push 20 bytes
113+
script.extend_from_slice(&self.hash[..]);
114+
script.push(0x88); // OP_EQUALVERIFY
115+
script.push(0xac); // OP_CHECKSIG
116+
script
117+
}
118+
AddressType::P2SH => {
119+
let mut script = Vec::with_capacity(23);
120+
script.push(0xa9); // OP_HASH160
121+
script.push(0x14); // Push 20 bytes
122+
script.extend_from_slice(&self.hash[..]);
123+
script.push(0x87); // OP_EQUAL
124+
script
125+
}
126+
}
127+
}
128+
}
129+
130+
impl FromStr for Address {
131+
type Err = Error;
132+
133+
fn from_str(s: &str) -> Result<Self> {
101134
let data = base58ck::decode_check(s)
102135
.map_err(|_| Error::InvalidAddress("Invalid base58 encoding".into()))?;
103136

@@ -132,30 +165,6 @@ impl Address {
132165
hash,
133166
})
134167
}
135-
136-
/// Get the script pubkey for this address
137-
pub fn script_pubkey(&self) -> Vec<u8> {
138-
match self.address_type {
139-
AddressType::P2PKH => {
140-
let mut script = Vec::with_capacity(25);
141-
script.push(0x76); // OP_DUP
142-
script.push(0xa9); // OP_HASH160
143-
script.push(0x14); // Push 20 bytes
144-
script.extend_from_slice(&self.hash[..]);
145-
script.push(0x88); // OP_EQUALVERIFY
146-
script.push(0xac); // OP_CHECKSIG
147-
script
148-
}
149-
AddressType::P2SH => {
150-
let mut script = Vec::with_capacity(23);
151-
script.push(0xa9); // OP_HASH160
152-
script.push(0x14); // Push 20 bytes
153-
script.extend_from_slice(&self.hash[..]);
154-
script.push(0x87); // OP_EQUAL
155-
script
156-
}
157-
}
158-
}
159168
}
160169

161170
impl fmt::Display for Address {

key-wallet/src/derivation.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl KeyDerivation for ExtendedPrivKey {
2828
secp: &Secp256k1<C>,
2929
path: &DerivationPath,
3030
) -> Result<ExtendedPrivKey> {
31-
self.derive_priv(secp, path).map_err(Into::into)
31+
self.derive_priv(secp, path).map_err(Error::Bip32)
3232
}
3333

3434
fn derive_pub<C: secp256k1::Signing>(
@@ -74,7 +74,7 @@ impl HDWallet {
7474

7575
/// Derive a key at the given path
7676
pub fn derive(&self, path: &DerivationPath) -> Result<ExtendedPrivKey> {
77-
self.master_key.derive_priv(&self.secp, path).map_err(Into::into)
77+
self.master_key.derive_priv(&self.secp, path).map_err(Error::Bip32)
7878
}
7979

8080
/// Derive a public key at the given path
@@ -158,15 +158,19 @@ impl AccountDerivation {
158158
let path = format!("m/0/{}", index)
159159
.parse::<DerivationPath>()
160160
.map_err(|e| Error::InvalidDerivationPath(e.to_string()))?;
161-
self.account_key.derive_pub(&self.secp, &path).map_err(Into::into)
161+
let priv_key = self.account_key.derive_priv(&self.secp, &path)
162+
.map_err(Error::Bip32)?;
163+
Ok(ExtendedPubKey::from_priv(&self.secp, &priv_key))
162164
}
163165

164166
/// Derive an internal (change) address at index
165167
pub fn change_address(&self, index: u32) -> Result<ExtendedPubKey> {
166168
let path = format!("m/1/{}", index)
167169
.parse::<DerivationPath>()
168170
.map_err(|e| Error::InvalidDerivationPath(e.to_string()))?;
169-
self.account_key.derive_pub(&self.secp, &path).map_err(Into::into)
171+
let priv_key = self.account_key.derive_priv(&self.secp, &path)
172+
.map_err(Error::Bip32)?;
173+
Ok(ExtendedPubKey::from_priv(&self.secp, &priv_key))
170174
}
171175
}
172176

key-wallet/tests/address_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Address tests
22
3+
use std::str::FromStr;
34
use bitcoin_hashes::{hash160, Hash};
45
use key_wallet::address::{Address, AddressGenerator, AddressType};
56
use key_wallet::derivation::HDWallet;
@@ -98,7 +99,6 @@ fn test_address_generator() {
9899
let wallet = HDWallet::from_seed(&seed, Network::Dash).unwrap();
99100

100101
// Get account public key
101-
let account = wallet.bip44_account(0).unwrap();
102102
let path = key_wallet::DerivationPath::from(vec![
103103
key_wallet::ChildNumber::from_hardened_idx(44).unwrap(),
104104
key_wallet::ChildNumber::from_hardened_idx(5).unwrap(),

key-wallet/tests/mnemonic_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Mnemonic tests
22
33
use key_wallet::mnemonic::{Language, Mnemonic};
4-
use key_wallet::{ExtendedPrivKey, Network};
4+
use key_wallet::Network;
55

66
#[test]
77
fn test_mnemonic_validation() {

0 commit comments

Comments
 (0)