ethers_signers/trezor/
types.rs1#![allow(clippy::upper_case_acronyms)]
2use std::fmt;
5use thiserror::Error;
6
7use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress, U256};
8use trezor_client::client::AccessListItem as Trezor_AccessListItem;
9
10#[derive(Clone, Debug)]
11pub enum DerivationType {
13 TrezorLive(usize),
15 Other(String),
18}
19
20impl fmt::Display for DerivationType {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
22 write!(
23 f,
24 "{}",
25 match self {
26 DerivationType::TrezorLive(index) => format!("m/44'/60'/{index}'/0/0"),
27 DerivationType::Other(inner) => inner.to_owned(),
28 }
29 )
30 }
31}
32
33#[derive(Error, Debug)]
34pub enum TrezorError {
36 #[error(transparent)]
38 TrezorError(#[from] trezor_client::error::Error),
39 #[error("Trezor was not able to retrieve device features")]
40 FeaturesError,
41 #[error("Not able to unpack value for TrezorTransaction.")]
42 DataError,
43 #[error(transparent)]
45 HexError(#[from] hex::FromHexError),
46 #[error(transparent)]
48 SemVerError(#[from] semver::Error),
49 #[error("Trezor ethereum app requires at least version: {0:?}")]
51 UnsupportedFirmwareVersion(String),
52 #[error("Does not support ENS.")]
53 NoENSSupport,
54 #[error("Unable to access trezor cached session.")]
55 CacheError(String),
56}
57
58pub struct TrezorTransaction {
60 pub nonce: Vec<u8>,
61 pub gas: Vec<u8>,
62 pub gas_price: Vec<u8>,
63 pub value: Vec<u8>,
64 pub to: String,
65 pub data: Vec<u8>,
66 pub max_fee_per_gas: Vec<u8>,
67 pub max_priority_fee_per_gas: Vec<u8>,
68 pub access_list: Vec<Trezor_AccessListItem>,
69}
70
71impl TrezorTransaction {
72 fn to_trimmed_big_endian(_value: &U256) -> Vec<u8> {
73 let mut trimmed_value = [0_u8; 32];
74 _value.to_big_endian(&mut trimmed_value);
75 trimmed_value[_value.leading_zeros() as usize / 8..].to_vec()
76 }
77
78 pub fn load(tx: &TypedTransaction) -> Result<Self, TrezorError> {
79 let to: String = match tx.to() {
80 Some(v) => match v {
81 NameOrAddress::Name(_) => return Err(TrezorError::NoENSSupport),
82 NameOrAddress::Address(value) => hex::encode_prefixed(value),
83 },
84 None => "".to_string(),
86 };
87
88 let nonce = tx.nonce().map_or(vec![], Self::to_trimmed_big_endian);
89 let gas = tx.gas().map_or(vec![], Self::to_trimmed_big_endian);
90 let gas_price = tx.gas_price().map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
91 let value = tx.value().map_or(vec![], Self::to_trimmed_big_endian);
92 let data = tx.data().map_or(vec![], |v| v.to_vec());
93
94 match tx {
95 TypedTransaction::Eip2930(_) | TypedTransaction::Legacy(_) => Ok(Self {
96 nonce,
97 gas,
98 gas_price,
99 value,
100 to,
101 data,
102 max_fee_per_gas: vec![],
103 max_priority_fee_per_gas: vec![],
104 access_list: vec![],
105 }),
106 TypedTransaction::Eip1559(eip1559_tx) => {
107 let max_fee_per_gas =
108 eip1559_tx.max_fee_per_gas.map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
109
110 let max_priority_fee_per_gas = eip1559_tx
111 .max_priority_fee_per_gas
112 .map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
113
114 let mut access_list: Vec<Trezor_AccessListItem> = Vec::new();
115 for item in &eip1559_tx.access_list.0 {
116 let address: String = hex::encode_prefixed(item.address);
117 let mut storage_keys: Vec<Vec<u8>> = Vec::new();
118
119 for key in &item.storage_keys {
120 storage_keys.push(key.as_bytes().to_vec())
121 }
122
123 access_list.push(Trezor_AccessListItem { address, storage_keys })
124 }
125
126 Ok(Self {
127 nonce,
128 gas,
129 gas_price,
130 value,
131 to,
132 data,
133 max_fee_per_gas,
134 max_priority_fee_per_gas,
135 access_list,
136 })
137 }
138 #[cfg(feature = "optimism")]
139 TypedTransaction::DepositTransaction(_) => Ok(Self {
140 nonce,
141 gas,
142 gas_price,
143 value,
144 to,
145 data,
146 max_fee_per_gas: vec![],
147 max_priority_fee_per_gas: vec![],
148 access_list: vec![],
149 }),
150 }
151 }
152}