1
- from typing import Optional
2
1
from eth_account import Account
3
2
from eth_account .messages import encode_defunct , encode_typed_data
3
+ from eth_account .datastructures import SignedSetCodeAuthorization
4
+ from eth_account .typed_transactions .set_code_transaction import Authorization
5
+ from eth_keys .datatypes import Signature
4
6
import rlp
5
7
6
8
7
- # eth_account requires it for some reason
8
- def normalize_vrs (vrs : tuple ) -> tuple :
9
- vrs_l = []
10
- for elem in vrs :
11
- vrs_l .append (elem .lstrip (b'\x00 ' ))
12
- return tuple (vrs_l )
13
-
14
-
15
9
def get_selector_from_data (data : str ) -> bytes :
16
10
raw_data = bytes .fromhex (data [2 :])
17
11
return raw_data [:4 ]
18
12
19
13
20
- def recover_message (msg , vrs : tuple ) -> bytes :
14
+ def recover_message (msg , vrs : tuple [ int , int , int ] ) -> bytes :
21
15
if isinstance (msg , dict ): # EIP-712
22
16
smsg = encode_typed_data (full_message = msg )
23
17
else : # EIP-191
24
18
smsg = encode_defunct (primitive = msg )
25
- addr = Account .recover_message (smsg , normalize_vrs ( vrs ) )
19
+ addr = Account .recover_message (smsg , vrs )
26
20
return bytes .fromhex (addr [2 :])
27
21
28
22
29
- def recover_transaction (tx_params , vrs : tuple , raw_tx_param : Optional [bytes ] = None ) -> bytes :
30
- if raw_tx_param is None :
31
- raw_tx = Account .create ().sign_transaction (tx_params ).rawTransaction
32
- else :
33
- raw_tx = raw_tx_param
23
+ def recover_transaction (tx_params , vrs : tuple [int , int , int ]) -> bytes :
24
+ raw_tx = Account .create ().sign_transaction (tx_params ).raw_transaction
34
25
prefix = bytes ()
35
26
if raw_tx [0 ] in [0x01 , 0x02 , 0x04 ]:
36
27
prefix = raw_tx [:1 ]
@@ -44,7 +35,7 @@ def recover_transaction(tx_params, vrs: tuple, raw_tx_param: Optional[bytes] = N
44
35
trunc_chain_id >>= 8
45
36
46
37
trunc_target = trunc_chain_id * 2 + 35
47
- trunc_v = int . from_bytes ( vrs [0 ], "big" )
38
+ trunc_v = vrs [0 ]
48
39
49
40
if (trunc_target & 0xff ) == trunc_v :
50
41
parity = 0
@@ -56,15 +47,35 @@ def recover_transaction(tx_params, vrs: tuple, raw_tx_param: Optional[bytes] = N
56
47
57
48
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
58
49
full_v = parity + tx_params ["chainId" ] * 2 + 35
59
- # 9 bytes would be big enough even for the biggest chain ID
60
- vrs = (int (full_v ).to_bytes (9 , "big" ), vrs [1 ], vrs [2 ])
50
+ vrs = (full_v , vrs [1 ], vrs [2 ])
61
51
else :
62
52
# Pre EIP-155 TX
63
53
assert False
64
54
decoded = rlp .decode (raw_tx )
65
- if raw_tx_param is None :
66
- reencoded = rlp .encode (decoded [:- 3 ] + list (normalize_vrs (vrs )))
67
- else :
68
- reencoded = rlp .encode (decoded + list (normalize_vrs (vrs )))
55
+ reencoded = rlp .encode (decoded [:- 3 ] + list (vrs ))
69
56
addr = Account .recover_transaction (prefix + reencoded )
70
57
return bytes .fromhex (addr [2 :])
58
+
59
+
60
+ # Code inspired by :
61
+ # https://github.com/ethereum/eth-account/blob/a1ba20c9a112d3534ac3296f21f51e2f5127bf9b/eth_account/account.py#L1057
62
+ def get_authorization_obj (chain_id : int ,
63
+ nonce : int ,
64
+ address : bytes ,
65
+ vrs : tuple [int , int , int ]) -> SignedSetCodeAuthorization :
66
+ unsigned_authorization = Authorization (chain_id , address , nonce )
67
+ sig = Signature (vrs = vrs )
68
+ return SignedSetCodeAuthorization (
69
+ chain_id = chain_id ,
70
+ address = address ,
71
+ nonce = nonce ,
72
+ y_parity = sig .v ,
73
+ r = sig .r ,
74
+ s = sig .s ,
75
+ signature = sig ,
76
+ authorization_hash = unsigned_authorization .hash (),
77
+ )
78
+
79
+
80
+ def recover_authorization (chain_id : int , nonce : int , address : bytes , vrs : tuple [int , int , int ]) -> bytes :
81
+ return get_authorization_obj (chain_id , nonce , address , vrs ).authority
0 commit comments