View Source
const (
	// InitUserLotLimit is the number of lots a new user is permitted to have in
	// active orders and swaps. The market should multiply their lot size by
	// this number to get the limit in units of the base asset. This is
	// potentially a per-market setting instead of an auth constant.
	InitUserTakerLotLimit = 6
	AbsTakerLotLimit      = 150
	BookedLotLimit        = 1200
View Source
const DefaultRequestTimeout = 30 * time.Second

DefaultRequestTimeout is the default timeout for requests to wait for responses from connected users after the request is successfully sent.


View Source
var (
	ErrUserNotConnected = dex.ErrorKind("user not connected")


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 struct {
	// contains filtered or unexported fields

AuthManager handles authentication-related tasks, including validating client signatures, maintaining association between accounts and `comms.Link`s, and signing messages with the DEX's private key. AuthManager manages requests to the 'connect' route.

func NewAuthManager

func NewAuthManager(cfg *Config) *AuthManager

NewAuthManager is the constructor for an AuthManager.

func (*AuthManager) Auth

func (auth *AuthManager) Auth(user account.AccountID, msg, sig []byte) error

Auth validates the signature/message pair with the users public key.

func (*AuthManager) ExpectUsers

func (auth *AuthManager) ExpectUsers(users map[account.AccountID]struct{}, within time.Duration)

ExpectUsers specifies which users are expected to connect within a certain time or have their orders unbooked (revoked). This should be run prior to starting the AuthManager. This is not part of the constructor since it is convenient to obtain this information from the Market's Books, and Market requires the AuthManager. The same information could be pulled from storage, but the Market is the authoritative book. The AuthManager should be started via Run immediately after calling ExpectUsers so the users can connect.

func (*AuthManager) ForgiveMatchFail

func (auth *AuthManager) ForgiveMatchFail(user account.AccountID, mid order.MatchID) (forgiven, unbanned bool, err error)

ForgiveMatchFail forgives a user for a specific match failure, potentially allowing them to resume trading if their score becomes passing.

func (*AuthManager) GraceLimit

func (auth *AuthManager) GraceLimit() int

GraceLimit returns the number of initial orders allowed for a new user before the cancellation rate threshold is enforced.

func (*AuthManager) Inaction

func (auth *AuthManager) Inaction(user account.AccountID, misstep NoActionStep, mmid db.MarketMatchID, matchValue uint64, refTime time.Time, oid order.OrderID)

Inaction registers an inaction violation by the user at the given step. The refTime is time to which the at-fault user's inaction deadline for the match is referenced. e.g. For a swap that failed in TakerSwapCast, refTime would be the maker's redeem time, which is recorded in the DB when the server validates the maker's redemption and informs the taker, and is roughly when the actor was first able to take the missed action. TODO: provide lots instead of value, or convert to lots somehow. But, Swapper has no clue about lot size, and neither does DB!

func (*AuthManager) MissedPreimage

func (auth *AuthManager) MissedPreimage(user account.AccountID, epochEnd time.Time, oid order.OrderID)

MissedPreimage registers a missed preimage violation by the user.

func (*AuthManager) Notify

func (auth *AuthManager) Notify(acctID account.AccountID, msg *msgjson.Message)

Notify sends a message to a client. The message should be a notification. See msgjson.NewNotification.

func (*AuthManager) Penalize

func (auth *AuthManager) Penalize(user account.AccountID, lastRule account.Rule, extraDetails string) error

Penalize closes the user's account, unbooks all of their orders, and notifies them of this action while citing the provided rule that corresponds to their most recent infraction.

func (*AuthManager) PreimageSuccess

func (auth *AuthManager) PreimageSuccess(user account.AccountID, epochEnd time.Time, oid order.OrderID)

PreimageSuccess registers an accepted preimage for the user.

func (*AuthManager) RecordCancel

func (auth *AuthManager) RecordCancel(user account.AccountID, oid, target order.OrderID, t time.Time)

RecordCancel records a user's executed cancel order, including the canceled order ID, and the time when the cancel was executed.

func (*AuthManager) RecordCompletedOrder

func (auth *AuthManager) RecordCompletedOrder(user account.AccountID, oid order.OrderID, t time.Time)

RecordCompletedOrder records a user's completed order, where completed means a swap involving the order was successfully completed and the order is no longer on the books if it ever was.

func (*AuthManager) Request

func (auth *AuthManager) Request(user account.AccountID, msg *msgjson.Message, f func(comms.Link, *msgjson.Message)) error

Request sends the Request-type msgjson.Message to the client identified by the specified account ID. The user must respond within DefaultRequestTimeout of the request. Late responses are not handled.

func (*AuthManager) RequestWithTimeout

func (auth *AuthManager) RequestWithTimeout(user account.AccountID, msg *msgjson.Message, f func(comms.Link, *msgjson.Message),
	expireTimeout time.Duration, expire func()) error

RequestWithTimeout sends the Request-type msgjson.Message to the client identified by the specified account ID. If the user responds within expireTime of the request, the response handler is called, otherwise the expire function is called. If the response handler is called, it is guaranteed that the request Message.ID is equal to the response Message.ID (see handleResponse).

func (*AuthManager) Route

func (auth *AuthManager) Route(route string, handler func(account.AccountID, *msgjson.Message) *msgjson.Error)

Route wraps the comms.Route function, storing the response handler with the associated clientInfo, and sending the message on the current comms.Link for the client.

func (*AuthManager) Run

func (auth *AuthManager) Run(ctx context.Context)

Run runs the AuthManager until the context is canceled. Satisfies the dex.Runner interface.

func (*AuthManager) Send

func (auth *AuthManager) Send(user account.AccountID, msg *msgjson.Message) error

Send sends the non-Request-type msgjson.Message to the client identified by the specified account ID. The message is sent asynchronously, so an error is only generated if the specified user is not connected and authorized, if the message fails marshalling, or if the link is in a failing state. See dex/ws.(*WSLink).Send for more information.

func (*AuthManager) Sign

func (auth *AuthManager) Sign(signables ...msgjson.Signable) error

Sign signs the msgjson.Signables with the DEX private key.

func (*AuthManager) Suspended

func (auth *AuthManager) Suspended(user account.AccountID) (found, suspended bool)

Suspended indicates the the user exists (is presently connected) and is suspended. This does not access the persistent storage.

func (*AuthManager) SwapSuccess

func (auth *AuthManager) SwapSuccess(user account.AccountID, mmid db.MarketMatchID, value uint64, redeemTime time.Time)

SwapSuccess registers the successful completion of a swap by the given user. TODO: provide lots instead of value, or convert to lots somehow. But, Swapper has no clue about lot size, and neither does DB!

func (*AuthManager) Unban

func (auth *AuthManager) Unban(user account.AccountID) error

Unban forgives a user, allowing them to resume trading if their score permits it. This is primarily useful for reversing a manual ban. Use ForgiveMatchFail to forgive specific match negotiation failures.

func (*AuthManager) UserOrderLimitAdjustment

func (auth *AuthManager) UserOrderLimitAdjustment(user account.AccountID, base, quote uint32) int64

UserOrderLimitAdjustment returns a delta in units of the base asset to the user's allowed order quantity. This should be added to the market's base order size limit.

type Config

type Config struct {
	// Storage is an interface for storing and retrieving account-related info.
	Storage Storage
	// Signer is an interface that signs messages. In practice, Signer is
	// satisfied by a secp256k1.PrivateKey.
	Signer Signer
	// RegistrationFee is the DEX registration fee, in atoms DCR
	RegistrationFee uint64
	// FeeConfs is the number of confirmations required on the registration fee
	// before registration can be completed with notifyfee.
	FeeConfs int64
	// FeeChecker is a method for getting the registration fee output info.
	FeeChecker FeeChecker
	// UserUnbooker is a function for unbooking all of a user's orders.
	UserUnbooker func(account.AccountID)
	// MiaUserTimeout is how long after a user disconnects until UserUnbooker is
	// called for that user.
	MiaUserTimeout time.Duration

	CancelThreshold float64
	Anarchy         bool
	FreeCancels     bool
	// BanScore defines the penalty score when an account gets closed.
	BanScore uint32

Config is the configuration settings for the AuthManager, and the only argument to its constructor.

type FeeChecker

type FeeChecker func(coinID []byte) (addr string, val uint64, confs int64, err error)

FeeChecker is a function for retrieving the details for a fee payment. It is satisfied by (dcr.Backend).FeeCoin.

type NoActionStep

type NoActionStep uint8

NoActionStep is the action that the user failed to take. This is used to define valid inputs to the Inaction method.

const (
	SwapSuccess NoActionStep = iota // success included for accounting purposes

func (NoActionStep) String

func (step NoActionStep) String() string

String returns the description of the NoActionStep's corresponding Violation.

func (NoActionStep) Violation

func (step NoActionStep) Violation() Violation

Violation returns the corresponding Violation for the misstep represented by the NoActionStep.

type Signer

type Signer interface {
	Sign(hash []byte) *ecdsa.Signature
	PubKey() *secp256k1.PublicKey

Signer signs messages. It is likely a secp256k1.PrivateKey.

type Storage

type Storage interface {
	// CloseAccount closes the account for violation of the specified rule.
	CloseAccount(account.AccountID, account.Rule) error
	// RestoreAccount opens an account that was closed by CloseAccount.
	RestoreAccount(account.AccountID) error
	ForgiveMatchFail(mid order.MatchID) (bool, error)
	// Account retrieves account info for the specified account ID.
	Account(account.AccountID) (acct *account.Account, paid, open bool)
	UserOrderStatuses(aid account.AccountID, base, quote uint32, oids []order.OrderID) ([]*db.OrderStatus, error)
	ActiveUserOrderStatuses(aid account.AccountID) ([]*db.OrderStatus, error)
	CompletedUserOrders(aid account.AccountID, N int) (oids []order.OrderID, compTimes []int64, err error)
	ExecutedCancelsForUser(aid account.AccountID, N int) (oids, targets []order.OrderID, execTimes []int64, err error)
	CompletedAndAtFaultMatchStats(aid account.AccountID, lastN int) ([]*db.MatchOutcome, error)
	PreimageStats(user account.AccountID, lastN int) ([]*db.PreimageResult, error)
	AllActiveUserMatches(aid account.AccountID) ([]*db.MatchData, error)
	MatchStatuses(aid account.AccountID, base, quote uint32, matchIDs []order.MatchID) ([]*db.MatchStatus, error)
	CreateAccount(*account.Account) (string, error)
	AccountRegAddr(account.AccountID) (string, error)
	PayAccount(account.AccountID, []byte) error

Storage updates and fetches account-related data from what is presumably a database.

type SwapAmounts

type SwapAmounts struct {
	Swapped    int64
	StuckLong  int64
	StuckShort int64
	Spoofed    int64

SwapAmounts breaks down the quantities of completed swaps in four rough categories: successfully swapped (Swapped), failed with counterparty funds locked for the long/maker lock time (StuckLong), failed with counterparty funds locked for the short/taker lock time (StuckShort), and failed to initiate swap following match with no funds locked in contracts (Spoofed).

type Violation

type Violation int32

Violation represents a specific infraction. For example, not broadcasting a swap contract transaction by the deadline as the maker.

const (
	ViolationInvalid Violation = iota - 2

func (Violation) Score

func (v Violation) Score() int32

Score returns the Violation's score, which is a representation of the relative severity of the infraction.

func (Violation) String

func (v Violation) String() string

String returns a description of the Violation.