pub mod permit2;
use alloy_provider::Provider;
use rand::seq::IndexedRandom;
use std::collections::HashMap;
use x402_types::chain::ChainProviderOps;
use x402_types::proto;
use x402_types::proto::v2;
use x402_types::scheme::{
X402SchemeFacilitator, X402SchemeFacilitatorBuilder, X402SchemeFacilitatorError,
};
use crate::V2Eip155Upto;
use crate::chain::{Eip155MetaTransactionProvider, Eip155SignerAddresses};
use crate::v1_eip155_exact::facilitator::Eip155ExactError;
use crate::v2_eip155_upto::types;
impl<P> X402SchemeFacilitatorBuilder<P> for V2Eip155Upto
where
P: Eip155MetaTransactionProvider
+ ChainProviderOps
+ Eip155SignerAddresses
+ Send
+ Sync
+ 'static,
Eip155ExactError: From<P::Error>,
{
fn build(
&self,
provider: P,
_config: Option<serde_json::Value>,
) -> Result<Box<dyn X402SchemeFacilitator>, Box<dyn std::error::Error>> {
Ok(Box::new(V2Eip155UptoFacilitator::new(provider)))
}
}
pub struct V2Eip155UptoFacilitator<P> {
provider: P,
}
impl<P> V2Eip155UptoFacilitator<P> {
pub fn new(provider: P) -> Self {
Self { provider }
}
}
#[async_trait::async_trait]
impl<P> X402SchemeFacilitator for V2Eip155UptoFacilitator<P>
where
P: Eip155MetaTransactionProvider + ChainProviderOps + Eip155SignerAddresses + Send + Sync,
P::Inner: Provider,
Eip155ExactError: From<P::Error>,
{
async fn verify(
&self,
request: &proto::VerifyRequest,
) -> Result<proto::VerifyResponse, X402SchemeFacilitatorError> {
let verify_request = types::VerifyRequest::try_from(request)?;
let verify_response = permit2::verify_permit2_payment(
&self.provider,
&verify_request.payment_payload,
&verify_request.payment_requirements,
)
.await?;
Ok(verify_response.into())
}
async fn settle(
&self,
request: &proto::SettleRequest,
) -> Result<proto::SettleResponse, X402SchemeFacilitatorError> {
let settle_request = types::SettleRequest::try_from(request)?;
let settle_response = permit2::settle_permit2_payment(
&self.provider,
&settle_request.payment_payload,
&settle_request.payment_requirements,
)
.await?;
Ok(settle_response.into())
}
async fn supported(&self) -> Result<proto::SupportedResponse, X402SchemeFacilitatorError> {
let chain_id = self.provider.chain_id();
let signer_addresses = Eip155SignerAddresses::signer_addresses(&self.provider);
let mut rng = rand::rng();
let facilitator_address = signer_addresses.choose(&mut rng);
let extra = facilitator_address
.map(|addr| types::UptoSupportedExtra {
facilitator_address: addr,
})
.and_then(|extra| serde_json::to_value(extra).ok());
let kinds = vec![proto::SupportedPaymentKind {
x402_version: v2::X402Version2.into(),
scheme: types::UptoScheme.to_string(),
network: chain_id.clone().into(),
extra,
}];
let signers = {
let mut signers = HashMap::with_capacity(1);
let signer_addresses = ChainProviderOps::signer_addresses(&self.provider);
signers.insert(chain_id, signer_addresses);
signers
};
Ok(proto::SupportedResponse {
kinds,
extensions: Vec::new(),
signers,
})
}
}