fix(indexer): clob_get_* -> dex_get_* to match D-Chain read RPC (red H1)

The D-Chain read surface (luxfi/dex pkg/dchain/read.go:50-53) serves
dex_get_{markets,trades,orders,book}; the CLOB source still called the old
clob_get_* names -> 404 -> empty dex subgraph while real fills matched
on-chain (lux.exchange showed no markets though the chain was correct).

Proven: GOWORK=off go test ./indexer/ -run TestCLOB green.
This commit is contained in:
2026-06-25 15:52:07 -07:00
parent 9e363a5913
commit 61ec197a34
3 changed files with 16 additions and 16 deletions
+11 -11
View File
@@ -4,7 +4,7 @@
// on an EVM chain (C-Chain). That is the cross-chain SETTLEMENT view. The native
// trading engine, however, IS the D-Chain (dexvm): a trade is a consensus state
// transition matched at Block.Verify, not an EVM event. Its committed state is
// served by the read RPC at /ext/bc/D/dex/clob_get_{markets,trades,orders,book}
// served by the read RPC at /ext/bc/D/dex/dex_get_{markets,trades,orders,book}
// (GET, self-describing JSON; see luxfi/dex pkg/dchain/read.go). Nothing on the
// EVM side carries those fills, so without this source the dex subgraph stays
// empty on a native-DEX deployment.
@@ -44,7 +44,7 @@ import (
// hammering the node. Matches the EVM poller's cadence.
const clobPollInterval = 3 * time.Second
// clobTradePage bounds one incremental clob_get_trades response. The trade log is
// clobTradePage bounds one incremental dex_get_trades response. The trade log is
// paged by accepted height via the `since` cursor, so this only caps a single
// catch-up batch — a long history is drained across successive polls.
const clobTradePage = 1000
@@ -54,7 +54,7 @@ const clobTradePage = 1000
// trade cursor and writes Market/Fill/Order entities the dex resolvers read.
type CLOBSource struct {
// base is the D-Chain read-RPC root, e.g.
// http://node:9650/ext/bc/D/dex (clob_get_* are appended as /<method>).
// http://node:9650/ext/bc/D/dex (dex_get_* are appended as /<method>).
// Trailing "/" is trimmed on construction so joins are unambiguous.
base string
store *storage.Store
@@ -196,10 +196,10 @@ type clobOrdersResp struct {
// ── reads ─────────────────────────────────────────────────────────────────────
// fetchMarkets reads clob_get_markets (every market + its book summary + head).
// fetchMarkets reads dex_get_markets (every market + its book summary + head).
func (c *CLOBSource) fetchMarkets(ctx context.Context) ([]clobMarket, clobHead, error) {
var resp clobMarketsResp
if err := c.get(ctx, "clob_get_markets", nil, &resp); err != nil {
if err := c.get(ctx, "dex_get_markets", nil, &resp); err != nil {
return nil, clobHead{}, err
}
return resp.Markets, resp.clobHead, nil
@@ -220,7 +220,7 @@ func (c *CLOBSource) drainTrades(ctx context.Context) error {
"since": strconv.FormatUint(since, 10),
"limit": strconv.Itoa(clobTradePage),
}
if err := c.get(ctx, "clob_get_trades", params, &resp); err != nil {
if err := c.get(ctx, "dex_get_trades", params, &resp); err != nil {
return err
}
if len(resp.Trades) == 0 {
@@ -250,12 +250,12 @@ func (c *CLOBSource) drainTrades(ctx context.Context) error {
}
}
// refreshOrders reads a market's resting book (clob_get_orders) and overwrites the
// refreshOrders reads a market's resting book (dex_get_orders) and overwrites the
// market's Order entities. The order id is namespaced by poolID so two markets'
// order ids (which restart per market) never collide in the shared entity table.
func (c *CLOBSource) refreshOrders(ctx context.Context, poolID string) error {
var resp clobOrdersResp
if err := c.get(ctx, "clob_get_orders", map[string]string{"market": poolID}, &resp); err != nil {
if err := c.get(ctx, "dex_get_orders", map[string]string{"market": poolID}, &resp); err != nil {
return err
}
for i := range resp.Orders {
@@ -306,14 +306,14 @@ func (c *CLOBSource) writeMarket(m *clobMarket) {
// maker/taker order ids give the FE a complete trade-history row.
//
// SCOPE — no per-market attribution here: the 80-byte on-chain trade row carries
// NO poolID (it is the frozen GPU ABI), so clob_get_trades is a GLOBAL,
// NO poolID (it is the frozen GPU ABI), so dex_get_trades is a GLOBAL,
// height-ordered log. Attributing a historical fill to a market by its order id is
// not reliable (a fully-filled order leaves the book, so the current
// clob_get_orders set cannot map every past fill back). Rather than FABRICATE a
// dex_get_orders set cannot map every past fill back). Rather than FABRICATE a
// per-market volume by mis-attributing the global log, the truthful split is:
// Fill entities are the global trade feed (the trade-history view), and every
// PER-MARKET figure the FE shows (open orders, depth, best bid/ask, remaining) is
// taken from clob_get_markets' authoritative per-market book summary in
// taken from dex_get_markets' authoritative per-market book summary in
// writeMarket. This keeps both views correct without inventing data the chain
// does not expose.
func (c *CLOBSource) writeTrade(t *clobTrade) {
+4 -4
View File
@@ -36,9 +36,9 @@ func (s *clobStub) server(t *testing.T) *httptest.Server {
s.hits[method]++
w.Header().Set("Content-Type", "application/json")
switch method {
case "clob_get_markets":
case "dex_get_markets":
fmt.Fprint(w, s.marketsBody)
case "clob_get_trades":
case "dex_get_trades":
var since uint64
fmt.Sscanf(r.URL.Query().Get("since"), "%d", &since)
rows := make([]string, 0, len(s.trades))
@@ -52,7 +52,7 @@ func (s *clobStub) server(t *testing.T) *httptest.Server {
}
fmt.Fprintf(w, `{"height":209,"lastAccepted":"abc","root":"deadbeef","count":%d,"trades":[%s]}`,
len(rows), strings.Join(rows, ","))
case "clob_get_orders":
case "dex_get_orders":
m := r.URL.Query().Get("market")
if body, ok := s.ordersBody[m]; ok {
fmt.Fprint(w, body)
@@ -67,7 +67,7 @@ func (s *clobStub) server(t *testing.T) *httptest.Server {
return srv
}
// liveMarketsBody is the clob_get_markets body captured from lux-devnet luxd-0:
// liveMarketsBody is the dex_get_markets body captured from lux-devnet luxd-0:
// one unbound pool, two bound markets (LUX/LETH, LUX/LUSD) whose hex symbols
// decode to human pair names.
const liveMarketsBody = `{"height":209,"lastAccepted":"YtNQ","root":"dba7","count":3,"markets":[` +
+1 -1
View File
@@ -51,7 +51,7 @@ type Config struct {
StartBlock uint64
// DexRPC, when non-empty, is the native D-Chain (dexvm) CLOB read-RPC root —
// e.g. http://node:9650/ext/bc/D/dex. Setting it runs an ADDITIONAL, orthogonal
// CLOBSource (clob.go) that polls clob_get_{markets,trades,orders} and writes
// CLOBSource (clob.go) that polls dex_get_{markets,trades,orders} and writes
// the same Market/Fill/Order entities the EVM 0x9999 path writes. This is the
// native trading source: a D-Chain trade is a consensus state transition, not an
// EVM log, so it never appears on the EVM RPC. Empty => EVM-only (unchanged).