@crifine/sdk
The measurement method, an independent verifier, and the decision policy — all pure, all checkable.
npm install @crifine/sdkZero runtime dependencies. Node 20+, Workers, Deno, browser.
Verify a published number
This is the part that makes keyless verification real rather than rhetorical. It recomputes an estimate from its own evidence and reports whether the claim follows from the data beside it.
import { verifyUrl } from "@crifine/sdk";
const verdict = await verifyUrl("https://crifine.app/api/v1/exit/aave-v3-weth");
if (!verdict.matches) {
console.error("does not follow from its evidence:", verdict.problems);
}
verdict.deltaBps; // signed: negative means the claim was optimisticRun the method
import { walkLadder } from "@crifine/sdk/ladder";
const result = walkLadder(
[
{ bps: 5, usd: 612_000 },
{ bps: 10, usd: 548_000 },
{ bps: 25, usd: 471_000 },
],
4820, // oracle price
1_000_000, // the size you actually want to move
);
result.exitGapPct;
result.exceedsBook; // true = past the edge of the data, not a price- Size is required.
walkLadderthrows on zero — there is no such thing as *the* fill price. - Past the book is flagged, not extrapolated. The remainder is charged at a penalty rate and
exceedsBookis set.
Decide what to do
Every agent that consumes this data writes the same branch. decide writes it once, so the ordering is settled in one place — and the ordering is the part people get wrong.
import { decide, blocks } from "@crifine/sdk/policy";
const decision = decide(estimate, {
maxGapPct: -2, // required, and must be negative
minDaysObserved: 30, // refuse an estimate with too little record behind it
allowClosedMarket: false,
minResizeUsd: 50_000,
});
decision.action; // "proceed" | "resize" | "hold" | "defer" | "refuse"
decision.reason; // one sentence, safe to log
blocks(decision); // true for refuse / hold / deferDerivations
| Function | Answers |
|---|---|
stressWindow(series, days) | Worst condition in a window, not the average. |
depthDecay(series) | How fast the book thinned after the largest move. |
rankRoutes(estimates) | Best venue at one size. Throws on mixed sizes. |
gapSeries(series, ladder, size) | The record recomputed at *your* size. |
severity(gapPct) | ok / watch / bad banding. |
Call the API
import { CrifineClient } from "@crifine/sdk";
import { x402Fetch } from "@crifine/x402";
const crifine = new CrifineClient({
fetch: x402Fetch({ maxPerCall: 0.01, settle }),
});
await crifine.exit("aave-v3-weth", 5_000_000);
await crifine.evidence("aave-v3-weth"); // free, keyless, no paymentPayment is injected, not bundled, so the package stays dependency-free for callers who only read the free endpoints. Transient failures (429, 5xx) are retried with backoff; a 402 is never retried — payment belongs to the injected fetch, and retrying it blind is how an unattended agent pays twice.