declare const DECODED_EVENT_TYPES: readonly ["stx_transfer", "stx_mint", "stx_burn", "stx_lock", "ft_transfer", "ft_mint", "ft_burn", "nft_transfer", "nft_mint", "nft_burn", "print"]; type DecodedEventType = (typeof DECODED_EVENT_TYPES)[number]; /** Every chain-event filter member across all four surfaces: the 10 decoded * token/STX types, the three contract-shaped types (spelled as subgraphs and * triggers spell them — Index/Streams project `print_event` → `print`), and * the five sBTC lifecycle types (Subscriptions-only). */ declare const CHAIN_EVENT_FILTER_TYPES: readonly ["stx_transfer", "stx_mint", "stx_burn", "stx_lock", "ft_transfer", "ft_mint", "ft_burn", "nft_transfer", "nft_mint", "nft_burn", "contract_call", "contract_deploy", "print_event", "sbtc_deposit", "sbtc_withdrawal_create", "sbtc_withdrawal_accept", "sbtc_withdrawal_reject", "sbtc_withdrawal_swept_confirmed"]; type ChainEventFilterType = (typeof CHAIN_EVENT_FILTER_TYPES)[number]; type AbiUInt128 = "uint128"; type AbiInt128 = "int128"; type AbiBool = "bool"; type AbiPrincipal = "principal"; type AbiTraitReference = "trait_reference"; type AbiNone = "none"; type AbiStringAscii = { "string-ascii": { length: L } }; type AbiStringUtf8 = { "string-utf8": { length: L } }; type AbiBuffer = { buff: { length: L } }; type AbiPrimitiveType = AbiUInt128 | AbiInt128 | AbiBool | AbiPrincipal | AbiTraitReference | AbiNone | AbiStringAscii | AbiStringUtf8 | AbiBuffer; interface AbiListType { list: { type: AbiType length: number }; } interface AbiTupleType { tuple: ReadonlyArray<{ name: string type: AbiType }>; } interface AbiOptionalType { optional: AbiType; } interface AbiResponseType { response: { ok: AbiType error: AbiType }; } /** Discriminated union of all Clarity value types (primitives, buffers, lists, tuples, optionals, responses). */ type AbiType = AbiPrimitiveType | AbiListType | AbiTupleType | AbiOptionalType | AbiResponseType; type FunctionAccess = "public" | "read-only" | "private"; interface FunctionArg { name: string; type: AbiType; } /** A single Clarity function definition with name, access level, arguments, and return type. */ interface AbiFunction { name: string; access: FunctionAccess; args: ReadonlyArray; outputs: AbiType; } type VariableAccess = "constant" | "variable"; interface AbiVariable { name: string; type: AbiType; access: VariableAccess; } interface AbiMap { name: string; key: AbiType; value: AbiType; } interface AbiFungibleToken { name: string; } interface AbiNonFungibleToken { name: string; type: AbiType; } type TraitFunctionAccess = Exclude; interface AbiTraitFunction { name: string; access: TraitFunctionAccess; args: ReadonlyArray; outputs: AbiType; } interface AbiTraitDefinition { name: string; functions: ReadonlyArray; } /** Full Clarity contract ABI including functions, maps, variables, and token definitions. */ interface AbiContract { functions: ReadonlyArray; maps?: ReadonlyArray; variables?: ReadonlyArray; fungible_tokens?: ReadonlyArray; non_fungible_tokens?: ReadonlyArray; implemented_traits?: ReadonlyArray; defined_traits?: ReadonlyArray; } /** A validated Stacks principal (standard or contract). Branded so downstream * code can require "already validated" without re-checking. */ type Principal = string & { readonly __principal: unique symbol }; /** * `::` — the shape a fungible/non-fungible asset filter * takes, expressed so the compiler can check it. * * The most common mistake in this API is passing a CONTRACT ID * (`SP….sbtc-token`) where an asset identifier (`SP….sbtc-token::sbtc-token`) * belongs, and the failure mode is a query that quietly returns zero rows. The * two differ structurally by `::`, so a template-literal type catches it at the * call site — no brand, no cast, literals just work. * * A value that is only known at runtime (config, env) is not narrow enough on * purpose; run it through {@link assetId} once, which validates and narrows. * * Wildcard patterns (Subscriptions/Subgraphs-only) are admitted by the second arm — they * are legitimately not full identifiers (`SPB.*`), and the runtime validator * short-circuits on them for the same reason. */ type AssetIdentifier = `${string}::${string}` | `${string}*${string}`; /** * Narrow a runtime string to an {@link AssetIdentifier}, validating it. * * The escape hatch for config-driven values: `assetId(process.env.ASSET!)` * throws on a contract id instead of letting it through to a zero-row query. */ declare function assetId(value: string): AssetIdentifier; /** `true` for a standard (`SP…`/`ST…`) or contract (`SP….name`) principal. * Shares {@link parsePrincipal} with the ABI guards so the two surfaces can't * disagree about what a principal is. */ declare function isPrincipal(value: string): value is Principal; /** Subscriptions and Subgraph sources match `*` wildcards in * principal/identifier patterns; every * other surface treats the value literally. */ declare function hasWildcard(value: string): boolean; /** Throw unless `value` is a principal or a wildcard pattern. The factories * call this so a swapped argument (asset id where a sender belongs, typo'd * address) fails at construction — not as a silent zero-row query. */ declare function assertPrincipalish(field: string, value: string): void; /** Throw unless `value` looks like `SP….contract::asset` (or a wildcard). */ declare function assertAssetIdentifier(field: string, value: string): void; /** Throw unless `value` is a contract id `SP….name` (or a wildcard). */ declare function assertContractId(field: string, value: string): void; /** Scalar print field types (structural mirror of the subgraphs `ColumnType`). */ type PrintScalarType = "uint" | "int" | "text" | "principal" | "boolean" | "timestamp" | "jsonb"; /** * One declared print field — structural mirror of `PrintField` in * `@secondlayer/subgraphs`. Composite forms exist because real print payloads * nest: a vocabulary that could only say `"jsonb"` is what let a flat-field * declaration type-check while every event decoded to null. * * Kept literal through `toSubgraphSource()` so handler narrowing survives. */ type PrintFieldType = PrintScalarType | { type: PrintFieldType optional: true } | { tuple: Record } | { list: PrintFieldType }; interface StxTransferSpec { type: "stx_transfer"; sender?: string; recipient?: string; minAmount?: bigint; maxAmount?: bigint; } interface StxMintSpec { type: "stx_mint"; recipient?: string; minAmount?: bigint; } interface StxBurnSpec { type: "stx_burn"; sender?: string; minAmount?: bigint; } interface StxLockSpec { type: "stx_lock"; lockedAddress?: string; minAmount?: bigint; } /** Scope to contracts conforming to a trait/standard (e.g. "sip-010") instead * of a fixed contract. Index + Subgraphs + Webhooks; Streams has no * trait resolution — `toStreamsParams()` throws if set. */ type TraitScope = { trait?: string }; /** Scope to a DYNAMIC address set discovered from another source's events — * a Subgraphs-only concept (`toSubgraphSource()` keeps it; every other * projection throws). Structural mirror of the subgraphs `FactoryScope`: * `stacks` is the dependency-graph leaf and cannot import it. */ type FactoryScope = { factory?: { /** Source name whose events reveal the addresses. */ from: string /** Dotted path to the address on that source's payload (e.g. "data.pool"). */ field: string } }; interface FtTransferSpec extends TraitScope { type: "ft_transfer"; assetIdentifier?: AssetIdentifier; sender?: string; recipient?: string; minAmount?: bigint; } interface FtMintSpec extends TraitScope { type: "ft_mint"; assetIdentifier?: AssetIdentifier; recipient?: string; minAmount?: bigint; } interface FtBurnSpec extends TraitScope { type: "ft_burn"; assetIdentifier?: AssetIdentifier; sender?: string; minAmount?: bigint; } interface NftTransferSpec extends TraitScope { type: "nft_transfer"; assetIdentifier?: AssetIdentifier; sender?: string; recipient?: string; } interface NftMintSpec extends TraitScope { type: "nft_mint"; assetIdentifier?: AssetIdentifier; recipient?: string; } interface NftBurnSpec extends TraitScope { type: "nft_burn"; assetIdentifier?: AssetIdentifier; sender?: string; } interface ContractCallSpec extends TraitScope, FactoryScope { type: "contract_call"; /** One contract id, or a set of them (max 20). Mirrors the subgraphs * filter — a router plus its pools is one source, not N. */ contractId?: string | readonly string[]; functionName?: string; caller?: string; /** Contract ABI (`as const`) — preserved literally so `toSubgraphSource()` * keeps typing `event.input` in `defineSubgraph`. */ abi?: AbiContract; } interface ContractDeploySpec { type: "contract_deploy"; deployer?: string; contractName?: string; } interface PrintEventSpec extends TraitScope, FactoryScope { type: "print_event"; /** One contract id, or a set of them (max 20). */ contractId?: string | readonly string[]; topic?: string; /** Per-topic field schema — preserved literally so `toSubgraphSource()` * keeps the discriminated-union narrowing of `event.data`. */ prints?: Record>; } interface SbtcDepositSpec { type: "sbtc_deposit"; sender?: string; minAmount?: bigint; maxAmount?: bigint; bitcoinTxid?: string; requestId?: number; } interface SbtcWithdrawalCreateSpec { type: "sbtc_withdrawal_create"; sender?: string; minAmount?: bigint; maxAmount?: bigint; requestId?: number; } interface SbtcWithdrawalAcceptSpec { type: "sbtc_withdrawal_accept"; requestId?: number; sweepTxid?: string; } interface SbtcWithdrawalRejectSpec { type: "sbtc_withdrawal_reject"; requestId?: number; } interface SbtcWithdrawalSweptConfirmedSpec { type: "sbtc_withdrawal_swept_confirmed"; requestId?: number; sweepTxid?: string; } type ChainEventFilterSpec = StxTransferSpec | StxMintSpec | StxBurnSpec | StxLockSpec | FtTransferSpec | FtMintSpec | FtBurnSpec | NftTransferSpec | NftMintSpec | NftBurnSpec | ContractCallSpec | ContractDeploySpec | PrintEventSpec | SbtcDepositSpec | SbtcWithdrawalCreateSpec | SbtcWithdrawalAcceptSpec | SbtcWithdrawalRejectSpec | SbtcWithdrawalSweptConfirmedSpec; type SpecFor = Extract; /** The members expressible as subgraph sources (everything but the * Webhooks-only sBTC lifecycle types). Instantiating * `ChainEventFilter` keeps `toSubgraphSource` present: * the conditional in `ProjectionsFor` evaluates over this whole union * (non-distributive at an instantiated site), and every member qualifies. */ type SubgraphMemberType = Exclude; /** A subgraph-source-shaped filter object (the `toSubgraphSource()` output / * `fromSubgraphSource()` input). */ type SubgraphSourceSpec = Extract; /** Wire shape of a chain trigger (Webhooks), derived per member from * the spec: same fields, with `bigint` amounts stringified (uint128 exceeds * JS safe integers) and the type-only `abi`/`prints` decorations dropped. * Structurally assignable to the SDK's `ChainTrigger` union. */ type ChainTriggerOf = { [K in keyof Omit] : Exclude | (bigint extends S[K] ? string : never) }; /** Loose trigger shape (any member). */ type ChainTriggerShape = ChainTriggerOf; /** Params fragment for `index.events.*` (spread into list/walk/consume). */ type IndexEventsParamsShape = { eventType: DecodedEventType /** A spec's contract set passes through verbatim (the API takes up to 20). */ contractId?: string | readonly string[] assetIdentifier?: AssetIdentifier sender?: string recipient?: string trait?: string }; /** Params fragment for `index.contractCalls.*`. */ type ContractCallsParamsShape = { /** A spec's contract set passes through verbatim (the API takes up to 20). */ contractId?: string | readonly string[] functionName?: string /** Populated from the spec's `caller` — the endpoint filters by tx sender, * which is the caller. */ sender?: string trait?: string }; /** Params fragment for `streams.events.*`. */ type StreamsParamsShape = { types: readonly DecodedEventType[] contractId?: string | readonly string[] sender?: string recipient?: string assetIdentifier?: AssetIdentifier }; type DecodedMember = "stx_transfer" | "stx_mint" | "stx_burn" | "stx_lock" | "ft_transfer" | "ft_mint" | "ft_burn" | "nft_transfer" | "nft_mint" | "nft_burn" | "print_event"; type ProjectionsFor< T extends ChainEventFilterType, S > = { /** Wire trigger for `subscriptions.create({ triggers: [...] })`. BigInt * amounts become strings here — the one sanctioned boundary. */ toChainTrigger(): ChainTriggerOf } & (T extends DecodedMember ? { /** Params for `index.events.list/walk/consume` (merge your own * `limit`/`fromHeight`/`txContext` etc. on top). */ toIndexParams>(extra?: Extra): IndexEventsParamsShape & Extra /** Params for `streams.events.list/consume/stream`. Throws if the * filter uses `trait` (Streams has no trait resolution) or a * min/max amount (Streams filters have no amount predicates). */ toStreamsParams>(extra?: Extra): StreamsParamsShape & Extra } : {}) & (T extends "contract_call" ? { /** Params for `index.contractCalls.list/walk/consume`. */ toContractCallsParams>(extra?: Extra): ContractCallsParamsShape & Extra } : {}) & (T extends Exclude ? { /** The `sources` entry for `defineSubgraph` — literal `prints`/`abi` * types are preserved, so handler narrowing survives. */ toSubgraphSource(): S } : {}); /** * A canonical chain-event filter: the spec fields plus the projections its * member supports. Write the filter once; project it to a query * (`toIndexParams`), a stream (`toStreamsParams`), a webhook trigger * (`toChainTrigger`), or a subgraph source (`toSubgraphSource`). */ type ChainEventFilter< T extends ChainEventFilterType = ChainEventFilterType, S extends { type: T } = SpecFor > = S & ProjectionsFor; /** Build a canonical filter: validated spec + the projections its member * supports (methods are attached per member at runtime, matching the * type-level gating exactly). `const F` preserves field literals — a * `prints`/`abi` declaration keeps its exact type through * `toSubgraphSource()`, which is what feeds `defineSubgraph` narrowing. */ declare function makeChainEventFilter< T extends ChainEventFilterType, const F extends Omit, "type"> >(type: T, fields: F): ChainEventFilter; /** * Rehydrate a canonical filter from a subgraph-source-shaped object (the * inverse of `toSubgraphSource`). Powers migration and the round-trip * property gate: `toSubgraphSource(fromSubgraphSource(f))` must deep-equal * `f` for every production subgraph source. */ declare function fromSubgraphSource(source: SubgraphSourceSpec): ChainEventFilter; type Fields = Omit, "type">; /** The `on.*` namespace, annotated explicitly — bunup's dts emitter needs an * annotation on exported values (an inferred object of generic factories * collapses to `{}` in the emitted declarations). */ interface OnNamespace { stxTransfer(fields?: Fields<"stx_transfer">): ChainEventFilter<"stx_transfer">; stxMint(fields?: Fields<"stx_mint">): ChainEventFilter<"stx_mint">; stxBurn(fields?: Fields<"stx_burn">): ChainEventFilter<"stx_burn">; stxLock(fields?: Fields<"stx_lock">): ChainEventFilter<"stx_lock">; ftTransfer(fields?: Fields<"ft_transfer">): ChainEventFilter<"ft_transfer">; ftMint(fields?: Fields<"ft_mint">): ChainEventFilter<"ft_mint">; ftBurn(fields?: Fields<"ft_burn">): ChainEventFilter<"ft_burn">; nftTransfer(fields?: Fields<"nft_transfer">): ChainEventFilter<"nft_transfer">; nftMint(fields?: Fields<"nft_mint">): ChainEventFilter<"nft_mint">; nftBurn(fields?: Fields<"nft_burn">): ChainEventFilter<"nft_burn">; /** `abi` literals are preserved (`const A`) so `toSubgraphSource()` keeps * typing `event.input` inside `defineSubgraph`. */ contractCall(fields?: Omit, "type" | "abi"> & { abi?: A }): ChainEventFilter<"contract_call", { type: "contract_call" } & Omit, "type" | "abi"> & { abi?: A }>; contractDeploy(fields?: Fields<"contract_deploy">): ChainEventFilter<"contract_deploy">; /** Canonical member is `print_event` (as Subgraphs and Subscriptions spell * it); `toIndexParams`/`toStreamsParams` project to `print`. `prints` * literals are preserved (`const P`) for per-topic `event.data` narrowing. */ print> | undefined = undefined>(fields?: Omit, "type" | "prints"> & { prints?: P }): ChainEventFilter<"print_event", { type: "print_event" } & Omit, "type" | "prints"> & { prints?: P }>; sbtcDeposit(fields?: Fields<"sbtc_deposit">): ChainEventFilter<"sbtc_deposit">; sbtcWithdrawalCreate(fields?: Fields<"sbtc_withdrawal_create">): ChainEventFilter<"sbtc_withdrawal_create">; sbtcWithdrawalAccept(fields?: Fields<"sbtc_withdrawal_accept">): ChainEventFilter<"sbtc_withdrawal_accept">; sbtcWithdrawalReject(fields?: Fields<"sbtc_withdrawal_reject">): ChainEventFilter<"sbtc_withdrawal_reject">; sbtcWithdrawalSweptConfirmed(fields?: Fields<"sbtc_withdrawal_swept_confirmed">): ChainEventFilter<"sbtc_withdrawal_swept_confirmed">; } /** * `on.*` — one filter vocabulary for every surface. * * ```ts * import { on } from "@secondlayer/stacks/filters"; * * const usdc = on.ftTransfer({ assetIdentifier: USDC, minAmount: 1_000_000n }); * * sl.index.events.list(usdc.toIndexParams({ limit: 100 })); // pull * sl.streams.events.consume({ ...usdc.toStreamsParams(), onBatch }); * sl.subscriptions.create({ name, url, triggers: [usdc.toChainTrigger()] }); * defineSubgraph({ sources: { usdc: usdc.toSubgraphSource() }, schema, handlers }); * ``` * * A surface a member can't reach is a missing method (compile error), and a * field a surface can't express throws at projection time — never a silent * zero-row or over-wide match. */ declare const on: OnNamespace; export { on, makeChainEventFilter, isPrincipal, hasWildcard, fromSubgraphSource, assetId, assertPrincipalish, assertContractId, assertAssetIdentifier, SubgraphSourceSpec, SubgraphMemberType, StxTransferSpec, StxMintSpec, StxLockSpec, StxBurnSpec, StreamsParamsShape, SpecFor, SbtcWithdrawalSweptConfirmedSpec, SbtcWithdrawalRejectSpec, SbtcWithdrawalCreateSpec, SbtcWithdrawalAcceptSpec, SbtcDepositSpec, PrintScalarType, PrintFieldType, PrintEventSpec, Principal, NftTransferSpec, NftMintSpec, NftBurnSpec, IndexEventsParamsShape, FtTransferSpec, FtMintSpec, FtBurnSpec, DecodedEventType, DECODED_EVENT_TYPES, ContractDeploySpec, ContractCallsParamsShape, ContractCallSpec, ChainTriggerShape, ChainTriggerOf, ChainEventFilterType, ChainEventFilterSpec, ChainEventFilter, CHAIN_EVENT_FILTER_TYPES, AssetIdentifier };