.md

Introduction

Decoded Stacks chain data, backfilled from genesis, reorg-safe and kept current. Trust, and verify it yourself.

Do you already have an API layer?

index.tsts
import { Index } from "@secondlayer/sdk";
await new Index().events.consume({
eventType: "ft_transfer",
fromCursor: await db.loadCheckpoint(),
onBatch: async (events, envelope, ctx) => {
await db.commit(events, ctx.cursor);
return ctx.cursor;
},
onReorg: (reorg) => db.deleteFromHeight(reorg.fork_point_height),
});

, and when a reorg lands. You keep your schema and serve it however you already do. Index →

subgraph.config.tsts
import { defineSubgraph } from "@secondlayer/subgraphs";
export default defineSubgraph({
name: "sbtc-flows",
startBlock: 8000000,
sources: { transfers: { type: "ft_transfer", assetIdentifier: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token" } },
schema: { transfers: { columns: { amount: { type: "uint" }, sender: { type: "principal" } } } },
handlers: {
transfers: (event, ctx) => ctx.insert("transfers", { amount: event.amount, sender: event.sender }),
},
});

The , and fills a table that REST serves. You get an API you didn't write. That's the point, and the tradeoff. Subgraphs →

indexer.tsts
await sl.streams.events.consume({
types: ["ft_transfer"],
fromCursor: await db.loadCheckpoint(),
onBatch: async (events, envelope, ctx) => {
await db.insertEvents(events, ctx.cursor);
return ctx.cursor;
},
onReorg: (reorg) => db.deleteFromHeight(reorg.fork_point_height),
});

You get , and a . This is what Index is built on. Streams →

Five commands from key to a row you can check against Bitcoin. Keys come from /account/keys.

Using an agent? bunx skills add ryanwaits/secondlayer --skill secondlayer -y

Install and set your key

Every command and example reads these two variables.

$bun add -g @secondlayer/cli
$export SECONDLAYER_API_URL=https://api.secondlayer.tools
$export SECONDLAYER_API_KEY=sk-sl_...

Create a subgraph

Scaffolds a typed subgraph from a contract's events.

$secondlayer subgraphs create my-balances --from-contract SP....my-contract

Deploy

Set a startBlock first: the event and transaction rows it reads bill. Reads of your own tables are free.

$secondlayer subgraphs deploy subgraphs/my-balances.ts

Query

$curl -H "Authorization: Bearer $SECONDLAYER_API_KEY" \
"$SECONDLAYER_API_URL/v1/subgraphs/my-balances/balances"

Verify

Proves the block your rows came from against Bitcoin. Verification →

$secondlayer verify block 9137005

Prefer your own box? Self-host is the same product on your Postgres.

Edit on GitHub