dex: drop redundant 'core' — pkg/dexcore → pkg/dex (package + dex_ error prefixes)

The package lived at dex/pkg/dexcore (package dexcore) with 'dexcore:' error
prefixes, while every sibling is short (api, client, dchain, consensus) and every
other dex error says 'dex:'. The 'core' qualifier is redundant inside the dex
module. Rename pkg/dexcore → pkg/dex (package dex), unify error prefixes
dexcore: → dex:, update the 5 importers (dexseed, dexfillproof). Tests green
(pkg/dex, 1.398s); dvenue + dexvm plugin rebuild; e2e swap re-proven (seed 12
orders + cross → fill @ 12.5125).
This commit is contained in:
2026-06-25 23:15:44 -07:00
parent 38485adee3
commit ad3129ec7a
24 changed files with 100 additions and 100 deletions
+6 -6
View File
@@ -8,7 +8,7 @@
// real fill with CONSERVED balances.
//
// It needs NO EVM key and NO deployed ERC-20: every asset is a canonical
// dexcore.DeriveAssetID over a REAL on-chain reference (EVM_NATIVE LUX on the
// dex.DeriveAssetID over a REAL on-chain reference (EVM_NATIVE LUX on the
// C-Chain + the real UTXO LUX assetID on the X-Chain). Neither is an
// ascii-of-symbol id, so there is zero synthetic poison — the same structural
// safety as cmd/dexseed.
@@ -37,7 +37,7 @@ import (
"os"
"time"
"github.com/luxfi/dex/pkg/dexcore"
"github.com/luxfi/dex/pkg/dex"
"github.com/luxfi/dex/pkg/zapwire"
"github.com/luxfi/ids"
)
@@ -137,8 +137,8 @@ func getMarkets(base string) getMarketsResp {
return r
}
func mustDerive(networkID uint32, chain ids.ID, kind dexcore.AssetKind, ref []byte, what string) ids.ID {
id, err := dexcore.DeriveAssetID(networkID, chain, kind, ref)
func mustDerive(networkID uint32, chain ids.ID, kind dex.AssetKind, ref []byte, what string) ids.ID {
id, err := dex.DeriveAssetID(networkID, chain, kind, ref)
if err != nil {
die("derive %s: %v", what, err)
}
@@ -175,8 +175,8 @@ func main() {
}
// REAL assets, canonical derivation, zero synthetic content.
baseID := mustDerive(uint32(*networkID), cChain, dexcore.AssetKindEVMNative, dexcore.EVMNativeMarker, "base EVM_NATIVE LUX")
quoteID := mustDerive(uint32(*networkID), xChain, dexcore.AssetKindUTXO, luxAsset[:], "quote UTXO LUX")
baseID := mustDerive(uint32(*networkID), cChain, dex.AssetKindEVMNative, dex.EVMNativeMarker, "base EVM_NATIVE LUX")
quoteID := mustDerive(uint32(*networkID), xChain, dex.AssetKindUTXO, luxAsset[:], "quote UTXO LUX")
if baseID == quoteID {
die("base==quote (not a market)")
}
+2 -2
View File
@@ -4,12 +4,12 @@
// Command dexseed is the CANONICAL real-market seeder for the live native D-Chain
// DEX. It seeds REAL markets onto the in-luxd CLOB ingestion seam (POST
// /ext/bc/D/dex/dex_* with FROZEN zapwire frames) using REAL, consensus-native asset
// identities — dexcore.DeriveAssetID(networkID, C-chainID, kind, canonicalRef) — for
// identities — dex.DeriveAssetID(networkID, C-chainID, kind, canonicalRef) — for
// every side of every market.
//
// SAFE AGAINST A SHARED CLUSTER BY CONSTRUCTION (no guard, no loopback fence): dexseed
// NEVER builds an ascii-of-symbol id. Every asset it opens is admitted ONLY if its
// (kind, ref) derives a well-formed canonical AssetID via dexcore.DeriveAssetID — the
// (kind, ref) derives a well-formed canonical AssetID via dex.DeriveAssetID — the
// SAME identity the chain's resolver computes — and the chain's own permissionless
// resolver additionally proves each side is backed by live on-chain code (the
// EXTCODESIZE reality gate) before binding the market. A synthetic/malformed ref is
+10 -10
View File
@@ -7,7 +7,7 @@ import (
"encoding/hex"
"testing"
"github.com/luxfi/dex/pkg/dexcore"
"github.com/luxfi/dex/pkg/dex"
"github.com/luxfi/dex/pkg/zapwire"
"github.com/luxfi/ids"
)
@@ -16,7 +16,7 @@ import (
// ids under. It is the same id the live devnet validators serve.
const devnetCChain = "Bm8X7THQtS2txLrQWTDXN8a4JDuhP4KGybUE754LLSiVFLQ7v"
// Golden AssetID vectors — pinned bytes the dexcore identity primitive MUST produce for
// Golden AssetID vectors — pinned bytes the dex identity primitive MUST produce for
// fixed (networkID, C-chainID, kind, ref) tuples. These are NOT recomputed from the
// same call under test; they are CONSTANTS frozen here, so a drift in DeriveAssetID's
// fold (domain tag, length-prefix discipline, field order) breaks this test. The C-Chain
@@ -51,7 +51,7 @@ func erc20Addr(lastByte byte) []byte {
func TestGoldenAssetIDs(t *testing.T) {
cid := mustCChain(t)
natID, err := dexcore.DeriveAssetID(3, cid, dexcore.AssetKindEVMNative, dexcore.EVMNativeMarker)
natID, err := dex.DeriveAssetID(3, cid, dex.AssetKindEVMNative, dex.EVMNativeMarker)
if err != nil {
t.Fatalf("derive native id: %v", err)
}
@@ -59,7 +59,7 @@ func TestGoldenAssetIDs(t *testing.T) {
t.Fatalf("native(3) AssetID drift:\n got %s\n want %s", got, goldenNativeID3)
}
ercID, err := dexcore.DeriveAssetID(3, cid, dexcore.AssetKindERC20, erc20Addr(0x01))
ercID, err := dex.DeriveAssetID(3, cid, dex.AssetKindERC20, erc20Addr(0x01))
if err != nil {
t.Fatalf("derive erc20 id: %v", err)
}
@@ -110,7 +110,7 @@ func TestResolveID_RejectsSynthetic(t *testing.T) {
// THE BRICKING FORM: an ascii-of-symbol "address" — "LUX" left in a byte
// slice that is NOT a 20-byte token address.
name: "ascii-ticker-LUX (not 20 bytes)",
spec: assetSpec{Kind: dexcore.AssetKindERC20, Ref: []byte("LUX")},
spec: assetSpec{Kind: dex.AssetKindERC20, Ref: []byte("LUX")},
},
{
// An ascii ticker right-shaped to 20 bytes is still NOT a real token, but the
@@ -119,19 +119,19 @@ func TestResolveID_RejectsSynthetic(t *testing.T) {
// here and rely on the chain's EXTCODESIZE gate for shaped-but-fake. The
// all-zero ERC-20 address (== the native marker) MUST be refused locally.
name: "ERC20 zero address (== native marker, not a token)",
spec: assetSpec{Kind: dexcore.AssetKindERC20, Ref: make([]byte, 20)},
spec: assetSpec{Kind: dex.AssetKindERC20, Ref: make([]byte, 20)},
},
{
name: "ERC20 wrong length (33 bytes)",
spec: assetSpec{Kind: dexcore.AssetKindERC20, Ref: make([]byte, 33)},
spec: assetSpec{Kind: dex.AssetKindERC20, Ref: make([]byte, 33)},
},
{
name: "invalid kind (0)",
spec: assetSpec{Kind: dexcore.AssetKindInvalid, Ref: erc20Addr(0x01)},
spec: assetSpec{Kind: dex.AssetKindInvalid, Ref: erc20Addr(0x01)},
},
{
name: "EVM_NATIVE with a non-marker ref",
spec: assetSpec{Kind: dexcore.AssetKindEVMNative, Ref: erc20Addr(0x01)},
spec: assetSpec{Kind: dex.AssetKindEVMNative, Ref: erc20Addr(0x01)},
},
}
for _, tc := range cases {
@@ -295,7 +295,7 @@ func TestRealMarketFrames(t *testing.T) {
// synthetic quote ref — no frames are returned for a market the chain would refuse.
func TestRealMarketFrames_RejectsSyntheticQuote(t *testing.T) {
cid := mustCChain(t)
syntheticQuote := assetSpec{Kind: dexcore.AssetKindERC20, Ref: []byte("LUSD")} // ascii ticker, not 20 bytes
syntheticQuote := assetSpec{Kind: dex.AssetKindERC20, Ref: []byte("LUSD")} // ascii ticker, not 20 bytes
open, dep, place, _, err := realMarketFrames(3, cid, nativeSpec(), syntheticQuote, "maker", 1.0, 1.0, 3, [32]byte{})
if err == nil {
t.Fatal("realMarketFrames MUST reject a synthetic (ascii-ticker) quote ref")
+8 -8
View File
@@ -7,7 +7,7 @@ import (
"crypto/sha256"
"fmt"
"github.com/luxfi/dex/pkg/dexcore"
"github.com/luxfi/dex/pkg/dex"
"github.com/luxfi/dex/pkg/zapwire"
"github.com/luxfi/ids"
)
@@ -18,7 +18,7 @@ import (
// main.go is the thin transport that POSTs these frames over HTTP.
//
// THE IDENTITY RULE this file enforces (and the reason this seeder is SAFE against a
// shared cluster, with no guard needed): every asset handle is the dexcore CANONICAL
// shared cluster, with no guard needed): every asset handle is the dex CANONICAL
// AssetID — DeriveAssetID(networkID, C-chainID, kind, canonicalRef) — the SAME
// consensus-native identity primitive the on-chain resolver computes. It is NEVER an
// ascii-of-symbol id (the synthetic form, e.g. 0x4c5558 = "LUX", that bricked the
@@ -38,14 +38,14 @@ var poolIDDomain = []byte("lux:dex:dexseed:poolid:v1")
// AssetID the chain keys by. It deliberately carries NO ticker/symbol — identity is
// the derived id, never a string.
type assetSpec struct {
Kind dexcore.AssetKind
Kind dex.AssetKind
Ref []byte
}
// nativeSpec is the canonical EVM_NATIVE (LUX) asset spec: the EVM zero-address
// native marker. Its derived id is the chain's own coin under the bound network.
func nativeSpec() assetSpec {
return assetSpec{Kind: dexcore.AssetKindEVMNative, Ref: dexcore.EVMNativeMarker}
return assetSpec{Kind: dex.AssetKindEVMNative, Ref: dex.EVMNativeMarker}
}
// erc20Spec builds an ERC20 asset spec from a 20-byte token contract address. The
@@ -53,18 +53,18 @@ func nativeSpec() assetSpec {
func erc20Spec(addr []byte) assetSpec {
ref := make([]byte, len(addr))
copy(ref, addr)
return assetSpec{Kind: dexcore.AssetKindERC20, Ref: ref}
return assetSpec{Kind: dex.AssetKindERC20, Ref: ref}
}
// resolveID derives the canonical, consensus-native 32-byte AssetID for this spec
// under (networkID, cChainID). It is the SINGLE admission gate in the seeder: a
// synthetic/malformed ref (wrong length, zero ERC-20 address, non-marker native ref,
// invalid kind) is REFUSED here by dexcore.DeriveAssetID — so no frame is ever built,
// invalid kind) is REFUSED here by dex.DeriveAssetID — so no frame is ever built,
// let alone sent, for an asset that is not a well-formed real on-chain identity. This
// is byte-identical to what the chain's resolver derives, so a market this seeder
// opens binds the SAME id the chain admits.
func (a assetSpec) resolveID(networkID uint32, cChainID ids.ID) (ids.ID, error) {
id, err := dexcore.DeriveAssetID(networkID, cChainID, a.Kind, a.Ref)
id, err := dex.DeriveAssetID(networkID, cChainID, a.Kind, a.Ref)
if err != nil {
return ids.Empty, fmt.Errorf("resolve %s asset id: %w", a.Kind, err)
}
@@ -93,7 +93,7 @@ func poolIDFor(baseID, quoteID ids.ID) [32]byte {
// writeLenPrefixed writes an 8-byte big-endian length followed by b, so the fold is
// injective (no two distinct field tuples share a preimage) — the same discipline as
// dexcore's assetFolder.
// dex's assetFolder.
func writeLenPrefixed(h interface{ Write([]byte) (int, error) }, b []byte) {
var lp [8]byte
lp[0] = byte(len(b) >> 56)
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"crypto/sha256"
@@ -15,7 +15,7 @@ import (
// assetid.go is the CANONICAL real-asset identity primitive for the whole DEX value
// path. It is the SINGLE place that derives the 32-byte AssetID of a real on-chain
// asset from WHERE IT REALLY LIVES — (networkID, sourceChainID, assetKind,
// canonicalRef). It lives in dexcore (the lowest shared leaf) so BOTH the 0x9999
// canonicalRef). It lives in dex (the lowest shared leaf) so BOTH the 0x9999
// cEVM value path (precompile/dex) AND the chains/dexvm registry compute the SAME
// id from the same fields: a registered AssetID and a swap-derived AssetID are
// directly comparable, by construction, with no risk of two derivations drifting.
@@ -36,7 +36,7 @@ import (
// UTXO assetID can never collide). The result is an ids.ID — the SAME identity space
// the on-chain atomic objects already use — never a string ticker.
//
// This is the consensus-native asset identity. The dexcore ledger's AssetID alias is
// This is the consensus-native asset identity. The dex ledger's AssetID alias is
// [32]byte and an ids.ID is [32]byte, so DeriveAssetID's output is directly usable as
// a ledger AssetID via AssetIDFromID.
@@ -89,11 +89,11 @@ var EVMNativeMarker = make([]byte, 20)
var (
// ErrInvalidKind is returned when an asset's kind is not one of the three.
ErrInvalidKind = errors.New("dexcore: asset kind is not EVM_NATIVE, ERC20 or UTXO")
ErrInvalidKind = errors.New("dex: asset kind is not EVM_NATIVE, ERC20 or UTXO")
// ErrBadRef is returned when a canonical reference does not match its kind's shape.
ErrBadRef = errors.New("dexcore: canonical reference does not match asset kind")
ErrBadRef = errors.New("dex: canonical reference does not match asset kind")
// ErrEmptyChainID is returned when the source chain of an asset is the empty id.
ErrEmptyChainID = errors.New("dexcore: asset source chain id is empty")
ErrEmptyChainID = errors.New("dex: asset source chain id is empty")
)
// domAssetV1 is the domain-separation tag folded as the FIRST field of every AssetID
@@ -163,7 +163,7 @@ func DeriveAssetID(networkID uint32, sourceChainID ids.ID, kind AssetKind, ref [
return f.sum(), nil
}
// AssetIDFromID adapts a consensus-native ids.ID to the dexcore ledger AssetID alias
// AssetIDFromID adapts a consensus-native ids.ID to the dex ledger AssetID alias
// ([32]byte). They are the same underlying array; this is the one named conversion so
// the value path keys the ledger by the canonical derived id, never an ad-hoc handle.
func AssetIDFromID(id ids.ID) AssetID { return AssetID(id) }
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"encoding/hex"
@@ -11,9 +11,9 @@ import (
)
// assetid_test.go pins the CANONICAL asset identity. The decisive property is CROSS-HOME
// PARITY: dexcore.DeriveAssetID must produce the byte-identical id that
// PARITY: dex.DeriveAssetID must produce the byte-identical id that
// chains/dexvm/registry.DeriveAssetID produces for the same inputs, because the value
// path (precompile/dex, over dexcore) and the admission authority (the registry) must
// path (precompile/dex, over dex) and the admission authority (the registry) must
// name the SAME asset by the SAME 32-byte id — a registered AssetID and a swap-derived
// AssetID are compared directly. The expected vectors below were emitted by the chains
// registry's own DeriveAssetID; if either implementation's preimage discipline drifts,
@@ -30,10 +30,10 @@ func chainAllOnes() ids.ID {
}
// AssetIDGoldenVectors is the CANONICAL cross-home golden KAT (MED-1): the fixed
// (networkID, chainID, kind, ref) -> 32-byte AssetID mapping that BOTH dexcore and
// (networkID, chainID, kind, ref) -> 32-byte AssetID mapping that BOTH dex and
// chains/dexvm/registry MUST reproduce byte-for-byte. The byte-identity these vectors
// pin is the foundation of the resolve<->register equivalence the value path depends on:
// a swap-derived AssetID (dexcore, via the precompile resolver) and a registered AssetID
// a swap-derived AssetID (dex, via the precompile resolver) and a registered AssetID
// (the chains registry) name the SAME asset by the SAME id, by construction. The mirror
// test in chains/dexvm/registry asserts these EXACT bytes, so a drift in either home's
// preimage discipline fails CI in both places, never silently in prod.
+3 -3
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"encoding/binary"
@@ -107,7 +107,7 @@ func ReadBookWatermark(db database.KeyValueReader, poolID [32]byte) (uint64, err
return 0, err
}
if len(v) != 8 {
return 0, fmt.Errorf("dexcore: corrupt book watermark len=%d", len(v))
return 0, fmt.Errorf("dex: corrupt book watermark len=%d", len(v))
}
return binary.BigEndian.Uint64(v), nil
}
@@ -150,7 +150,7 @@ func RebuildBook(db database.Iteratee, poolID [32]byte, symbol string) (*lx.Orde
for it.Next() {
row, ok := lx.DecodeRow(it.Value())
if !ok {
return nil, fmt.Errorf("dexcore: corrupt order row under %x (len %d)", poolID[:8], len(it.Value()))
return nil, fmt.Errorf("dex: corrupt order row under %x (len %d)", poolID[:8], len(it.Value()))
}
rows = append(rows, row)
}
+12 -12
View File
@@ -1,11 +1,11 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import "errors"
// The dexcore error set. Each names a fail-closed condition: when settlement
// The dex error set. Each names a fail-closed condition: when settlement
// cannot proceed soundly, it returns one of these and the caller aborts the whole
// transition (the cEVM tx reverts, the dchain block is rejected) — value never
// moves on a degraded path.
@@ -13,11 +13,11 @@ var (
// ErrInsufficientAvailable is returned when a debit/lock exceeds an account's
// available balance. The custody gate maps it to a deterministic per-tx reject
// (the order does not rest, nothing is locked).
ErrInsufficientAvailable = errors.New("dexcore: insufficient available balance")
ErrInsufficientAvailable = errors.New("dex: insufficient available balance")
// ErrInsufficientLocked is returned when an unlock/spend exceeds an account's
// locked balance — it would mint against the ledger. Hard refusal.
ErrInsufficientLocked = errors.New("dexcore: insufficient locked balance")
ErrInsufficientLocked = errors.New("dex: insufficient locked balance")
// ErrMissingSettlementUser is the fail-closed sentinel: a fill against a
// resting maker (or a cancel of a resting order) found NO orderuser: identity
@@ -26,45 +26,45 @@ var (
// only be state corruption — never a normal path. There is NO fallback to the
// matcher's 8-byte handle (that would make compact-handle collisions value-
// bearing — a critical theft bug), so the transition is rejected.
ErrMissingSettlementUser = errors.New("dexcore: resting order has no full settlement identity (orderuser: row missing)")
ErrMissingSettlementUser = errors.New("dex: resting order has no full settlement identity (orderuser: row missing)")
// ErrFillMissingUnits is returned when a fill on the consensus path lacks the
// authoritative integer lane (BaseUnits/QuoteUnits). The matcher sets it on
// every consensus fill; a missing lane is a programming error, refused rather
// than mis-settled from the lossy float view.
ErrFillMissingUnits = errors.New("dexcore: fill missing integer units (BaseUnits/QuoteUnits)")
ErrFillMissingUnits = errors.New("dex: fill missing integer units (BaseUnits/QuoteUnits)")
// ErrFillUnitsOverflow is returned when a fill's integer lane exceeds uint64 —
// the ledger is uint64-unit; an overflowing fill is refused, never truncated.
ErrFillUnitsOverflow = errors.New("dexcore: fill integer units exceed uint64")
ErrFillUnitsOverflow = errors.New("dex: fill integer units exceed uint64")
// ErrDustPriceOrZeroLock is the named "no free executable order" reject: an
// executable order (size>0, and for a limit price>0) whose notional floors to a
// ZERO lock — a sub-tick BUY price (ceil(size*price)==0) or a sub-unit SELL
// size. Such an order would rest/cross while reserving NOTHING. The custody gate
// maps it to a deterministic per-tx reject.
ErrDustPriceOrZeroLock = errors.New("dexcore: executable order locks zero (dust price or sub-unit size)")
ErrDustPriceOrZeroLock = errors.New("dex: executable order locks zero (dust price or sub-unit size)")
// ErrUnknownMarket is returned when a swap/route targets a market with no
// recorded (base,quote) asset binding — value cannot be checked. Fail closed.
ErrUnknownMarket = errors.New("dexcore: market has no asset binding")
ErrUnknownMarket = errors.New("dex: market has no asset binding")
// ErrNoLiquidity is returned by the router when NO configured source can fill
// any of the requested amount (neither the CLOB nor an AMM crosses). A swap
// that fills nothing returns this so the caller reverts rather than locking the
// taker's input against a zero fill.
ErrNoLiquidity = errors.New("dexcore: no liquidity across any source for this swap")
ErrNoLiquidity = errors.New("dex: no liquidity across any source for this swap")
// ErrPriceLimit is the taker-authenticated MEV floor breach: the realized fill
// price violated the taker's own worst-acceptable price (derived from the V4
// SqrtPriceLimitX96). The whole swap reverts — a sandwiching counterparty/
// proposer cannot force a fill outside the taker's limit.
ErrPriceLimit = errors.New("dexcore: realized price violates taker price limit")
ErrPriceLimit = errors.New("dex: realized price violates taker price limit")
// ErrBuyRequiresLimit is returned for an exact-input BUY (taker spends quote) with
// no price limit. A bare market buy off a quote budget has unbounded slippage — a
// sandwicher could price the taker arbitrarily badly — so a BUY MUST carry the V4
// SqrtPriceLimitX96-derived ceiling. A SELL needs no limit (its base input is
// exact and a market sell's worst case is bounded by the book).
ErrBuyRequiresLimit = errors.New("dexcore: exact-input BUY requires a price limit (unbounded-slippage market buy refused)")
ErrBuyRequiresLimit = errors.New("dex: exact-input BUY requires a price limit (unbounded-slippage market buy refused)")
)
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"math/big"
@@ -109,7 +109,7 @@ func ExecuteSwap(db Store, router *Router, req SwapRequest) (*SwapResult, error)
// SignedLegs returns the swap's signed (inAsset, -in) and (outAsset, +out) so the
// caller maps them to the V4 BalanceDelta legs by matching the asset id to
// currency0 (base) / currency1 (quote). This keeps dexcore free of the V4 currency-
// currency0 (base) / currency1 (quote). This keeps dex free of the V4 currency-
// ordering convention while giving the caller exactly the signed magnitudes.
func (r *SwapResult) SignedLegs() (inAsset AssetID, inNeg *big.Int, outAsset AssetID, outPos *big.Int) {
return r.AmountInAsset, new(big.Int).Neg(new(big.Int).SetUint64(r.AmountIn)),
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"testing"
@@ -11,10 +11,10 @@ import (
"github.com/luxfi/dex/pkg/lx"
)
// harness_test.go is the dexcore proof harness. It uses REAL asset ids — the
// harness_test.go is the dex proof harness. It uses REAL asset ids — the
// left-pad of a real 20-byte EVM token address (the production assetID), NEVER a
// synthetic ASCII-ticker handle. The Store is an in-memory database that satisfies
// dexcore.Store exactly as the precompile's 0x9999-storage adapter and dchain's
// dex.Store exactly as the precompile's 0x9999-storage adapter and dchain's
// versiondb overlay do, so the logic proven here is the identical logic both homes
// run.
@@ -60,7 +60,7 @@ func market(tag byte) [32]byte {
return p
}
// newStore returns a fresh in-memory dexcore.Store.
// newStore returns a fresh in-memory dex.Store.
func newStore() Store { return memdb.New() }
// seedMarket opens a market binding (base, quote) and returns its pool id.
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"math/big"
@@ -18,7 +18,7 @@ import (
// EVM-storage namespace. Either way the D writes are part of the SAME state the
// block commits.
// - The C surface (the EVM-adapter): the taker's EVM token/native balance and the
// 0x9999 vault pots. These cannot be written by dexcore directly (dexcore is
// 0x9999 vault pots. These cannot be written by dex directly (dex is
// store-agnostic and knows nothing of EVM balances), so the router RECORDS the
// required C-side deltas here, and the CALLER (the precompile's 0x9999 swap Run)
// applies them to the EVM StateDB in the SAME Run.
@@ -33,7 +33,7 @@ import (
// simply does not exist here.
// CDeltaKind tags a recorded C-surface value move so the caller applies it to the
// correct EVM account/pot. dexcore stays store-agnostic by naming WHAT must move,
// correct EVM account/pot. dex stays store-agnostic by naming WHAT must move,
// not HOW (which is EVM-specific and lives in the precompile).
type CDeltaKind uint8
@@ -65,7 +65,7 @@ type CDelta struct {
//
// The journal is APPEND-ONLY during routing and CONSUMED once at the end of the
// swap Run. It holds no Store reference and performs no I/O — it is a plain value
// the router fills and the caller drains, which keeps dexcore free of any EVM
// the router fills and the caller drains, which keeps dex free of any EVM
// dependency and makes the C/D split auditable in one place.
type Journal struct {
cDeltas []CDelta
@@ -75,7 +75,7 @@ type Journal struct {
func NewJournal() *Journal { return &Journal{} }
// recordC appends a C-surface delta. amount must be non-negative; a zero amount is
// dropped (no move). Internal to dexcore — sources call the typed helpers below.
// dropped (no move). Internal to dex — sources call the typed helpers below.
func (j *Journal) recordC(kind CDeltaKind, asset AssetID, amount *big.Int) {
if amount == nil || amount.Sign() <= 0 {
return
+10 -10
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package dexcore is the SHARED, caller-agnostic deterministic core of the Lux
// Package dex is the SHARED, caller-agnostic deterministic core of the Lux
// DEX: the CLOB custody ledger, the integer-exact settlement of matcher fills,
// the fail-closed maker-identity discipline, the smart-order-router across
// on-chain liquidity sources, and the execution root. It is a pure function of
@@ -26,7 +26,7 @@
// lifecycle, because every unit a fill removes from one account's locked is added
// to exactly one other account's available — checked integer arithmetic, no
// float, no silent overflow.
package dexcore
package dex
import (
"encoding/binary"
@@ -35,10 +35,10 @@ import (
"github.com/luxfi/database"
)
// Store is the key/value surface dexcore reads and writes its state over. It is
// Store is the key/value surface dex reads and writes its state over. It is
// exactly database's read/write/delete + prefix-iteration contract, which both
// homes already satisfy: dchain hands it a versiondb overlay, the precompile
// hands it a 0x9999-EVM-storage adapter. dexcore NEVER assumes a concrete store;
// hands it a 0x9999-EVM-storage adapter. dex NEVER assumes a concrete store;
// the only requirements are the ones named here.
type Store interface {
database.KeyValueReaderWriterDeleter
@@ -129,7 +129,7 @@ func readU64(db database.KeyValueReader, key []byte) (uint64, error) {
return 0, err
}
if len(v) != 8 {
return 0, fmt.Errorf("dexcore: corrupt ledger value len=%d", len(v))
return 0, fmt.Errorf("dex: corrupt ledger value len=%d", len(v))
}
return binary.BigEndian.Uint64(v), nil
}
@@ -168,7 +168,7 @@ func CreditAvailable(db Store, user AccountID, asset AssetID, amount uint64) err
return err
}
if cur+amount < cur {
return fmt.Errorf("dexcore: available credit overflow user=%x asset=%x", user, asset)
return fmt.Errorf("dex: available credit overflow user=%x asset=%x", user, asset)
}
return writeU64(db, balanceLedgerKey(prefixBalance, user, asset), cur+amount)
}
@@ -206,7 +206,7 @@ func LockFromAvailable(db Store, user AccountID, asset AssetID, amount uint64) e
return err
}
if cur+amount < cur {
return fmt.Errorf("dexcore: locked credit overflow user=%x asset=%x", user, asset)
return fmt.Errorf("dex: locked credit overflow user=%x asset=%x", user, asset)
}
return writeU64(db, balanceLedgerKey(prefixLocked, user, asset), cur+amount)
}
@@ -283,7 +283,7 @@ func ReadMarketAssets(db database.KeyValueReader, poolID [32]byte) (base, quote
return base, quote, false, gerr
}
if len(v) != 64 {
return base, quote, false, fmt.Errorf("dexcore: corrupt market assets len=%d", len(v))
return base, quote, false, fmt.Errorf("dex: corrupt market assets len=%d", len(v))
}
copy(base[:], v[0:32])
copy(quote[:], v[32:64])
@@ -326,7 +326,7 @@ func GetOrderLock(db database.KeyValueReader, poolID [32]byte, orderID uint64) (
return asset, 0, false, gerr
}
if len(v) != 40 {
return asset, 0, false, fmt.Errorf("dexcore: corrupt order lock len=%d", len(v))
return asset, 0, false, fmt.Errorf("dex: corrupt order lock len=%d", len(v))
}
copy(asset[:], v[0:32])
return asset, binary.BigEndian.Uint64(v[32:40]), true, nil
@@ -375,7 +375,7 @@ func GetOrderUser(db database.KeyValueReader, poolID [32]byte, orderID uint64) (
return user, false, gerr
}
if len(v) != len(user) {
return user, false, fmt.Errorf("dexcore: corrupt order user len=%d", len(v))
return user, false, fmt.Errorf("dex: corrupt order user len=%d", len(v))
}
copy(user[:], v)
return user, true, nil
@@ -1,13 +1,13 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import "encoding/binary"
// memamm_test.go is an in-Store implementation of AMMPool for the proof suite — the
// exact analog of the precompile's real V2/V3 pool view, but with reserves stored as
// a dexcore Store row instead of cEVM contract storage. dexcore's constant-product
// a dex Store row instead of cEVM contract storage. dex's constant-product
// math + routing run identically over either backend; the test proves the math and
// the journal, the precompile proves the real-pool reserve read. Reserves live
// ENTIRELY in the Store (no package-global state), so two concurrent tests over two
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"errors"
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"fmt"
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"bytes"
@@ -30,9 +30,9 @@ func buildSeededEconomy(t *testing.T, db Store, tag byte) [32]byte {
return pid
}
// snapshotAllRows dumps every (key,value) under the dexcore ledger/book prefixes
// snapshotAllRows dumps every (key,value) under the dex ledger/book prefixes
// into a sorted, canonical byte image — the cross-store equality witness. Two stores
// with the same image hold byte-identical dexcore state.
// with the same image hold byte-identical dex state.
func snapshotAllRows(t *testing.T, db *memdb.Database) []byte {
t.Helper()
var buf bytes.Buffer
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"errors"
@@ -12,11 +12,11 @@ import (
// resolver.go is the ADMISSION port of the value path, in the owner's PERMISSIONLESS
// PUBLIC model: the abstraction the 0x9999 cEVM router depends on to ADMIT a market (or
// swap) over an asset by PROVING its canonical identity — NOT by checking it against an
// allowlist. dexcore (the lowest shared leaf) defines the port; the chains/dexvm
// allowlist. dex (the lowest shared leaf) defines the port; the chains/dexvm
// AssetResolver satisfies it; the EVM plugin boot injects a value into the precompile env.
// This is dependency inversion: the value path names the property it needs ("what is the
// canonical id of this real asset, and is it a well-formed real reference on MY network?")
// and the resolver answers it, WITHOUT dexcore or the precompile importing the resolver
// and the resolver answers it, WITHOUT dex or the precompile importing the resolver
// package (no upward dependency, no cycle).
//
// PERMISSIONLESS + PUBLIC (the protocol rule). An asset trades IFF its canonical identity
@@ -105,14 +105,14 @@ var (
// binding, an explicitly DISABLED asset (a per-asset deny or emergency halt), or a
// synthetic-fake reference. It is NOT "not in an allowlist": a well-formed real
// reference on the bound network always resolves. The whole swap/market-open reverts.
ErrAssetNotResolved = errors.New("dexcore: asset canonical identity does not resolve on this network (malformed, wrong network/chain, disabled, or synthetic)")
ErrAssetNotResolved = errors.New("dex: asset canonical identity does not resolve on this network (malformed, wrong network/chain, disabled, or synthetic)")
// ErrNoAssetResolver is returned when a market-open/swap requires real-asset admission
// but no resolver was injected. FAIL-CLOSED: with the value path live and no resolver
// wired, it refuses rather than admitting a left-padded address as if it were a real,
// network-bound asset. (A resolver is injected at boot on any node that runs the value
// path; a paper/non-value node never reaches the value path.)
ErrNoAssetResolver = errors.New("dexcore: no asset resolver configured (refusing real-asset market/swap; fail-closed)")
ErrNoAssetResolver = errors.New("dex: no asset resolver configured (refusing real-asset market/swap; fail-closed)")
// ErrAssetNotOnChain is the AUTHORITATIVE reality refusal: an asset RESOLVES (its
// canonical identity is well-formed on this network) but is NOT backed by live on-chain
@@ -120,14 +120,14 @@ var (
// right now). This is the live-state form of "synthetic asset": a fabricated reference
// resolves to a well-formed id but carries no code, so it is refused here. The
// swap/market-open reverts BEFORE any debit.
ErrAssetNotOnChain = errors.New("dexcore: asset has no live on-chain backing (token address has no contract code); refusing market/swap")
ErrAssetNotOnChain = errors.New("dex: asset has no live on-chain backing (token address has no contract code); refusing market/swap")
// ErrNoOnChainVerifier is returned when real-asset admission requires the live on-
// chain reality check but no verifier was injected. FAIL-CLOSED: the value path will
// not admit an asset it cannot prove is backed by live code, exactly as it will not
// admit one it cannot resolve. (The precompile injects a code-size-backed verifier on
// every value-path market open; a caller that cannot supply one must not trade value.)
ErrNoOnChainVerifier = errors.New("dexcore: no on-chain asset verifier configured (refusing real-asset market/swap; fail-closed)")
ErrNoOnChainVerifier = errors.New("dex: no on-chain asset verifier configured (refusing real-asset market/swap; fail-closed)")
)
// RequireRealOnChain proves an asset is backed by live on-chain code via v and maps any
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"errors"
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"encoding/binary"
@@ -15,7 +15,7 @@ import (
// binary-Merkle construction the standalone D-Chain uses (vms/xvm execution_root
// lineage), now derived over the in-process state a swap leaves behind. In the
// cEVM home this is subsumed by the EVM block state root (every D write is a 0x9999
// storage write, so it is already committed by the EVM trie). dexcore still exposes
// storage write, so it is already committed by the EVM trie). dex still exposes
// a DEX-scoped root so a test (and a cross-validator diff) can compare the exact
// resulting DEX state independent of the surrounding EVM trie, and so the dchain
// home keeps an explicit DEX execution root.
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"math/big"
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"fmt"
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"github.com/luxfi/dex/pkg/lx"
@@ -12,7 +12,7 @@ import (
// cEVM, so their state is read in-process and the swap executes in-process
// (deterministic constant-product math; every validator replays identically).
//
// dexcore is store-agnostic and knows nothing of EVM contract layout, so the
// dex is store-agnostic and knows nothing of EVM contract layout, so the
// concrete reserve read+write is injected via AMMPool: the precompile implements it
// over the real V2/V3 pool contract storage; a test implements it over an in-Store
// reserve row. The constant-product MATH (lx.ConstantProductOut, 128-bit exact) and
@@ -22,7 +22,7 @@ import (
// contract.
// AMMPool is the precompile-injected view+executor of one V2/V3 pool, keyed by the
// market poolID. dexcore reads reserves to price/route and writes them back after a
// market poolID. dex reads reserves to price/route and writes them back after a
// fill; the implementer maps (base,quote) to the pool's token0/token1 reserves in
// cEVM contract storage. All methods are pure replayable functions of prior state —
// NO live external call.
@@ -31,7 +31,7 @@ type AMMPool interface {
// ok=false when no pool exists for this poolID (the router then skips the AMM).
Reserves(db Store, poolID [32]byte) (baseReserve, quoteReserve uint64, ok bool, err error)
// SetReserves writes the pool's post-fill reserves back. dexcore calls this once
// SetReserves writes the pool's post-fill reserves back. dex calls this once
// after an AMM fill with the new (baseReserve, quoteReserve).
SetReserves(db Store, poolID [32]byte, baseReserve, quoteReserve uint64) error
@@ -120,7 +120,7 @@ func (s *AMMSource) ExecuteSwap(db Store, req SwapRequest, remainingIn uint64, j
if serr := SpendLocked(db, req.TakerUser, inAsset, inUsed); serr != nil {
return Fill{}, 0, 0, serr
}
// Credit the taker's dexcore AVAILABLE with the proceeds — SYMMETRIC with the CLOB
// Credit the taker's dex AVAILABLE with the proceeds — SYMMETRIC with the CLOB
// source (whose SettleFills credits the taker's available). This makes the D-surface
// settlement consistent across BOTH sources: after any swap the taker's available
// holds exactly the proceeds the journal records, so a caller that drains the
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"math/big"
@@ -1,7 +1,7 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dexcore
package dex
import (
"errors"