mirror of
https://github.com/luxfi/graph.git
synced 2026-09-24 00:26:07 +00:00
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:
+11
-11
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user