Documentation
¶
Overview ¶
Package buyer implements an x402 buyer sidecar that handles payments using pre-signed ERC-3009 TransferWithAuthorization vouchers. The sidecar acts as an OpenAI-compatible reverse proxy — it intercepts 402 responses from upstream sellers, attaches pre-signed payment headers, and retries automatically.
The agent pre-signs a bounded batch of authorizations and stores them in a ConfigMap. The sidecar reads from this pool and has zero signer access. Spending is bounded by design: max loss = N * price.
Index ¶
- Constants
- Variables
- func EncodePayment(payment x402types.PaymentPayload) (string, error)
- func NewPaymentError(code, msg string, err error) error
- type AuthsFile
- type Config
- type DefaultPaymentSelector
- type PaymentCallback
- type PaymentError
- type PaymentEvent
- type PaymentEventType
- type PaymentSelector
- type PreSignedAuth
- type PreSignedSigner
- func (s *PreSignedSigner) CanSign(req *x402types.PaymentRequirements) bool
- func (s *PreSignedSigner) ConfirmSpend(auth *PreSignedAuth) error
- func (s *PreSignedSigner) GetMaxAmount() *big.Int
- func (s *PreSignedSigner) GetPriority() int
- func (s *PreSignedSigner) GetTokens() []TokenConfig
- func (s *PreSignedSigner) HoldSign(req *x402types.PaymentRequirements) (*x402types.PaymentPayload, *PreSignedAuth, error)
- func (s *PreSignedSigner) Network() string
- func (s *PreSignedSigner) ReleaseSpend(auth *PreSignedAuth)
- func (s *PreSignedSigner) Remaining() int
- func (s *PreSignedSigner) Scheme() string
- func (s *PreSignedSigner) Sign(req *x402types.PaymentRequirements) (*x402types.PaymentPayload, error)
- func (s *PreSignedSigner) Spent() int
- type Proxy
- type SettlementResponse
- type Signer
- type StateStore
- type TokenConfig
- type UpstreamConfig
Constants ¶
const ( ErrCodeInvalidRequirements = "invalid_requirements" ErrCodeSigningFailed = "signing_failed" )
Error code constants.
Variables ¶
var ErrNoValidSigner = errors.New("no valid signer found for payment requirements")
ErrNoValidSigner is returned when no signer in the pool can satisfy any requirement.
Functions ¶
func EncodePayment ¶
func EncodePayment(payment x402types.PaymentPayload) (string, error)
EncodePayment converts a v2 PaymentPayload to a base64-encoded JSON string for the X-PAYMENT HTTP header.
func NewPaymentError ¶
NewPaymentError creates a PaymentError with the given code and message.
Types ¶
type AuthsFile ¶
type AuthsFile map[string][]*PreSignedAuth
AuthsFile is the top-level structure for the pre-signed authorizations file, loaded from the x402-buyer-auths ConfigMap. Keys are upstream names matching Config.Upstreams.
func LoadAuthsDir ¶
LoadAuthsDir reads per-upstream auth files from a directory. Each *.json file contains an array of PreSignedAuth for one upstream.
type Config ¶
type Config struct {
Upstreams map[string]UpstreamConfig `json:"upstreams"`
}
Config is the top-level sidecar configuration, loaded from a JSON file mounted from the x402-buyer-config ConfigMap.
func LoadConfig ¶
LoadConfig reads and parses the sidecar config from a JSON file.
func LoadConfigDir ¶
LoadConfigDir reads per-upstream config files from a directory. Each *.json file is one upstream, keyed by the filename stem (e.g. "42.json" → key "42"). This is the SSA-compatible format where the controller applies one key per PurchaseRequest via Server-Side Apply.
type DefaultPaymentSelector ¶
type DefaultPaymentSelector struct{}
DefaultPaymentSelector iterates signers by priority and picks the first match.
func (*DefaultPaymentSelector) SelectAndSign ¶
func (s *DefaultPaymentSelector) SelectAndSign(requirements []x402types.PaymentRequirements, signers []Signer) (*x402types.PaymentPayload, error)
SelectAndSign finds the first signer that can satisfy any requirement and signs it.
type PaymentCallback ¶
type PaymentCallback func(PaymentEvent)
PaymentCallback receives payment lifecycle events.
type PaymentError ¶
PaymentError wraps an error with an x402-specific error code.
func (*PaymentError) Error ¶
func (e *PaymentError) Error() string
func (*PaymentError) Unwrap ¶
func (e *PaymentError) Unwrap() error
type PaymentEvent ¶
type PaymentEvent struct {
Type PaymentEventType
Timestamp time.Time
Duration time.Duration
Method string
URL string
Network string
Scheme string
Amount string
Asset string
Recipient string
Transaction string
Payer string
Error error
}
PaymentEvent is emitted by the buyer transport for Prometheus instrumentation.
type PaymentEventType ¶
type PaymentEventType string
PaymentEventType identifies the kind of payment event.
const ( PaymentEventAttempt PaymentEventType = "attempt" PaymentEventSuccess PaymentEventType = "success" PaymentEventFailure PaymentEventType = "failure" // PaymentEventUnsettled indicates the upstream returned 2xx without a // successful X-PAYMENT-RESPONSE. The auth was consumed locally but no // on-chain settlement has been observed. PaymentEventUnsettled PaymentEventType = "unsettled" )
type PaymentSelector ¶
type PaymentSelector interface {
SelectAndSign(requirements []x402types.PaymentRequirements, signers []Signer) (*x402types.PaymentPayload, error)
}
PaymentSelector picks a requirement and signs it.
func NewDefaultPaymentSelector ¶
func NewDefaultPaymentSelector() PaymentSelector
NewDefaultPaymentSelector returns a DefaultPaymentSelector.
type PreSignedAuth ¶
type PreSignedAuth struct {
Signature string `json:"signature"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
ValidAfter string `json:"validAfter"`
ValidBefore string `json:"validBefore"`
Nonce string `json:"nonce"`
}
PreSignedAuth is a single pre-signed ERC-3009 TransferWithAuthorization voucher. Each voucher is single-use — consumed when the facilitator calls settle() on-chain.
type PreSignedSigner ¶
type PreSignedSigner struct {
// contains filtered or unexported fields
}
PreSignedSigner implements Signer using pre-signed ERC-3009 TransferWithAuthorization vouchers. It pops one auth from the pool per Sign() call. The pool is finite — once exhausted, CanSign returns false.
Thread-safe via sync.Mutex.
func NewPreSignedSigner ¶
func NewPreSignedSigner(network, payTo, asset, price string, auths []*PreSignedAuth, spent int, onConsume func(*PreSignedAuth) error) *PreSignedSigner
NewPreSignedSigner creates a signer backed by a pool of pre-signed auths.
func (*PreSignedSigner) CanSign ¶
func (s *PreSignedSigner) CanSign(req *x402types.PaymentRequirements) bool
CanSign checks if this signer can satisfy the given payment requirement. Returns true if network, payTo, asset, and amount match and there are remaining auths in the pool.
func (*PreSignedSigner) ConfirmSpend ¶
func (s *PreSignedSigner) ConfirmSpend(auth *PreSignedAuth) error
ConfirmSpend persists a nonce as consumed after a successful paid upstream response. The auth must be the pointer returned from HoldSign for this hold.
func (*PreSignedSigner) GetMaxAmount ¶
func (s *PreSignedSigner) GetMaxAmount() *big.Int
GetMaxAmount returns nil (no per-call limit — bounded by pool size instead).
func (*PreSignedSigner) GetPriority ¶
func (s *PreSignedSigner) GetPriority() int
GetPriority returns 0 (highest priority).
func (*PreSignedSigner) GetTokens ¶
func (s *PreSignedSigner) GetTokens() []TokenConfig
GetTokens returns the single USDC token this signer handles.
func (*PreSignedSigner) HoldSign ¶
func (s *PreSignedSigner) HoldSign(req *x402types.PaymentRequirements) (*x402types.PaymentPayload, *PreSignedAuth, error)
HoldSign removes one auth from the pool and builds a payment payload without persisting consume (no onConsume). The caller must invoke exactly one of ConfirmSpend or ReleaseSpend with the returned auth.
func (*PreSignedSigner) Network ¶
func (s *PreSignedSigner) Network() string
Network returns the blockchain network this signer operates on.
func (*PreSignedSigner) ReleaseSpend ¶
func (s *PreSignedSigner) ReleaseSpend(auth *PreSignedAuth)
ReleaseSpend returns a held auth to the pool after a failed payment attempt (network error or upstream HTTP error). It reverses HoldSign's in-memory reservation so the voucher can be retried.
func (*PreSignedSigner) Remaining ¶
func (s *PreSignedSigner) Remaining() int
Remaining returns the number of pre-signed authorizations left in the pool.
func (*PreSignedSigner) Scheme ¶
func (s *PreSignedSigner) Scheme() string
Scheme returns "exact" — the only payment scheme for EVM x402.
func (*PreSignedSigner) Sign ¶
func (s *PreSignedSigner) Sign(req *x402types.PaymentRequirements) (*x402types.PaymentPayload, error)
Sign pops one pre-signed authorization from the pool and returns it as a PaymentPayload, then persists local consume only after ConfirmSpend succeeds. Returns an error when the pool is exhausted.
func (*PreSignedSigner) Spent ¶
func (s *PreSignedSigner) Spent() int
Spent returns the number of authorizations consumed so far.
type Proxy ¶
type Proxy struct {
// contains filtered or unexported fields
}
Proxy is an OpenAI-compatible reverse proxy that routes requests to upstream x402-gated endpoints, attaching pre-signed payment headers automatically.
Routing:
- OpenAI-compatible chat/responses paths resolve the upstream from the requested model.
- /upstream/<name>/... remains available for compatibility.
func NewProxy ¶
func NewProxy(cfg *Config, auths AuthsFile, state *StateStore) (*Proxy, error)
NewProxy creates a proxy from the given config and auth pools.
type SettlementResponse ¶
type SettlementResponse struct {
Success bool `json:"success"`
ErrorReason string `json:"errorReason,omitempty"`
Transaction string `json:"transaction,omitempty"`
Network string `json:"network"`
Payer string `json:"payer"`
}
SettlementResponse is the decoded X-PAYMENT-RESPONSE header.
func DecodeSettlement ¶
func DecodeSettlement(encoded string) (SettlementResponse, error)
DecodeSettlement decodes a base64-encoded X-PAYMENT-RESPONSE header.
type Signer ¶
type Signer interface {
Network() string
Scheme() string
CanSign(req *x402types.PaymentRequirements) bool
Sign(req *x402types.PaymentRequirements) (*x402types.PaymentPayload, error)
GetPriority() int
GetTokens() []TokenConfig
GetMaxAmount() *big.Int
}
Signer produces x402 v2 payment payloads for a specific network and scheme. The buyer proxy holds an array of signers and selects the first one that can satisfy an incoming 402's requirements.
type StateStore ¶
type StateStore struct {
// contains filtered or unexported fields
}
StateStore tracks consumed authorization nonces so hot reloads and restarts do not reintroduce already-spent vouchers from the ConfigMap source.
func LoadStateStore ¶
func LoadStateStore(path string) (*StateStore, error)
LoadStateStore loads consumed authorization state from disk. Missing files are treated as an empty state.
func (*StateStore) ConsumedCount ¶
func (s *StateStore) ConsumedCount(upstream string) int
ConsumedCount returns the number of consumed authorizations for an upstream.
func (*StateStore) IsConsumed ¶
func (s *StateStore) IsConsumed(upstream, nonce string) bool
IsConsumed reports whether a nonce was already consumed for an upstream.
func (*StateStore) MarkConsumed ¶
func (s *StateStore) MarkConsumed(upstream, nonce string) error
MarkConsumed records a consumed authorization nonce and persists the updated state to disk.
type TokenConfig ¶
type TokenConfig struct {
Address string `json:"address"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
Priority int `json:"priority"`
}
TokenConfig describes a token a signer can pay with.
type UpstreamConfig ¶
type UpstreamConfig struct {
// URL is the upstream base URL (e.g. "https://seller.example.com/services/qwen").
URL string `json:"url"`
// RemoteModel is the concrete upstream model served by this purchased route.
// The LiteLLM paid/* namespace resolves to this model before the sidecar
// forwards the request to the seller.
RemoteModel string `json:"remoteModel,omitempty"`
// Network is the blockchain network identifier (e.g. "base-sepolia").
Network string `json:"network"`
// PayTo is the seller's receiving address.
PayTo string `json:"payTo"`
// Asset is the token contract address (e.g. USDC on Base Sepolia).
Asset string `json:"asset"`
// Price is the amount in atomic units per request (e.g. "1000" for 0.001 USDC).
Price string `json:"price"`
}
UpstreamConfig describes a single x402-gated upstream endpoint.