arbos/util/
address_alias.rs

1use alloy_primitives::Address;
2
3/// The offset applied to L1 addresses when they appear on L2.
4/// This prevents a contract on L1 from impersonating an L2 address.
5pub const ADDRESS_ALIAS_OFFSET: Address = {
6    let bytes: [u8; 20] = [
7        0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8        0x00, 0x00, 0x00, 0x11, 0x11,
9    ];
10    Address::new(bytes)
11};
12
13/// The inverse offset for remapping L2 aliased addresses back to L1.
14///
15/// Equals 2^160 - ADDRESS_ALIAS_OFFSET so that
16/// `(x + ADDRESS_ALIAS_OFFSET + INVERSE_ADDRESS_ALIAS_OFFSET) mod 2^160 == x`.
17pub const INVERSE_ADDRESS_ALIAS_OFFSET: Address = {
18    let bytes: [u8; 20] = [
19        0xee, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
20        0xff, 0xff, 0xff, 0xee, 0xef,
21    ];
22    Address::new(bytes)
23};
24
25/// Applies the L1→L2 address alias offset.
26pub fn remap_l1_address(l1_address: Address) -> Address {
27    address_add(l1_address, ADDRESS_ALIAS_OFFSET)
28}
29
30/// Removes the L1→L2 address alias offset.
31pub fn inverse_remap_l1_address(l2_address: Address) -> Address {
32    address_add(l2_address, INVERSE_ADDRESS_ALIAS_OFFSET)
33}
34
35/// Wrapping addition of two addresses (treated as 160-bit integers).
36fn address_add(a: Address, b: Address) -> Address {
37    let a_bytes = a.0 .0;
38    let b_bytes = b.0 .0;
39    let mut result = [0u8; 20];
40    let mut carry: u16 = 0;
41    for i in (0..20).rev() {
42        let sum = a_bytes[i] as u16 + b_bytes[i] as u16 + carry;
43        result[i] = sum as u8;
44        carry = sum >> 8;
45    }
46    Address::new(result)
47}
48
49/// Whether a transaction type uses address aliasing.
50pub fn does_tx_type_alias(tx_type: u8) -> bool {
51    // ArbitrumUnsignedTx = 0x65, ArbitrumContractTx = 0x66, ArbitrumRetryTx = 0x68
52    matches!(tx_type, 0x65 | 0x66 | 0x68)
53}
54
55/// Whether a transaction type incurs L1 poster costs. Only standard
56/// EOA-signed tx types (Legacy / EIP-2930 / EIP-1559) pay; all
57/// Arbitrum-specific types (deposit, unsigned, contract, retry,
58/// submit-retryable, internal) skip L1 charging.
59pub fn tx_type_has_poster_costs(tx_type: u8) -> bool {
60    !matches!(
61        tx_type,
62        0x64  // ArbitrumDepositTx
63        | 0x65 // ArbitrumUnsignedTx
64        | 0x66 // ArbitrumContractTx
65        | 0x68 // ArbitrumRetryTx
66        | 0x69 // ArbitrumSubmitRetryableTx
67        | 0x6a // ArbitrumInternalTx
68    )
69}