> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dexpaprika.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Coverage checker

> Use this tool to quickly verify whether an asset exists in DexPaprika’s dataset. Enter a contract address, token name, or ticker symbol; we’ll search our coverage and show the closest matches.

export function CoverageResults({externalData}) {
  const [tokens, setTokens] = useState(null);
  const [lastQuery, setLastQuery] = useState("");
  const PRIMARY = "#16A34A";
  const fmtNum = n => n === null || n === undefined || Number.isNaN(n) ? "—" : Number(n).toLocaleString(undefined, {
    maximumFractionDigits: 6
  });
  const trunc = (a = "") => a && a.length > 20 ? `${a.slice(0, 8)}…${a.slice(-6)}` : a || "—";
  useEffect(() => {
    try {
      const raw = sessionStorage.getItem(STORE_LAST);
      if (raw) {
        const {query, tokens} = JSON.parse(raw);
        if (Array.isArray(tokens)) {
          setTokens(tokens);
          setLastQuery(query || "");
        }
      }
    } catch {}
  }, []);
  useEffect(() => {
    if (externalData && Array.isArray(externalData.tokens)) {
      setTokens(externalData.tokens);
      setLastQuery(externalData.query || "");
    }
  }, [externalData]);
  if (tokens === null) return null;
  return <div className="space-y-2">
      {lastQuery && <div className="text-sm opacity-70">
          Results for: <span className="font-medium">{lastQuery}</span>
        </div>}

      {tokens.length === 0 ? <div>No results.</div> : <div style={{
    overflowX: "auto"
  }}>
          <table className="w-full table-auto text-sm">
            <thead>
              <tr>
                <th className="text-left py-2 pr-4">Contract Address</th>
                <th className="text-left py-2 pr-4">Network</th>
                <th className="text-left py-2 pr-4">Ticker</th>
                <th className="text-left py-2 pr-4">Name</th>
                <th className="text-left py-2 pr-4">Price (USD)</th>
                <th className="text-left py-2 pr-4">DexPaprika</th>
                <th className="text-left py-2 pr-4">Latest JSON</th>
              </tr>
            </thead>
            <tbody>
              {tokens.map((t, i) => {
    const network = t.chain || t.network || "";
    const address = t.id || t.address || "";
    const dexUrl = network && address ? `https://dexpaprika.com/${encodeURIComponent(network)}/token/${encodeURIComponent(address)}` : null;
    const jsonUrl = network && address ? `https://api.dexpaprika.com/networks/${encodeURIComponent(network)}/tokens/${encodeURIComponent(address)}` : null;
    return <tr key={`${network}:${address}:${i}`}>
                    <td className="py-2 pr-4">
                      <span className="font-mono text-xs" title={address}>{trunc(address)}</span>
                    </td>
                    <td className="py-2 pr-4">{network || "—"}</td>
                    <td className="py-2 pr-4">{t.symbol ?? "—"}</td>
                    <td className="py-2 pr-4">
                      <span className="whitespace-normal break-words" style={{
      wordBreak: "break-word",
      whiteSpace: "normal"
    }}>
                        {t.name ?? "—"}
                      </span>
                    </td>
                    <td className="py-2 pr-4">{fmtNum(t.price_usd)}</td>
                    <td className="py-2 pr-4">
                      {dexUrl ? <a href={dexUrl} target="_blank" rel="noopener noreferrer" className="px-3 py-1 rounded text-white" style={{
      backgroundColor: PRIMARY
    }}>
                          Open
                        </a> : "—"}
                    </td>
                    <td className="py-2 pr-4">
                      {jsonUrl ? <a href={jsonUrl} target="_blank" rel="noopener noreferrer" className="px-3 py-1 rounded text-white" style={{
      backgroundColor: PRIMARY
    }}>
                          View
                        </a> : "—"}
                    </td>
                  </tr>;
  })}
            </tbody>
          </table>
        </div>}
    </div>;
}

