diff --git a/benchmarks/network-coverage.yml b/benchmarks/network-coverage.yml index 82dedfed..e015946a 100644 --- a/benchmarks/network-coverage.yml +++ b/benchmarks/network-coverage.yml @@ -32,9 +32,9 @@ seo_intro: | abstract: | We benchmark how many networks each major onchain data provider lists in its public "supported networks" endpoint. The harness fetches the - official listing every six hours from six providers (GeckoTerminal, - Codex, Mobula, CoinPaprika, CoinStats and Dune via Sim API), - deduplicates by chain id and counts. Mainnet only, + official listing every six hours from five providers (GeckoTerminal, + Codex, Mobula, CoinPaprika and Dune via Sim API), deduplicates by + chain id and counts. Mainnet only, testnets are excluded because providers list them inconsistently and the comparison is meant to reflect what a builder can integrate against in production. Coverage breadth is one dimension of a data provider's @@ -47,7 +47,6 @@ methodology: - "Codex: GraphQL `getNetworks` query at https://graph.codex.io/graphql with an official API key." - "Mobula: GET /api/1/blockchains with an Authorization API key." - "CoinPaprika: GET /v1/contracts (no auth). Lists platforms supported for contract lookup." - - "CoinStats: GET /wallet/blockchains with X-API-KEY." - "Dune (via Sim API): GET https://api.sim.dune.com/v1/evm/supported-chains (no auth). EVM only, mainnets filtered via the `mainnet` tag." - "Cadence: full refresh every 6 hours." - "Counting: a provider's network is counted once per unique chain id; mainnet only." @@ -82,7 +81,7 @@ faq: # Real metrics exposed by the network-coverage harness: # networks_supported_total{provider="geckoterminal"|"codex"|"mobula"| -# "coinpaprika"|"coinstats"|"dune"} +# "coinpaprika"|"dune"} # -> gauge, the unique-chain count from the latest successful refresh. # network_supported{provider, chain_id, slug, name} -> gauge (1 per # network; useful for diff queries on the site if we add a @@ -141,19 +140,6 @@ providers: sample_size: networks_supported_total{provider="coinpaprika"} series: networks_supported_total{provider="coinpaprika"} - - slug: coinstats - name: CoinStats - tag: Portfolio + market data - formula: "Count of blockchains returned by CoinStats's `/wallet/blockchains` endpoint, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="coinstats"} - p90: networks_supported_total{provider="coinstats"} - p99: networks_supported_total{provider="coinstats"} - mean: networks_supported_total{provider="coinstats"} - success: clamp_max(networks_supported_total{provider="coinstats"} > bool 0, 1) - sample_size: networks_supported_total{provider="coinstats"} - series: networks_supported_total{provider="coinstats"} - - slug: dune name: Dune tag: Onchain analytics + Sim API diff --git a/harnesses/network-coverage/cmd/script/coinstats.go b/harnesses/network-coverage/cmd/script/coinstats.go deleted file mode 100644 index 344c6ee7..00000000 --- a/harnesses/network-coverage/cmd/script/coinstats.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "time" -) - -const coinstatsBlockchainsURL = "https://openapiv1.coinstats.app/wallet/blockchains" - -// CoinStats /wallet/blockchains returns a flat JSON array of: -// {connectionId, name, icon, chain} -// `connectionId` is the slug (e.g. "binancesmartchain"), `chain` is the -// category enum (e.g. "binance_smart"), `name` is the human label. -type coinstatsBlockchain struct { - ConnectionID string `json:"connectionId"` - Name string `json:"name"` - Chain string `json:"chain"` -} - -func fetchCoinStats(cfg *Config) ProviderResult { - res := ProviderResult{Provider: "coinstats"} - if cfg.CoinStatsAPIKey == "" { - res.Err = "missing_api_key" - return res - } - - client := &http.Client{Timeout: 15 * time.Second} - req, _ := http.NewRequest("GET", coinstatsBlockchainsURL, nil) - req.Header.Set("X-API-KEY", cfg.CoinStatsAPIKey) - req.Header.Set("Accept", "application/json") - - resp, err := client.Do(req) - if err != nil { - res.Err = fmt.Sprintf("request_error: %v", err) - return res - } - defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) - - if resp.StatusCode != 200 { - res.Err = fmt.Sprintf("status_%d", resp.StatusCode) - return res - } - - var arr []coinstatsBlockchain - if err := json.Unmarshal(body, &arr); err != nil { - res.Err = fmt.Sprintf("parse_error: %v", err) - return res - } - - for _, b := range arr { - res.Networks = append(res.Networks, Network{ - ChainID: b.Chain, - Slug: b.ConnectionID, - Name: b.Name, - }) - } - return res -} diff --git a/harnesses/network-coverage/cmd/script/config.go b/harnesses/network-coverage/cmd/script/config.go index 83d27ab8..1bbdc805 100644 --- a/harnesses/network-coverage/cmd/script/config.go +++ b/harnesses/network-coverage/cmd/script/config.go @@ -12,7 +12,6 @@ type Config struct { CodexAPIKey string // official Codex Bearer (preferred — no mint, no proxy) CodexSessionCookie string // fallback path: mint JWT from Defined.fi cookie DefinedTokenURL string // optional: pre-minted JWT sidecar - CoinStatsAPIKey string SimDuneAPIKey string // optional — Sim's public endpoint works keyless, but a key avoids rate limits HTTPProxy string RefreshInterval time.Duration @@ -25,7 +24,6 @@ func loadConfig() *Config { CodexAPIKey: os.Getenv("CODEX_API_KEY"), CodexSessionCookie: os.Getenv("DEFINED_SESSION_COOKIE"), DefinedTokenURL: os.Getenv("DEFINED_TOKEN_SERVICE_URL"), - CoinStatsAPIKey: os.Getenv("COINSTATS_API_KEY"), SimDuneAPIKey: os.Getenv("SIM_DUNE_API_KEY"), HTTPProxy: os.Getenv("HTTP_PROXY"), RefreshInterval: 6 * time.Hour, @@ -47,8 +45,8 @@ func loadConfig() *Config { } else if c.CodexSessionCookie != "" { codexAuth = "cookie+mint" } - fmt.Printf("Config: refresh=%v, testnets=%v, mobula_key=%v, codex=%s, coinstats_key=%v, sim_dune_key=%v\n", + fmt.Printf("Config: refresh=%v, testnets=%v, mobula_key=%v, codex=%s, sim_dune_key=%v\n", c.RefreshInterval, c.IncludeTestnets, c.MobulaAPIKey != "", codexAuth, - c.CoinStatsAPIKey != "", c.SimDuneAPIKey != "") + c.SimDuneAPIKey != "") return c } diff --git a/harnesses/network-coverage/cmd/script/main.go b/harnesses/network-coverage/cmd/script/main.go index b8c544c4..cb8f157c 100644 --- a/harnesses/network-coverage/cmd/script/main.go +++ b/harnesses/network-coverage/cmd/script/main.go @@ -73,7 +73,11 @@ func fetchAll(cfg *Config) { {"codex", fetchCodex}, {"coinpaprika", fetchCoinPaprika}, {"dune", fetchSimDune}, - {"coinstats", fetchCoinStats}, + // coinstats dropped 2026-07-16: the free tier exhausts credits + // well below the harness cadence, so /wallet/blockchains returns + // HTTP 406 "Credits limit reached" on every fetch and never + // publishes a networks count. Re-add when a paid key is + // provisioned; the removed adapter is one revert away in git. } var wg sync.WaitGroup