Skip to main content

unified_bridge/
bridge_exit.rs

1use agglayer_primitives::{
2    keccak::{keccak256, keccak256_combine},
3    Address, Digest, Hashable, U256,
4};
5use hex_literal::hex;
6use serde::{Deserialize, Serialize};
7
8use crate::{LeafType, NetworkId, TokenInfo, L1_ETH};
9
10const EMPTY_METADATA_HASH: Digest = Digest(hex!(
11    "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
12));
13
14impl Hashable for TokenInfo {
15    #[inline]
16    fn hash(&self) -> Digest {
17        keccak256_combine([
18            &self.origin_network.to_be_bytes(),
19            self.origin_token_address.as_slice(),
20        ])
21    }
22}
23
24/// Represents a token bridge exit from the network.
25// TODO: Change it to an enum depending on `leaf_type`.
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27#[cfg_attr(feature = "testutils", derive(arbitrary::Arbitrary))]
28pub struct BridgeExit {
29    pub leaf_type: LeafType,
30
31    /// Unique ID for the token being transferred.
32    pub token_info: TokenInfo,
33
34    /// Network which the token is transferred to
35    pub dest_network: NetworkId,
36    /// Address which will own the received token
37    pub dest_address: Address,
38
39    /// Token amount sent
40    pub amount: U256,
41
42    pub metadata: Option<Digest>,
43}
44
45impl BridgeExit {
46    /// Creates a new [`BridgeExit`].
47    #[inline]
48    pub fn new(
49        leaf_type: LeafType,
50        origin_network: NetworkId,
51        origin_token_address: Address,
52        dest_network: NetworkId,
53        dest_address: Address,
54        amount: U256,
55        metadata: Vec<u8>,
56    ) -> Self {
57        Self {
58            leaf_type,
59            token_info: TokenInfo {
60                origin_network,
61                origin_token_address,
62            },
63            dest_network,
64            dest_address,
65            amount,
66            metadata: Some(keccak256(metadata.as_slice())),
67        }
68    }
69
70    #[inline]
71    pub fn is_transfer(&self) -> bool {
72        self.leaf_type == LeafType::Transfer
73    }
74}
75
76impl Hashable for BridgeExit {
77    #[inline]
78    fn hash(&self) -> Digest {
79        keccak256_combine([
80            [self.leaf_type as u8].as_slice(),
81            &self.token_info.origin_network.to_be_bytes(),
82            self.token_info.origin_token_address.as_slice(),
83            &self.dest_network.to_be_bytes(),
84            self.dest_address.as_slice(),
85            &self.amount.to_be_bytes::<32>(),
86            &self.metadata.unwrap_or(EMPTY_METADATA_HASH).0,
87        ])
88    }
89}
90
91impl BridgeExit {
92    #[inline]
93    pub fn is_message(&self) -> bool {
94        self.leaf_type == LeafType::Message
95    }
96
97    /// Returns the [`TokenInfo`] considered for the the given amount.
98    /// The amount corresponds to L1 ETH if the bridge exit is a message.
99    #[inline]
100    pub fn amount_token_info(&self) -> TokenInfo {
101        match self.leaf_type {
102            LeafType::Message => L1_ETH,
103            LeafType::Transfer => self.token_info,
104        }
105    }
106}