use alloy::primitives::{Address, address};
#[derive(Debug, Clone, Copy)]
pub struct NetworkAddresses {
pub identity: Address,
pub reputation: Address,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Network {
EthereumMainnet,
EthereumSepolia,
BaseMainnet,
BaseSepolia,
PolygonMainnet,
PolygonAmoy,
ArbitrumMainnet,
ArbitrumSepolia,
CeloMainnet,
CeloAlfajores,
GnosisMainnet,
ScrollMainnet,
ScrollSepolia,
TaikoMainnet,
MonadMainnet,
MonadTestnet,
BscMainnet,
BscTestnet,
AbstractMainnet,
AbstractTestnet,
AvalancheMainnet,
AvalancheTestnet,
LineaMainnet,
LineaSepolia,
MantleMainnet,
MantleSepolia,
MegaEthMainnet,
MegaEthTestnet,
OptimismMainnet,
OptimismSepolia,
}
const MAINNET_IDENTITY: Address = address!("8004A169FB4a3325136EB29fA0ceB6D2e539a432");
const MAINNET_REPUTATION: Address = address!("8004BAa17C55a88189AE136b182e5fdA19dE9b63");
const TESTNET_IDENTITY: Address = address!("8004A818BFB912233c491871b3d84c89A494BD9e");
const TESTNET_REPUTATION: Address = address!("8004B663056A597Dffe9eCcC1965A193B7388713");
impl Network {
#[must_use]
pub const fn addresses(self) -> NetworkAddresses {
match self {
Self::EthereumMainnet
| Self::BaseMainnet
| Self::PolygonMainnet
| Self::ArbitrumMainnet
| Self::CeloMainnet
| Self::GnosisMainnet
| Self::ScrollMainnet
| Self::TaikoMainnet
| Self::MonadMainnet
| Self::BscMainnet
| Self::AbstractMainnet
| Self::AvalancheMainnet
| Self::LineaMainnet
| Self::MantleMainnet
| Self::MegaEthMainnet
| Self::OptimismMainnet => NetworkAddresses {
identity: MAINNET_IDENTITY,
reputation: MAINNET_REPUTATION,
},
Self::EthereumSepolia
| Self::BaseSepolia
| Self::PolygonAmoy
| Self::ArbitrumSepolia
| Self::CeloAlfajores
| Self::ScrollSepolia
| Self::MonadTestnet
| Self::BscTestnet
| Self::AbstractTestnet
| Self::AvalancheTestnet
| Self::LineaSepolia
| Self::MantleSepolia
| Self::MegaEthTestnet
| Self::OptimismSepolia => NetworkAddresses {
identity: TESTNET_IDENTITY,
reputation: TESTNET_REPUTATION,
},
}
}
#[must_use]
pub const fn chain_id(self) -> u64 {
match self {
Self::EthereumMainnet => 1,
Self::EthereumSepolia => 11_155_111,
Self::BaseMainnet => 8453,
Self::BaseSepolia => 84532,
Self::PolygonMainnet => 137,
Self::PolygonAmoy => 80002,
Self::ArbitrumMainnet => 42161,
Self::ArbitrumSepolia => 421_614,
Self::CeloMainnet => 42220,
Self::CeloAlfajores => 44787,
Self::GnosisMainnet => 100,
Self::ScrollMainnet => 534_352,
Self::ScrollSepolia => 534_351,
Self::TaikoMainnet => 167_000,
Self::MonadMainnet => 143,
Self::MonadTestnet => 10143,
Self::BscMainnet => 56,
Self::BscTestnet => 97,
Self::AbstractMainnet => 2741,
Self::AbstractTestnet => 11124,
Self::AvalancheMainnet => 43114,
Self::AvalancheTestnet => 43113,
Self::LineaMainnet => 59144,
Self::LineaSepolia => 59141,
Self::MantleMainnet => 5000,
Self::MantleSepolia => 5003,
Self::MegaEthMainnet => 4326,
Self::MegaEthTestnet => 6342,
Self::OptimismMainnet => 10,
Self::OptimismSepolia => 11_155_420,
}
}
pub const ALL: &[Self] = &[
Self::EthereumMainnet,
Self::EthereumSepolia,
Self::BaseMainnet,
Self::BaseSepolia,
Self::PolygonMainnet,
Self::PolygonAmoy,
Self::ArbitrumMainnet,
Self::ArbitrumSepolia,
Self::CeloMainnet,
Self::CeloAlfajores,
Self::GnosisMainnet,
Self::ScrollMainnet,
Self::ScrollSepolia,
Self::TaikoMainnet,
Self::MonadMainnet,
Self::MonadTestnet,
Self::BscMainnet,
Self::BscTestnet,
Self::AbstractMainnet,
Self::AbstractTestnet,
Self::AvalancheMainnet,
Self::AvalancheTestnet,
Self::LineaMainnet,
Self::LineaSepolia,
Self::MantleMainnet,
Self::MantleSepolia,
Self::MegaEthMainnet,
Self::MegaEthTestnet,
Self::OptimismMainnet,
Self::OptimismSepolia,
];
#[must_use]
pub fn from_chain_id(chain_id: u64) -> Option<Self> {
Self::ALL.iter().find(|n| n.chain_id() == chain_id).copied()
}
#[must_use]
pub fn agent_registry_prefix(self) -> String {
format!("eip155:{}:{}", self.chain_id(), self.addresses().identity)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_has_no_duplicate_chain_ids() {
let mut ids: Vec<u64> = Network::ALL.iter().map(|n| n.chain_id()).collect();
ids.sort_unstable();
let before = ids.len();
ids.dedup();
assert_eq!(
before,
ids.len(),
"Network::ALL contains duplicate chain IDs"
);
}
#[test]
fn test_chain_id_round_trip() {
for &network in Network::ALL {
let id = network.chain_id();
assert_eq!(
Network::from_chain_id(id),
Some(network),
"from_chain_id({id}) should return the original variant"
);
}
}
#[test]
fn test_from_chain_id_unknown_returns_none() {
assert_eq!(Network::from_chain_id(999_999_999), None);
}
#[test]
fn test_create2_mainnet_addresses_are_consistent() {
let reference = Network::EthereumMainnet.addresses();
for &network in Network::ALL {
let addrs = network.addresses();
if addrs.identity != reference.identity {
continue;
}
assert_eq!(
addrs.reputation,
reference.reputation,
"chain {} has matching identity but mismatched reputation",
network.chain_id()
);
}
}
#[test]
fn test_testnet_addresses_differ_from_mainnet() {
let mainnet = Network::EthereumMainnet.addresses();
let testnet = Network::EthereumSepolia.addresses();
assert_ne!(mainnet.identity, testnet.identity);
assert_ne!(mainnet.reputation, testnet.reputation);
}
#[test]
fn test_agent_registry_prefix_format() {
let network = Network::EthereumMainnet;
let prefix = network.agent_registry_prefix();
let expected = format!(
"eip155:{}:{}",
network.chain_id(),
network.addresses().identity
);
assert_eq!(prefix, expected);
}
}