alloy_eip5792/
wallet.rs

1use alloy_primitives::{map::HashMap, Address, ChainId};
2use serde::{Deserialize, Serialize};
3
4/// The capability to perform [EIP-7702][eip-7702] delegations, sponsored by the sequencer.
5///
6/// The sequencer will only perform delegations, and act on behalf of delegated accounts, if the
7/// account delegates to one of the addresses specified within this capability.
8///
9/// [eip-7702]: https://eips.ethereum.org/EIPS/eip-7702
10#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
11pub struct DelegationCapability {
12    /// A list of valid delegation contracts.
13    pub addresses: Vec<Address>,
14}
15
16/// Wallet capabilities for a specific chain.
17#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
18pub struct Capabilities {
19    /// The capability to delegate.
20    pub delegation: DelegationCapability,
21}
22
23/// A map of wallet capabilities per chain ID.
24#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
25pub struct WalletCapabilities(
26    #[serde(with = "alloy_serde::quantity::hashmap")] pub HashMap<ChainId, Capabilities>,
27);
28
29impl WalletCapabilities {
30    /// Get the capabilities of the wallet API for the specified chain ID.
31    pub fn get(&self, chain_id: ChainId) -> Option<&Capabilities> {
32        self.0.get(&chain_id)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use alloy_primitives::{address, map::HashMap};
40
41    #[test]
42    fn ser() {
43        let caps = WalletCapabilities(HashMap::from_iter([(
44            0x69420,
45            Capabilities {
46                delegation: DelegationCapability {
47                    addresses: vec![address!("90f79bf6eb2c4f870365e785982e1f101e93b906")],
48                },
49            },
50        )]));
51        assert_eq!(serde_json::to_string(&caps).unwrap(), "{\"0x69420\":{\"delegation\":{\"addresses\":[\"0x90f79bf6eb2c4f870365e785982e1f101e93b906\"]}}}");
52    }
53
54    #[test]
55    fn de() {
56        let caps: WalletCapabilities = serde_json::from_str(
57            r#"{
58                    "0x69420": {
59                        "delegation": {
60                            "addresses": ["0x90f79bf6eb2c4f870365e785982e1f101e93b906"]
61                        }
62                    }
63                }"#,
64        )
65        .expect("could not deser");
66
67        assert_eq!(
68            caps,
69            WalletCapabilities(HashMap::from_iter([(
70                0x69420,
71                Capabilities {
72                    delegation: DelegationCapability {
73                        addresses: vec![address!("90f79bf6eb2c4f870365e785982e1f101e93b906")],
74                    },
75                },
76            )]))
77        );
78    }
79
80    #[test]
81    fn test_get_capabilities() {
82        let caps = WalletCapabilities(HashMap::from_iter([(
83            0x69420,
84            Capabilities {
85                delegation: DelegationCapability {
86                    addresses: vec![address!("90f79bf6eb2c4f870365e785982e1f101e93b906")],
87                },
88            },
89        )]));
90
91        // Retrieve an existing chain ID.
92        let capabilities = caps.get(0x69420);
93        assert!(capabilities.is_some());
94        assert_eq!(
95            capabilities.unwrap().delegation.addresses[0],
96            address!("90f79bf6eb2c4f870365e785982e1f101e93b906")
97        );
98
99        // Try to retrieve a non-existing chain ID.
100        let non_existing_capabilities = caps.get(0x12345);
101        assert!(non_existing_capabilities.is_none());
102    }
103
104    #[test]
105    fn test_capabilities_with_empty_delegation() {
106        let caps = WalletCapabilities(HashMap::from_iter([(
107            0x12345,
108            Capabilities { delegation: DelegationCapability { addresses: vec![] } },
109        )]));
110
111        // Verify that delegation exists but contains no addresses.
112        let capabilities = caps.get(0x12345).unwrap();
113        assert!(capabilities.delegation.addresses.is_empty());
114
115        // Serialize and ensure JSON output is correct.
116        let serialized = serde_json::to_string(&caps).unwrap();
117        assert_eq!(serialized, "{\"0x12345\":{\"delegation\":{\"addresses\":[]}}}");
118    }
119}