Files
maker/coherence_config.go
zeekayandHanzo Dev 1ac4c806b2 Go 1.27.1, and the code it can say more simply
Modules declare go 1.27.1 and the build images follow. go fix applied the
modernizers; omitzero is not applied, since it changes what the JSON says.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 19:23:15 -07:00

193 lines
7.4 KiB
Go

// Copyright (C) 2019-2026, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package maker
import (
"context"
"fmt"
"log/slog"
"maps"
"strconv"
"strings"
"github.com/luxfi/geth/common"
)
// coherence_config.go parses the 12-factor market spec and builds the composite
// reference oracle. The spec is the single source of truth for WHICH markets the
// service pegs and WHAT each tracks. Three orthogonal reference SOURCE forms, one
// per pricing reality:
// - a Kraken query pair -> the live CEX mid (a USD-quoted major)
// - "fixed:<price>" -> a configured constant (a non-Kraken asset)
// - "ratio:<pair>/<denom>" -> Kraken(pair) / denom (a LUX-quoted major)
//
// The ratio form is how a base is quoted in a numeraire the CEX does not list: LETH
// priced in LUX is (ETH/USD)_kraken / (LUX/USD)_denom. It composes the live CEX
// oracle with the LUX/USD reference into the base/LUX mid, so an L*/LUX book pegs to
// the real cross-rate — never a fabricated price, never a second oracle to reconcile.
//
// COHERENCE_MARKETS = "SYMBOL=SOURCE:BASE:QUOTE[:SIZE],..."
//
// SYMBOL the reference symbol, e.g. ETH/USD or LETH/LUX
// SOURCE a Kraken query pair (ETHUSD, XBTUSD), "fixed:<price>", or
// "ratio:<krakenPair>/<denomUSD>"
// BASE the base (priced) ERC-20 address (currency candidate)
// QUOTE the quote (numeraire) ERC-20 address
// SIZE optional resting size per side in base units (default 100000)
//
// Examples:
//
// ETH/USD=ETHUSD:0xEth..:0xUsd..
// LUX/USD=fixed:12.5:0xLux..:0xUsd..
// LETH/LUX=ratio:ETHUSD/12.5:0xLeth..:0xWlux..
// RatioRef is a cross-rate reference: mid(symbol) = Kraken(Pair) / Denom. Pair is
// the CEX-listed leg (e.g. ETHUSD), Denom the numeraire's USD price (e.g. LUX/USD).
type RatioRef struct {
Pair string
Denom float64
}
// ParseCoherenceMarkets parses the market spec into resolved markets plus the three
// reference maps that build the oracle: Kraken pairs, fixed mids, and ratio refs.
func ParseCoherenceMarkets(spec string) ([]CoherenceMarket, map[string]string, map[string]float64, map[string]RatioRef, error) {
spec = strings.TrimSpace(spec)
if spec == "" {
return nil, nil, nil, nil, fmt.Errorf("empty COHERENCE_MARKETS")
}
var markets []CoherenceMarket
krakenPairs := map[string]string{}
fixed := map[string]float64{}
ratio := map[string]RatioRef{}
for entry := range strings.SplitSeq(spec, ",") {
entry = strings.TrimSpace(entry)
if entry == "" {
continue
}
sym, rest, ok := strings.Cut(entry, "=")
if !ok {
return nil, nil, nil, nil, fmt.Errorf("market %q: want SYMBOL=SOURCE:BASE:QUOTE", entry)
}
sym = strings.TrimSpace(sym)
fields := strings.Split(strings.TrimSpace(rest), ":")
var krakenPair string
var fixedPrice float64
var ratioRef RatioRef
switch {
case len(fields) >= 2 && strings.EqualFold(fields[0], "fixed"):
// "fixed:<price>" consumes two colon fields (source + value).
p, err := strconv.ParseFloat(fields[1], 64)
if err != nil || p <= 0 {
return nil, nil, nil, nil, fmt.Errorf("market %s: bad fixed price %q", sym, fields[1])
}
fixedPrice = p
fields = fields[2:]
case len(fields) >= 2 && strings.EqualFold(fields[0], "ratio"):
// "ratio:<pair>/<denom>" consumes two colon fields (source + "pair/denom").
pair, denomStr, ok := strings.Cut(fields[1], "/")
if !ok || strings.TrimSpace(pair) == "" {
return nil, nil, nil, nil, fmt.Errorf("market %s: ratio wants <krakenPair>/<denom>, got %q", sym, fields[1])
}
denom, err := strconv.ParseFloat(strings.TrimSpace(denomStr), 64)
if err != nil || denom <= 0 {
return nil, nil, nil, nil, fmt.Errorf("market %s: bad ratio denom %q", sym, denomStr)
}
ratioRef = RatioRef{Pair: strings.TrimSpace(pair), Denom: denom}
fields = fields[2:]
default:
krakenPair = fields[0]
fields = fields[1:]
}
if len(fields) < 2 {
return nil, nil, nil, nil, fmt.Errorf("market %s: want SOURCE:BASE:QUOTE[:SIZE]", sym)
}
base := common.HexToAddress(strings.TrimSpace(fields[0]))
quote := common.HexToAddress(strings.TrimSpace(fields[1]))
if base == (common.Address{}) || quote == (common.Address{}) {
return nil, nil, nil, nil, fmt.Errorf("market %s: base/quote must be non-zero ERC-20 addresses", sym)
}
var size uint64
if len(fields) >= 3 {
n, err := strconv.ParseUint(strings.TrimSpace(fields[2]), 10, 64)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("market %s: bad size %q", sym, fields[2])
}
size = n
}
markets = append(markets, CoherenceMarket{
Symbol: sym, KrakenPair: krakenPair, Base: base, Quote: quote, Size: size,
})
switch {
case krakenPair != "":
krakenPairs[sym] = krakenPair
case ratioRef.Pair != "":
ratio[sym] = ratioRef
default:
fixed[sym] = fixedPrice
}
}
if len(markets) == 0 {
return nil, nil, nil, nil, fmt.Errorf("no markets parsed from %q", spec)
}
return markets, krakenPairs, fixed, ratio, nil
}
// compositeOracle routes each symbol to its reference: a live Kraken mid for a
// CEX-listed major, a configured fixed mid for a non-Kraken asset, or a cross-rate
// (Kraken(pair)/denom) for a base quoted in a non-USD numeraire (LETH/LUX). It
// satisfies Oracle (GetMidPrice). Composed, not braided — each source prices the
// symbols it knows; an unknown symbol errors (never a fabricated price). The Kraken
// feed serves BOTH the direct majors and the ratio legs from ONE feed: a ratio
// symbol is registered in the feed under its own symbol keyed to the underlying
// pair, then divided by the denom here.
type compositeOracle struct {
kraken MidProvider // live Kraken feed (nil if no Kraken/ratio markets)
fixed map[string]float64 // symbol -> fixed reference mid
ratio map[string]RatioRef // symbol -> (kraken leg, USD denom); mid = Kraken(leg)/denom
}
// NewCoherenceOracle builds the composite reference from the parsed maps. The
// Kraken feed reuses provider_kraken.go (the live-proven public-data oracle) for
// both the direct majors and every ratio leg, so there is exactly ONE live feed.
func NewCoherenceOracle(krakenPairs map[string]string, fixed map[string]float64, ratio map[string]RatioRef, logger *slog.Logger) Oracle {
// One symbol->pair map for the shared feed: direct majors keyed by their own
// symbol, ratio symbols keyed to their underlying Kraken leg.
feedPairs := map[string]string{}
maps.Copy(feedPairs, krakenPairs)
for sym, r := range ratio {
feedPairs[sym] = r.Pair
}
var kf MidProvider
if len(feedPairs) > 0 {
kf = NewKrakenFeed(feedPairs, "kraken", logger)
}
return &compositeOracle{kraken: kf, fixed: fixed, ratio: ratio}
}
// GetMidPrice returns the live reference for a symbol: a ratio cross-rate first
// (its Kraken leg divided by the denom), then a direct Kraken mid, then a fixed mid.
func (o *compositeOracle) GetMidPrice(ctx context.Context, symbol string) (float64, error) {
if r, ok := o.ratio[symbol]; ok {
if o.kraken == nil {
return 0, fmt.Errorf("no kraken feed for ratio %s", symbol)
}
leg, err := o.kraken.GetMidPrice(ctx, symbol)
if err != nil || leg <= 0 {
return 0, fmt.Errorf("ratio leg %s (%s): %v", symbol, r.Pair, err)
}
return leg / r.Denom, nil
}
if o.kraken != nil {
if mid, err := o.kraken.GetMidPrice(ctx, symbol); err == nil && mid > 0 {
return mid, nil
}
}
if p, ok := o.fixed[symbol]; ok && p > 0 {
return p, nil
}
return 0, fmt.Errorf("no reference for %s", symbol)
}