Skip to main content

foundry_common/
constants.rs

1//! Commonly used constants.
2
3use alloy_eips::Typed2718;
4use alloy_network::AnyTxEnvelope;
5use alloy_primitives::{Address, B256, Signature, address};
6use std::time::Duration;
7
8/// The dev chain-id, inherited from hardhat
9pub const DEV_CHAIN_ID: u64 = 31337;
10
11/// The first four bytes of the call data for a function call specifies the function to be called.
12pub const SELECTOR_LEN: usize = 4;
13
14/// Maximum size in bytes (0x6000) that a contract can have.
15pub const CONTRACT_MAX_SIZE: usize = 24576;
16
17/// Default request timeout for http requests
18///
19/// Note: this is only used so that connections, that are discarded on the server side won't stay
20/// open forever. We assume some nodes may have some backoff baked into them and will delay some
21/// responses. This timeout should be a reasonable amount of time to wait for a request.
22pub const REQUEST_TIMEOUT: Duration = Duration::from_secs(45);
23
24/// Alchemy free tier cups: <https://docs.alchemy.com/reference/pricing-plans>
25pub const ALCHEMY_FREE_TIER_CUPS: u64 = 330;
26
27/// Logged when an error is indicative that the user is trying to fork from a non-archive node.
28pub const NON_ARCHIVE_NODE_WARNING: &str = "\
29It looks like you're trying to fork from an older block with a non-archive node which is not \
30supported. Please try to change your RPC url to an archive node if the issue persists.";
31
32/// Arbitrum L1 sender address of the first transaction in every block.
33/// `0x00000000000000000000000000000000000a4b05`
34pub const ARBITRUM_SENDER: Address = address!("0x00000000000000000000000000000000000a4b05");
35
36/// The system address, the sender of the first transaction in every block:
37/// `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001`
38///
39/// See also <https://github.com/ethereum-optimism/optimism/blob/65ec61dde94ffa93342728d324fecf474d228e1f/specs/deposits.md#l1-attributes-deposited-transaction>
40pub const OPTIMISM_SYSTEM_ADDRESS: Address = address!("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001");
41
42/// The system address, the sender of the first transaction in every block:
43pub const MONAD_SYSTEM_ADDRESS: Address = address!("0x6f49a8F621353f12378d0046E7d7e4b9B249DC9e");
44
45/// HyperEVM system address that credits HyperCore -> HyperEVM native transfers.
46///
47/// These are legacy envelopes with `gasPrice = 0` and a receipt `gasUsed` of `0`, so replaying one
48/// as a regular transaction fails base fee validation and aborts the whole block replay.
49pub const HYPERLIQUID_SYSTEM_ADDRESS: Address =
50    address!("0x2222222222222222222222222222222222222222");
51
52/// MegaETH system address for `Set Slots` in the MegaETH oracle.
53///
54/// Transactions from this sender are submitted with gas price 0.
55///
56/// See: <https://mega.etherscan.io/address/0xa887dcb9d5f39ef79272801d05abdf707cfbbd1d>
57pub const MEGA_SYSTEM_ADDRESS: Address = address!("0xa887dcb9d5f39ef79272801d05abdf707cfbbd1d");
58
59/// Transaction identifier of System transaction types
60pub const SYSTEM_TRANSACTION_TYPE: u8 = 126;
61
62/// Default user agent set as the header for requests that don't specify one.
63pub const DEFAULT_USER_AGENT: &str = concat!("foundry/", env!("CARGO_PKG_VERSION"));
64
65/// Prefix for auto-generated type bindings using `forge bind-json`.
66pub const TYPE_BINDING_PREFIX: &str = "string constant schema_";
67
68/// Returns whether the sender is a known L2 system sender that is the first tx in every block.
69///
70/// Transactions from these senders usually don't have a any fee information OR set absurdly high fees that exceed the gas limit (See: <https://github.com/foundry-rs/foundry/pull/10608>)
71///
72/// See: [ARBITRUM_SENDER], [OPTIMISM_SYSTEM_ADDRESS], [MONAD_SYSTEM_ADDRESS],
73/// [MEGA_SYSTEM_ADDRESS], [HYPERLIQUID_SYSTEM_ADDRESS] and [Address::ZERO]
74pub fn is_known_system_sender(sender: Address) -> bool {
75    [
76        ARBITRUM_SENDER,
77        OPTIMISM_SYSTEM_ADDRESS,
78        MONAD_SYSTEM_ADDRESS,
79        MEGA_SYSTEM_ADDRESS,
80        HYPERLIQUID_SYSTEM_ADDRESS,
81        Address::ZERO,
82    ]
83    .contains(&sender)
84}
85
86pub fn is_impersonated_tx(tx: &AnyTxEnvelope) -> bool {
87    if let AnyTxEnvelope::Ethereum(tx) = tx {
88        return is_impersonated_sig(tx.signature(), tx.ty());
89    }
90    false
91}
92
93pub fn is_impersonated_sig(sig: &Signature, ty: u8) -> bool {
94    let impersonated_sig =
95        Signature::from_scalars_and_parity(B256::with_last_byte(1), B256::with_last_byte(1), false);
96    ty != SYSTEM_TRANSACTION_TYPE && (sig == &impersonated_sig || sig.r() == impersonated_sig.r())
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_constant_sender() {
105        let arb = address!("0x00000000000000000000000000000000000a4b05");
106        assert_eq!(arb, ARBITRUM_SENDER);
107        let base = address!("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001");
108        assert_eq!(base, OPTIMISM_SYSTEM_ADDRESS);
109    }
110}