maili_common/deposit/
source.rs

1//! Classification of deposit transaction source
2
3use alloc::string::String;
4use alloy_primitives::{keccak256, B256};
5
6/// Source domain identifiers for deposit transactions.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u8)]
9pub enum DepositSourceDomainIdentifier {
10    /// A user deposit source.
11    User = 0,
12    /// A L1 info deposit source.
13    L1Info = 1,
14    /// An upgrade deposit source.
15    Upgrade = 2,
16}
17
18/// Source domains for deposit transactions.
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub enum DepositSourceDomain {
21    /// A user deposit source.
22    User(UserDepositSource),
23    /// A L1 info deposit source.
24    L1Info(L1InfoDepositSource),
25    /// An upgrade deposit source.
26    Upgrade(UpgradeDepositSource),
27}
28
29impl DepositSourceDomain {
30    /// Returns the source hash.
31    pub fn source_hash(&self) -> B256 {
32        match self {
33            Self::User(ds) => ds.source_hash(),
34            Self::L1Info(ds) => ds.source_hash(),
35            Self::Upgrade(ds) => ds.source_hash(),
36        }
37    }
38}
39
40/// A L1 info deposit transaction source.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct L1InfoDepositSource {
43    /// The L1 block hash.
44    pub l1_block_hash: B256,
45    /// The sequence number.
46    pub seq_number: u64,
47}
48
49impl L1InfoDepositSource {
50    /// Creates a new [L1InfoDepositSource].
51    pub const fn new(l1_block_hash: B256, seq_number: u64) -> Self {
52        Self { l1_block_hash, seq_number }
53    }
54
55    /// Returns the source hash.
56    pub fn source_hash(&self) -> B256 {
57        let mut input = [0u8; 32 * 2];
58        input[..32].copy_from_slice(&self.l1_block_hash[..]);
59        input[32 * 2 - 8..].copy_from_slice(&self.seq_number.to_be_bytes());
60        let deposit_id_hash = keccak256(input);
61        let mut domain_input = [0u8; 32 * 2];
62        let identifier_bytes: [u8; 8] =
63            (DepositSourceDomainIdentifier::L1Info as u64).to_be_bytes();
64        domain_input[32 - 8..32].copy_from_slice(&identifier_bytes);
65        domain_input[32..].copy_from_slice(&deposit_id_hash[..]);
66        keccak256(domain_input)
67    }
68}
69
70/// A deposit transaction source.
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72pub struct UserDepositSource {
73    /// The L1 block hash.
74    pub l1_block_hash: B256,
75    /// The log index.
76    pub log_index: u64,
77}
78
79impl UserDepositSource {
80    /// Creates a new [UserDepositSource].
81    pub const fn new(l1_block_hash: B256, log_index: u64) -> Self {
82        Self { l1_block_hash, log_index }
83    }
84
85    /// Returns the source hash.
86    pub fn source_hash(&self) -> B256 {
87        let mut input = [0u8; 32 * 2];
88        input[..32].copy_from_slice(&self.l1_block_hash[..]);
89        input[32 * 2 - 8..].copy_from_slice(&self.log_index.to_be_bytes());
90        let deposit_id_hash = keccak256(input);
91        let mut domain_input = [0u8; 32 * 2];
92        let identifier_bytes: [u8; 8] = (DepositSourceDomainIdentifier::User as u64).to_be_bytes();
93        domain_input[32 - 8..32].copy_from_slice(&identifier_bytes);
94        domain_input[32..].copy_from_slice(&deposit_id_hash[..]);
95        keccak256(domain_input)
96    }
97}
98
99/// An upgrade deposit transaction source.
100///
101/// This implements the translation of upgrade-tx identity information to a deposit source-hash,
102/// which makes the deposit uniquely identifiable.
103/// System-upgrade transactions have their own domain for source-hashes,
104/// to not conflict with user-deposits or deposited L1 information.
105/// The intent identifies the upgrade-tx uniquely, in a human-readable way.
106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
107pub struct UpgradeDepositSource {
108    /// The intent.
109    pub intent: String,
110}
111
112impl UpgradeDepositSource {
113    /// Creates a new [UpgradeDepositSource].
114    pub const fn new(intent: String) -> Self {
115        Self { intent }
116    }
117
118    /// Returns the source hash.
119    pub fn source_hash(&self) -> B256 {
120        let intent_hash = keccak256(self.intent.as_bytes());
121        let mut domain_input = [0u8; 32 * 2];
122        let identifier_bytes: [u8; 8] =
123            (DepositSourceDomainIdentifier::Upgrade as u64).to_be_bytes();
124        domain_input[32 - 8..32].copy_from_slice(&identifier_bytes);
125        domain_input[32..].copy_from_slice(&intent_hash[..]);
126        keccak256(domain_input)
127    }
128}