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