ergo_lib_wasm/wallet/derivation_path.rs
1//! Derivation path according to
2//! BIP-44 <https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki>
3//! and EIP-3 <https://github.com/ergoplatform/eips/blob/master/eip-0003.md>
4
5use derive_more::FromStr;
6use ergo_lib::wallet::derivation_path::ChildIndexError;
7use ergo_lib::wallet::derivation_path::ChildIndexHardened;
8use ergo_lib::wallet::derivation_path::ChildIndexNormal;
9use ergo_lib::wallet::derivation_path::DerivationPath as InnerDerivationPath;
10use wasm_bindgen::prelude::*;
11
12use crate::error_conversion::to_js;
13
14extern crate derive_more;
15use derive_more::{From, Into};
16
17/// According to
18/// BIP-44 <https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki>
19/// and EIP-3 <https://github.com/ergoplatform/eips/blob/master/eip-0003.md>
20#[wasm_bindgen]
21#[derive(PartialEq, Eq, Debug, Clone, From, Into, FromStr)]
22pub struct DerivationPath(InnerDerivationPath);
23
24#[wasm_bindgen]
25impl DerivationPath {
26 /// Create derivation path for a given account index (hardened) and address indices
27 /// `m / 44' / 429' / acc' / 0 / address[0] / address[1] / ...`
28 /// or `m / 44' / 429' / acc' / 0` if address indices are empty
29 /// change is always zero according to EIP-3
30 /// acc is expected as a 31-bit value (32th bit should not be set)
31 pub fn new(acc: u32, address_indices: &[u32]) -> Result<DerivationPath, JsValue> {
32 let acc = ChildIndexHardened::from_31_bit(acc).map_err(to_js)?;
33 let address_indices = address_indices
34 .iter()
35 .map(|i| ChildIndexNormal::normal(*i))
36 .collect::<Result<Vec<ChildIndexNormal>, ChildIndexError>>()
37 .map_err(to_js)?;
38 Ok(DerivationPath(InnerDerivationPath::new(
39 acc,
40 address_indices,
41 )))
42 }
43
44 /// Create root derivation path
45 pub fn master_path() -> Self {
46 DerivationPath(InnerDerivationPath::master_path())
47 }
48
49 /// Returns the length of the derivation path
50 pub fn depth(&self) -> usize {
51 self.0.depth()
52 }
53
54 /// Returns a new path with the last element of the deriviation path being increased, e.g. m/1/2 -> m/1/3
55 /// Returns an empty path error if the path is empty (master node)
56 pub fn next(&self) -> Result<DerivationPath, JsValue> {
57 Ok(self.0.next().map_err(to_js)?.into())
58 }
59
60 /// String representation of derivation path
61 /// E.g m/44'/429'/0'/0/1
62 #[wasm_bindgen(js_name = toString)]
63 #[allow(clippy::inherent_to_string)]
64 pub fn to_string(&self) -> String {
65 self.0.to_string()
66 }
67
68 /// Create a derivation path from a formatted string
69 /// E.g "m/44'/429'/0'/0/1"
70 pub fn from_string(path: &str) -> Result<DerivationPath, JsValue> {
71 Ok(path.parse::<InnerDerivationPath>().map_err(to_js)?.into())
72 }
73
74 /// For 0x21 Sign Transaction command of Ergo Ledger App Protocol
75 /// P2PK Sign (0x0D) instruction
76 /// Sign calculated TX hash with private key for provided BIP44 path.
77 /// Data:
78 ///
79 /// Field
80 /// Size (B)
81 /// Description
82 ///
83 /// BIP32 path length
84 /// 1
85 /// Value: 0x02-0x0A (2-10). Number of path components
86 ///
87 /// First derivation index
88 /// 4
89 /// Big-endian. Value: 44’
90 ///
91 /// Second derivation index
92 /// 4
93 /// Big-endian. Value: 429’ (Ergo coin id)
94 ///
95 /// Optional Third index
96 /// 4
97 /// Big-endian. Any valid bip44 hardened value.
98 /// ...
99 /// Optional Last index
100 /// 4
101 /// Big-endian. Any valid bip44 value.
102 ///
103 pub fn ledger_bytes(&self) -> Vec<u8> {
104 self.0.ledger_bytes()
105 }
106}