Beamline fields
A rule reads the fields of one event. There are 17: 15 for transfer rows and 2 for liquidity samples. The list is also returned as data.fields from Validate a rule. Field names ignore case.
#All fields
| Field | Type | Values | Null case |
|---|---|---|---|
chain | text | ethereum, base, bnb, arbitrum, solana | Never |
token | text | Curated symbol, or ETH, or SOL | Never |
token_address | text | Contract or mint address | null on native rows |
kind | text | token or native | Never |
from | text | Sender address | Never |
to | text | Recipient address | Never |
from_label | text | Name from the label set | null when not labeled |
to_label | text | Name from the label set | null when not labeled |
from_type | text | Label type | null when not labeled |
to_type | text | Label type | null when not labeled |
tx | text | Transaction hash or signature | Never |
usd | number | Value at index time, at least 100,000 | Never |
amount | number | Token units after decimals | Never |
block | number | Block number or slot | Never |
sampled | boolean | true on Solana rows | Never |
liquidity_usd | number | Liquidity sample in USD | Liquidity rules only |
change_pct | number | Liquidity change in percent over the sample window | Liquidity rules only |
A null text field compares as the empty string. to_type != "exchange" is true on a row with no label.
#Liquidity rules
A rule that names liquidity_usd or change_pct, or holds the text "liquidity", is a liquidity rule. It runs on liquidity samples and never on transfers. Every other rule runs on transfers and never on samples.
| Fact | Value |
|---|---|
| Tokens | Curated tokens, except stablecoins and wrapped native assets: symbols that begin with USD, DAI, FDUSD, wSOL, WETH, WBNB or WMATIC |
| Chains | All seven, for the tokens that remain |
| Sample interval | About 5 minutes, and only while an enabled liquidity rule exists |
| Change window | Up to 12 samples, so about one hour. window_minutes in the event gives the real span. |
| Source | Token report market logic on DexScreener pools, with outlier pools left out |
| Other fields on the event | chain, token, token_address, and kind set to liquidity |
| Payload type | liquidity.matched |
The samples are held in memory, so a restart empties the window. The first sample after a restart can fire nothing. change_pct then measures a shorter span. Validate a rule tests stored transfers only, so a liquidity rule shows matched: 0 there. That result says nothing about the rule.
Numbers can be negative, so change_pct <= -30 is valid.
#Notes by field
#chain
Rows exist only for ethereum, base, bnb, arbitrum and solana. A rule naming optimism or polygon is valid and never matches, because those chains have no index. See chain coverage.
#token
The symbol. Symbols repeat across chains. token == "USDC" matches on all chains. Use token_address or add chain to narrow it.
| Chain | Tokens in rows |
|---|---|
ethereum | USDC, USDT, WETH, WBTC, DAI, ETH |
base | USDC, WETH, USDbC, cbBTC, DAI |
bnb | USDT, USDC, WBNB, BTCB, ETH |
arbitrum | USDC, USDT, WETH, WBTC |
solana | USDC, USDT, wSOL, JUP, BONK, WIF, JTO, PYTH, RAY, JitoSOL, mSOL, SOL |
ETH means two things. With kind == "native" it is native ETH on Ethereum. With chain == "bnb" it is a bridged token.
#token_address
Case does not matter. On native rows, it reads as an empty string, so token_address == "" selects them. Use kind == "native" for clarity.
#kind
native covers ETH on Ethereum and SOL on Solana. Everything else is token.
#from, to
EVM addresses are stored in lowercase, and comparison ignores case, so you can paste a checksummed address. startswith works for vanity prefixes.
On Solana, these fields come from balance changes. They hold the owners with the largest decrease and largest increase in that transaction. See the data model.
#from_label, to_label
Names can be corrected in later releases, so a rule on an exact name can stop matching. For stable logic, use from_type and to_type, or match the address. contains is useful for groups of wallets:
to_label contains "binance"#from_type, to_type
Values: exchange, dex, bridge, lending, staking, token, issuer, launchpad, infrastructure. The list is small and hand-curated, so to_type == "exchange" finds only the exchange wallets it knows. See labels.
The Null address label has type infrastructure. Match mints and burns on the label:
from_label == "Null address"#usd
Set at index time from a CoinGecko price. Stored rows are at or above $100,000, so a lower bound below that has no effect, and an upper bound below that matches nothing. Use suffixes: usd >= 2.5m.
#amount
Token units after decimals, as a double. It is useful for assets with a volatile price, where you care about units:
token == "WETH" and amount >= 1000#block
Rarely useful in a live rule, because block numbers differ by chain. It works in POST /rules/validate to look at a range of stored rows.
#sampled
true on Solana rows only. Read sampling. Add not sampled to keep Solana out of an alert.
#tx
The full hash. It matches at most a few rows, so it is useful only for testing against stored rows.
#Fields that are not available
| You might expect | Why it is absent | What to do |
|---|---|---|
ts, time of day | Rules read a single row with no time logic | Filter in your receiver with data.ts |
| Price, price change | Rows hold a USD value, not a price | Call Asset prices in your receiver |
| Wallet balance | Not on the row | Call Wallet overview in your receiver |
| Token report status | Not on the row | Call Token report in your receiver |
| Sums and counts over time | Rules have no state | Keep state in your receiver |
These are the limits of the language today. Your receiver can add any of these, using the same public API.
#Check a field
Send a rule to the validate endpoint and read sample to see real rows with all fields.
curl -s -X POST "https://farbeamlabs.com/api/v1/rules/validate" \
-H "content-type: application/json" \
-d '{"expression":"to_type == \"exchange\" and usd >= 500k"}'const res = await fetch("https://farbeamlabs.com/api/v1/rules/validate", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ expression: 'to_type == "exchange" and usd >= 500k' }),
});
const { data } = await res.json();
console.log(data.tested, data.matched, data.sample[0], data.fields);import requests
res = requests.post(
"https://farbeamlabs.com/api/v1/rules/validate",
json={"expression": 'to_type == "exchange" and usd >= 500k'},
timeout=30,
)
data = res.json()["data"]
print(data["tested"], data["matched"], data["fields"])