pub mod eip2612;
pub mod permit2;
use alloy_provider::Provider;
use rand::seq::IndexedRandom;
use serde::{Deserialize, Serialize};
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;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct V2Eip155UptoFacilitatorConfig {
#[serde(default)]
pub eip2612_gas_sponsoring: bool,
}
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>> {
let config: V2Eip155UptoFacilitatorConfig = config
.and_then(|c| serde_json::from_value(c).ok())
.unwrap_or_default();
Ok(Box::new(V2Eip155UptoFacilitator::new(provider, config)))
}
}
pub struct V2Eip155UptoFacilitator<P> {
provider: P,
eip2612_gas_sponsoring: bool,
}
impl<P> V2Eip155UptoFacilitator<P> {
pub fn new(provider: P, config: V2Eip155UptoFacilitatorConfig) -> Self {
Self {
provider,
eip2612_gas_sponsoring: config.eip2612_gas_sponsoring,
}
}
}
#[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,
self.eip2612_gas_sponsoring,
&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,
self.eip2612_gas_sponsoring,
&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 mut extensions = vec![];
if self.eip2612_gas_sponsoring {
extensions.push(eip2612::EXTENSION_KEY.to_string());
}
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,
extensions: extensions.clone(),
})
.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,
signers,
})
}
}