primitives/transaction/
authorization.rs1use cfx_types::{Address, BigEndianHash, H256, U256};
2use cfxkey::{public_to_address, Signature};
3use keccak_hash::keccak;
4use rlp::RlpStream;
5use rlp_derive::{RlpDecodable, RlpEncodable};
6use serde::{Deserialize, Serialize};
7
8pub const AUTH_MAGIC: u8 = 0x05;
9
10pub const CODE_PREFIX_7702: &'static [u8] = b"\xef\x01\x00";
11
12#[derive(
13 Debug,
14 Clone,
15 PartialEq,
16 Eq,
17 Serialize,
18 Deserialize,
19 RlpEncodable,
20 RlpDecodable,
21)]
22#[serde(rename_all = "camelCase")]
23pub struct AuthorizationListItem {
24 pub chain_id: U256,
25 pub address: Address,
26 pub nonce: u64,
27 pub y_parity: u8,
28 pub r: U256,
29 pub s: U256,
30}
31
32pub type AuthorizationList = Vec<AuthorizationListItem>;
33
34impl AuthorizationListItem {
35 pub fn is_valid_y_parity(&self) -> bool {
36 self.y_parity == 0 || self.y_parity == 1
37 }
38
39 pub fn is_chain_id_valid(&self, chain_id: u64) -> bool {
40 self.chain_id == U256::from(chain_id) || self.chain_id.is_zero()
41 }
42
43 pub fn is_nonce_valid(&self) -> bool { self.nonce < u64::MAX }
44
45 pub fn hash(&self) -> H256 {
46 let mut rlp = RlpStream::new_list(3);
47 rlp.append(&self.chain_id)
48 .append(&self.address)
49 .append(&self.nonce);
50
51 let mut hash_input = vec![AUTH_MAGIC];
52 hash_input.extend_from_slice(rlp.as_raw());
53
54 keccak(hash_input)
55 }
56
57 pub fn signature(&self) -> Option<Signature> {
58 let r: H256 = BigEndianHash::from_uint(&self.r);
59 let s: H256 = BigEndianHash::from_uint(&self.s);
60 let signature = Signature::from_rsv(&r, &s, self.y_parity);
61 if !signature.is_low_s() || !signature.is_valid() {
62 return None;
63 }
64 Some(signature)
65 }
66
67 pub fn authority(&self) -> Option<Address> {
68 let signature = self.signature()?;
69 let hash = self.hash();
70 if let Ok(public) = cfxkey::recover(&signature, &hash) {
71 Some(public_to_address(&public, false))
72 } else {
73 None
74 }
75 }
76}
77
78pub fn extract_7702_payload(code: &[u8]) -> Option<Address> {
79 if code.starts_with(CODE_PREFIX_7702) {
80 let (_prefix, payload) = code.split_at(CODE_PREFIX_7702.len());
81 if payload.len() == Address::len_bytes() {
82 Some(Address::from_slice(payload))
83 } else {
84 None
85 }
86 } else {
87 None
88 }
89}