File tree Expand file tree Collapse file tree 3 files changed +80
-0
lines changed Expand file tree Collapse file tree 3 files changed +80
-0
lines changed Original file line number Diff line number Diff line change 22
22
from ethereum .utils .byte import left_pad_zero_bytes
23
23
24
24
from ..fork_types import Address
25
+ from ..vm .exceptions import InvalidParameter
26
+
27
+ MAX_ADDRESS = Address (b"\xff " * 20 )
25
28
26
29
27
30
def to_address (data : Union [Uint , U256 ]) -> Address :
@@ -41,6 +44,31 @@ def to_address(data: Union[Uint, U256]) -> Address:
41
44
return Address (data .to_be_bytes32 ()[- 20 :])
42
45
43
46
47
+ def to_address_without_mask (data : U256 ) -> Address :
48
+ """
49
+ Convert a Uint or U256 value to a valid address (20 bytes).
50
+ Raises a `ValueError` if the data is larger than `MAX_ADDRESS
51
+
52
+ Parameters
53
+ ----------
54
+ data :
55
+ The string to be converted to bytes.
56
+
57
+ Raises
58
+ ------
59
+ InvalidParameter
60
+ If `data` is larger than `MAX_ADDRESS`.
61
+
62
+ Returns
63
+ -------
64
+ address : `Address`
65
+ The obtained address.
66
+ """
67
+ if data > U256 .from_be_bytes (MAX_ADDRESS ):
68
+ raise InvalidParameter ("Address is too large" )
69
+ return Address (data .to_be_bytes32 ()[- 20 :])
70
+
71
+
44
72
def compute_contract_address (address : Address , nonce : Uint ) -> Address :
45
73
"""
46
74
Computes address of the new account that needs to be created.
Original file line number Diff line number Diff line change @@ -210,6 +210,7 @@ class Ops(enum.Enum):
210
210
DELEGATECALL = 0xF4
211
211
CREATE2 = 0xF5
212
212
STATICCALL = 0xFA
213
+ PAY = 0xFC
213
214
REVERT = 0xFD
214
215
SELFDESTRUCT = 0xFF
215
216
@@ -361,6 +362,7 @@ class Ops(enum.Enum):
361
362
Ops .DELEGATECALL : system_instructions .delegatecall ,
362
363
Ops .SELFDESTRUCT : system_instructions .selfdestruct ,
363
364
Ops .STATICCALL : system_instructions .staticcall ,
365
+ Ops .PAY : system_instructions .pay ,
364
366
Ops .REVERT : system_instructions .revert ,
365
367
Ops .CREATE2 : system_instructions .create2 ,
366
368
}
Original file line number Diff line number Diff line change 31
31
compute_contract_address ,
32
32
compute_create2_contract_address ,
33
33
to_address ,
34
+ to_address_without_mask ,
34
35
)
35
36
from ...vm .eoa_delegation import access_delegation
36
37
from .. import (
@@ -742,3 +743,52 @@ def revert(evm: Evm) -> None:
742
743
743
744
# PROGRAM COUNTER
744
745
pass
746
+
747
+
748
+ def pay (evm : Evm ) -> None :
749
+ """
750
+ Transfer ether to an account.
751
+
752
+ Parameters
753
+ ----------
754
+ evm :
755
+ The current EVM frame.
756
+ """
757
+ # STACK
758
+ to = to_address_without_mask (pop (evm .stack ))
759
+ value = pop (evm .stack )
760
+
761
+ # GAS
762
+ if to in evm .accessed_addresses :
763
+ access_gas_cost = GAS_WARM_ACCESS
764
+ else :
765
+ evm .accessed_addresses .add (to )
766
+ access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
767
+
768
+ create_gas_cost = (
769
+ Uint (0 )
770
+ if is_account_alive (evm .message .block_env .state , to ) or value == 0
771
+ else GAS_NEW_ACCOUNT
772
+ )
773
+
774
+ transfer_gas_cost = Uint (0 ) if value == U256 (0 ) else GAS_CALL_VALUE
775
+
776
+ charge_gas (evm , access_gas_cost + create_gas_cost + transfer_gas_cost )
777
+
778
+ # OPERATION
779
+ if evm .message .is_static :
780
+ raise WriteInStaticContext ("Cannot PAY in static context" )
781
+
782
+ try :
783
+ move_ether (
784
+ evm .message .block_env .state ,
785
+ evm .message .current_target ,
786
+ to ,
787
+ value ,
788
+ )
789
+ push (evm .stack , U256 (1 ))
790
+ except AssertionError :
791
+ push (evm .stack , U256 (0 ))
792
+
793
+ # PROGRAM COUNTER
794
+ evm .pc += Uint (1 )
You can’t perform that action at this time.
0 commit comments