ethers_signers/ledger/
types.rs

1#![allow(clippy::upper_case_acronyms)]
2//! Helpers for interacting with the Ethereum Ledger App
3//! [Official Docs](https://github.com/LedgerHQ/app-ethereum/blob/master/doc/ethapp.asc)
4use std::fmt;
5use thiserror::Error;
6
7#[derive(Clone, Debug)]
8/// Ledger wallet type
9pub enum DerivationType {
10    /// Ledger Live-generated HD path
11    LedgerLive(usize),
12    /// Legacy generated HD Path
13    Legacy(usize),
14    /// Any other path
15    Other(String),
16}
17
18impl fmt::Display for DerivationType {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
20        write!(
21            f,
22            "{}",
23            match self {
24                DerivationType::Legacy(index) => format!("m/44'/60'/0'/{index}"),
25                DerivationType::LedgerLive(index) => format!("m/44'/60'/{index}'/0/0"),
26                DerivationType::Other(inner) => inner.to_owned(),
27            }
28        )
29    }
30}
31
32#[derive(Error, Debug)]
33/// Error when using the Ledger transport
34pub enum LedgerError {
35    /// Underlying ledger transport error
36    #[error(transparent)]
37    LedgerError(#[from] coins_ledger::errors::LedgerError),
38    /// Device response was unexpectedly none
39    #[error("Received unexpected response from device. Expected data in response, found none.")]
40    UnexpectedNullResponse,
41    #[error(transparent)]
42    /// Error when converting from a hex string
43    HexError(#[from] hex::FromHexError),
44    #[error(transparent)]
45    /// Error when converting a semver requirement
46    SemVerError(#[from] semver::Error),
47    /// Error type from Eip712Error message
48    #[error("error encoding eip712 struct: {0:?}")]
49    Eip712Error(String),
50    /// Error when signing EIP712 struct with not compatible Ledger ETH app
51    #[error("Ledger ethereum app requires at least version: {0:?}")]
52    UnsupportedAppVersion(String),
53    /// Got a response, but it didn't contain as much data as expected
54    #[error("Cannot deserialize ledger response, insufficient bytes. Got {got} expected at least {at_least}")]
55    ShortResponse { got: usize, at_least: usize },
56    /// Payload is empty
57    #[error("Payload must not be empty")]
58    EmptyPayload,
59}
60
61pub const P1_FIRST: u8 = 0x00;
62
63#[repr(u8)]
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[allow(non_camel_case_types)]
66pub enum INS {
67    GET_PUBLIC_KEY = 0x02,
68    SIGN = 0x04,
69    GET_APP_CONFIGURATION = 0x06,
70    SIGN_PERSONAL_MESSAGE = 0x08,
71    SIGN_ETH_EIP_712 = 0x0C,
72}
73
74impl std::fmt::Display for INS {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self {
77            INS::GET_PUBLIC_KEY => write!(f, "GET_PUBLIC_KEY"),
78            INS::SIGN => write!(f, "SIGN"),
79            INS::GET_APP_CONFIGURATION => write!(f, "GET_APP_CONFIGURATION"),
80            INS::SIGN_PERSONAL_MESSAGE => write!(f, "SIGN_PERSONAL_MESSAGE"),
81            INS::SIGN_ETH_EIP_712 => write!(f, "SIGN_ETH_EIP_712"),
82        }
83    }
84}
85
86#[repr(u8)]
87#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88#[allow(non_camel_case_types)]
89pub enum P1 {
90    NON_CONFIRM = 0x00,
91    MORE = 0x80,
92}
93
94#[repr(u8)]
95#[derive(Debug, Copy, Clone, Eq, PartialEq)]
96#[allow(non_camel_case_types)]
97pub enum P2 {
98    NO_CHAINCODE = 0x00,
99}