Skip to content
LogoLogo

Market board

The market board is a public list of open swap offers. A taker finds an offer and a price without already knowing the maker. The board never holds coins or keys: it stores offer links, checks them against the chain, and passes acceptances back to the maker, who still signs last. Design, rules and research: Market board.

For a swap at once, without waiting for a maker, use a dealer pool. The board runs behind the gateway at /market/v1 and needs no account. In the wallets it is the Market tab of the Swap screen; the explorer shows a read-only copy.

Read the board

import { createClient, listMarketPairs, listMarketOffers, listMarketTrades } from 'arrekta-sdk'
 
const gw = createClient({ url: 'http://127.0.0.1:3000' })
const pairs = await listMarketPairs(gw)           // [{ pair: 'GOLD/ARRK', best_bid, best_ask, last_price, … }]
const { base, quote } = pairs[0]
const book = await listMarketOffers(gw, { base: base.asset, quote: quote.asset }) // best price first
const trades = await listMarketTrades(gw, { base: base.asset, quote: quote.asset, limit: 20 })
from arrekta_sdk import Client
 
gw = Client("http://127.0.0.1:3000")
pairs = gw.list_market_pairs()
base, quote = pairs[0]["base"]["asset"], pairs[0]["quote"]["asset"]
book = gw.list_market_offers(base=base, quote=quote)
trades = gw.list_market_trades(base=base, quote=quote, limit=20)

ARRK is always the quote asset. side: "sell" means the maker gives the base asset, and price is quote per base in display units. Amounts are base-unit strings.

List an offer

Any valid arrektaswap: offer can be listed if its transaction is version 2 with valid_until set, it expires within 30 days, and its coins are unspent and not behind another listing. Posting the same offer twice returns the existing listing.

import { postMarketOffer, marketOfferId } from 'arrekta-sdk'
 
const listed = await postMarketOffer(gw, { offer: link }) // { id, state: 'open', … }
listed.id === marketOfferId(offer.pst)                  // the id is derived from the offer itself
from arrekta_sdk import market_offer_id
 
listed = gw.post_market_offer(link)
assert listed["id"] == market_offer_id(offer.pst)

Take an offer

Build and sign your half exactly as for a shared link (Take it, then complete it), then hand the acceptance to the board. The board checks it and the maker collects it.

import { postMarketAcceptance } from 'arrekta-sdk'
await postMarketAcceptance(gw, { id: offer.id, acceptance }) // { txid, offer_id, state: 'pending' }
gw.post_market_acceptance(offer["id"], acceptance)

The maker reads waiting acceptances with listMarketAcceptances / list_market_acceptances, checks each one with swapAcceptanceMatches, signs and broadcasts. The board marks the offer filling, then filled once the transaction is in a block, and records the trade.

Withdraw an offer

Withdrawing needs no transaction. Sign a message with the key of any of the offer's coins. The offer was never signed, so nobody can fill it from a saved copy.

import { cancelMarketOffer, signMarketCancel } from 'arrekta-sdk'
await cancelMarketOffer(gw, { id, ...signMarketCancel(inputKey, id, 'regtest') })
from arrekta_sdk import sign_market_cancel
gw.cancel_market_offer(id, **sign_market_cancel(input_key, id, "regtest"))

In a wallet

@arrekta/wallet-core wraps all of this, and the board URL is the wallet's gateway setting:

// maker: list it and let the wallet complete fills while it is unlocked
const offer = await maker.createSwapOffer({ give: { asset: 'GOLD', amount: '10' }, want: { asset: 'ARRK', amount: '5' }, post: true, autoComplete: true })
 
// taker: browse, then take (the acceptance goes to the maker through the board)
const [pair] = await taker.marketPairs()
const [best] = await taker.marketBook({ base: pair.base.asset, quote: pair.quote.asset })
const take = await taker.prepareMarketTake(best.id) // preview first
await taker.confirmSwapTake(take.id)
 
// maker: picks it up (watch() also does this every 20 s)
await maker.syncBoard() // { completed: [txid] }

cancelSwap(id) releases the coins and withdraws the listing. Errors from the board come back as market-unavailable when the gateway cannot be reached, otherwise with the board's own code (coin-spent, input-in-offer, too-many-offers, offer-closed, …).