ethers_eip2718/
eip1559.rs1use ethers_primitives::*;
2
3use serde::{Deserialize, Serialize};
4use serde_ethrlp::RlpEncoder;
5
6use super::{keccak256, AccessList, H256};
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9#[serde(rename_all = "camelCase")]
10pub struct Eip1559TransactionRequest {
11 pub chain_id: U256,
12
13 pub nonce: U256,
15 pub max_priority_fee_per_gas: U256,
17
18 pub max_fee_per_gas: U256,
19 pub gas: U256,
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub to: Option<Address>,
24 pub value: Option<U256>,
26 #[serde(skip_serializing_if = "Option::is_none")]
29 pub data: Option<Bytes>,
30
31 pub access_list: AccessList,
32}
33
34impl Eip1559TransactionRequest {
35 pub fn sign_hash(&self) -> anyhow::Result<H256> {
37 Ok(keccak256(self.rlp()?.0).into())
38 }
39
40 pub fn rlp(&self) -> anyhow::Result<Bytes> {
41 let mut s = RlpEncoder::default();
42 (
43 &self.chain_id,
44 &self.nonce,
45 &self.max_priority_fee_per_gas,
46 &self.max_fee_per_gas,
47 &self.gas,
48 &self.to,
49 &self.value,
50 &self.data,
51 &self.access_list,
52 )
53 .serialize(&mut s)?;
54
55 let mut buff = vec![0x02u8];
56
57 let mut append = s.finalize()?.into();
58
59 buff.append(&mut append);
60
61 Ok(buff.into())
62 }
63
64 pub fn rlp_signed(&self, signature: Eip1559Signature) -> anyhow::Result<Bytes> {
66 let mut s = RlpEncoder::default();
67
68 (
69 &self.chain_id,
70 &self.nonce,
71 &self.max_priority_fee_per_gas,
72 &self.max_fee_per_gas,
73 &self.gas,
74 &self.to,
75 &self.value,
76 &self.data,
77 &self.access_list,
78 signature.v,
79 signature.r,
80 signature.s,
81 )
82 .serialize(&mut s)?;
83
84 let mut buff = vec![0x02u8];
85
86 let mut append = s.finalize()?.into();
87
88 buff.append(&mut append);
89
90 Ok(buff.into())
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use ethers_primitives::Eip1559Signature;
97 use serde_json::json;
98
99 use crate::Eip1559TransactionRequest;
100
101 #[test]
102 fn test_rlp() {
103 let tx = json!({
104 "maxPriorityFeePerGas": "0x0",
105 "maxFeePerGas": "0x0",
106 "gas": "0x0",
107 "nonce": "0x0",
108 "to": null,
109 "value": "0x0",
110 "chainId": "0x1",
111 "type": "0x02",
112 "data": "0x00",
113 "accessList": [
114 {
115 "address": "0x0000000000000000000000000000000000000000",
116 "storageKeys": [
117 "0x0000000000000000000000000000000000000000000000000000000000000000"
118 ]
119 },
120 {
121 "address": "0x0000000000000000000000000000000000000000",
122 "storageKeys": [
123 "0x0000000000000000000000000000000000000000000000000000000000000000"
124 ]
125 }
126 ]
127 });
128
129 let tx: Eip1559TransactionRequest = serde_json::from_value(tx).unwrap();
130
131 assert_eq!(
132 tx.rlp().unwrap().to_string(),
133 "0x02f87a0180808080808000f870f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000"
134 );
135
136 let sig: Eip1559Signature = "0x007a53fb20b46d9cc2600d8dc3168a698d41c0dec029d46db4ba88ffe359bbe4092536bd58c593edcda36c5f2e35ed4db158b0cab202b6b2648403117e483a9b30".parse().unwrap();
137
138 assert_eq!(
139 tx.rlp_signed(sig).unwrap().to_string(),
140 "0x02f8bd0180808080808000f870f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000f7940000000000000000000000000000000000000000e1a0000000000000000000000000000000000000000000000000000000000000000080a07a53fb20b46d9cc2600d8dc3168a698d41c0dec029d46db4ba88ffe359bbe409a02536bd58c593edcda36c5f2e35ed4db158b0cab202b6b2648403117e483a9b30"
141 );
142 }
143}