feat: sell and buy services in multiple currencies + networks#655
Open
OisinKyne wants to merge 4 commits into
Open
feat: sell and buy services in multiple currencies + networks#655OisinKyne wants to merge 4 commits into
OisinKyne wants to merge 4 commits into
Conversation
…t making multi-service agents
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem to be solved
I want to sell services in USDC alongside their OBOL offerings, particularly to be able to sell on Base where x402scan is but OBOL is not. This PR allows service offers to list multiple payment options. It also allows people to sell in tokens other than USDC and OBOL though not fully supported best in class on the stack. This grants some flexibility to the stack users who want to sell something in their utility token, but don't want to fork and build an entire parallel Obol Stack to do it. Future updates can make the support for alternative tokens more best in class.
Summary
Lets a single service (agent or HTTP) be sold in multiple currencies/networks at once -- advertised as one x402 endpoint whose 402 response lists every accepted payment, with the buyer choosing which to pay. Previously each
ServiceOffercarried exactly one payment, so the only way to offer "10 OBOL on Ethereum or 1 USDC on Base" was hand-POSTing N separate offers (N URLs, N storefront cards, duplicated registration). Now it's one offer, one URL, one card, one command.The change is end-to-end: create -> CRD -> verifier -> catalog -> storefront -> buyer selection.
What changed
Schema (backward-compatible)
ServiceOffer.spec.payments[](canonical multi-payment) added alongside the existing singularspec.payment(kept as the always-set primary =payments[0]).EffectivePayments()normalizes both, so every existing CR, thestack upresume replay, andstack importkeep working untouched.spec.listing{weight, category}for storefront ordering/grouping.maxTimeoutSeconds(different chains, different block times).Verifier (
internal/x402) -- the protocol layer was already multi-payment (the 402acceptsis an array, andfindMatchingRequirementV1//verify//settleact on whichever requirement the buyer matched). This wires it up:RouteRulecarries all options,matchPaidRouteFullemits onePaymentRequirementsper option, and metrics attribute revenue to the actual chain/asset paid (via a newOnPaymentMatchedhook). No change to settlement correctness.Seller CLI (
obol sell agent|http) -- repeatable--acceptflag:token=<symbol>resolves the registry asset;asset=0x...is an escape hatch for any ERC-20 on a supported chain. Plus--weight/--category. ERC-8004 registration uses the first option's network.sell statuslists all options;sell update --acceptreplaces the set.On-chain asset autofill -- for raw
asset=0x..., missingdecimals/symbol/EIP-712 domain are read best-effort from the chain (decimals()/symbol()/EIP-5267eip712Domain()) andtransferdefaults to Permit2; errors-to-specify if unresolvable. Registry/USDC options make zero RPC calls (no new cluster dependency for the common path).Agent factory (
factory.py) -- mirrors--accept+ autofill (in-pod eRPC),--weight/--category. Sub-agent wallet creation flipped to opt-in, and--pay-tonow defaults to the master Hermes wallet so a sub-agent needn't provision its own signer just to sell. Also closes the handoff pain points:--descriptiondecoupled from--register,statusauto-discovers all offers, skill resolution searches both layouts.Buyer skill (
buy.py) --pay/pay-agent/buyaccept--token/--network/--payment-optionto choose among advertised options (auto-selects when there's one; prompts on a TTY; errors with the list otherwise).--token/--networkalso guard against paying the wrong asset.Catalog + storefront --
/api/services.jsonentries gainpayments[](flat fields still mirror the primary); the storefrontServiceCardrenders all options with a payment selector that re-targets the buy snippets, plus copyable per-service anchor links and weight-based ordering. Thedemospecial-casing was reworked into an ordinarycategory(removing bespokeisDemocode in the catalog, cards, and OpenGraph).Operational note (CRD re-apply required)
The ServiceOffer CRD gains
spec.payments/spec.listing. Strict decoding will reject offers using them until the updated CRD is applied -- re-runobol stack up(recreate the cluster if a running one doesn't refresh). Additive change; no data migration.Testing
EffectivePaymentsfallback, verifier multi-accept + settle-the-chosen-option,--acceptparser (registry/raw/dedup/errors), on-chain autofill merge (injected fetcher), catalogpayments[],sell statusmulti-payment, CRD field presence.factory.pyparser + EIP-5267 decode,buy.py_select_payment(token/network/index/single + error paths) verified fetcher), catalogpayments[],sell statusmulti-payment, CRD field presence.factory.pyparser + EIP-5267 decode,buy.py_select_payment(token/network/index/single + error paths) verified offline.tsc --noEmitclean.go test ./...green; both skillspy_compileclean.Out of scope (intentional)
obol sell inferencestays USDC/OBOL-curated (no arbitrary multi-currency on the standalone gateway).eip155:Nchains beyond the supported set (raw assets are limited to supported chains).obol buy inferenceoption-selection (catalog now exposespayments[]to build on).Tip: Open the Command Palette (Cmd+Shift+P) and run "Shell Command: Install 'code