Documentation ¶
Index ¶
- Constants
- func DisableLog()
- func OrderToMsgOrder(ord order.Order, mkt string) (*msgjson.BookOrderNote, error)
- func UseLogger(logger slog.Logger)
- type AuthManager
- type BookRouter
- type BookSource
- type Config
- type DataCollector
- type EpochQueue
- type Error
- type FeeFetcher
- type FeeSource
- type Market
- func (m *Market) Base() uint32
- func (m *Market) Book() (epoch int64, buys, sells []*order.LimitOrder)
- func (m *Market) Cancelable(oid order.OrderID) bool
- func (m *Market) CancelableBy(oid order.OrderID, aid account.AccountID) (bool, error)
- func (m *Market) CheckUnfilled(assetID uint32, user account.AccountID) (unbooked []*order.LimitOrder)
- func (m *Market) CoinLocked(asset uint32, coin coinlock.CoinID) bool
- func (m *Market) EpochDuration() uint64
- func (m *Market) FeedDone(feed <-chan *updateSignal) bool
- func (m *Market) MarketBuyBuffer() float64
- func (m *Market) MidGap() uint64
- func (m *Market) OrderFeed() <-chan *updateSignal
- func (m *Market) PurgeBook()
- func (m *Market) Quote() uint32
- func (m *Market) ResumeEpoch(asSoonAs time.Time) (startEpochIdx int64)
- func (m *Market) Run(ctx context.Context)
- func (m *Market) Running() bool
- func (m *Market) ScaleFeeRate(assetID uint32, feeRate uint64) uint64
- func (m *Market) SetFeeRateScale(assetID uint32, scale float64)
- func (m *Market) SetStartEpochIdx(startEpochIdx int64)
- func (m *Market) Start(ctx context.Context, startEpochIdx int64)
- func (m *Market) Status() *Status
- func (m *Market) SubmitOrder(rec *orderRecord) error
- func (m *Market) SubmitOrderAsync(rec *orderRecord) <-chan error
- func (m *Market) Suspend(asSoonAs time.Time, persistBook bool) (finalEpochIdx int64, finalEpochEnd time.Time)
- func (m *Market) SuspendASAP(persistBook bool) (finalEpochIdx int64, finalEpochEnd time.Time)
- func (m *Market) SwapDone(ord order.Order, match *order.Match, fail bool)
- func (m *Market) Unbook(lo *order.LimitOrder) bool
- func (m *Market) UnbookUserOrders(user account.AccountID)
- type MarketTunnel
- type OrderRouter
- type OrderRouterConfig
- type Status
- type Storage
- type SuspendEpoch
- type Swapper
Constants ¶
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") )
const ( // ZeroConfFeeRateThreshold is multiplied by the last known fee rate for an // asset to attain a minimum fee rate acceptable for zero-conf funding // coins. ZeroConfFeeRateThreshold = 0.9 )
Variables ¶
This section is empty.
Functions ¶
func DisableLog ¶
func DisableLog()
DisableLog disables all library log output. Logging output is disabled by default until UseLogger is called.
func OrderToMsgOrder ¶ added in v0.2.0
OrderToMsgOrder converts an order.Order into a *msgjson.BookOrderNote.
Types ¶
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) 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) RecordCompletedOrder(user account.AccountID, oid order.OrderID, t time.Time) UserSettlingLimit(user account.AccountID, mkt *dex.MarketInfo) 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, feeSource FeeSource) *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) Book ¶ added in v0.2.0
func (r *BookRouter) Book(mktName string) (*msgjson.OrderBook, error)
Book creates a copy of the book as a *msgjson.OrderBook.
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 Base() uint32 Quote() uint32 }
BookSource is a source of a market's order book and a feed of updates to the order book and epoch queue.
type Config ¶ added in v0.2.0
type Config struct { MarketInfo *dex.MarketInfo Storage Storage Swapper Swapper AuthManager AuthManager FeeFetcherBase FeeFetcher CoinLockerBase coinlock.CoinLocker FeeFetcherQuote FeeFetcher CoinLockerQuote coinlock.CoinLocker DataCollector DataCollector }
Config is the Market configuration.
type DataCollector ¶ added in v0.2.0
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 FeeFetcher ¶ added in v0.2.0
FeeFetcher is a fee fetcher for fetching fees. Fees are fickle, so fetch fees with FeeFetcher fairly frequently.
type FeeSource ¶ added in v0.2.0
FeeSource is a source of the last reported tx fee rate estimate for an asset.
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 ¶
NewMarket creates a new Market for the provided base and quote assets, with an epoch cycling at given duration in milliseconds.
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 ¶
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 ¶
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 ¶
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 ¶
EpochDuration returns the Market's epoch duration in milliseconds.
func (*Market) FeedDone ¶
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 ¶
MarketBuyBuffer returns the Market's market-buy buffer.
func (*Market) MidGap ¶
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) ResumeEpoch ¶
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 ¶
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 ¶
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) ScaleFeeRate ¶ added in v0.2.0
ScaleFeeRate scales the provided fee rate with the given asset's swap fee rate scale factor, which is 1.0 by default.
func (*Market) SetFeeRateScale ¶ added in v0.2.0
SetFeeRateScale sets a swap fee scale factor for the given asset. SetFeeRateScale should be called regardless of whether the Market is suspended.
func (*Market) SetStartEpochIdx ¶
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 ¶
Start begins order processing with a starting epoch index. See also SetStartEpochIdx and Run. Stop the Market by cancelling the context.
func (*Market) SubmitOrder ¶
SubmitOrder submits a new order for inclusion into the current epoch. This is the synchronous version of SubmitOrderAsync.
func (*Market) SubmitOrderAsync ¶
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 ¶
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) SwapDone ¶ added in v0.2.0
SwapDone registers a match for a given order as being finished. Whether the match was a successful or failed swap is indicated by fail. This is used to (1) register completed orders for cancellation rate purposes, and (2) to unbook at-fault limit orders.
Implementation note: Orders that have failed a swap or were canceled (see processReadyEpoch) are removed from the settling map regardless of any amount still setting for such orders.
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 ¶
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 FeeSource FeeSource }
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 Base, Quote uint32 }
Status describes the operation state of the Market.
type Storage ¶ added in v0.2.0
type Storage interface { db.OrderArchiver LastErr() error Fatal() <-chan struct{} Close() error InsertEpoch(ed *db.EpochResults) error MarketMatches(base, quote uint32) ([]*db.MatchDataWithCoins, error) }
Storage is the DB interface required by Market.
type SuspendEpoch ¶
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) CheckUnspent(ctx context.Context, 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.