alloy_eips/
eip7002.rs

1//! Contains the system contract and [WithdrawalRequest] types, first introduced in the [Prague hardfork](https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md).
2//!
3//! See also [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002): Execution layer triggerable withdrawals
4
5use alloy_primitives::{address, bytes, Address, Bytes, FixedBytes};
6
7/// The caller to be used when calling the EIP-7002 withdrawal requests contract at the end of the
8/// block.
9pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");
10
11/// The address for the EIP-7002 withdrawal requests contract.
12pub const WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS: Address =
13    address!("0x00000961Ef480Eb55e80D19ad83579A64c007002");
14
15/// The code for the EIP-7002 withdrawal requests contract.
16pub static WITHDRAWAL_REQUEST_PREDEPLOY_CODE: Bytes = bytes!("   3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd");
17
18/// The [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685) request type for withdrawal requests.
19pub const WITHDRAWAL_REQUEST_TYPE: u8 = 0x01;
20
21/// The [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) defined maximum withdrawal requests per block.
22pub const MAX_WITHDRAWAL_REQUESTS_PER_BLOCK: usize = 16;
23
24/// Represents an execution layer triggerable withdrawal request.
25///
26/// See [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002).
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29#[cfg_attr(feature = "ssz", derive(ssz_derive::Encode, ssz_derive::Decode))]
30#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
31pub struct WithdrawalRequest {
32    /// Address of the source of the exit.
33    pub source_address: Address,
34    /// Validator public key.
35    pub validator_pubkey: FixedBytes<48>,
36    /// Amount of withdrawn ether in gwei.
37    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::displayfromstr"))]
38    pub amount: u64,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44    use alloy_primitives::hex;
45
46    #[test]
47    #[cfg(feature = "serde")]
48    fn test_serde_withdrawal_request() {
49        // Sample JSON input representing a withdrawal request
50        let json_data = r#"{
51            "source_address":"0xAE0E8770147AaA6828a0D6f642504663F10F7d1E",
52            "validator_pubkey":"0x8e8d8749f6bc79b78be7cc6e49ff640e608454840c360b344c3a4d9b7428e280e7f40d2271bad65d8cbbfdd43cb8793b",
53            "amount":"1"
54        }"#;
55
56        // Deserialize the JSON into a WithdrawalRequest struct
57        let withdrawal_request: WithdrawalRequest =
58            serde_json::from_str(json_data).expect("Failed to deserialize");
59
60        // Verify the deserialized content
61        assert_eq!(
62            withdrawal_request.source_address,
63            address!("AE0E8770147AaA6828a0D6f642504663F10F7d1E")
64        );
65        assert_eq!(
66            withdrawal_request.validator_pubkey,
67            FixedBytes::<48>::from(hex!("8e8d8749f6bc79b78be7cc6e49ff640e608454840c360b344c3a4d9b7428e280e7f40d2271bad65d8cbbfdd43cb8793b"))
68        );
69        assert_eq!(withdrawal_request.amount, 1);
70
71        // Serialize the struct back into JSON
72        let serialized_json =
73            serde_json::to_string(&withdrawal_request).expect("Failed to serialize");
74
75        // Check if the serialized JSON matches the expected JSON structure
76        let expected_json = r#"{"source_address":"0xae0e8770147aaa6828a0d6f642504663f10f7d1e","validator_pubkey":"0x8e8d8749f6bc79b78be7cc6e49ff640e608454840c360b344c3a4d9b7428e280e7f40d2271bad65d8cbbfdd43cb8793b","amount":"1"}"#;
77        assert_eq!(serialized_json, expected_json);
78    }
79}