1use ethers_core::{
5 types::{Address, NameOrAddress, Selector, TransactionRequest, H160, H256},
6 utils::keccak256,
7};
8
9pub const ENS_ADDRESS: Address = H160([
11 0, 0, 0, 0, 0, 12, 46, 7, 78, 198, 154, 13, 251, 41, 151, 186, 108, 125, 46, 30,
13]);
14
15const ENS_REVERSE_REGISTRAR_DOMAIN: &str = "addr.reverse";
17
18const RESOLVER: Selector = [1, 120, 184, 191];
20
21pub const ADDR_SELECTOR: Selector = [59, 59, 87, 222];
23
24pub const NAME_SELECTOR: Selector = [105, 31, 52, 49];
26
27pub const FIELD_SELECTOR: Selector = [89, 209, 212, 60];
29
30pub const INTERFACE_SELECTOR: Selector = [1, 255, 201, 167];
32
33pub fn get_resolver<T: Into<NameOrAddress>>(ens_address: T, name: &str) -> TransactionRequest {
35 let data = [&RESOLVER[..], &namehash(name).0].concat();
37 TransactionRequest {
38 data: Some(data.into()),
39 to: Some(ens_address.into()),
40 ..Default::default()
41 }
42}
43
44pub fn supports_interface<T: Into<NameOrAddress>>(
46 resolver_address: T,
47 selector: Selector,
48) -> TransactionRequest {
49 let data = [&INTERFACE_SELECTOR[..], &selector[..], &[0; 28]].concat();
50 TransactionRequest {
51 data: Some(data.into()),
52 to: Some(resolver_address.into()),
53 ..Default::default()
54 }
55}
56
57pub fn resolve<T: Into<NameOrAddress>>(
59 resolver_address: T,
60 selector: Selector,
61 name: &str,
62 parameters: Option<&[u8]>,
63) -> TransactionRequest {
64 let data = [&selector[..], &namehash(name).0, parameters.unwrap_or_default()].concat();
65 TransactionRequest {
66 data: Some(data.into()),
67 to: Some(resolver_address.into()),
68 ..Default::default()
69 }
70}
71
72pub fn reverse_address(addr: Address) -> String {
74 format!("{addr:?}.{ENS_REVERSE_REGISTRAR_DOMAIN}")[2..].to_string()
75}
76
77pub fn namehash(name: &str) -> H256 {
79 if name.is_empty() {
80 return H256::zero()
81 }
82
83 let name = name.replace('\u{fe0f}', "");
85
86 name.rsplit('.')
88 .fold([0u8; 32], |node, label| keccak256([node, keccak256(label.as_bytes())].concat()))
89 .into()
90}
91
92pub fn bytes_32ify(n: u64) -> Vec<u8> {
94 let b = n.to_be_bytes();
95 [[0; 32][b.len()..].to_vec(), b.to_vec()].concat()
96}
97
98pub fn parameterhash(name: &str) -> Vec<u8> {
100 let bytes = name.as_bytes();
101 let key_bytes =
102 [&bytes_32ify(64), &bytes_32ify(bytes.len().try_into().unwrap()), bytes].concat();
103 match key_bytes.len() % 32 {
104 0 => key_bytes,
105 n => [key_bytes, [0; 32][n..].to_vec()].concat(),
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 fn assert_hex(hash: H256, val: &str) {
114 assert_eq!(hash.0.to_vec(), hex::decode(val).unwrap());
115 }
116
117 #[test]
118 fn test_namehash() {
119 for (name, expected) in &[
120 ("", "0000000000000000000000000000000000000000000000000000000000000000"),
121 ("foo.eth", "de9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f"),
122 ("eth", "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"),
123 ("alice.eth", "0x787192fc5378cc32aa956ddfdedbf26b24e8d78e40109add0eea2c1a012c3dec"),
124 ("ret↩️rn.eth", "0x3de5f4c02db61b221e7de7f1c40e29b6e2f07eb48d65bf7e304715cd9ed33b24"),
125 ] {
126 assert_hex(namehash(name), expected);
127 }
128 }
129
130 #[test]
131 fn test_parametershash() {
132 assert_eq!(
133 parameterhash("avatar").to_vec(),
134 vec![
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0, 6, 97, 118, 97, 116, 97, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
139 ]
140 );
141 }
142}