Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client/{webserver,app}: Update Market Making UI #2491

Merged
merged 6 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions client/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ type LogConfig struct {
LocalLogs bool `long:"loglocal" description:"Use local time zone time stamps in log entries."`
}

// MMConfig encapsulates the settings specific to market making.
type MMConfig struct {
BotConfigPath string `long:"botConfigPath"`
}

// Config is the common application configuration definition. This composite
// struct captures the configuration needed for core and both web and rpc
// servers, as well as some application-level directives.
Expand All @@ -129,6 +134,7 @@ type Config struct {
RPCConfig
WebConfig
LogConfig
MMConfig
// AppData and ConfigPath should be parsed from the command-line,
// as it makes no sense to set these in the config file itself. If no values
// are assigned, defaults will be used.
Expand All @@ -149,7 +155,7 @@ type Config struct {
// Web creates a configuration for the webserver. This is a Config method
// instead of a WebConfig method because Language is an app-level setting used
// by both core and rpcserver.
func (cfg *Config) Web(c *core.Core, log dex.Logger, utc bool) *webserver.Config {
func (cfg *Config) Web(c *core.Core, mm *mm.MarketMaker, log dex.Logger, utc bool) *webserver.Config {
addr := cfg.WebAddr
host, _, err := net.SplitHostPort(addr)
if err == nil && host != "" {
Expand All @@ -168,6 +174,7 @@ func (cfg *Config) Web(c *core.Core, log dex.Logger, utc bool) *webserver.Config

return &webserver.Config{
Core: c,
MarketMaker: mm,
Addr: cfg.WebAddr,
CustomSiteDir: cfg.SiteDir,
Logger: log,
Expand Down Expand Up @@ -201,6 +208,15 @@ func (cfg *Config) Core(log dex.Logger) *core.Config {
}
}

// MarketMakerConfigPath returns the path to the market maker config file.
func (cfg *Config) MarketMakerConfigPath() string {
if cfg.MMConfig.BotConfigPath != "" {
return cfg.MMConfig.BotConfigPath
}
_, _, mmCfgPath := setNet(cfg.AppData, cfg.Net.String())
return mmCfgPath
}

var DefaultConfig = Config{
AppData: defaultApplicationDirectory,
ConfigPath: defaultConfigPath,
Expand Down Expand Up @@ -288,13 +304,13 @@ func ResolveConfig(appData string, cfg *Config) error {
switch {
case cfg.Testnet:
cfg.Net = dex.Testnet
defaultDBPath, defaultLogPath = setNet(appData, "testnet")
defaultDBPath, defaultLogPath, _ = setNet(appData, "testnet")
case cfg.Simnet:
cfg.Net = dex.Simnet
defaultDBPath, defaultLogPath = setNet(appData, "simnet")
defaultDBPath, defaultLogPath, _ = setNet(appData, "simnet")
default:
cfg.Net = dex.Mainnet
defaultDBPath, defaultLogPath = setNet(appData, "mainnet")
defaultDBPath, defaultLogPath, _ = setNet(appData, "mainnet")
}
defaultHost := DefaultHostByNetwork(cfg.Net)

Expand Down Expand Up @@ -335,10 +351,11 @@ func ResolveConfig(appData string, cfg *Config) error {
// files. It returns a suggested path for the database file and a log file. If
// using a file rotator, the directory of the log filepath as parsed by
// filepath.Dir is suitable for use.
func setNet(applicationDirectory, net string) (dbPath, logPath string) {
func setNet(applicationDirectory, net string) (dbPath, logPath, mmCfgPath string) {
netDirectory := filepath.Join(applicationDirectory, net)
logDirectory := filepath.Join(netDirectory, "logs")
logFilename := filepath.Join(logDirectory, "dexc.log")
mmCfgFilename := filepath.Join(netDirectory, "mm_cfg.json")
err := os.MkdirAll(netDirectory, 0700)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create net directory: %v\n", err)
Expand All @@ -349,7 +366,7 @@ func setNet(applicationDirectory, net string) (dbPath, logPath string) {
fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err)
os.Exit(1)
}
return filepath.Join(netDirectory, "dexc.db"), logFilename
return filepath.Join(netDirectory, "dexc.db"), logFilename, mmCfgFilename
}

// DefaultHostByNetwork accepts configured network and returns the network
Expand Down
46 changes: 34 additions & 12 deletions client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,43 @@ var (
defaultWalletBirthdayUnix = 1622668320
defaultWalletBirthday = time.Unix(int64(defaultWalletBirthdayUnix), 0)

multiFundingOpts = []*asset.ConfigOption{
multiFundingOpts = []*asset.OrderOption{
{
Key: multiSplitKey,
DisplayName: "External fee rate estimates",
Description: "Allow split funding transactions that pre-size outputs to " +
"prevent excessive overlock.",
IsBoolean: true,
DefaultValue: true,
ConfigOption: asset.ConfigOption{
Key: multiSplitKey,
DisplayName: "Allow multi split",
Description: "Allow split funding transactions that pre-size outputs to " +
"prevent excessive overlock.",
IsBoolean: true,
DefaultValue: true,
},
},
{
Key: multiSplitBufferKey,
DisplayName: "External fee rate estimates",
Description: "Add an integer percent buffer to split output amounts to " +
"facilitate output reuse",
DefaultValue: true,
ConfigOption: asset.ConfigOption{
Key: multiSplitBufferKey,
DisplayName: "Multi split buffer",
Description: "Add an integer percent buffer to split output amounts to " +
"facilitate output reuse. This is only required for quote assets.",
DefaultValue: 5,
DependsOn: multiSplitKey,
},
QuoteAssetOnly: true,
XYRange: &asset.XYRange{
Start: asset.XYRangePoint{
Label: "0%",
X: 0,
Y: 0,
},
End: asset.XYRangePoint{
Label: "100%",
X: 100,
Y: 100,
},
XUnit: "%",
YUnit: "%",
RoundX: true,
RoundY: true,
},
},
}

Expand Down
46 changes: 34 additions & 12 deletions client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,21 +231,43 @@ var (
IsBirthdayConfig: true,
}}

multiFundingOpts = []*asset.ConfigOption{
multiFundingOpts = []*asset.OrderOption{
{
Key: multiSplitKey,
DisplayName: "External fee rate estimates",
Description: "Allow split funding transactions that pre-size outputs to " +
"prevent excessive overlock.",
IsBoolean: true,
DefaultValue: true,
ConfigOption: asset.ConfigOption{
Key: multiSplitKey,
DisplayName: "Allow multi split",
Description: "Allow split funding transactions that pre-size outputs to " +
"prevent excessive overlock.",
IsBoolean: true,
DefaultValue: true,
},
},
{
Key: multiSplitBufferKey,
DisplayName: "External fee rate estimates",
Description: "Add an integer percent buffer to split output amounts to " +
"facilitate output reuse",
DefaultValue: true,
ConfigOption: asset.ConfigOption{
Key: multiSplitBufferKey,
DisplayName: "Multi split buffer",
Description: "Add an integer percent buffer to split output amounts to " +
"facilitate output reuse. This is only required for quote assets.",
DefaultValue: 5,
DependsOn: multiSplitKey,
},
QuoteAssetOnly: true,
XYRange: &asset.XYRange{
Start: asset.XYRangePoint{
Label: "0%",
X: 0,
Y: 0,
},
End: asset.XYRangePoint{
Label: "100%",
X: 100,
Y: 100,
},
XUnit: "%",
YUnit: "%",
RoundX: true,
RoundY: true,
},
},
}

Expand Down
5 changes: 4 additions & 1 deletion client/asset/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ type WalletDefinition struct {
// users e.g. via dynamically generated GUI forms.
ConfigOpts []*ConfigOption `json:"configopts"`
// MultiFundingOpts are options related to funding multi-trades.
MultiFundingOpts []*ConfigOption `json:"multifundingopts"`
MultiFundingOpts []*OrderOption `json:"multifundingopts"`
// NoAuth indicates that the wallet does not implement the Authenticator
// interface. A better way to check is to use the wallet traits but wallet
// construction is presently required to discern traits.
Expand Down Expand Up @@ -332,6 +332,9 @@ type ConfigOption struct {
// this option N times.
RepeatN int32 `json:"repeatN"`
Required bool `json:"required"`
// DependsOn is the key of another config option that if is set to true,
// this config option will be shown.
DependsOn string `json:"dependsOn"`

// ShowByDefault to show or not options on "hide advanced options".
ShowByDefault bool `json:"showByDefault,omitempty"`
Expand Down
11 changes: 7 additions & 4 deletions client/asset/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ type BooleanConfig struct {
// linear, e.g. y = mx + b. The value submitted to FundOrder/Swap/Redeem should
// specify the x value.
type XYRange struct {
Start XYRangePoint `json:"start"`
End XYRangePoint `json:"end"`
XUnit string `json:"xUnit"`
YUnit string `json:"yUnit"`
Start XYRangePoint `json:"start"`
End XYRangePoint `json:"end"`
XUnit string `json:"xUnit"`
YUnit string `json:"yUnit"`
RoundX bool `json:"roundX"`
RoundY bool `json:"roundY"`
}

// XYRangePoint is a point specifying the start or end of an XYRange.
Expand All @@ -31,6 +33,7 @@ type XYRangePoint struct {
// OrderOption is an available option for an order.
type OrderOption struct {
ConfigOption
QuoteAssetOnly bool `json:"quoteAssetOnly"`

// Fields below are mutually exclusive. The consumer should use nilness to
// determine what type of option to display.
Expand Down
4 changes: 2 additions & 2 deletions client/cmd/dexc-desktop/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func mainCore() error {
if cfg.Experimental {
// TODO: on shutdown, stop market making and wait for trades to be
// canceled.
marketMaker, err = mm.NewMarketMaker(clientCore, logMaker.Logger("MM"))
marketMaker, err = mm.NewMarketMaker(clientCore, cfg.MarketMakerConfigPath(), logMaker.Logger("MM"))
if err != nil {
return fmt.Errorf("error creating market maker: %w", err)
}
Expand All @@ -210,7 +210,7 @@ func mainCore() error {
}()
}

webSrv, err := webserver.New(cfg.Web(clientCore, logMaker.Logger("WEB"), utc))
webSrv, err := webserver.New(cfg.Web(clientCore, marketMaker, logMaker.Logger("WEB"), utc))
if err != nil {
return fmt.Errorf("failed creating web server: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions client/cmd/dexc-desktop/app_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func mainCore() error {
if cfg.Experimental {
// TODO: on shutdown, stop market making and wait for trades to be
// canceled.
marketMaker, err = mm.NewMarketMaker(clientCore, logMaker.Logger("MM"))
marketMaker, err = mm.NewMarketMaker(clientCore, cfg.MarketMakerConfigPath(), logMaker.Logger("MM"))
if err != nil {
return fmt.Errorf("error creating market maker: %w", err)
}
Expand Down Expand Up @@ -270,7 +270,7 @@ func mainCore() error {

// Default to serving the web interface over TLS.
cfg.WebTLS = true
webSrv, err := webserver.New(cfg.Web(clientCore, logMaker.Logger("WEB"), utc))
webSrv, err := webserver.New(cfg.Web(clientCore, marketMaker, logMaker.Logger("WEB"), utc))
if err != nil {
return fmt.Errorf("failed creating web server: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions client/cmd/dexc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func runCore(cfg *app.Config) error {
if cfg.Experimental {
// TODO: on shutdown, stop market making and wait for trades to be
// canceled.
marketMaker, err = mm.NewMarketMaker(clientCore, logMaker.Logger("MM"))
marketMaker, err = mm.NewMarketMaker(clientCore, cfg.MarketMakerConfigPath(), logMaker.Logger("MM"))
if err != nil {
return fmt.Errorf("error creating market maker: %w", err)
}
Expand Down Expand Up @@ -157,7 +157,7 @@ func runCore(cfg *app.Config) error {
}

if !cfg.NoWeb {
webSrv, err := webserver.New(cfg.Web(clientCore, logMaker.Logger("WEB"), utc))
webSrv, err := webserver.New(cfg.Web(clientCore, marketMaker, logMaker.Logger("WEB"), utc))
if err != nil {
return fmt.Errorf("failed creating web server: %w", err)
}
Expand Down
6 changes: 6 additions & 0 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -10320,6 +10320,12 @@ func (c *Core) FiatRateSources() map[string]bool {
return rateSources
}

// FiatConversionRates are the currently cached fiat conversion rates. Must have
// 1 or more fiat rate sources enabled.
func (c *Core) FiatConversionRates() map[uint32]float64 {
return c.fiatConversions()
}

// fiatConversions returns fiat rate for all supported assets that have a
// wallet.
func (c *Core) fiatConversions() map[uint32]float64 {
Expand Down
4 changes: 4 additions & 0 deletions client/core/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ func (c *Core) logNote(n Notification) {
logFun("notify: %v", n)
}

func (c *Core) Broadcast(n Notification) {
c.notify(n)
}

// notify sends a notification to all subscribers. If the notification is of
// sufficient severity, it is stored in the database.
func (c *Core) notify(n Notification) {
Expand Down
20 changes: 13 additions & 7 deletions client/mm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ const (
Amount
)

// MarketMakingConfig is the overall configuration of the market maker.
type MarketMakingConfig struct {
BotConfigs []*BotConfig `json:"botConfigs"`
CexConfigs []*CEXConfig `json:"cexConfigs"`
}

// CEXConfig is a configuration for connecting to a CEX API.
type CEXConfig struct {
// CEXName is the name of the cex.
CEXName string `json:"cexName"`
// Name is the name of the cex.
Name string `json:"name"`
// APIKey is the API key for the CEX.
APIKey string `json:"apiKey"`
// APISecret is the API secret for the CEX.
Expand All @@ -43,16 +49,16 @@ type BotConfig struct {
QuoteBalance uint64 `json:"quoteBalance"`

// Only one of the following configs should be set
MMCfg *MarketMakingConfig `json:"marketMakingConfig,omitempty"`
MMWithCEXCfg *MarketMakingWithCEXConfig `json:"marketMakingWithCEXConfig,omitempty"`
ArbCfg *SimpleArbConfig `json:"arbConfig,omitempty"`
BasicMMConfig *BasicMarketMakingConfig `json:"basicMarketMakingConfig,omitempty"`
SimpleArbConfig *SimpleArbConfig `json:"simpleArbConfig,omitempty"`
MMWithCEXConfig *MarketMakingWithCEXConfig `json:"marketMakingWithCEXConfig,omitempty"`

Disabled bool `json:"disabled"`
}

func (c *BotConfig) requiresPriceOracle() bool {
if c.MMCfg != nil {
return c.MMCfg.OracleWeighting != nil && *c.MMCfg.OracleWeighting > 0
if c.BasicMMConfig != nil {
return c.BasicMMConfig.OracleWeighting != nil && *c.BasicMMConfig.OracleWeighting > 0
}
return false
}
Expand Down
Loading