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.
14pub const INVERSE_ADDRESS_ALIAS_OFFSET: Address = {
15 let bytes: [u8; 20] = [
16 0xee, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17 0x00, 0x00, 0x00, 0xee, 0xef,
18 ];
19 Address::new(bytes)
20};
21
22/// Applies the L1→L2 address alias offset.
23pub fn remap_l1_address(l1_address: Address) -> Address {
24 address_add(l1_address, ADDRESS_ALIAS_OFFSET)
25}
26
27/// Removes the L1→L2 address alias offset.
28pub fn inverse_remap_l1_address(l2_address: Address) -> Address {
29 address_add(l2_address, INVERSE_ADDRESS_ALIAS_OFFSET)
30}
31
32/// Wrapping addition of two addresses (treated as 160-bit integers).
33fn address_add(a: Address, b: Address) -> Address {
34 let a_bytes = a.0 .0;
35 let b_bytes = b.0 .0;
36 let mut result = [0u8; 20];
37 let mut carry: u16 = 0;
38 for i in (0..20).rev() {
39 let sum = a_bytes[i] as u16 + b_bytes[i] as u16 + carry;
40 result[i] = sum as u8;
41 carry = sum >> 8;
42 }
43 Address::new(result)
44}
45
46/// Whether a transaction type uses address aliasing.
47pub fn does_tx_type_alias(tx_type: u8) -> bool {
48 // ArbitrumUnsignedTx = 0x65, ArbitrumContractTx = 0x66, ArbitrumRetryTx = 0x68
49 matches!(tx_type, 0x65 | 0x66 | 0x68)
50}
51
52/// Whether a transaction type incurs L1 poster costs and standard fee distribution.
53///
54/// In Nitro, the GasChargingHook sets SkipL1Charging=false for ALL on-chain txs,
55/// meaning poster gas is computed for every tx that enters the EVM. Only types that
56/// end early in StartTxHook (deposit, internal, submit-retryable) never reach the
57/// gas charging phase. RetryTx has its own special gas/fee handling.
58///
59/// UnsignedTx (0x65) and ContractTx (0x66) are L1→L2 messages that execute through
60/// the normal EVM path and MUST have poster costs and fee distribution, matching
61/// standard user txs.
62pub fn tx_type_has_poster_costs(tx_type: u8) -> bool {
63 !matches!(
64 tx_type,
65 0x64 // ArbitrumDepositTx — ends early in StartTxHook
66 | 0x68 // ArbitrumRetryTx — has its own fee path in EndTxHook
67 | 0x69 // ArbitrumSubmitRetryableTx — ends early in StartTxHook
68 | 0x6a // ArbitrumInternalTx — ends early in StartTxHook
69 )
70}