Skip to main content

Markets

A market, keyed by its name (town, harbor): vendors with fixed prices whose stock restocks on a schedule and limits what one player buys between restocks; an order book for each item it lists, matched at price-time priority at the resting order's price; and trades between two players, who each offer a bundle and accept the last offers. It holds nothing itself. What a player puts up waits in a hold in their own player hub, and the market moves each fill or accepted trade between the two hubs as steps each answers once, retrying until it hears back. It is not a ledger.

Starter: crate market, node type market (it calls player), keyed by name. Modules: kit.shops.at(key), kit.market.at(key) and kit.trades.at(key) in CrowdyJS and CrowdyPy; shops(), market() and trades() .at(key) in CrowdyCPP.

Endpoints​

EndpointWhoWhat
vendors, book { item }, stateanyoneVendors and their stock; an item's bids and asks; the market
buy { vendor, item, count }, sell { vendor, item, count }playersPays and gets together, in the player's hub: insufficient (gold or stock), limit (per player), full, forbidden (it does not buy them)
order { item, side, price, count }playersHolds a buy's price * count or a sell's items, then matches: insufficient, limit (open orders), not_found (no book)
cancel { order }, ordersthe order's playerWhat it still holds comes back; the caller's open orders
trade { with }, offer { trade, bundle }, accept { trade }, decline { trade }, tradesthe two playersAn offer is held at once and clears both acceptances; both accepting the last offers settles it; finished, not_ready, forbidden

A change that needs a player's hub that did not answer is refused unavailable; the kit's clients send it again with its action_id, and the market asks again by the same reference, so the change runs once (the same action_id with other arguments is refused conflict). A hold the market never heard back about is given back after a minute, and a resend after that is a new change. A market's key is at most 48 bytes.

Topics​

market: snapshots of the vendors' stock, each book's best prices and last trade, open trades and pending steps, at most once a second; changed messages naming the players whose orders or trades moved (what: orders, trades).

Config​

vendors (each id, offers with item, price, stock, per_player, buys_for, and a restock cron), book_items and the book_currency they trade in, orders_max (20 a player), trade_ms (how long a trade stays open), and player_type (player).

CrowdyJS​

const shop = kit.shops.at('town');
await shop.buy('smith', 'sword');
const book = kit.market.at('town');
await book.order({ item: 'ore', side: 'sell', price: 4, count: 10 });
const desk = kit.trades.at('town');
const trade = await desk.open(friendId);
await desk.offer(trade, { currency: { gold: 30 } });
await desk.accept(trade); // settles once the friend accepts the same offers

CrowdyCPP​

kit->shops().at("town").buy("smith", "sword", std::nullopt, [](crowdy::kit::KitReply r) {
if (r.code() == "limit") showSoldOut();
});
kit->market().at("town").order({"ore", "sell", 4, 10}, [](crowdy::kit::KitReply) {});
game.poll();

CrowdyPy​

await kit.shops.at("town").buy("smith", "sword")
await kit.market.at("town").order(item="ore", side="sell", price=4, count=10)
desk = kit.trades.at("town")
trade = await desk.open(friend_id)
await desk.offer(trade, {"currency": {"gold": 30}})