kobe_svm/
derivation_style.rs1use alloc::{format, string::String};
7use core::fmt;
8use core::str::FromStr;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
23#[non_exhaustive]
24pub enum DerivationStyle {
25 #[default]
37 Standard,
38
39 Trust,
50
51 LedgerLive,
62
63 #[deprecated(
70 note = "Use Standard style for new wallets. Legacy is only for recovering old Phantom/Sollet wallets."
71 )]
72 Legacy,
73}
74
75impl DerivationStyle {
76 #[must_use]
86 #[allow(deprecated)]
87 pub fn path(self, index: u32) -> String {
88 match self {
89 Self::Standard => format!("m/44'/501'/{index}'/0'"),
90 Self::Trust => format!("m/44'/501'/{index}'"),
91 Self::LedgerLive => format!("m/44'/501'/{index}'/0'/0'"),
92 Self::Legacy => format!("m/501'/{index}'/0/0"),
93 }
94 }
95
96 #[must_use]
98 #[allow(deprecated)]
99 pub const fn name(self) -> &'static str {
100 match self {
101 Self::Standard => "Standard (Phantom/Backpack)",
102 Self::Trust => "Trust (Ledger/Keystone)",
103 Self::LedgerLive => "Ledger Live",
104 Self::Legacy => "Legacy (deprecated)",
105 }
106 }
107
108 #[must_use]
110 #[allow(deprecated)]
111 pub const fn id(self) -> &'static str {
112 match self {
113 Self::Standard => "standard",
114 Self::Trust => "trust",
115 Self::LedgerLive => "ledger-live",
116 Self::Legacy => "legacy",
117 }
118 }
119
120 #[must_use]
122 #[allow(deprecated)]
123 pub const fn all() -> &'static [Self] {
124 &[Self::Standard, Self::Trust, Self::LedgerLive, Self::Legacy]
125 }
126}
127
128impl fmt::Display for DerivationStyle {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{}", self.name())
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq)]
136pub struct ParseDerivationStyleError(pub(crate) String);
137
138impl fmt::Display for ParseDerivationStyleError {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 write!(
141 f,
142 "invalid derivation style '{}', expected one of: standard, trust, ledger-live, legacy",
143 self.0
144 )
145 }
146}
147
148#[cfg(feature = "std")]
149impl std::error::Error for ParseDerivationStyleError {}
150
151#[allow(deprecated)]
152impl FromStr for DerivationStyle {
153 type Err = ParseDerivationStyleError;
154
155 fn from_str(s: &str) -> Result<Self, Self::Err> {
156 match s.to_lowercase().as_str() {
157 "standard" | "phantom" | "backpack" | "solflare" | "trezor" => Ok(Self::Standard),
159 "trust" | "trustwallet" | "ledger" | "ledger-native" | "ledgernative" | "keystone" => {
161 Ok(Self::Trust)
162 }
163 "ledger-live" | "ledgerlive" | "live" => Ok(Self::LedgerLive),
165 "legacy" | "old" | "sollet" => Ok(Self::Legacy),
167 _ => Err(ParseDerivationStyleError(s.into())),
168 }
169 }
170}
171
172#[cfg(test)]
173#[allow(deprecated)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_standard_paths() {
179 let style = DerivationStyle::Standard;
180 assert_eq!(style.path(0), "m/44'/501'/0'/0'");
181 assert_eq!(style.path(1), "m/44'/501'/1'/0'");
182 assert_eq!(style.path(10), "m/44'/501'/10'/0'");
183 }
184
185 #[test]
186 fn test_trust_paths() {
187 let style = DerivationStyle::Trust;
188 assert_eq!(style.path(0), "m/44'/501'/0'");
189 assert_eq!(style.path(1), "m/44'/501'/1'");
190 assert_eq!(style.path(10), "m/44'/501'/10'");
191 }
192
193 #[test]
194 fn test_ledger_live_paths() {
195 let style = DerivationStyle::LedgerLive;
196 assert_eq!(style.path(0), "m/44'/501'/0'/0'/0'");
197 assert_eq!(style.path(1), "m/44'/501'/1'/0'/0'");
198 assert_eq!(style.path(10), "m/44'/501'/10'/0'/0'");
199 }
200
201 #[test]
202 fn test_legacy_paths() {
203 let style = DerivationStyle::Legacy;
204 assert_eq!(style.path(0), "m/501'/0'/0/0");
205 assert_eq!(style.path(1), "m/501'/1'/0/0");
206 assert_eq!(style.path(10), "m/501'/10'/0/0");
207 }
208
209 #[test]
210 fn test_from_str() {
211 assert_eq!(
213 "standard".parse::<DerivationStyle>().unwrap(),
214 DerivationStyle::Standard
215 );
216 assert_eq!(
217 "phantom".parse::<DerivationStyle>().unwrap(),
218 DerivationStyle::Standard
219 );
220 assert_eq!(
221 "backpack".parse::<DerivationStyle>().unwrap(),
222 DerivationStyle::Standard
223 );
224
225 assert_eq!(
227 "trust".parse::<DerivationStyle>().unwrap(),
228 DerivationStyle::Trust
229 );
230 assert_eq!(
231 "ledger".parse::<DerivationStyle>().unwrap(),
232 DerivationStyle::Trust
233 );
234 assert_eq!(
235 "keystone".parse::<DerivationStyle>().unwrap(),
236 DerivationStyle::Trust
237 );
238
239 assert_eq!(
241 "ledger-live".parse::<DerivationStyle>().unwrap(),
242 DerivationStyle::LedgerLive
243 );
244
245 assert_eq!(
247 "legacy".parse::<DerivationStyle>().unwrap(),
248 DerivationStyle::Legacy
249 );
250 }
251
252 #[test]
253 fn test_from_str_invalid() {
254 assert!("invalid".parse::<DerivationStyle>().is_err());
255 }
256
257 #[test]
258 fn test_default() {
259 assert_eq!(DerivationStyle::default(), DerivationStyle::Standard);
260 }
261}