Make solana root key accessible on Ledger (#8421)

* Use 44/501 key as ledger id

* Add error codes
This commit is contained in:
Tyera Eulberg 2020-02-24 22:38:06 -07:00 committed by GitHub
parent 39282be486
commit b7755123c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 19 deletions

View File

@ -119,7 +119,7 @@ pub fn derivation_of(matches: &ArgMatches<'_>, name: &str) -> Option<DerivationP
matches.value_of(name).map(|derivation_str| { matches.value_of(name).map(|derivation_str| {
let derivation_str = derivation_str.replace("'", ""); let derivation_str = derivation_str.replace("'", "");
let mut parts = derivation_str.split('/'); let mut parts = derivation_str.split('/');
let account = parts.next().unwrap().parse::<u16>().unwrap(); let account = parts.next().map(|account| account.parse::<u16>().unwrap());
let change = parts.next().map(|change| change.parse::<u16>().unwrap()); let change = parts.next().map(|change| change.parse::<u16>().unwrap());
DerivationPath { account, change } DerivationPath { account, change }
}) })
@ -308,7 +308,7 @@ mod tests {
assert_eq!( assert_eq!(
derivation_of(&matches, "single"), derivation_of(&matches, "single"),
Some(DerivationPath { Some(DerivationPath {
account: 2, account: Some(2),
change: Some(3) change: Some(3)
}) })
); );
@ -319,7 +319,7 @@ mod tests {
assert_eq!( assert_eq!(
derivation_of(&matches, "single"), derivation_of(&matches, "single"),
Some(DerivationPath { Some(DerivationPath {
account: 2, account: Some(2),
change: None change: None
}) })
); );
@ -330,7 +330,7 @@ mod tests {
assert_eq!( assert_eq!(
derivation_of(&matches, "single"), derivation_of(&matches, "single"),
Some(DerivationPath { Some(DerivationPath {
account: 2, account: Some(2),
change: Some(3) change: Some(3)
}) })
); );

View File

@ -193,6 +193,10 @@ impl LedgerWallet {
match status { match status {
// These need to be aligned with solana Ledger app error codes, and clippy allowance removed // These need to be aligned with solana Ledger app error codes, and clippy allowance removed
0x6700 => Err(RemoteWalletError::Protocol("Incorrect length")), 0x6700 => Err(RemoteWalletError::Protocol("Incorrect length")),
0x6802 => Err(RemoteWalletError::Protocol("Invalid parameter")),
0x6803 => Err(RemoteWalletError::Protocol(
"Overflow: message longer than MAX_MESSAGE_LENGTH",
)),
0x6982 => Err(RemoteWalletError::Protocol( 0x6982 => Err(RemoteWalletError::Protocol(
"Security status not satisfied (Canceled by user)", "Security status not satisfied (Canceled by user)",
)), )),
@ -361,16 +365,20 @@ pub fn is_valid_ledger(vendor_id: u16, product_id: u16) -> bool {
fn extend_and_serialize(derivation_path: &DerivationPath) -> Vec<u8> { fn extend_and_serialize(derivation_path: &DerivationPath) -> Vec<u8> {
let byte = if derivation_path.change.is_some() { let byte = if derivation_path.change.is_some() {
4 4
} else { } else if derivation_path.account.is_some() {
3 3
} else {
2
}; };
let mut concat_derivation = vec![byte]; let mut concat_derivation = vec![byte];
concat_derivation.extend_from_slice(&SOL_DERIVATION_PATH_BE); concat_derivation.extend_from_slice(&SOL_DERIVATION_PATH_BE);
concat_derivation.extend_from_slice(&[0x80, 0]); if let Some(account) = derivation_path.account {
concat_derivation.extend_from_slice(&derivation_path.account.to_be_bytes());
if let Some(change) = derivation_path.change {
concat_derivation.extend_from_slice(&[0x80, 0]); concat_derivation.extend_from_slice(&[0x80, 0]);
concat_derivation.extend_from_slice(&change.to_be_bytes()); concat_derivation.extend_from_slice(&account.to_be_bytes());
if let Some(change) = derivation_path.change {
concat_derivation.extend_from_slice(&[0x80, 0]);
concat_derivation.extend_from_slice(&change.to_be_bytes());
}
} }
concat_derivation concat_derivation
} }

View File

@ -240,12 +240,12 @@ impl RemoteWalletInfo {
coin coin
))); )));
} }
if let Some(account) = parts.next() { derivation_path.account = parts
derivation_path.account = account.replace("'", "").parse::<u16>().unwrap(); .next()
derivation_path.change = parts .and_then(|account| account.replace("'", "").parse::<u16>().ok());
.next() derivation_path.change = parts
.and_then(|change| change.replace("'", "").parse::<u16>().ok()); .next()
} .and_then(|change| change.replace("'", "").parse::<u16>().ok());
} else { } else {
return Err(RemoteWalletError::InvalidDerivationPath( return Err(RemoteWalletError::InvalidDerivationPath(
"Derivation path too short, missing coin number".to_string(), "Derivation path too short, missing coin number".to_string(),
@ -273,18 +273,23 @@ impl RemoteWalletInfo {
#[derive(Default, PartialEq, Clone)] #[derive(Default, PartialEq, Clone)]
pub struct DerivationPath { pub struct DerivationPath {
pub account: u16, pub account: Option<u16>,
pub change: Option<u16>, pub change: Option<u16>,
} }
impl fmt::Debug for DerivationPath { impl fmt::Debug for DerivationPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let account = if let Some(account) = self.account {
format!("/{:?}'", account)
} else {
"".to_string()
};
let change = if let Some(change) = self.change { let change = if let Some(change) = self.change {
format!("/{:?}'", change) format!("/{:?}'", change)
} else { } else {
"".to_string() "".to_string()
}; };
write!(f, "m/44'/501'/{:?}'{}", self.account, change) write!(f, "m/44'/501'{}{}", account, change)
} }
} }
@ -328,7 +333,7 @@ mod tests {
assert_eq!( assert_eq!(
derivation_path, derivation_path,
DerivationPath { DerivationPath {
account: 1, account: Some(1),
change: Some(2), change: Some(2),
} }
); );
@ -344,7 +349,7 @@ mod tests {
assert_eq!( assert_eq!(
derivation_path, derivation_path,
DerivationPath { DerivationPath {
account: 1, account: Some(1),
change: Some(2), change: Some(2),
} }
); );