xmtp_id/scw_verifier/
remote_signature_verifier.rs1use super::{SmartContractSignatureVerifier, ValidationResponse, VerifierError};
2use crate::associations::AccountId;
3use alloy::primitives::{BlockNumber, Bytes};
4
5use xmtp_proto::{
6 backend_v1::{
7 VerifySmartContractWalletSignaturesRequest, VerifySmartContractWalletSignaturesResponse,
8 verify_smart_contract_wallet_signatures_request::Signature as VerifySmartContractWalletSignatureRequestSignature,
9 },
10 prelude::XmtpBackendClient,
11};
12
13pub struct RemoteSignatureVerifier<C> {
14 api: C,
15}
16
17impl<ApiClient> RemoteSignatureVerifier<ApiClient> {
18 pub fn new(api: ApiClient) -> Self {
19 Self { api }
20 }
21}
22
23#[xmtp_common::async_trait]
24impl<C> SmartContractSignatureVerifier for RemoteSignatureVerifier<C>
25where
26 C: XmtpBackendClient,
27{
28 async fn is_valid_signature(
29 &self,
30 account_id: AccountId,
31 hash: [u8; 32],
32 signature: Bytes,
33 block_number: Option<BlockNumber>,
34 ) -> Result<ValidationResponse, VerifierError> {
35 let result = self
36 .api
37 .verify_smart_contract_wallet_signatures(VerifySmartContractWalletSignaturesRequest {
38 signatures: vec![VerifySmartContractWalletSignatureRequestSignature {
39 account_id: account_id.into(),
40 block_number,
41 signature: signature.to_vec(),
42 hash: hash.to_vec(),
43 }],
44 })
45 .await
46 .map_err(|e| VerifierError::Other(Box::new(e) as Box<_>))?;
47
48 let VerifySmartContractWalletSignaturesResponse { responses } = result;
49
50 let response =
51 responses
52 .into_iter()
53 .next()
54 .ok_or(VerifierError::Io(std::io::Error::new(
55 std::io::ErrorKind::InvalidData,
56 "API returned empty response for signature verification request",
57 )))?;
58 Ok(ValidationResponse {
59 is_valid: response.is_valid,
60 block_number: response.block_number,
61 error: response.error,
62 })
63 }
64}
65
66impl<T> Clone for RemoteSignatureVerifier<T>
67where
68 T: Clone,
69{
70 fn clone(&self) -> Self {
71 Self {
72 api: self.api.clone(),
73 }
74 }
75}