1use alloy::contract::Error as ContractError;
2use alloy::primitives::Address;
3use alloy::providers::Provider;
4use alloy::sol;
5use alloy::sol_types::{SolCall, SolInterface};
6use thiserror::Error;
7
8sol!(
12 #[sol(rpc)]
13 interface IERC165 {
14 function supportsInterface(bytes4 interfaceID) external view returns (bool);
15 }
16);
17
18#[derive(Error, Debug)]
19pub enum XorSelectorsError {
20 #[error("no selectors")]
21 NoSelectors,
22}
23
24#[derive(Error, Debug)]
33pub enum Erc165Error {
34 #[error(transparent)]
38 Call(#[from] ContractError),
39}
40
41fn is_revert_like(e: &ContractError) -> bool {
46 e.as_revert_data().is_some() || matches!(e, ContractError::ZeroData(_, _))
47}
48
49pub trait XorSelectors<T: SolInterface> {
51 fn xor_selectors() -> Result<[u8; 4], XorSelectorsError> {
61 let selectors = T::selectors().collect::<Vec<_>>();
62 if selectors.is_empty() {
63 return Err(XorSelectorsError::NoSelectors);
64 }
65 let mut result = u32::from_be_bytes(selectors[0]);
66 for selector in &selectors[1..] {
67 result ^= u32::from_be_bytes(*selector);
68 }
69 Ok(result.to_be_bytes())
70 }
71}
72impl<T: SolInterface> XorSelectors<T> for T {}
73
74async fn supports_erc165_check1<P: Provider>(
82 provider: &P,
83 contract_address: Address,
84) -> Result<bool, Erc165Error> {
85 let contract = IERC165::new(contract_address, provider);
86 match contract
87 .supportsInterface(IERC165::supportsInterfaceCall::SELECTOR.into())
88 .call()
89 .await
90 {
91 Ok(v) => Ok(v),
92 Err(e) if is_revert_like(&e) => Ok(false),
93 Err(e) => Err(e.into()),
94 }
95}
96
97async fn supports_erc165_check2<P: Provider>(
105 provider: &P,
106 contract_address: Address,
107) -> Result<bool, Erc165Error> {
108 let contract = IERC165::new(contract_address, provider);
109 match contract
110 .supportsInterface([0xff, 0xff, 0xff, 0xff].into())
111 .call()
112 .await
113 {
114 Ok(v) => Ok(!v),
115 Err(e) if is_revert_like(&e) => Ok(false),
116 Err(e) => Err(e.into()),
117 }
118}
119
120pub async fn supports_erc165<P: Provider>(
132 provider: &P,
133 contract_address: Address,
134) -> Result<bool, Erc165Error> {
135 if !supports_erc165_check1(provider, contract_address).await? {
136 return Ok(false);
137 }
138 supports_erc165_check2(provider, contract_address).await
139}
140
141#[cfg(test)]
142mod tests {
143 use super::XorSelectors;
144 use super::*;
145 use alloy::providers::{ProviderBuilder, mock::Asserter};
146 use alloy::rpc::json_rpc::ErrorPayload;
147 use serde_json::json;
148
149 sol! {
151 #[sol(rpc)]
152 interface ITest {
153 function externalFn1() external pure returns (bool);
154 function externalFn2(uint256 val1, uint256 val2) external returns (uint256, bool);
155 function externalFn3(address add) external returns (address);
156 error SomeError();
157 event SomeEvent(uint256 value);
158 }
159 }
160
161 sol! {
162 interface IOne {
166 function only() external;
167 }
168 }
169
170 sol! {
171 interface ITwo {
175 function first() external;
176 function second(uint256 v) external;
177 }
178 }
179
180 fn mocked_provider(asserter: Asserter) -> impl Provider {
186 ProviderBuilder::new().connect_mocked_client(asserter)
187 }
188
189 fn revert_payload() -> ErrorPayload {
190 ErrorPayload {
191 code: -32003,
192 message: "execution reverted".into(),
193 data: Some(serde_json::value::to_raw_value(&json!("0x00")).unwrap()),
194 }
195 }
196
197 fn transport_error_payload() -> ErrorPayload {
202 ErrorPayload {
203 code: -32603,
204 message: "internal error".into(),
205 data: None,
206 }
207 }
208
209 #[test]
210 fn test_get_interface_id() {
211 let result = IERC165::IERC165Calls::xor_selectors().unwrap();
212 let expected: [u8; 4] = 0x01ffc9a7u32.to_be_bytes(); assert_eq!(result, expected);
214
215 let result = ITest::ITestCalls::xor_selectors().unwrap();
216 let expected: [u8; 4] = 0x3dcd3fedu32.to_be_bytes(); assert_eq!(result, expected);
218 }
219
220 #[test]
221 fn test_xor_selectors_single_selector_returns_that_selector() {
222 let result = IOne::IOneCalls::xor_selectors().unwrap();
225 let expected = IOne::onlyCall::SELECTOR;
226 assert_eq!(result, expected);
227 }
228
229 #[test]
230 fn test_xor_selectors_two_function_interface_xors_both() {
231 let result = ITwo::ITwoCalls::xor_selectors().unwrap();
237 let selectors = ITwo::ITwoCalls::selectors().collect::<Vec<_>>();
238 assert_eq!(selectors.len(), 2);
239 let manual = u32::from_be_bytes(selectors[0]) ^ u32::from_be_bytes(selectors[1]);
240 assert_eq!(result, manual.to_be_bytes());
241 assert_ne!(result, selectors[0]);
244 assert_ne!(result, selectors[1]);
245 }
246
247 #[tokio::test]
248 async fn test_supports_erc165_check1_true_response() {
249 let asserter = Asserter::new();
250 let address = Address::random();
251 asserter
252 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
253
254 let provider = mocked_provider(asserter);
255 let result = supports_erc165_check1(&provider, address).await.unwrap();
256 assert!(result);
257 }
258
259 #[tokio::test]
260 async fn test_supports_erc165_check1_false_response() {
261 let asserter = Asserter::new();
262 let address = Address::random();
263 asserter
264 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
265
266 let provider = mocked_provider(asserter);
267 let result = supports_erc165_check1(&provider, address).await.unwrap();
268 assert!(!result);
269 }
270
271 #[tokio::test]
272 async fn test_supports_erc165_check1_revert_response() {
273 let asserter = Asserter::new();
274 let address = Address::random();
275 asserter.push_failure(revert_payload());
276
277 let provider = mocked_provider(asserter);
278 let result = supports_erc165_check1(&provider, address).await.unwrap();
279 assert!(!result);
280 }
281
282 #[tokio::test]
283 async fn test_supports_erc165_check1_transport_error_propagates() {
284 let asserter = Asserter::new();
287 let address = Address::random();
288 asserter.push_failure(transport_error_payload());
289
290 let provider = mocked_provider(asserter);
291 let err = supports_erc165_check1(&provider, address)
292 .await
293 .unwrap_err();
294 assert!(matches!(err, Erc165Error::Call(_)));
295 }
296
297 #[tokio::test]
298 async fn test_supports_erc165_check1_zero_data_response() {
299 let asserter = Asserter::new();
304 let address = Address::random();
305 asserter.push_success(&"0x");
306
307 let provider = mocked_provider(asserter);
308 let result = supports_erc165_check1(&provider, address).await.unwrap();
309 assert!(!result);
310 }
311
312 #[tokio::test]
313 async fn test_supports_erc165_check2_returns_false() {
314 let asserter = Asserter::new();
315 let address = Address::random();
316 asserter
317 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
318
319 let provider = mocked_provider(asserter);
320 let result = supports_erc165_check2(&provider, address).await.unwrap();
321 assert!(result);
322 }
323
324 #[tokio::test]
325 async fn test_supports_erc165_check2_returns_true() {
326 let asserter = Asserter::new();
327 let address = Address::random();
328 asserter
329 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
330
331 let provider = mocked_provider(asserter);
332 let result = supports_erc165_check2(&provider, address).await.unwrap();
333 assert!(!result);
334 }
335
336 #[tokio::test]
337 async fn test_supports_erc165_check2_reverts() {
338 let asserter = Asserter::new();
339 let address = Address::random();
340 asserter.push_failure(revert_payload());
341
342 let provider = mocked_provider(asserter);
343 let result = supports_erc165_check2(&provider, address).await.unwrap();
344 assert!(!result);
345 }
346
347 #[tokio::test]
348 async fn test_supports_erc165_check2_transport_error_propagates() {
349 let asserter = Asserter::new();
352 let address = Address::random();
353 asserter.push_failure(transport_error_payload());
354
355 let provider = mocked_provider(asserter);
356 let err = supports_erc165_check2(&provider, address)
357 .await
358 .unwrap_err();
359 assert!(matches!(err, Erc165Error::Call(_)));
360 }
361
362 #[tokio::test]
363 async fn test_supports_erc165_both_checks_pass() {
364 let asserter = Asserter::new();
365 let address = Address::random();
366 asserter
368 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
369 asserter
371 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
372
373 let provider = mocked_provider(asserter);
374 let result = supports_erc165(&provider, address).await.unwrap();
375 assert!(result);
376 }
377
378 #[tokio::test]
379 async fn test_supports_erc165_check1_fails() {
380 let asserter = Asserter::new();
381 let address = Address::random();
382 asserter
384 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
385 asserter
387 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
388
389 let provider = mocked_provider(asserter);
390 let result = supports_erc165(&provider, address).await.unwrap();
391 assert!(!result);
392 }
393
394 #[tokio::test]
395 async fn test_supports_erc165_check2_fails() {
396 let asserter = Asserter::new();
397 let address = Address::random();
398 asserter
400 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
401 asserter
403 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
404
405 let provider = mocked_provider(asserter);
406 let result = supports_erc165(&provider, address).await.unwrap();
407 assert!(!result);
408 }
409
410 #[tokio::test]
411 async fn test_supports_erc165_check1_reverts() {
412 let asserter = Asserter::new();
413 let address = Address::random();
414 asserter.push_failure(revert_payload());
416 asserter
418 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000000");
419
420 let provider = mocked_provider(asserter);
421 let result = supports_erc165(&provider, address).await.unwrap();
422 assert!(!result);
423 }
424
425 #[tokio::test]
426 async fn test_supports_erc165_check2_reverts_after_check1_passes() {
427 let asserter = Asserter::new();
428 let address = Address::random();
429 asserter
431 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
432 asserter.push_failure(revert_payload());
434
435 let provider = mocked_provider(asserter);
436 let result = supports_erc165(&provider, address).await.unwrap();
437 assert!(!result);
438 }
439
440 #[tokio::test]
441 async fn test_supports_erc165_propagates_check1_transport_error() {
442 let asserter = Asserter::new();
445 let address = Address::random();
446 asserter.push_failure(transport_error_payload());
447
448 let provider = mocked_provider(asserter);
449 let err = supports_erc165(&provider, address).await.unwrap_err();
450 assert!(matches!(err, Erc165Error::Call(_)));
451 }
452
453 #[tokio::test]
454 async fn test_supports_erc165_propagates_check2_transport_error() {
455 let asserter = Asserter::new();
458 let address = Address::random();
459 asserter
460 .push_success(&"0x0000000000000000000000000000000000000000000000000000000000000001");
461 asserter.push_failure(transport_error_payload());
462
463 let provider = mocked_provider(asserter);
464 let err = supports_erc165(&provider, address).await.unwrap_err();
465 assert!(matches!(err, Erc165Error::Call(_)));
466 }
467}