ledger_ethereum/command/
get_address.rs1use ledger_transport::{APDUCommand, APDUErrorCode, Exchange};
2use ledger_zondax_generic::App;
3
4use crate::command::InstructionCode;
5use crate::types::{BIP44Path, EthError};
6use crate::{EthApp, LedgerAppError};
7
8#[derive(Debug)]
9pub struct Address {
10 pub public_key: Vec<u8>,
12 pub address: Vec<u8>,
14 pub chain_code: Option<Vec<u8>>,
16}
17
18impl<E> EthApp<E>
19where
20 E: Exchange + Send + Sync,
21 E::Error: std::error::Error,
22{
23 pub async fn address(
25 &self,
26 path: &BIP44Path,
27 enable_display: Option<bool>,
28 enabled_chain_code: Option<bool>,
29 ) -> Result<Address, EthError<E::Error>> {
30 let data = path.serialize_bip44();
31 let p1 = enable_display.map_or(0, |v| v as u8);
32 let p2 = enabled_chain_code.map_or(0, |v| v as u8);
33
34 let command = APDUCommand {
35 cla: Self::CLA,
36 ins: InstructionCode::GetAddress as _,
37 p1,
38 p2,
39 data,
40 };
41
42 let response = self
43 .transport
44 .exchange(&command)
45 .await
46 .map_err(LedgerAppError::TransportError)?;
47
48 let response_data = response.data();
49 match response.error_code() {
50 Ok(APDUErrorCode::NoError) => {}
51 Ok(err) => {
52 return Err(EthError::Ledger(LedgerAppError::AppSpecific(
53 err as _,
54 err.description(),
55 )))
56 }
57 Err(err) => {
58 return Err(EthError::Ledger(LedgerAppError::AppSpecific(
59 err,
60 "[APDU_ERROR] Unknown".to_string(),
61 )))
62 }
63 }
64
65 let public_key_len: usize = (*response_data
66 .first()
67 .ok_or(EthError::MissingResponseData("pubkey length".into()))?)
68 .into();
69
70 let pubkey_start = 1;
71 let pubkey_end = pubkey_start + public_key_len;
72 let public_key = response_data
73 .get(pubkey_start..pubkey_end)
74 .ok_or(EthError::MissingResponseData("public key".into()))?
75 .to_vec();
76
77 let address_len: usize = (*response_data
78 .get(pubkey_end)
79 .ok_or(EthError::MissingResponseData("address length".into()))?)
80 .into();
81 let address_start = pubkey_end + 1;
82 let address_end = address_start + address_len;
83 let address = response_data
84 .get(address_start..address_end)
85 .ok_or(EthError::MissingResponseData("address".into()))?
86 .to_vec();
87
88 let chain_code = if let Some(true) = enabled_chain_code {
89 let cc_start = address_end + 1;
90 let cc_end = address_start + address_len;
91 Some(
92 response_data
93 .get(cc_start..cc_end)
94 .ok_or(EthError::MissingResponseData("chain code".into()))?
95 .to_vec(),
96 )
97 } else {
98 None
99 };
100 Ok(Address {
101 public_key,
102 address,
103 chain_code,
104 })
105 }
106}