Deterministic risk rules for ERC-20 tokens on Base.
This is the open-source rule engine that powers Cassandra — a read-only risk surveillance agent for DeFi portfolios. Each rule takes a token address and returns one of three verdicts:
OK— no signal triggeredWARN— a soft signal; review and decideEXIT— a hard signal; the rule recommends closing the position
Verdicts are deterministic: same inputs, same call. Every verdict carries the
exact signal and reason that produced it, so any past decision can be
re-derived and audited.
It is: a small library of four onchain risk checks that the Cassandra live monitor at monitor.cassandradefi.com runs on every refresh. The code here is the code that runs in production.
It is not: a price oracle, a top-caller, an alpha source, or an upside optimizer. The rules answer one question — should this position be exited? — and nothing else.
| ID | Name | What it checks | EXIT threshold |
|---|---|---|---|
rule-01 |
Liquidity Depth Collapse | Paired-USD/ETH/cbBTC exit liquidity on DefiLlama, sampled over a 60-min rolling window | ≥60% drop in 60 min |
rule-02 |
Holder Concentration Spike | Top-10 non-CEX/LP/treasury holder share, from GoPlus | ≥80% of supply |
rule-04 |
Mint Authority & Upgrade Flag | Mint capability + EIP-1967 proxy + non-renounced EOA owner, from RPC + GoPlus | Mintable AND upgradeable AND EOA-owned |
rule-07 |
Honeypot & Transfer-Tax Behavior | GoPlus sell simulation + transfer-tax inspection | Honeypot or sell tax >30% |
WARN thresholds are documented inline in each rule file. The rule numbers are non-contiguous because more rules are scheduled but not yet released — the public roadmap and thresholds live at cassandradefi.com/rulebook.
Every rule is a single file in src/rules/ with the same shape:
async function evaluateRuleNN(token: TokenContext): Promise<RuleEvaluation>npm install @cassandra-defi/rules-engine
# or
pnpm add @cassandra-defi/rules-engineimport {evaluateToken} from '@cassandra-defi/rules-engine';
const verdict = await evaluateToken({
address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC on Base
chainId: 8453,
symbol: 'USDC',
});
console.log(verdict.composite); // 'OK' | 'WARN' | 'EXIT'
console.log(verdict.rules); // per-rule signals + reasonsTo evaluate a whole portfolio:
import {evaluateWallet} from '@cassandra-defi/rules-engine';
const snapshot = await evaluateWallet('0xYourWallet', [
{address: '0x...', chainId: 8453, symbol: 'TOKEN_A'},
{address: '0x...', chainId: 8453, symbol: 'TOKEN_B'},
]);You can also invoke individual rules directly — useful for backtesting or isolating one signal:
import {evaluateRule07} from '@cassandra-defi/rules-engine';
const r = await evaluateRule07({
address: '0x...',
chainId: 8453,
symbol: 'SUSPECT',
});
// { rule: 'rule-07', verdict: 'EXIT', signal: 'HONEYPOT', reason: '...' }Optional environment variables — falls back to a public Base RPC if neither is set:
| Var | Purpose |
|---|---|
ALCHEMY_BASE_URL |
Alchemy Base mainnet endpoint. Recommended in production. |
BASE_RPC_URL |
Generic Base RPC override. Used if ALCHEMY_BASE_URL is unset. |
GoPlus and DefiLlama endpoints are public and unauthenticated; no key is needed.
- Deterministic over predictive. Same inputs, same verdict. We do not train models; we encode rules. A rule that fires today on chain data can be replayed against the same chain data tomorrow.
- Conservative on EXIT. Each rule has an explicit threshold and a stated rationale. We would rather underfire EXIT than have one fire on a false positive — a wrongful EXIT is a realized loss.
- Inspectable. Every verdict ships with the exact
signal(terse) andreason(sentence) that produced it. Nothing is hidden behind a score. - Composable, not opinionated. The engine returns evidence; how you act on EXIT — alert, recommend, auto-exit — is your decision.
This library is what runs in production at monitor.cassandradefi.com. The thresholds above are the v0 thresholds. They are calibrated, not fitted — we have not backtested them to optimize precision/recall, because there is no revenue-weighted ground truth for "good exits" yet. Treat v0 as the starting point of public iteration.
The rule lineup is intentionally narrow. Holder-flow rules (large-wallet distribution, LP unstake), peer-divergence rules (price diverging from on-chain peers), and tokenomics rules (vesting cliff approaching) are on-deck. Issues + PRs welcome — see CONTRIBUTING below.
Found a rule we missed, a threshold we got wrong, or a historical rug we should backtest against? Open an issue. Contributions that materially change a threshold or add a rule will be credited in the next version of the rulebook.
MIT — see LICENSE.