export const CoverageChecker = ({mcpUrl = "https://mcp.dexpaprika.com/json-rpc", onUpdate}) => {
  const STORE_LAST = "dp:coverage:last";
  const CACHE_PREFIX = "dp:coverage:query:";
  const CACHE_TTL_MS = 5 * 60 * 1000;
  const EVT_NAME = "dp:coverage:update";
  const PRIMARY = "#16A34A";
  function cacheKey(q) {
    return `${CACHE_PREFIX}${q.toLowerCase().trim()}`;
  }
  function loadCache(q) {
    try {
      const raw = sessionStorage.getItem(cacheKey(q));
      if (!raw) return null;
      const {ts, data} = JSON.parse(raw);
      return Date.now() - ts > CACHE_TTL_MS ? null : data;
    } catch {
      return null;
    }
  }
  function saveCache(q, data) {
    try {
      sessionStorage.setItem(cacheKey(q), JSON.stringify({
        ts: Date.now(),
        data
      }));
    } catch {}
  }
  function saveLast(query, tokens) {
    try {
      sessionStorage.setItem(STORE_LAST, JSON.stringify({
        ts: Date.now(),
        query,
        tokens
      }));
    } catch {}
  }
  const [query, setQuery] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const initOnce = useRef(null);
  const HEADERS = useMemo(() => ({
    "Content-Type": "application/json"
  }), []);
  async function initializeIfNeeded() {
    if (!initOnce.current) {
      initOnce.current = fetch(mcpUrl, {
        method: "POST",
        headers: HEADERS,
        body: JSON.stringify({
          jsonrpc: "2.0",
          id: "init",
          method: "initialize",
          params: {}
        }),
        mode: "cors"
      }).catch(() => null);
    }
    return initOnce.current;
  }
  async function rpc(method, params, id = Date.now()) {
    await initializeIfNeeded();
    const res = await fetch(mcpUrl, {
      method: "POST",
      headers: HEADERS,
      body: JSON.stringify({
        jsonrpc: "2.0",
        id,
        method,
        params
      }),
      mode: "cors"
    });
    const text = await res.text();
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    let json;
    try {
      json = JSON.parse(text);
    } catch {
      throw new Error("Invalid JSON-RPC response");
    }
    if (json?.error) throw new Error(json.error.message || "RPC error");
    return json;
  }
  function parseToolsCall(rpcRes) {
    const c = rpcRes?.result?.content;
    if (Array.isArray(c) && c[0]?.type === "text") {
      try {
        return JSON.parse(c[0].text);
      } catch {}
    }
    return null;
  }
  function publish(query, tokens) {
    console.debug("[CoverageChecker] publish", {
      query,
      count: tokens?.length ?? 0
    });
    saveLast(query, tokens);
    try {
      if (typeof onUpdate === "function") onUpdate({
        query,
        tokens
      });
    } catch {}
  }
  async function doSearch(q) {
    setLoading(true);
    setError("");
    try {
      const cached = loadCache(q);
      if (cached) {
        publish(q, cached);
        return;
      }
      const rpcRes = await rpc("tools/call", {
        name: "search",
        arguments: {
          query: q
        }
      });
      const payload = parseToolsCall(rpcRes) || ({});
      const rows = Array.isArray(payload.tokens) ? payload.tokens : [];
      const map = new Map();
      for (const t of rows) {
        const chain = t.chain || t.network || "";
        const id = t.id || t.address || "";
        if (!chain || !id) continue;
        const key = `${chain}:${id}`;
        if (!map.has(key)) map.set(key, {
          ...t,
          chain,
          id
        });
      }
      const deduped = [...map.values()];
      saveCache(q, deduped);
      publish(q, deduped);
    } catch (e) {
      setError(e.message || "Couldn’t load results. Please try again.");
    } finally {
      setLoading(false);
    }
  }
  const onSubmit = e => {
    e.preventDefault();
    const q = query.trim();
    if (q.length < 3) {
      setError("Please type at least 3 characters.");
      return;
    }
    doSearch(q);
  };
  return <div className="space-y-2">
      <form onSubmit={onSubmit} className="flex gap-3 items-center">
        <div className="relative flex-1">
          <span className="absolute left-3 top-1/2 -translate-y-1/2 opacity-60" aria-hidden>
            🔍
          </span>
          <input className="w-full pl-9 pr-3 py-2 rounded-lg border border-neutral-300 bg-white dark:bg-transparent shadow-sm focus:outline-none" placeholder="Enter ticker, name, or contract (min 3 chars)…" value={query} onChange={e => {
    setQuery(e.target.value);
    if (error) setError("");
  }} aria-label="Search term" />
        </div>
        <button className="px-4 py-2 rounded-lg text-white disabled:opacity-60 disabled:cursor-not-allowed" style={{
    backgroundColor: PRIMARY
  }} type="submit" disabled={loading || query.trim().length < 3} title={query.trim().length < 3 ? "Type at least 3 characters" : ""}>
          {loading ? "Searching…" : "Search"}
        </button>
      </form>
      {error && <div role="alert" className="text-red-600 text-sm">{error}</div>}
    </div>;
};

<Tip>
  See also: [Networks](/api-reference/networks/get-a-list-of-available-blockchain-networks),
  [Liquidity pool endpoint](/api-reference/pools/get-a-pool-on-a-network),
  [Token data](/api-reference/tokens/get-a-tokens-latest-data-on-a-network)
</Tip>

export default function CoverageCheckerPage() {
  const [data, setData] = useState(null);
  return <>
      <CoverageChecker onUpdate={setData} />
      <CoverageResults externalData={data} />
    </>;
}

### FAQs

<AccordionGroup>
  <Accordion title="How do I use the results?">
    Copy the token or pool address and pass it to the corresponding REST endpoints along with the network.
  </Accordion>

  <Accordion title="Are lookups rate‑limited?">
    Public usage is allowed without keys; be considerate with high‑frequency queries.
  </Accordion>

  <Accordion title="Can I filter by network?">
    Yes. Provide the `network` when calling token/pool endpoints.
  </Accordion>
</AccordionGroup>

### Next steps

<CardGroup cols={2}>
  <Card title="Query a liquidity pool" icon="water" href="/api-reference/pools/get-a-pool-on-a-network">Get pool reserves and metrics</Card>
  <Card title="List pool transactions" icon="arrow-right-arrow-left" href="/api-reference/pools/get-transactions-of-a-pool-on-a-network-paging-can-be-used-up-to-100-pages">Fetch swaps/adds/removes</Card>
</CardGroup>

<script type="application/ld+json">
  {JSON.stringify({
        "@context": "https://schema.org",
        "@type": "FAQPage",
        "mainEntity": [
          {
            "@type": "Question",
            "name": "How do I use the results?",
            "acceptedAnswer": { "@type": "Answer", "text": "Copy the token or pool address and pass it to the corresponding REST endpoints along with the network." }
          },
          {
            "@type": "Question",
            "name": "Are lookups rate‑limited?",
            "acceptedAnswer": { "@type": "Answer", "text": "Public usage is allowed without keys; be considerate with high‑frequency queries." }
          },
          {
            "@type": "Question",
            "name": "Can I filter by network?",
            "acceptedAnswer": { "@type": "Answer", "text": "Yes. Provide the network when calling token/pool endpoints." }
          }
         ]
    })}
</script>
