Recipe: token screening
This recipe reads token reports for a list of addresses and prints the status of each check side by side. It makes reports easier to compare. It does not rank tokens, because Farbeam gives no composite score. You read the table and make your own judgment.
#Costs
A report costs 3 units. With no key, 30 units per minute allows 10 reports per minute. With a key, 120 units allow 40. The cache times on a report are 60 s for market data and 5 minutes for checks, so re-reading faster than that returns the same values and spends units.
#Code
# One token: list every check that is not a pass
curl -s "https://farbeamlabs.com/api/v1/tokens/ethereum/0xdAC17F958D2ee523a2206206994597C13D831ec7" \
| jq -r '.data.checks[] | select(.status != "pass") | [.id, .status, .detail] | @tsv'// screen.mjs: run with node screen.mjs
const TOKENS = [
["ethereum", "0xdAC17F958D2ee523a2206206994597C13D831ec7"],
["ethereum", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
["solana", "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"],
];
const headers = process.env.FARBEAM_KEY ? { Authorization: `Bearer ${process.env.FARBEAM_KEY}` } : {};
const pause = process.env.FARBEAM_KEY ? 1600 : 6100;
const rows = [];
for (const [chain, address] of TOKENS) {
const res = await fetch(`https://farbeamlabs.com/api/v1/tokens/${chain}/${address}`, { headers });
const { data, error } = await res.json();
if (error) {
rows.push({ token: address.slice(0, 10), error: error.code });
} else {
const row = {
token: data.token.symbol ?? address.slice(0, 10),
chain,
liquidity: data.market?.liquidity_usd ?? null,
failed_sources: data.sources.filter((s) => !s.ok).map((s) => s.name).join(" "),
...data.counts,
};
for (const check of data.checks) {
if (check.status === "fail" || check.status === "warn") row[check.id] = check.status;
}
rows.push(row);
}
await new Promise((resolve) => setTimeout(resolve, pause));
}
console.table(rows);# screen.py: run with python3 screen.py
import os, time
import requests
TOKENS = [
("ethereum", "0xdAC17F958D2ee523a2206206994597C13D831ec7"),
("ethereum", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"),
("solana", "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"),
]
key = os.environ.get("FARBEAM_KEY")
headers = {"Authorization": f"Bearer {key}"} if key else {}
pause = 1.6 if key else 6.1
for chain, address in TOKENS:
body = requests.get(f"https://farbeamlabs.com/api/v1/tokens/{chain}/{address}", headers=headers, timeout=30).json()
if "error" in body:
print(address, body["error"]["code"])
else:
d = body["data"]
flags = [f"{c['id']}={c['status']}" for c in d["checks"] if c["status"] in ("warn", "fail")]
unknown = [c["id"] for c in d["checks"] if c["status"] == "unknown"]
failed = [s["name"] for s in d["sources"] if not s["ok"]]
liquidity = (d["market"] or {}).get("liquidity_usd")
print(d["token"]["symbol"], chain, f"liquidity={liquidity}", flags, f"unknown={unknown}", f"failed_sources={failed}")
time.sleep(pause)The three tokens above are examples for the output, and they are not suggestions. Replace them with your own list.
#Reading the output
Read reading token reports first. Some rules for a table like this:
| Column | Note |
|---|---|
fail and warn counts | Do not sort by them as a score. Major stablecoins show warnings for admin powers. |
unknown | This is missing information. A token with many unknowns has been checked less. |
failed_sources | When this is not empty, unknown probably reflects a source failure. Read again later. |
liquidity | A sum across pools the source returned. Outlier pools are left out. |
Checks are read from third parties and can be wrong or out of date.
#Finding candidates to read
Trending pools gives a list of pools per chain. Each entry has a base_token, which you can pass to the report. A rank in that list is not a recommendation, and many new pools are thin.
import requests
pools = requests.get("https://farbeamlabs.com/api/v1/markets/pools", params={"chain": "base"}, timeout=30).json()["data"]
print([p["base_token"] for p in pools[:5]])#Handling errors
| Result | Meaning | Action |
|---|---|---|
400 invalid_address | The format does not match the chain | Check the chain and address pair |
404 not_found | No pool data and no token data | Often not a token. Solana reads Not a token or Not a token mint. |
429 rate_limited | Units used up | Wait for Retry-After |
502 upstream_unavailable | Every source failed | Retry later |
#What this recipe does not do
It makes no decision for you, and it does not check for scam websites or social claims. It does not read the code of a contract. Screening is the start of reading about a token and does not end it. Nothing here is advice to buy, sell or hold any token.