1use ethabi::{Contract, Token};
2use thiserror::Error;
3use web3::{
4 api::Eth,
5 signing::keccak256,
6 types::{Bytes, CallRequest}, Transport
7};
8
9use crate::account::Address;
10
11static MAGIC_EIP1271_VALUE: [u8; 4] = [22, 38, 186, 126];
12static EIP1654_ABI: &[u8] = include_bytes!("../contracts/SignatureValidator.json");
13
14#[derive(Error, Debug)]
15pub enum RPCCallError {
16
17 #[error("rpc resolver not implemented")]
18 NotImplemented,
19
20 #[error("error encoding params: {0}")]
21 Encode(ethabi::Error),
22
23 #[error("error calling rpc: {0}")]
24 Call(web3::Error),
25
26 #[error("error decoding result: {0}")]
27 Decode(ethabi::Error),
28}
29
30pub async fn rpc_call_is_valid_signature<T: Transport>(
32 eth: &Eth<T>,
33 address: Address,
34 message: String,
35 hash: Vec<u8>,
36) -> Result<bool, RPCCallError> {
37 let contract = Contract::load(EIP1654_ABI).map_err(RPCCallError::Encode)?;
38 let func = contract.function("isValidSignature")
39 .map_err(RPCCallError::Encode)?;
40
41 let call = func.encode_input(&[
42 Token::FixedBytes(keccak256(message.as_bytes()).to_vec()),
43 Token::Bytes(hash),
44 ]).map_err(RPCCallError::Encode)?;
45
46 let bytes = eth
47 .call(
48 CallRequest {
49 from: None,
50 to: Some(*address),
51 gas: None,
52 gas_price: None,
53 value: None,
54 data: Some(Bytes(call)),
55 transaction_type: None,
56 access_list: None,
57 max_fee_per_gas: None,
58 max_priority_fee_per_gas: None,
59 },
60 None,
61 )
62 .await
63 .map_err(RPCCallError::Call)?;
64
65 let output = func.decode_output(&bytes.0)
66 .map_err(RPCCallError::Decode)?;
67
68 if let Some(token) = output.first() {
69 if let Some(value) = token.clone().into_fixed_bytes() {
70 return Ok(value == MAGIC_EIP1271_VALUE);
71 }
72 }
73
74 Ok(false)
75}