Bidding in the Open Market
Buy scoped, time-bounded access to a listed tool through a signed bid, the provider's ask, and an acceptance backed by held funds.
On this page
Three signed records turn a published listing into a purchased, time-bounded grant: the buyer's bid, the provider's ask, and the buyer's acceptance against a funds hold. The grant inside the ask is an ordinary capability token, so the kernel admits or refuses every call made with it.
The protocol is the bidding module of the chio-open-market crate. Applications call bid() and accept() in process, pass signed records in memory, and carry them between parties over their own transport. Prices are posted: the provider signs an ask and the buyer accepts it. Auctions and order books are not part of the market.
The provider answers with a capability
SignedAskResponse carries bid_digest, the provider's quoted_price, and token_offer: a capability token minted with the provider's issuer key and bound to the buyer's subject. The provider authors every constraint on that token. Bidding in the open market.
chio.marketplace.*, the funds hold that makes acceptance admissible, and the digests that link each leg to the one before. Wire fields, bonds, and settlement are left out.ContractsEach record digests the one before it, so the acceptance binds the whole trade
A trade starts with a BidRequest, signed by the buyer, naming the listing, a ceiling price, a time window, and the scope it wants. The venue resolves the bid against the listing and its pricing hint and returns a SignedAskResponse: a quoted price plus a token offer, a capability minted with the provider's issuer key and bound to the buyer's subject key. A BidMintContext pairs the resolved listing with the issuer's signing key and the buyer's subject before anything is minted.
Acceptance is a separate signed step. The buyer signs a SignedAcceptedBid against the ask and a VerifiedReservationReceipt, a funds reservation (chio.marketplace.reservation-receipt.v1) whose signature is checked against the expected reservation authority before acceptance proceeds. The acceptance's bid_receipt_id names the receipt the kernel issued when it reserved the funds, so a settlement layer can verify bid, ask, and acceptance as one signed record.
pub fn bid(
request: &SignedBidRequest,
context: BidMintContext<'_>,
) -> Result<SignedAskResponse, BiddingError>;
pub fn accept(
ask: &SignedAskResponse,
reservation: &VerifiedReservationReceipt,
acceptor_keypair: &Keypair,
accepted_at: u64,
) -> Result<SignedAcceptedBid, BiddingError>;The ask carries bid_digest, and the acceptance carries both bid_digest and ask_digest. Verifying a trade means recomputing two digests, which ties three signatures to the same agreement. The ask carries the whole minted CapabilityToken, which is why the acceptance repeats its id, subject, and expiry instead of pointing at a registry.
Read the three record bodies
Each record is a SignedExportEnvelope around the body below, with camelCase keys on the wire. The bodies are defined in bidding.rs; the fee schedule in fee_schedule.rs and penalties in penalty.rs, all in chio-open-market.
// chio.marketplace.bid-request.v1
pub struct BidRequest {
pub schema: String,
pub agent_id: String,
/// Buyer-signed settlement address. Generic bids may omit it, while
/// cognition-market purchase coordinators require a valid EVM address.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub payout_destination: Option<String>,
pub listing_id: String,
pub max_price_per_call: MonetaryAmount,
pub window_seconds: u64,
pub requested_scope: RequestedScope,
pub issued_at: u64,
}
// chio.marketplace.ask-response.v1
pub struct AskResponse {
pub schema: String,
pub listing_id: String,
pub agent_id: String,
/// Canonicalized SHA-256 digest of the originating `BidRequest`.
pub bid_digest: String,
pub quoted_price: MonetaryAmount,
/// Minted capability token bound to the agent subject with the
/// provider's issuer key.
pub token_offer: CapabilityToken,
pub issued_at: u64,
pub expires_at: u64,
}
// chio.marketplace.accepted-bid.v1
pub struct AcceptedBid {
pub schema: String,
pub listing_id: String,
pub agent_id: String,
pub bid_digest: String,
/// Digest of the signed `AskResponse` being accepted.
pub ask_digest: String,
/// The receipt identifier issued by the kernel when the agent's funds
/// were reserved for this ask.
pub bid_receipt_id: String,
pub quoted_price: MonetaryAmount,
pub accepted_at: u64,
pub token_id: String,
pub token_subject: PublicKey,
pub token_expires_at: u64,
}The venue checks each record on its own before it mints a grant
bid() resolves the listing through chio_listing::search and applies the discovered pricing hint. It then runs each check below independently against the bid, the listing, and the hint.
- Signatures. The bid, the resolved listing, and its pricing hint each verify independently.
- Listing status. The listing is
Active; suspended, revoked, retired, and superseded listings are refused. - Freshness. A listing whose freshness window has elapsed is stale and refused, as a discovery search would drop it.
- Pricing expiry. A hint past its own
expires_atis refused, even when the listing is healthy. - Price. The bid's currency matches the advertised pricing, and its ceiling covers the quoted price.
- Scope and provider. The requested scope falls inside the listing's capability scope, and the listing, pricing, and issuer authority are bound to the same provider.
A failed check denies the bid with the BiddingError variant that names it. The venue supplies no fallback price.
The provider authors every constraint on the minted grant
The provider supplies BidMintContext at mint time, and its grant_constraints field is authored on the provider's side. A buyer has no field for requesting, altering, or dropping a constraint, so the constraint set on the token is a statement the provider signed.
On the plain marketplace path a provider may mint with no constraints. The delivery-committed path fixes them: bid_with_finding_purchase overwrites whatever the caller passed with exactly two constraints and turns proof of possession on.
bid_context.grant_constraints = vec![
Constraint::OutputDigestSha256(finding.payload_sha256.clone()),
Constraint::RequireFindingPurchase(Box::new(FindingPurchaseMarkerV1 {
finding_id: finding.finding_id.clone(),
listing_id: admission.listing_id().to_string(),
settlement: FindingSettlementSelector::LocalReversibleHold,
})),
];
bid_context.dpop_required = Some(true);The first constraint pins the grant to the payload digest the seller committed to, so the kernel refuses a delivery whose bytes hash differently. The second names the finding, the listing, and the settlement selector the purchase runs under. Both are minted before the buyer sees the payload.
Read more in Reveal and settlement, which follows a delivery whose bytes and pinned digest disagree.
Bonds back participation, and only an enforced sanction can slash one
An OpenMarketFeeScheduleArtifact is a signed fee schedule scoped to a namespace of listings. It sets a publication_fee, a dispute_fee, a market_participation_fee, and bond_requirements: per-bond-class collateral an operator posts before it acts, each with a slashable flag.
An OpenMarketPenaltyArtifact names one OpenMarketAbuseClass (SpamPublication, FraudulentListing, ReplayPublication, or UnverifiableListingBehavior) and one bond action: HoldBond, SlashBond, or ReverseSlash, which restores a slash later found incorrect. A dispute carries its own bond class, OpenMarketBondClass::Dispute, so contesting a penalty also takes a bond.
The pure function evaluate_open_market_penalty checks nine conditions before any bond moves:
- Each signed record (listing, fee schedule, charter, governance case, activation, penalty) has a valid signature.
- The records agree on the namespace.
- The records agree on operator authority.
- The fee schedule's scope matches: operator ids, actor kinds, admission classes.
- The fee schedule, charter, case, and penalty are unexpired.
- A bond requirement exists for the penalty's bond class.
- The governance case kind fits: a sanction needs an enforced sanction case, a reverse slash an appeal case.
- For a reverse slash, the prior penalty is valid.
- Currency and amounts are coherent.
The venue never slashes on its own authority. A slash requires an enforced Sanction case in chio-governance, the same case kind and enforced state that blocks admission elsewhere in the registry, so charter-scoped authority and case management run before any economic penalty.
Read more in Listing Disputes, which covers how a case reaches enforced and what blocks_admission means.
Discovery, bidding, and coverage live in three crates
Each crate answers a different question about the same listing.
| Crate | Role | Question it answers |
|---|---|---|
chio-listing | Signed registry and pricing hints | What exists, and roughly what it costs |
chio-open-market | Bid and ask venue | What price clears, right now |
chio-market | Liability and insurance | Who covers the economic risk |
Coverage quotes, binding, and claims in chio-market carry no capability authority; only the token from an accepted ask does. Capability Discovery covers the registry the venue reads listings from, and Liability Coverage covers the coverage market that shares part of the name.