1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use serde::{Deserialize, Serialize};
use starknet_rs_core::types::{EthAddress, Hash256, MsgToL1, MsgToL2};
use starknet_rs_ff::FieldElement;

use crate::contract_address::ContractAddress;
use crate::error::{DevnetResult, Error};
use crate::felt::{Calldata, EntryPointSelector, Felt, Nonce};
use crate::rpc::eth_address::EthAddressWrapper;
use crate::utils::into_vec;

/// An L1 to L2 message.
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MessageToL2 {
    pub l2_contract_address: ContractAddress,
    pub entry_point_selector: EntryPointSelector,
    pub l1_contract_address: ContractAddress,
    pub payload: Calldata,
    pub paid_fee_on_l1: Felt,
    pub nonce: Nonce,
}

impl MessageToL2 {
    pub fn hash(&self) -> DevnetResult<Hash256> {
        let msg_to_l2 = MsgToL2 {
            from_address: EthAddress::from_felt(&self.l1_contract_address.into()).map_err(
                |err| {
                    Error::ConversionError(crate::error::ConversionError::OutOfRangeError(
                        err.to_string(),
                    ))
                },
            )?,
            to_address: self.l2_contract_address.into(),
            selector: self.entry_point_selector.into(),
            payload: into_vec(&self.payload),
            nonce: u64::try_from(FieldElement::from(self.nonce)).map_err(|err| {
                Error::ConversionError(crate::error::ConversionError::OutOfRangeError(
                    err.to_string(),
                ))
            })?,
        };

        Ok(msg_to_l2.hash())
    }
}

pub type L2ToL1Payload = Vec<Felt>;

/// An L2 to L1 message.
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MessageToL1 {
    pub from_address: ContractAddress,
    pub to_address: EthAddressWrapper,
    pub payload: L2ToL1Payload,
}

impl MessageToL1 {
    /// Computes the hash of a `MessageToL1`.
    /// Re-uses the already tested hash computation
    /// from starknet-rs.
    pub fn hash(&self) -> Hash256 {
        let msg_to_l1 = MsgToL1 {
            from_address: self.from_address.into(),
            to_address: self.to_address.inner.clone().into(),
            payload: self.payload.clone().into_iter().map(|f| f.into()).collect(),
        };

        msg_to_l1.hash()
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OrderedMessageToL1 {
    pub order: usize,
    #[serde(flatten)]
    pub message: MessageToL1,
}

impl OrderedMessageToL1 {
    pub fn new(
        msg: &blockifier::execution::call_info::OrderedL2ToL1Message,
        from_address: ContractAddress,
    ) -> Self {
        Self {
            order: msg.order,
            message: MessageToL1 {
                from_address,
                to_address: msg.message.to_address.into(),
                payload: msg.message.payload.0.clone().into_iter().map(Felt::from).collect(),
            },
        }
    }
}