View Source
const (
	ErrMarketNotRunning       = Error("market not running")
	ErrInvalidOrder           = Error("order failed validation")
	ErrInvalidCommitment      = Error("order commitment invalid")
	ErrEpochMissed            = Error("order unexpectedly missed its intended epoch")
	ErrDuplicateOrder         = Error("order already in epoch") // maybe remove since this is ill defined
	ErrQuantityTooHigh        = Error("order quantity exceeds user limit")
	ErrDuplicateCancelOrder   = Error("equivalent cancel order already in epoch")
	ErrTooManyCancelOrders    = Error("too many cancel orders in current epoch")
	ErrCancelNotPermitted     = Error("cancel order account does not match targeted order account")
	ErrTargetNotActive        = Error("target order not active on this market")
	ErrTargetNotCancelable    = Error("targeted order is not a limit order with standing time-in-force")
	ErrSuspendedAccount       = Error("suspended account")
	ErrMalformedOrderResponse = Error("malformed order response")
	ErrInternalServer         = Error("internal server error")


This section is empty.


func DisableLog

func DisableLog()

    DisableLog disables all library log output. Logging output is disabled by default until UseLogger is called.

    func UseLogger

    func UseLogger(logger slog.Logger)

      UseLogger uses a specified Logger to output package logging info.


      type AuthManager

      type AuthManager interface {
      	Route(route string, handler func(account.AccountID, *msgjson.Message) *msgjson.Error)
      	Auth(user account.AccountID, msg, sig []byte) error
      	Suspended(user account.AccountID) (found, suspended bool)
      	Sign(...msgjson.Signable) error
      	Send(account.AccountID, *msgjson.Message) error
      	Request(account.AccountID, *msgjson.Message, func(comms.Link, *msgjson.Message)) error
      	RequestWithTimeout(account.AccountID, *msgjson.Message, func(comms.Link, *msgjson.Message), time.Duration, func()) error
      	PreimageSuccess(user account.AccountID, refTime time.Time, oid order.OrderID)
      	MissedPreimage(user account.AccountID, refTime time.Time, oid order.OrderID)
      	RecordCancel(user account.AccountID, oid, target order.OrderID, t time.Time)
      	UserOrderLimitAdjustment(user account.AccountID, base, quote uint32) int64

        The AuthManager handles client-related actions, including authorization and communications.

        type BookRouter

        type BookRouter struct {
        	// contains filtered or unexported fields

          BookRouter handles order book subscriptions, syncing the market with a group of subscribers, and maintaining an intermediate copy of the orderbook in message payload format for quick, full-book syncing.

          func NewBookRouter

          func NewBookRouter(sources map[string]BookSource) *BookRouter

            NewBookRouter is a constructor for a BookRouter. Routes are registered with comms and a monitoring goroutine is started for each BookSource specified. The input sources is a mapping of market names to sources for order and epoch queue information.

            func (*BookRouter) Run

            func (r *BookRouter) Run(ctx context.Context)

              Run implements dex.Runner, and is blocking.

              type BookSource

              type BookSource interface {
              	Book() (epoch int64, buys []*order.LimitOrder, sells []*order.LimitOrder)
              	OrderFeed() <-chan *updateSignal

                BookSource is a source of a market's order book and a feed of updates to the order book and epoch queue.

                type EpochQueue

                type EpochQueue struct {
                	// Epoch is the epoch index.
                	Epoch    int64
                	Duration int64
                	// Start and End define the time range of the epoch as [Start,End).
                	Start, End time.Time
                	// Orders holds the epoch queue orders in a map for quick lookups.
                	Orders map[order.OrderID]order.Order
                	// UserCancels counts the number of cancel orders per user.
                	UserCancels map[account.AccountID]uint32
                	// CancelTargets maps known targeted order IDs with the CancelOrder
                	CancelTargets map[order.OrderID]*order.CancelOrder

                  EpochQueue represents an epoch order queue. The methods are NOT thread safe by design.

                  func NewEpoch

                  func NewEpoch(idx int64, duration int64) *EpochQueue

                    NewEpoch creates an epoch with the given index and duration in milliseconds.

                    func (*EpochQueue) IncludesTime

                    func (eq *EpochQueue) IncludesTime(t time.Time) bool

                      IncludesTime checks if the given time falls in the epoch.

                      func (*EpochQueue) Insert

                      func (eq *EpochQueue) Insert(ord order.Order)

                        Stores an order in the Order slice, overwriting and pre-existing order.

                        func (*EpochQueue) OrderSlice

                        func (eq *EpochQueue) OrderSlice() []order.Order

                          OrderSlice extracts the orders in a slice. The slice ordering is random.

                          type Error

                          type Error string

                            Error is just a basic error.

                            func (Error) Error

                            func (e Error) Error() string

                              Error satisfies the error interface.

                              type Market

                              type Market struct {
                              	// contains filtered or unexported fields

                                Market is the market manager. It should not be overly involved with details of accounts and authentication. Via the account package it should request account status with new orders, verification of order signatures. The Market should also perform various account package callbacks such as order status updates so that the account package code can keep various data up-to-date, including order status, history, cancellation statistics, etc.

                                The Market performs the following: - Receiving and validating new order data (amounts vs. lot size, check fees,

                                utxos, sufficient market buy buffer, etc.).

                                - Putting incoming orders into the current epoch queue. - Maintain an order book, which must also implement matcher.Booker. - Initiate order matching via matcher.Match(book, currentQueue) - During and/or after matching:

                                * update the book (remove orders, add new standing orders, etc.)
                                * retire/archive the epoch queue
                                * publish the matches (and order book changes?)
                                * initiate swaps for each match (possibly groups of related matches)

                                - Cycle the epochs. - Recording all events with the archivist

                                func NewMarket

                                func NewMarket(mktInfo *dex.MarketInfo, storage db.DEXArchivist, swapper Swapper, authMgr AuthManager,
                                	coinLockerBase, coinLockerQuote coinlock.CoinLocker) (*Market, error)

                                  NewMarket creates a new Market for the provided base and quote assets, with an epoch cycling at given duration in milliseconds.

                                  func (*Market) Base

                                  func (m *Market) Base() uint32

                                    Base is the base asset ID.

                                    func (*Market) Book

                                    func (m *Market) Book() (epoch int64, buys, sells []*order.LimitOrder)

                                      Book retrieves the market's current order book and the current epoch index. If the Market is not yet running or the start epoch has not yet begun, the epoch index will be zero.

                                      func (*Market) Cancelable

                                      func (m *Market) Cancelable(oid order.OrderID) bool

                                        Cancelable determines if an order is a limit order with time-in-force standing that is in either the epoch queue or in the order book.

                                        func (*Market) CancelableBy

                                        func (m *Market) CancelableBy(oid order.OrderID, aid account.AccountID) (bool, error)

                                          CancelableBy determines if an order is cancelable by a certain account. This means: (1) an order in the book or epoch queue, (2) type limit with time-in-force standing (implied for book orders), and (3) AccountID field matching the provided account ID.

                                          func (*Market) CheckUnfilled

                                          func (m *Market) CheckUnfilled(assetID uint32, user account.AccountID) (unbooked []*order.LimitOrder)

                                            CheckUnfilled checks unfilled book orders belonging to a user and funded by coins for a given asset to ensure that their funding coins are not spent. If any of an order's funding coins are spent, the order is unbooked (removed from the in-memory book, revoked in the DB, a cancellation marked against the user, coins unlocked, and orderbook subscribers notified). See Unbook for details.

                                            func (*Market) CoinLocked

                                            func (m *Market) CoinLocked(asset uint32, coin coinlock.CoinID) bool

                                              CoinLocked checks if a coin is locked. The asset is specified since we should not assume that a CoinID for one asset cannot be made to match another asset's CoinID.

                                              func (*Market) EpochDuration

                                              func (m *Market) EpochDuration() uint64

                                                EpochDuration returns the Market's epoch duration in milliseconds.

                                                func (*Market) FeedDone

                                                func (m *Market) FeedDone(feed <-chan *updateSignal) bool

                                                  FeedDone informs the market that the caller is finished receiving from the given channel, which should have been obtained from OrderFeed. If the channel was a registered order feed channel from OrderFeed, it is closed and removed so that no further signals will be send on the channel.

                                                  func (*Market) MarketBuyBuffer

                                                  func (m *Market) MarketBuyBuffer() float64

                                                    MarketBuyBuffer returns the Market's market-buy buffer.

                                                    func (*Market) MidGap

                                                    func (m *Market) MidGap() uint64

                                                      MidGap returns the mid-gap market rate, which is ths rate halfway between the best buy order and the best sell order in the order book. If one side has no orders, the best order rate on other side is returned. If both sides have no orders, 0 is returned.

                                                      func (*Market) OrderFeed

                                                      func (m *Market) OrderFeed() <-chan *updateSignal

                                                        OrderFeed provides a new order book update channel. Channels provided before the market starts and while a market is running are both valid. When the market stops, channels are closed (invalidated), and new channels should be requested if the market starts again.

                                                        func (*Market) PurgeBook

                                                        func (m *Market) PurgeBook()

                                                          PurgeBook flushes all booked orders from the in-memory book and persistent storage. In terms of storage, this means changing orders with status booked to status revoked.

                                                          func (*Market) Quote

                                                          func (m *Market) Quote() uint32

                                                            Quote is the quote asset ID.

                                                            func (*Market) ResumeEpoch

                                                            func (m *Market) ResumeEpoch(asSoonAs time.Time) (startEpochIdx int64)

                                                              ResumeEpoch gets the next available resume epoch index for the currently configured epoch duration for the market and the provided earliest allowable start time. The market must be running, otherwise the zero index is returned.

                                                              func (*Market) Run

                                                              func (m *Market) Run(ctx context.Context)

                                                                Run is the main order processing loop, which takes new orders, notifies book subscribers, and cycles the epochs. The caller should cancel the provided Context to stop the market. The outgoing order feed channels persist after Run returns for possible Market resume, and for Swapper's unbook callback to function using sendToFeeds.

                                                                func (*Market) Running

                                                                func (m *Market) Running() bool

                                                                  Running indicates is the market is accepting new orders. This will return false when suspended, but false does not necessarily mean Run has stopped since a start epoch may be set. Note that this method is of limited use and communicating subsystems shouldn't rely on the result for correct operation since a market could start or stop. Rather, they should infer or be informed of market status rather than rely on this.

                                                                  TODO: Instead of using Running in OrderRouter and DEX, these types should track statuses (known suspend times).

                                                                  func (*Market) SetStartEpochIdx

                                                                  func (m *Market) SetStartEpochIdx(startEpochIdx int64)

                                                                    SetStartEpochIdx sets the starting epoch index. This should generally be called before Run, or Start used to specify the index at the same time.

                                                                    func (*Market) Start

                                                                    func (m *Market) Start(ctx context.Context, startEpochIdx int64)

                                                                      Start begins order processing with a starting epoch index. See also SetStartEpochIdx and Run. Stop the Market by cancelling the context.

                                                                      func (*Market) Status

                                                                      func (m *Market) Status() *Status

                                                                        Status returns the current operating state of the Market.

                                                                        func (*Market) SubmitOrder

                                                                        func (m *Market) SubmitOrder(rec *orderRecord) error

                                                                          SubmitOrder submits a new order for inclusion into the current epoch. This is the synchronous version of SubmitOrderAsync.

                                                                          func (*Market) SubmitOrderAsync

                                                                          func (m *Market) SubmitOrderAsync(rec *orderRecord) <-chan error

                                                                            SubmitOrderAsync submits a new order for inclusion into the current epoch. When submission is completed, an error value will be sent on the channel. This is the asynchronous version of SubmitOrder.

                                                                            func (*Market) Suspend

                                                                            func (m *Market) Suspend(asSoonAs time.Time, persistBook bool) (finalEpochIdx int64, finalEpochEnd time.Time)

                                                                              Suspend requests the market to gracefully suspend epoch cycling as soon as the given time, always allowing the epoch including that time to complete. If the time is before the current epoch, the current epoch will be the last.

                                                                              func (*Market) SuspendASAP

                                                                              func (m *Market) SuspendASAP(persistBook bool) (finalEpochIdx int64, finalEpochEnd time.Time)

                                                                                SuspendASAP suspends requests the market to gracefully suspend epoch cycling as soon as possible, always allowing an active epoch to close. See also Suspend.

                                                                                func (*Market) Unbook

                                                                                func (m *Market) Unbook(lo *order.LimitOrder) bool

                                                                                  Unbook allows the DEX manager to remove a booked order. This does: (1) remove the order from the in-memory book, (2) unlock funding order coins, (3) set the order's status in the DB to "revoked", (4) inform the auth manager of the action for cancellation ratio accounting, and (5) send an 'unbook' notification to subscribers of this market's order book. Note that this presently treats the user as at-fault by counting the revocation in the user's cancellation statistics.

                                                                                  func (*Market) UnbookUserOrders

                                                                                  func (m *Market) UnbookUserOrders(user account.AccountID)

                                                                                    UnbookUserOrders unbooks all orders belonging to a user, unlocks the coins that were used to fund the unbooked orders, changes the orders' statuses to revoked in the DB, and notifies orderbook subscribers.

                                                                                    type MarketTunnel

                                                                                    type MarketTunnel interface {
                                                                                    	// SubmitOrder submits the order to the market for insertion into the epoch
                                                                                    	// queue.
                                                                                    	SubmitOrder(*orderRecord) error
                                                                                    	// MidGap returns the mid-gap market rate, which is ths rate halfway between
                                                                                    	// the best buy order and the best sell order in the order book.
                                                                                    	MidGap() uint64
                                                                                    	// MarketBuyBuffer is a coefficient that when multiplied by the market's lot
                                                                                    	// size specifies the minimum required amount for a market buy order.
                                                                                    	MarketBuyBuffer() float64
                                                                                    	// CoinLocked should return true if the CoinID is currently a funding Coin
                                                                                    	// for an active DEX order. This is required for Coin validation to prevent
                                                                                    	// a user from submitting multiple orders spending the same Coin. This
                                                                                    	// method will likely need to check all orders currently in the epoch queue,
                                                                                    	// the order book, and the swap monitor, since UTXOs will still be unspent
                                                                                    	// according to the asset backends until the client broadcasts their
                                                                                    	// initialization transaction.
                                                                                    	// DRAFT NOTE: This function could also potentially be handled by persistent
                                                                                    	// storage, since active orders and active matches are tracked there.
                                                                                    	CoinLocked(assetID uint32, coinID order.CoinID) bool
                                                                                    	// Cancelable determines whether an order is cancelable. A cancelable order
                                                                                    	// is a limit order with time-in-force standing either in the epoch queue or
                                                                                    	// in the order book.
                                                                                    	Cancelable(order.OrderID) bool
                                                                                    	// Suspend suspends the market as soon as a given time, returning the final
                                                                                    	// epoch index and and time at which that epoch closes.
                                                                                    	Suspend(asSoonAs time.Time, persistBook bool) (finalEpochIdx int64, finalEpochEnd time.Time)
                                                                                    	// Running indicates is the market is accepting new orders. This will return
                                                                                    	// false when suspended, but false does not necessarily mean Run has stopped
                                                                                    	// since a start epoch may be set.
                                                                                    	Running() bool
                                                                                    	// CheckUnfilled checks a user's unfilled book orders that are funded by
                                                                                    	// coins for a given asset to ensure that their funding coins are not spent.
                                                                                    	// If any of an unfilled order's funding coins are spent, the order is
                                                                                    	// unbooked (removed from the in-memory book, revoked in the DB, a
                                                                                    	// cancellation marked against the user, coins unlocked, and orderbook
                                                                                    	// subscribers notified). See Unbook for details.
                                                                                    	CheckUnfilled(assetID uint32, user account.AccountID) (unbooked []*order.LimitOrder)

                                                                                      MarketTunnel is a connection to a market.

                                                                                      type OrderRouter

                                                                                      type OrderRouter struct {
                                                                                      	// contains filtered or unexported fields

                                                                                        OrderRouter handles the 'limit', 'market', and 'cancel' DEX routes. These are authenticated routes used for placing and canceling orders.

                                                                                        func NewOrderRouter

                                                                                        func NewOrderRouter(cfg *OrderRouterConfig) *OrderRouter

                                                                                          NewOrderRouter is a constructor for an OrderRouter.

                                                                                          func (*OrderRouter) Run

                                                                                          func (r *OrderRouter) Run(ctx context.Context)

                                                                                          func (*OrderRouter) Suspend

                                                                                          func (r *OrderRouter) Suspend(asSoonAs time.Time, persistBooks bool) map[string]*SuspendEpoch

                                                                                            Suspend is like SuspendMarket, but for all known markets.

                                                                                            func (*OrderRouter) SuspendMarket

                                                                                            func (r *OrderRouter) SuspendMarket(mktName string, asSoonAs time.Time, persistBooks bool) *SuspendEpoch

                                                                                              SuspendMarket schedules a suspension of a given market, with the option to persist the orders on the book (or purge the book automatically on market shutdown). The scheduled final epoch and suspend time are returned. Note that OrderRouter is a proxy for this request to the ultimate Market. This is done because OrderRouter is the entry point for new orders into the market. TODO: track running, suspended, and scheduled-suspended markets, appropriately blocking order submission according to the schedule rather than just checking Market.Running prior to submitting incoming orders to the Market.

                                                                                              type OrderRouterConfig

                                                                                              type OrderRouterConfig struct {
                                                                                              	AuthManager AuthManager
                                                                                              	Assets      map[uint32]*asset.BackedAsset
                                                                                              	Markets     map[string]MarketTunnel

                                                                                                OrderRouterConfig is the configuration settings for an OrderRouter.

                                                                                                type Status

                                                                                                type Status struct {
                                                                                                	Running       bool
                                                                                                	EpochDuration uint64 // to compute times from epoch inds
                                                                                                	ActiveEpoch   int64
                                                                                                	StartEpoch    int64
                                                                                                	SuspendEpoch  int64
                                                                                                	PersistBook   bool

                                                                                                  Status describes the operation state of the Market.

                                                                                                  type SuspendEpoch

                                                                                                  type SuspendEpoch struct {
                                                                                                  	Idx int64
                                                                                                  	End time.Time

                                                                                                    SuspendEpoch holds the index and end time of final epoch marking the suspension of a market.

                                                                                                    type Swapper

                                                                                                    type Swapper interface {
                                                                                                    	Negotiate(matchSets []*order.MatchSet, offBook map[order.OrderID]bool)
                                                                                                    	CheckUnspent(asset uint32, coinID []byte) error
                                                                                                    	UserSwappingAmt(user account.AccountID, base, quote uint32) (amt, count uint64)
                                                                                                    	ChainsSynced(base, quote uint32) (bool, error)

                                                                                                      Swapper coordinates atomic swaps for one or more matchsets.