ledger_ethereum/command/
sign_transaction.rs1use ledger_transport::{APDUCommand, APDUErrorCode, Exchange};
2use ledger_zondax_generic::{App, LedgerAppError};
3
4use crate::command::InstructionCode;
5use crate::types::{BIP44Path, ChunkPayloadType, EthError, LedgerEthTransactionResolution};
6use crate::EthApp;
7
8#[derive(Debug)]
9pub struct Signature {
10 pub v: u8,
11 pub r: [u8; 32],
12 pub s: [u8; 32],
13}
14
15impl<E> EthApp<E>
16where
17 E: Exchange + Send + Sync,
18 E::Error: std::error::Error,
19{
20 pub async fn sign(
22 &self,
23 path: &BIP44Path,
24 raw_tx: &[u8],
25 _resolution: Option<LedgerEthTransactionResolution>,
27 ) -> Result<Signature, EthError<E::Error>> {
28 let mut data = vec![];
29 let path = path.serialize_bip44();
30 data.extend_from_slice(&path);
31 data.extend_from_slice(raw_tx);
32
33 let command = APDUCommand {
34 cla: Self::CLA,
35 ins: InstructionCode::SignTransaction as _,
36 p1: ChunkPayloadType::First as u8,
37 p2: 0x00,
38 data,
39 };
40
41 let response = self.send_chunks(command).await?;
42
43 let response_data = response.data();
44 match response.error_code() {
45 Ok(APDUErrorCode::NoError) if response_data.is_empty() => {
46 return Err(EthError::Ledger(LedgerAppError::NoSignature))
47 }
48 Ok(APDUErrorCode::NoError) if response_data.len() < 3 => {
50 return Err(EthError::Ledger(LedgerAppError::InvalidSignature))
51 }
52 Ok(APDUErrorCode::NoError) => {}
53 Ok(err) => {
54 return Err(EthError::Ledger(LedgerAppError::AppSpecific(
55 err as _,
56 err.description(),
57 )))
58 }
59 Err(err) => {
60 return Err(EthError::Ledger(LedgerAppError::AppSpecific(
61 err,
62 "[APDU_ERROR] Unknown".to_string(),
63 )))
64 }
65 }
66
67 let v = response_data
68 .first()
69 .ok_or(EthError::MissingResponseData(
70 "signature v component".into(),
71 ))?
72 .to_owned();
73 let r = response_data
74 .get(1..33)
75 .ok_or(EthError::MissingResponseData(
76 "signature r component".into(),
77 ))?
78 .try_into() .unwrap();
80 let s = response_data
81 .get(33..65)
82 .ok_or(EthError::MissingResponseData(
83 "signature s component".into(),
84 ))?
85 .try_into() .unwrap();
87 Ok(Signature { v, r, s })
88 }
89}