sorocharge-x402
x402 protocol v2’s exact scheme on Stellar. Wire types and shapes are copied verbatim
from x402-foundation/x402’s specs/schemes/exact/scheme_exact_stellar.md and
specs/x402-specification-v2.md.
Client
X402Client
#![allow(unused)]
fn main() {
impl X402Client {
pub fn new(request_timeout: std::time::Duration) -> Result<Self, X402Error>;
pub async fn get_with_payment(
&self,
url: &str,
signer: &dyn sorocharge_signer::Signer,
network_passphrase: &str,
current_ledger: u32,
) -> Result<reqwest::Response, X402Error>;
}
}
See Paying with x402.
Facilitator
Facilitator
#![allow(unused)]
fn main() {
impl<'a> Facilitator<'a> {
pub fn new(
rpc: &'a stellar_rpc_client::Client,
signer: &'a dyn sorocharge_signer::Signer,
network_passphrase: String,
config: FacilitatorConfig,
) -> Self;
pub async fn verify(&self, request: &VerifyRequest) -> Result<VerifyResponse, X402Error>;
pub async fn settle(&self, request: &SettleRequest) -> Result<SettlementResponse, X402Error>;
pub fn supported(&self) -> SupportedResponse;
}
}
#![allow(unused)]
fn main() {
pub struct FacilitatorConfig {
pub max_transaction_fee_stroops: i64, // default 50_000
pub inclusion_buffer_stroops: i64, // default 100 (the spec's required minimum)
}
}
SettleRequest is a type alias for VerifyRequest — the spec gives /settle the
identical request shape as /verify. See
Running an x402 facilitator.
Wire types
All of these derive Serialize/Deserialize with camelCase field names matching the
spec exactly.
#![allow(unused)]
fn main() {
pub struct ResourceInfo { pub url: String, pub description: Option<String>, pub mime_type: Option<String> }
pub struct StellarExtra { pub are_fees_sponsored: bool }
pub struct PaymentRequirements {
pub scheme: String, // always "exact"
pub network: String, // "stellar:pubnet" | "stellar:testnet"
pub amount: String, // decimal string, base units
pub asset: String, // SEP-41 SAC contract (C...)
pub pay_to: String, // recipient account (G...)
pub max_timeout_seconds: u64,
pub extra: StellarExtra,
}
pub struct PaymentRequired {
pub x402_version: u32, // 2
pub error: Option<String>,
pub resource: ResourceInfo,
pub accepts: Vec<PaymentRequirements>,
pub extensions: serde_json::Map<String, serde_json::Value>,
}
pub struct StellarPayload { pub transaction: String } // base64 TransactionEnvelope
pub struct PaymentPayload {
pub x402_version: u32,
pub resource: Option<ResourceInfo>,
pub accepted: PaymentRequirements,
pub payload: StellarPayload,
pub extensions: serde_json::Map<String, serde_json::Value>,
}
pub struct VerifyRequest {
pub x402_version: u32,
pub payment_payload: PaymentPayload,
pub payment_requirements: PaymentRequirements,
}
pub struct VerifyResponse {
pub is_valid: bool,
pub invalid_reason: Option<String>,
pub payer: Option<String>,
}
pub struct SettlementResponse {
pub success: bool,
pub error_reason: Option<String>,
pub payer: Option<String>,
pub transaction: String, // tx hash, or "" if none broadcast
pub network: String,
pub amount: Option<String>,
}
pub struct SupportedKind { pub x402_version: u32, pub scheme: String, pub network: String }
pub struct SupportedResponse {
pub kinds: Vec<SupportedKind>,
pub extensions: Vec<String>,
pub signers: std::collections::BTreeMap<String, Vec<String>>, // "stellar:*" -> addresses
}
}
Headers
| Header | Direction | Content |
|---|---|---|
PAYMENT-REQUIRED | Server → Client | Base64 JSON PaymentRequired |
PAYMENT-SIGNATURE | Client → Server | Base64 JSON PaymentPayload |
PAYMENT-RESPONSE | Server → Client | Base64 JSON SettlementResponse |
X402Error
| Variant | Meaning |
|---|---|
HttpRequestFailed { reason } | The HTTP request itself failed. |
UnexpectedStatus { status } | Neither 402 nor 200. |
MissingPaymentRequiredHeader | A 402 carried no PAYMENT-REQUIRED header. |
InvalidPaymentRequired { reason } | The header didn’t base64/JSON-decode. |
NoAcceptablePaymentRequirements | No accepts[] entry matches scheme + network. |
UnsupportedNetwork { network } | No CAIP-2 mapping for this network. |
Signing(SorochargeError) | sorocharge-signer failed to build or sign. |
XdrEncodingFailed { reason } / XdrDecodingFailed { reason } | XDR (de)serialization failed. |
InvalidPaymentPayload { reason } | The credential’s JSON didn’t match the expected shape. |
UnexpectedTransactionShape { reason } | Not a bare SEP-41 transfer — wrong op count, function, args, or a smuggled sub-invocation. |
ForbiddenCredentialType | sorobanCredentialsSourceAccount or sorobanCredentialsAddressWithDelegates — the spec forbids both for this scheme. |
FacilitatorAddressConflict | The facilitator’s own address appeared where the safety checks forbid it. |
RpcFailed { reason } | A Stellar RPC call failed. |
FeeExceedsCeiling { fee_stroops, ceiling_stroops } | The settlement-derived fee exceeded max_transaction_fee_stroops. |
SettlementFailed { reason } | Verified, but on-chain submission failed. |