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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#![allow(clippy::upper_case_acronyms)]
use std::fmt;
use thiserror::Error;
use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress, U256};
use trezor_client::client::AccessListItem as Trezor_AccessListItem;
#[derive(Clone, Debug)]
pub enum DerivationType {
TrezorLive(usize),
Other(String),
}
impl fmt::Display for DerivationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(
f,
"{}",
match self {
DerivationType::TrezorLive(index) => format!("m/44'/60'/{index}'/0/0"),
DerivationType::Other(inner) => inner.to_owned(),
}
)
}
}
#[derive(Error, Debug)]
pub enum TrezorError {
#[error(transparent)]
TrezorError(#[from] trezor_client::error::Error),
#[error("Trezor was not able to retrieve device features")]
FeaturesError,
#[error("Not able to unpack value for TrezorTransaction.")]
DataError,
#[error(transparent)]
HexError(#[from] hex::FromHexError),
#[error(transparent)]
SemVerError(#[from] semver::Error),
#[error("Trezor ethereum app requires at least version: {0:?}")]
UnsupportedFirmwareVersion(String),
#[error("Does not support ENS.")]
NoENSSupport,
#[error("Unable to access trezor cached session.")]
CacheError(String),
}
pub struct TrezorTransaction {
pub nonce: Vec<u8>,
pub gas: Vec<u8>,
pub gas_price: Vec<u8>,
pub value: Vec<u8>,
pub to: String,
pub data: Vec<u8>,
pub max_fee_per_gas: Vec<u8>,
pub max_priority_fee_per_gas: Vec<u8>,
pub access_list: Vec<Trezor_AccessListItem>,
}
impl TrezorTransaction {
fn to_trimmed_big_endian(_value: &U256) -> Vec<u8> {
let mut trimmed_value = [0_u8; 32];
_value.to_big_endian(&mut trimmed_value);
trimmed_value[_value.leading_zeros() as usize / 8..].to_vec()
}
pub fn load(tx: &TypedTransaction) -> Result<Self, TrezorError> {
let to: String = match tx.to() {
Some(v) => match v {
NameOrAddress::Name(_) => return Err(TrezorError::NoENSSupport),
NameOrAddress::Address(value) => format!("0x{}", hex::encode(value)),
},
None => "".to_string(),
};
let nonce = tx.nonce().map_or(vec![], Self::to_trimmed_big_endian);
let gas = tx.gas().map_or(vec![], Self::to_trimmed_big_endian);
let gas_price = tx.gas_price().map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
let value = tx.value().map_or(vec![], Self::to_trimmed_big_endian);
let data = tx.data().map_or(vec![], |v| v.to_vec());
match tx {
TypedTransaction::Eip2930(_) | TypedTransaction::Legacy(_) => Ok(Self {
nonce,
gas,
gas_price,
value,
to,
data,
max_fee_per_gas: vec![],
max_priority_fee_per_gas: vec![],
access_list: vec![],
}),
TypedTransaction::Eip1559(eip1559_tx) => {
let max_fee_per_gas =
eip1559_tx.max_fee_per_gas.map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
let max_priority_fee_per_gas = eip1559_tx
.max_priority_fee_per_gas
.map_or(vec![], |v| Self::to_trimmed_big_endian(&v));
let mut access_list: Vec<Trezor_AccessListItem> = Vec::new();
for item in &eip1559_tx.access_list.0 {
let address: String = format!("0x{}", hex::encode(item.address));
let mut storage_keys: Vec<Vec<u8>> = Vec::new();
for key in &item.storage_keys {
storage_keys.push(key.as_bytes().to_vec())
}
access_list.push(Trezor_AccessListItem { address, storage_keys })
}
Ok(Self {
nonce,
gas,
gas_price,
value,
to,
data,
max_fee_per_gas,
max_priority_fee_per_gas,
access_list,
})
}
}
}
}