use std::str::FromStr;
use crate::error::SignPaymentError;
use alloy::primitives::{Address, B256};
use alloy::signers::Signer;
use async_trait::async_trait;
use rpc::{
CorePublicParameters, PaymentGuaranteeRequestClaims, PaymentGuaranteeRequestClaimsV1,
PaymentGuaranteeRequestClaimsV2, PaymentGuaranteeRequestEssentials, SigningScheme,
};
use serde::Deserialize;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone, Deserialize)]
pub struct PaymentSignature {
pub signature: String,
pub scheme: SigningScheme,
}
#[async_trait]
pub trait PaymentSigner: Send + Sync {
async fn sign_claims(
&self,
params: &CorePublicParameters,
claims: PaymentGuaranteeRequestClaims,
scheme: SigningScheme,
) -> Result<PaymentSignature, SignPaymentError>;
async fn sign_request(
&self,
params: &CorePublicParameters,
claims: PaymentGuaranteeRequestClaimsV1,
scheme: SigningScheme,
) -> Result<PaymentSignature, SignPaymentError> {
self.sign_claims(params, PaymentGuaranteeRequestClaims::V1(claims), scheme)
.await
}
async fn sign_request_v2(
&self,
params: &CorePublicParameters,
claims: PaymentGuaranteeRequestClaimsV2,
scheme: SigningScheme,
) -> Result<PaymentSignature, SignPaymentError> {
self.sign_claims(
params,
PaymentGuaranteeRequestClaims::V2(Box::new(claims)),
scheme,
)
.await
}
}
#[async_trait]
impl<S> PaymentSigner for S
where
S: Signer + Send + Sync,
{
async fn sign_claims(
&self,
params: &CorePublicParameters,
claims: PaymentGuaranteeRequestClaims,
scheme: SigningScheme,
) -> Result<PaymentSignature, SignPaymentError> {
let signer_addr = self.address();
let expected = Address::from_str(claims.user_address())
.map_err(|_| SignPaymentError::InvalidUserAddress)?;
if signer_addr != expected {
return Err(SignPaymentError::AddressMismatch {
signer: signer_addr,
claims: claims.user_address().to_owned(),
});
}
let digest: B256 = match scheme {
SigningScheme::Eip712 => crate::digest::eip712_digest_for_claims(params, &claims)
.map_err(|e| SignPaymentError::Failed(e.to_string()))?,
SigningScheme::Eip191 => {
let user = Address::from_str(claims.user_address())
.map_err(|_| SignPaymentError::InvalidUserAddress)?;
let recipient = Address::from_str(claims.recipient_address())
.map_err(|_| SignPaymentError::InvalidRecipientAddress)?;
crate::digest::eip191_digest_for_claims(&claims, user, recipient)
.map_err(|e| SignPaymentError::Failed(e.to_string()))?
}
};
let sig = self
.sign_hash(&digest)
.await
.map_err(|e| SignPaymentError::Failed(e.to_string()))?;
Ok(PaymentSignature {
signature: sig.to_string(),
scheme,
})
}
}