@secondlayer/sdk 6.18.0 → 6.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -328,8 +328,15 @@ const { data } = await sl.subgraphs.list();
328
328
  // Get
329
329
  const subgraph = await sl.subgraphs.get("my-subgraph");
330
330
 
331
- // Query table
332
- const rows = await sl.subgraphs.queryTable("my-subgraph", "transfers", {
331
+ // Open read (/v1) — keyless for public subgraphs; pass apiKey for your private ones
332
+ const { rows, next_cursor, tip } = await sl.subgraphs.rows("my-subgraph", "transfers", {
333
+ order: "desc",
334
+ limit: 50,
335
+ // cursor: next_cursor — pass back to resume
336
+ });
337
+
338
+ // Authed control-plane query (/api)
339
+ const page = await sl.subgraphs.queryTable("my-subgraph", "transfers", {
333
340
  sort: "block_height",
334
341
  order: "desc",
335
342
  limit: 50,
@@ -344,8 +351,12 @@ const spec = await sl.subgraphs.openapi("my-subgraph");
344
351
  const source = await sl.subgraphs.getSource("my-subgraph");
345
352
  const gaps = await sl.subgraphs.gaps("my-subgraph");
346
353
 
347
- // Deploy
348
- const result = await sl.subgraphs.deploy({ name, sources, schema, handlerCode });
354
+ // Deploy — managed deploys default visibility "public", BYO default "private"
355
+ const result = await sl.subgraphs.deploy({ name, sources, schema, handlerCode, visibility: "public" });
356
+
357
+ // Flip visibility — publish claims the global public name (409 PUBLIC_NAME_TAKEN if claimed)
358
+ await sl.subgraphs.publish("my-subgraph");
359
+ await sl.subgraphs.unpublish("my-subgraph");
349
360
  ```
350
361
 
351
362
  Stream rows live with the typed client — each table exposes `subscribe`
@@ -483,6 +494,52 @@ verifySecondlayerSignature(
483
494
  Prefer the per-subscription HMAC (Standard Webhooks) secret instead? Use
484
495
  `verifyWebhookSignature(rawBody, headers, secret)` — raw body first.
485
496
 
497
+ ## x402 pay-per-call (accountless)
498
+
499
+ Call the public `/v1/*` reads with **no API key, no account, no Stripe** — pay a
500
+ few hundredths of a cent per request from a Stacks wallet. Payment is **gasless**
501
+ (you sign; we sponsor the STX fee) and uses standard **x402 v2** on `stacks:1`.
502
+ Supported assets: **sBTC** (default), **USDCx**, **STX**.
503
+
504
+ > Keyed (`sk-sl_`) requests bypass x402 and bill through your plan — x402 is for
505
+ > accountless callers.
506
+
507
+ Drop-in `fetch` that pays on `402` automatically:
508
+
509
+ ```typescript
510
+ import { withX402, readX402Receipt } from "@secondlayer/sdk";
511
+ import { privateKeyToAccount } from "@secondlayer/stacks/accounts";
512
+
513
+ const x402fetch = withX402(fetch, {
514
+ account: privateKeyToAccount(process.env.AGENT_STACKS_KEY!), // funded with sBTC/USDCx
515
+ preferAssets: ["sBTC", "USDCx", "STX"], // optional (this is the default)
516
+ maxAmountPerCall: { sBTC: 2000n }, // optional spend guard (atomic units)
517
+ });
518
+
519
+ const res = await x402fetch(
520
+ "https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer",
521
+ );
522
+ const data = await res.json();
523
+ readX402Receipt(res); // { success, txid, payer, network } | null
524
+ ```
525
+
526
+ Or a small client returning `{ data, payment }`:
527
+
528
+ ```typescript
529
+ import { createX402Client } from "@secondlayer/sdk";
530
+
531
+ const sl = createX402Client({ account, baseUrl: "https://api.secondlayer.tools" });
532
+ const { data, payment } = await sl.get("/v1/index/events", {
533
+ query: { event_type: "ft_transfer" },
534
+ });
535
+ ```
536
+
537
+ The SDK selects an offer by `preferAssets` (skipping any over `maxAmountPerCall`,
538
+ else throws `X402SpendGuardError`), auto-resolves your account nonce, signs
539
+ origin-only, and retries. A paid call settles on-chain before returning
540
+ (confirmed-tier today, ~seconds; near-instant optimistic serve for Index/Streams
541
+ is rolling out). Discover capabilities at `GET /x402/supported`.
542
+
486
543
  ## Error Handling
487
544
 
488
545
  ```typescript
package/dist/index.d.ts CHANGED
@@ -52,6 +52,16 @@ interface SubgraphOperationStatus {
52
52
  createdAt: string;
53
53
  updatedAt: string;
54
54
  }
55
+ /** /v1 cursor envelope for subgraph table reads. */
56
+ interface SubgraphRowsEnvelope<T = unknown> {
57
+ rows: T[];
58
+ next_cursor: string | null;
59
+ tip: {
60
+ block_height: number
61
+ subgraph_height: number
62
+ blocks_behind: number
63
+ };
64
+ }
55
65
  interface BundleSubgraphResponse {
56
66
  ok: true;
57
67
  name: string;
@@ -94,6 +104,29 @@ declare class Subgraphs extends BaseClient {
94
104
  }): Promise<{
95
105
  message: string
96
106
  }>;
107
+ /**
108
+ * Publish: claim the name in the global public namespace and open anon
109
+ * reads on /v1/subgraphs/:name. 409 PUBLIC_NAME_TAKEN if another account
110
+ * holds the public name.
111
+ */
112
+ publish(name: string): Promise<{
113
+ name: string
114
+ visibility: "public"
115
+ url: string
116
+ }>;
117
+ /** Make reads private again (owning account's bearer key required). */
118
+ unpublish(name: string): Promise<{
119
+ name: string
120
+ visibility: "private"
121
+ }>;
122
+ /**
123
+ * Open /v1 read: cursor-paginated rows. Anon works for public subgraphs;
124
+ * pass an apiKey on the client for private ones. Resume with the returned
125
+ * `next_cursor`.
126
+ */
127
+ rows<T = unknown>(name: string, table: string, params?: Omit<SubgraphQueryParams, "offset" | "sort"> & {
128
+ cursor?: string
129
+ }): Promise<SubgraphRowsEnvelope<T>>;
97
130
  /** Recent reindex/backfill operations for a subgraph, newest first. */
98
131
  operations(name: string): Promise<{
99
132
  operations: SubgraphOperationStatus[]
@@ -232,6 +265,13 @@ declare class Contracts extends BaseClient {
232
265
  constructor(options?: Partial<SecondLayerOptions>);
233
266
  /** Find contracts conforming to `trait`. `trait` is required (server 400s without it). */
234
267
  list(params: ContractsListParams): Promise<ContractsEnvelope>;
268
+ /**
269
+ * Fetch a single contract from the registry by id (the prod-safe ABI source).
270
+ * Pass `{ includeAbi: true }` for the full ABI blob. Resolves null on 404.
271
+ */
272
+ get(contractId: string, opts?: {
273
+ includeAbi?: boolean
274
+ }): Promise<ContractSummary | null>;
235
275
  }
236
276
  /**
237
277
  * Typed client for the Foundation Datasets REST API (`/v1/datasets/*`).
@@ -382,6 +422,85 @@ declare class Datasets extends BaseClient {
382
422
  private paramsToQuery;
383
423
  private cursorDataset;
384
424
  }
425
+ import { RewardSet } from "@secondlayer/shared/node/consensus";
426
+ import { MerkleProofStep } from "@secondlayer/shared/node/nakamoto";
427
+ /**
428
+ * Trustless transaction-inclusion proof verification.
429
+ *
430
+ * Given a proof from `GET /v1/index/transactions/:txid/proof`, the consumer
431
+ * re-derives everything itself — it does NOT trust any value Secondlayer
432
+ * computed. Anchored level: (1) recompute the txid from the raw tx bytes, (2)
433
+ * fold it up the merkle path to the header's `tx_merkle_root`, (3) recompute the
434
+ * header's `block_hash` and `index_block_hash` from the raw header — "this tx is
435
+ * included in a header any node can corroborate". Consensus level (when the proof
436
+ * carries a `consensus` field, or a `rewardSet` is passed): additionally recover
437
+ * the header's signer signatures and confirm ≥70% of reward-set signer weight
438
+ * signed the block.
439
+ *
440
+ * Note: uses Node's crypto via `@secondlayer/shared` (same as the Streams
441
+ * signature verify); intended for Node/server verification.
442
+ */
443
+ interface TransactionProof {
444
+ txid: string;
445
+ index_block_hash: string;
446
+ block_height: number;
447
+ tx_index: number;
448
+ /** Raw consensus-serialized transaction bytes (hex). */
449
+ raw_tx: string;
450
+ /** Raw Nakamoto block-header bytes (hex) — parsed + re-hashed by the verifier. */
451
+ raw_header: string;
452
+ /** Authentication path from the tx leaf to `tx_merkle_root`. */
453
+ tx_merkle_path: MerkleProofStep[];
454
+ /** Present when consensus-level verification is available: the reward cycle and
455
+ * its signer set, against which the header's signer signatures are checked. */
456
+ consensus?: {
457
+ reward_cycle: number
458
+ reward_set: RewardSet
459
+ };
460
+ }
461
+ interface TransactionProofVerifyResult {
462
+ /** Highest level actually verified. "consensus" requires the proof's
463
+ * `consensus` field and a met signer-weight threshold. */
464
+ level: "anchored" | "consensus";
465
+ /** Recomputed txid === proof.txid. */
466
+ txidMatches: boolean;
467
+ /** Merkle path folds the txid to the header's tx_merkle_root. */
468
+ includedInHeader: boolean;
469
+ /** Recomputed block_hash + index_block_hash match the header / proof. */
470
+ headerSelfConsistent: boolean;
471
+ /** Basis points (0–10000) of reward-set signer weight that signed the block.
472
+ * Only set when the proof carries a `consensus` field. */
473
+ signerWeightBps?: number;
474
+ /** ≥70% of signer weight signed. Only set with a `consensus` field. */
475
+ thresholdMet?: boolean;
476
+ /** Which reward set the signer check used: "provided" (caller-resolved →
477
+ * fully trustless) or "embedded" (the one Secondlayer put in the proof). */
478
+ rewardSetSource?: "provided" | "embedded";
479
+ /** All applicable checks passed (incl. the threshold when consensus is present). */
480
+ ok: boolean;
481
+ errors: string[];
482
+ }
483
+ /**
484
+ * Resolve a reward set directly from a stacks-node (`/v3/stacker_set/{cycle}`),
485
+ * so a caller can verify the consensus layer against a node IT trusts rather than
486
+ * the reward set Secondlayer embedded in the proof. Pass the result as
487
+ * `verifyTransactionProof(proof, { rewardSet })`.
488
+ */
489
+ declare function fetchRewardSet(opts: {
490
+ nodeUrl: string
491
+ cycle: number
492
+ fetchImpl?: typeof fetch
493
+ }): Promise<RewardSet | null>;
494
+ /**
495
+ * Verify a transaction-inclusion proof. Every check is recomputed client-side,
496
+ * so a `true` result does not rely on trusting Secondlayer. Pass
497
+ * `{ rewardSet }` (resolved via {@link fetchRewardSet} from your own node) to
498
+ * verify the consensus layer against a reward set you trust rather than the one
499
+ * embedded in the proof.
500
+ */
501
+ declare function verifyTransactionProof(proof: TransactionProof, opts?: {
502
+ rewardSet?: RewardSet
503
+ }): TransactionProofVerifyResult;
385
504
  type IndexTip = {
386
505
  block_height: number
387
506
  lag_seconds: number
@@ -882,6 +1001,30 @@ type MempoolWalkParams = Omit<MempoolListParams, "limit"> & {
882
1001
  batchSize?: number
883
1002
  signal?: AbortSignal
884
1003
  };
1004
+ /**
1005
+ * `index.ftTransfers` — callable shorthand for `.list()`, with `.list`/`.walk`
1006
+ * still available: `await sl.index.ftTransfers({ contractId })`.
1007
+ *
1008
+ * The API accepts `contract_id`/`sender`/`recipient` equality filters only —
1009
+ * no amount filtering and no asset-slug resolution on /v1/index/ft-transfers.
1010
+ */
1011
+ interface FtTransfersResource {
1012
+ (params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
1013
+ list(params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
1014
+ walk(params?: FtTransfersWalkParams): AsyncIterable<FtTransfer>;
1015
+ }
1016
+ /** `index.nftTransfers` — callable shorthand for `.list()` (see {@link FtTransfersResource}). */
1017
+ interface NftTransfersResource {
1018
+ (params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
1019
+ list(params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
1020
+ walk(params?: NftTransfersWalkParams): AsyncIterable<NftTransfer>;
1021
+ }
1022
+ /** `index.events` — callable shorthand for `.list()`; `eventType` is required. */
1023
+ interface IndexEventsResource {
1024
+ (params: EventsListParams): Promise<EventsEnvelope>;
1025
+ list(params: EventsListParams): Promise<EventsEnvelope>;
1026
+ walk(params: EventsWalkParams): AsyncIterable<IndexEvent>;
1027
+ }
885
1028
  /** Per-event-type filter vocabulary in the {@link IndexDiscovery} doc. */
886
1029
  type IndexEventTypeFilters = {
887
1030
  columns?: string[]
@@ -906,19 +1049,13 @@ declare class Index extends BaseClient {
906
1049
  * learn what's queryable (and which types accept `trait`) instead of hardcoding.
907
1050
  */
908
1051
  discover(): Promise<IndexDiscovery>;
909
- readonly ftTransfers: {
910
- list: (params?: FtTransfersListParams) => Promise<FtTransfersEnvelope>
911
- walk: (params?: FtTransfersWalkParams) => AsyncIterable<FtTransfer>
912
- };
913
- readonly nftTransfers: {
914
- list: (params?: NftTransfersListParams) => Promise<NftTransfersEnvelope>
915
- walk: (params?: NftTransfersWalkParams) => AsyncIterable<NftTransfer>
916
- };
917
- /** Generic decoded events by `event_type` (the full /v1/index/events surface). */
918
- readonly events: {
919
- list: (params: EventsListParams) => Promise<EventsEnvelope>
920
- walk: (params: EventsWalkParams) => AsyncIterable<IndexEvent>
921
- };
1052
+ /** Callable: `index.ftTransfers(params)` ≡ `index.ftTransfers.list(params)`. */
1053
+ readonly ftTransfers: FtTransfersResource;
1054
+ /** Callable: `index.nftTransfers(params)` ≡ `index.nftTransfers.list(params)`. */
1055
+ readonly nftTransfers: NftTransfersResource;
1056
+ /** Generic decoded events by `event_type` (the full /v1/index/events surface).
1057
+ * Callable: `index.events(params)` ≡ `index.events.list(params)`. */
1058
+ readonly events: IndexEventsResource;
922
1059
  readonly contractCalls: {
923
1060
  list: (params?: ContractCallsListParams) => Promise<ContractCallsEnvelope>
924
1061
  walk: (params?: ContractCallsWalkParams) => AsyncIterable<IndexContractCall>
@@ -941,6 +1078,7 @@ declare class Index extends BaseClient {
941
1078
  list: (params?: TransactionsListParams) => Promise<TransactionsEnvelope>
942
1079
  walk: (params?: TransactionsWalkParams) => AsyncIterable<IndexTransaction>
943
1080
  get: (txId: string) => Promise<TransactionEnvelope | null>
1081
+ getProof: (txId: string) => Promise<TransactionProof | null>
944
1082
  };
945
1083
  /** Decoded PoX-4 stacking actions. Empty (with a `notes` hint) when the
946
1084
  * platform's PoX-4 decoder is disabled. */
@@ -970,6 +1108,11 @@ declare class Index extends BaseClient {
970
1108
  private walkBlocks;
971
1109
  private listTransactions;
972
1110
  private getTransaction;
1111
+ /** Fetch the inclusion proof for a tx (raw tx + Nakamoto header + merkle path)
1112
+ * to verify client-side with `verifyTransactionProof`. 404 → null. A 503
1113
+ * (`PROOF_TX_SET_INCOMPLETE` / `PROOF_NODE_UNAVAILABLE`) surfaces as an
1114
+ * ApiError — the proof can't be assembled on this deployment right now. */
1115
+ private getTransactionProof;
973
1116
  private walkTransactions;
974
1117
  private listStacking;
975
1118
  private walkStacking;
@@ -1297,6 +1440,36 @@ type StreamsEventsConsumeParams = {
1297
1440
  maxEmptyPolls?: number
1298
1441
  signal?: AbortSignal
1299
1442
  };
1443
+ /**
1444
+ * One yielded page from {@link StreamsClient.consume} — the
1445
+ * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
1446
+ * `cursor` (the checkpoint to persist and resume from).
1447
+ */
1448
+ type StreamsBatch = {
1449
+ /** Canonical events of this page, in cursor order. */
1450
+ events: StreamsEvent[]
1451
+ /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
1452
+ cursor: string | null
1453
+ tip: StreamsTip
1454
+ /** Chain reorgs reported alongside this page; empty when none. */
1455
+ reorgs: StreamsReorg[]
1456
+ };
1457
+ type StreamsConsumeParams = {
1458
+ /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
1459
+ cursor?: string | null
1460
+ types?: readonly StreamsEventType[]
1461
+ notTypes?: readonly StreamsEventType[]
1462
+ contractId?: StreamsFilterValue
1463
+ sender?: StreamsFilterValue
1464
+ recipient?: StreamsFilterValue
1465
+ assetIdentifier?: string
1466
+ /** Events per page (the `limit` query param). Default 100. */
1467
+ batchSize?: number
1468
+ /** Poll interval while caught up at the tip, in ms. Default 2000. */
1469
+ intervalMs?: number
1470
+ /** Abort to end the iteration. */
1471
+ signal?: AbortSignal
1472
+ };
1300
1473
  type StreamsEventsConsumeResult = {
1301
1474
  cursor: string | null
1302
1475
  pages: number
@@ -1365,6 +1538,21 @@ type StreamsDumps = {
1365
1538
  download(file: StreamsDumpFile): Promise<Uint8Array>
1366
1539
  };
1367
1540
  type StreamsClient = {
1541
+ /**
1542
+ * Follow Streams as an async iterator of page batches.
1543
+ *
1544
+ * Yields one {@link StreamsBatch} per `GET /v1/streams/events` page — the
1545
+ * existing envelope (`events`, `next_cursor` → `cursor`, `tip`, `reorgs`)
1546
+ * with zero extra API calls. Batches are chosen over per-block groupings
1547
+ * because the envelope is page-keyed, so every yield is exactly one fetch.
1548
+ * Empty pages are skipped; at the tip the iterator re-polls every
1549
+ * `intervalMs` (default 2000) until aborted via `signal`.
1550
+ *
1551
+ * Reorgs are surfaced on the batch (`batch.reorgs`) but the cursor is not
1552
+ * rewound automatically — use `events.consume` with `onReorg` for managed
1553
+ * rollback semantics.
1554
+ */
1555
+ consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
1368
1556
  events: {
1369
1557
  list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
1370
1558
  byTxId(txId: string): Promise<StreamsEventsListEnvelope>
@@ -1861,6 +2049,152 @@ declare const Cursor: {
1861
2049
  }
1862
2050
  };
1863
2051
  type DecodedEventRow = DecodedFtTransfer | DecodedNftTransfer | DecodedStxTransfer | DecodedStxMint | DecodedStxBurn | DecodedStxLock | DecodedFtMint | DecodedFtBurn | DecodedNftMint | DecodedNftBurn | DecodedPrint;
2052
+ import { X402TokenSymbol } from "@secondlayer/shared/x402";
2053
+ import { LocalAccount } from "@secondlayer/stacks/accounts";
2054
+ import { StacksChain } from "@secondlayer/stacks/chains";
2055
+ /**
2056
+ * Client for the x402 pay-per-request rail. Turns a 402 challenge into a signed
2057
+ * `PAYMENT-SIGNATURE` and retries — gasless (the agent signs origin-only; the
2058
+ * facilitator sponsors the STX fee) and accountless (no key/Stripe/session).
2059
+ *
2060
+ * Three layers:
2061
+ * - `withX402(fetch, opts)` — drop-in fetch that auto-pays on 402.
2062
+ * - `createX402Client(opts)` — `.get/.post` returning `{ data, payment }`.
2063
+ * - `buildSignedX402Payment` / `readX402Challenge` — primitives for custom transports.
2064
+ */
2065
+ type X402Accept = {
2066
+ scheme: "exact"
2067
+ network: string
2068
+ asset: string
2069
+ /** Atomic units. */
2070
+ amount: string
2071
+ payTo: string
2072
+ maxTimeoutSeconds: number
2073
+ extra: {
2074
+ nonce: string
2075
+ }
2076
+ };
2077
+ type X402Challenge = {
2078
+ x402Version: number
2079
+ accepts: X402Accept[]
2080
+ error?: string
2081
+ };
2082
+ /** Decoded `PAYMENT-RESPONSE` settlement receipt. */
2083
+ type X402Receipt = {
2084
+ success: boolean
2085
+ /** Settlement tier: `optimistic` (served on broadcast-accept, reconciled
2086
+ * async) or `confirmed` (canonical). Absent on older deployments. */
2087
+ state?: "optimistic" | "confirmed"
2088
+ txid: string
2089
+ payer: string
2090
+ network: string
2091
+ };
2092
+ /** Bitcoin-native first — sBTC is the compelling micropay asset; USDCx the
2093
+ * dollar peg; STX the fallback. Override via `preferAssets`. */
2094
+ declare const DEFAULT_PREFER_ASSETS: X402TokenSymbol[];
2095
+ /** Thrown when no offered asset is within the caller's spend guard / preferences. */
2096
+ declare class X402SpendGuardError extends Error {
2097
+ constructor(message: string);
2098
+ }
2099
+ /** Read the x402 challenge from a 402 response — prefer the wire header, fall
2100
+ * back to the JSON body. */
2101
+ declare function readX402Challenge(res: Response): Promise<X402Challenge | null>;
2102
+ /** Read the settlement receipt from a paid 200 response. */
2103
+ declare function readX402Receipt(res: Response): X402Receipt | null;
2104
+ type SelectOfferOptions = {
2105
+ preferAssets?: X402TokenSymbol[]
2106
+ maxAmountPerCall?: Partial<Record<X402TokenSymbol, bigint>>
2107
+ };
2108
+ /** Choose an `accepts[]` entry by preference order, skipping any that exceed the
2109
+ * per-asset spend cap. Throws {@link X402SpendGuardError} if none qualify. */
2110
+ declare function selectOffer(challenge: X402Challenge, opts?: SelectOfferOptions): {
2111
+ accept: X402Accept
2112
+ symbol: X402TokenSymbol
2113
+ };
2114
+ /** Fetch the payer account's next nonce from a Stacks node (`/v2/accounts`). */
2115
+ declare function resolveAccountNonce(address: string, nodeUrl?: string): Promise<number>;
2116
+ type BuildSignedX402PaymentOptions = {
2117
+ challenge: X402Challenge
2118
+ account: LocalAccount
2119
+ /** The payer account's next nonce. */
2120
+ accountNonce: bigint | number | string
2121
+ /** Preferred asset string (e.g. an sBTC/USDCx id). Defaults to the first offer. */
2122
+ asset?: string
2123
+ chain?: StacksChain
2124
+ };
2125
+ /** Build a signed, base64 `PAYMENT-SIGNATURE` header for one `accepts[]` entry. */
2126
+ declare function buildSignedX402Payment(opts: BuildSignedX402PaymentOptions): Promise<{
2127
+ header: string
2128
+ accept: X402Accept
2129
+ }>;
2130
+ type WithX402Options = SelectOfferOptions & {
2131
+ account: LocalAccount
2132
+ /** Override the payer nonce; auto-resolved from `nodeUrl` when omitted. */
2133
+ accountNonce?: bigint | number | string
2134
+ /** Node for auto-nonce lookup. Defaults to {@link DEFAULT_NONCE_NODE_URL}. */
2135
+ nodeUrl?: string
2136
+ chain?: StacksChain
2137
+ /** Fired just before the paid retry (the call then blocks on confirmed-tier
2138
+ * settle, or returns near-instantly on an optimistic surface). */
2139
+ onSettling?: (info: {
2140
+ asset: string
2141
+ amount: string
2142
+ }) => void
2143
+ /** Abort the paid retry after this long. */
2144
+ timeoutMs?: number
2145
+ };
2146
+ type X402Fetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
2147
+ /**
2148
+ * Wrap a `fetch` so requests transparently pay on 402: select an offer (by
2149
+ * `preferAssets` + `maxAmountPerCall`), resolve the nonce, sign origin-only, and
2150
+ * retry once with `PAYMENT-SIGNATURE`. Returns the final `Response` (read the
2151
+ * receipt with {@link readX402Receipt}).
2152
+ *
2153
+ * @example
2154
+ * const x402fetch = withX402(fetch, { account });
2155
+ * const res = await x402fetch("https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer");
2156
+ */
2157
+ declare function withX402(baseFetch: typeof fetch, opts: WithX402Options): X402Fetch;
2158
+ type X402ClientOptions = WithX402Options & {
2159
+ baseUrl: string
2160
+ /** Override the underlying fetch (tests). */
2161
+ fetch?: typeof fetch
2162
+ };
2163
+ type X402Result<T = unknown> = {
2164
+ data: T
2165
+ /** Settlement receipt, or null if the response carried none. */
2166
+ payment: X402Receipt | null
2167
+ response: Response
2168
+ };
2169
+ type X402Client = {
2170
+ get<T = unknown>(path: string, o?: {
2171
+ query?: Record<string, string>
2172
+ }): Promise<X402Result<T>>
2173
+ post<T = unknown>(path: string, o?: {
2174
+ body?: unknown
2175
+ }): Promise<X402Result<T>>
2176
+ };
2177
+ /**
2178
+ * A small client over {@link withX402}: `.get/.post` against `baseUrl`, returning
2179
+ * parsed JSON plus the settlement receipt.
2180
+ *
2181
+ * @example
2182
+ * const sl = createX402Client({ account, baseUrl: "https://api.secondlayer.tools" });
2183
+ * const { data, payment } = await sl.get("/v1/index/events", { query: { event_type: "ft_transfer" } });
2184
+ */
2185
+ declare function createX402Client(opts: X402ClientOptions): X402Client;
2186
+ /** Caller-supplied fetch that re-runs the request with the given extra headers. */
2187
+ type X402FetchFn = (extraHeaders: Record<string, string>) => Promise<Response>;
2188
+ type PayAndRetryOptions = Omit<WithX402Options, never> & {
2189
+ /** Required here (use `withX402` for auto-nonce). */
2190
+ accountNonce: bigint | number | string
2191
+ };
2192
+ /**
2193
+ * Low-level: run a request via a caller-controlled fetch; if it 402s, pay and
2194
+ * retry once. Prefer {@link withX402} for the common case (it auto-resolves the
2195
+ * nonce + selects the asset). Kept for custom transports.
2196
+ */
2197
+ declare function payAndRetry(doFetch: X402FetchFn, opts: PayAndRetryOptions): Promise<Response>;
1864
2198
  import { SubgraphAgentSchema as SubgraphAgentSchema3, SubgraphSpecFormat as SubgraphSpecFormat2, SubgraphSpecOptions as SubgraphSpecOptions3 } from "@secondlayer/shared/subgraphs/spec";
1865
2199
  import { ByoBreakingChangeDetails } from "@secondlayer/shared/errors";
1866
2200
  /**
@@ -2026,85 +2360,6 @@ declare function verifyWebhookSignature(rawBody: string, headers: WebhookHeaderI
2026
2360
  * ```
2027
2361
  */
2028
2362
  declare function verifySecondlayerSignature(rawBody: string, headers: WebhookHeaderInput, publicKeyPem: string): boolean;
2029
- import { RewardSet } from "@secondlayer/shared/node/consensus";
2030
- import { MerkleProofStep } from "@secondlayer/shared/node/nakamoto";
2031
- /**
2032
- * Trustless transaction-inclusion proof verification.
2033
- *
2034
- * Given a proof from `GET /v1/index/transactions/:txid/proof`, the consumer
2035
- * re-derives everything itself — it does NOT trust any value Secondlayer
2036
- * computed. Anchored level: (1) recompute the txid from the raw tx bytes, (2)
2037
- * fold it up the merkle path to the header's `tx_merkle_root`, (3) recompute the
2038
- * header's `block_hash` and `index_block_hash` from the raw header — "this tx is
2039
- * included in a header any node can corroborate". Consensus level (when the proof
2040
- * carries a `consensus` field, or a `rewardSet` is passed): additionally recover
2041
- * the header's signer signatures and confirm ≥70% of reward-set signer weight
2042
- * signed the block.
2043
- *
2044
- * Note: uses Node's crypto via `@secondlayer/shared` (same as the Streams
2045
- * signature verify); intended for Node/server verification.
2046
- */
2047
- interface TransactionProof {
2048
- txid: string;
2049
- index_block_hash: string;
2050
- block_height: number;
2051
- tx_index: number;
2052
- /** Raw consensus-serialized transaction bytes (hex). */
2053
- raw_tx: string;
2054
- /** Raw Nakamoto block-header bytes (hex) — parsed + re-hashed by the verifier. */
2055
- raw_header: string;
2056
- /** Authentication path from the tx leaf to `tx_merkle_root`. */
2057
- tx_merkle_path: MerkleProofStep[];
2058
- /** Present when consensus-level verification is available: the reward cycle and
2059
- * its signer set, against which the header's signer signatures are checked. */
2060
- consensus?: {
2061
- reward_cycle: number
2062
- reward_set: RewardSet
2063
- };
2064
- }
2065
- interface TransactionProofVerifyResult {
2066
- /** Highest level actually verified. "consensus" requires the proof's
2067
- * `consensus` field and a met signer-weight threshold. */
2068
- level: "anchored" | "consensus";
2069
- /** Recomputed txid === proof.txid. */
2070
- txidMatches: boolean;
2071
- /** Merkle path folds the txid to the header's tx_merkle_root. */
2072
- includedInHeader: boolean;
2073
- /** Recomputed block_hash + index_block_hash match the header / proof. */
2074
- headerSelfConsistent: boolean;
2075
- /** Basis points (0–10000) of reward-set signer weight that signed the block.
2076
- * Only set when the proof carries a `consensus` field. */
2077
- signerWeightBps?: number;
2078
- /** ≥70% of signer weight signed. Only set with a `consensus` field. */
2079
- thresholdMet?: boolean;
2080
- /** Which reward set the signer check used: "provided" (caller-resolved →
2081
- * fully trustless) or "embedded" (the one Secondlayer put in the proof). */
2082
- rewardSetSource?: "provided" | "embedded";
2083
- /** All applicable checks passed (incl. the threshold when consensus is present). */
2084
- ok: boolean;
2085
- errors: string[];
2086
- }
2087
- /**
2088
- * Resolve a reward set directly from a stacks-node (`/v3/stacker_set/{cycle}`),
2089
- * so a caller can verify the consensus layer against a node IT trusts rather than
2090
- * the reward set Secondlayer embedded in the proof. Pass the result as
2091
- * `verifyTransactionProof(proof, { rewardSet })`.
2092
- */
2093
- declare function fetchRewardSet(opts: {
2094
- nodeUrl: string
2095
- cycle: number
2096
- fetchImpl?: typeof fetch
2097
- }): Promise<RewardSet | null>;
2098
- /**
2099
- * Verify a transaction-inclusion proof. Every check is recomputed client-side,
2100
- * so a `true` result does not rely on trusting Secondlayer. Pass
2101
- * `{ rewardSet }` (resolved via {@link fetchRewardSet} from your own node) to
2102
- * verify the consensus layer against a reward set you trust rather than the one
2103
- * embedded in the proof.
2104
- */
2105
- declare function verifyTransactionProof(proof: TransactionProof, opts?: {
2106
- rewardSet?: RewardSet
2107
- }): TransactionProofVerifyResult;
2108
2363
  import { RewardSet as RewardSet2 } from "@secondlayer/shared/node/consensus";
2109
2364
  /** Make a cvToValue result JSON-serializable: Clarity (u)ints decode to bigint,
2110
2365
  * which JSON.stringify can't handle — convert recursively to strings. */
@@ -2112,4 +2367,4 @@ declare function toJsonSafe(value: unknown): unknown;
2112
2367
  /** Decode a hex-encoded Clarity value to JSON-safe JS (uints as strings,
2113
2368
  * buffers as `0x…` hex, tuples as objects). Returns the input hex on failure. */
2114
2369
  declare function decodeClarityValue(hex: string): unknown;
2115
- export { verifyWebhookSignature, verifyTransactionProof, verifySecondlayerSignature, trigger, toJsonSafe, isStxTransfer, isStxMint, isStxLock, isStxBurn, isPrint, isNftTransfer, isNftMint, isNftBurn, isFtTransfer, isFtMint, isFtBurn, getSubgraph, fetchRewardSet, decodeStxTransfer, decodeStxMint, decodeStxLock, decodeStxBurn, decodePrint, decodeNftTransfer, decodeNftMint, decodeNftBurn, decodeFtTransfer, decodeFtMint, decodeFtBurn, decodeClarityValue, createStreamsClient, VersionConflictError, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, UpdateProjectParams, TransactionsWalkParams, TransactionsListParams, TransactionsEnvelope, TransactionProofVerifyResult, TransactionProof, TransactionEnvelope, Subscriptions, SubscriptionSummary2 as SubscriptionSummary, SubscriptionStatus, SubscriptionRuntime, SubscriptionKind, SubscriptionFormat, SubscriptionDetail2 as SubscriptionDetail, Subgraphs, SubgraphSpecOptions3 as SubgraphSpecOptions, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphOperationStatus, SubgraphAgentSchema3 as SubgraphAgentSchema, StreamsUsage, StreamsTip, StreamsSignatureError, StreamsServerError, StreamsReorgsListParams, StreamsReorgsListEnvelope, StreamsReorgContext, StreamsReorg, StreamsEventsSubscribeParams, StreamsEventsStreamParams, StreamsEventsListParams, StreamsEventsListEnvelope, StreamsEventsEnvelope, StreamsEventsConsumeResult, StreamsEventsConsumeParams, StreamsEventType, StreamsEventPayload, StreamsEvent, StreamsDumpsManifest, StreamsDumps, StreamsDumpFile, StreamsClient, StreamsCanonicalBlock, StreamsBatchContext, StackingWalkParams, StackingListParams, StackingEnvelope, SecondLayerOptions, SecondLayer, ScopedKeyProduct, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, Pox4CallsParams, NftTransfersWalkParams, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStackingAction, IndexReorg, IndexPostCondition, IndexMempoolTransaction, IndexEventTypeFilters, IndexEventType, IndexEvent, IndexDiscovery, IndexContractCall, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, DeliveryRow2 as DeliveryRow, DecodedStxTransferPayload, DecodedStxTransfer, DecodedStxMintPayload, DecodedStxMint, DecodedStxLockPayload, DecodedStxLock, DecodedStxBurnPayload, DecodedStxBurn, DecodedPrintValue, DecodedPrintPayload, DecodedPrint, DecodedNftTransferPayload, DecodedNftTransfer, DecodedNftMintPayload, DecodedNftMint, DecodedNftBurnPayload, DecodedNftBurn, DecodedFtTransferPayload, DecodedFtTransfer, DecodedFtMintPayload, DecodedFtMint, DecodedFtBurnPayload, DecodedFtBurn, DecodedEventRow, DecodedEventColumns, DeadRow2 as DeadRow, Datasets, DatasetRow, CursorListParams, CursorEnvelope, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, CreateProjectParams, CreateApiKeyResponse, CreateApiKeyParams, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ChainTriggerType, ChainTrigger, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, CURSOR_SLUGS, ByoBreakingChangeError, ByoBreakingChangeDetails, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };
2370
+ export { withX402, verifyWebhookSignature, verifyTransactionProof, verifySecondlayerSignature, trigger, toJsonSafe, selectOffer, resolveAccountNonce, readX402Receipt, readX402Challenge, payAndRetry, isStxTransfer, isStxMint, isStxLock, isStxBurn, isPrint, isNftTransfer, isNftMint, isNftBurn, isFtTransfer, isFtMint, isFtBurn, getSubgraph, fetchRewardSet, decodeStxTransfer, decodeStxMint, decodeStxLock, decodeStxBurn, decodePrint, decodeNftTransfer, decodeNftMint, decodeNftBurn, decodeFtTransfer, decodeFtMint, decodeFtBurn, decodeClarityValue, createX402Client, createStreamsClient, buildSignedX402Payment, X402SpendGuardError, X402Result, X402Receipt, X402Fetch, X402ClientOptions, X402Client, X402Challenge, X402Accept, WithX402Options, VersionConflictError, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, UpdateProjectParams, TransactionsWalkParams, TransactionsListParams, TransactionsEnvelope, TransactionProofVerifyResult, TransactionProof, TransactionEnvelope, Subscriptions, SubscriptionSummary2 as SubscriptionSummary, SubscriptionStatus, SubscriptionRuntime, SubscriptionKind, SubscriptionFormat, SubscriptionDetail2 as SubscriptionDetail, Subgraphs, SubgraphSpecOptions3 as SubgraphSpecOptions, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphOperationStatus, SubgraphAgentSchema3 as SubgraphAgentSchema, StreamsUsage, StreamsTip, StreamsSignatureError, StreamsServerError, StreamsReorgsListParams, StreamsReorgsListEnvelope, StreamsReorgContext, StreamsReorg, StreamsEventsSubscribeParams, StreamsEventsStreamParams, StreamsEventsListParams, StreamsEventsListEnvelope, StreamsEventsEnvelope, StreamsEventsConsumeResult, StreamsEventsConsumeParams, StreamsEventType, StreamsEventPayload, StreamsEvent, StreamsDumpsManifest, StreamsDumps, StreamsDumpFile, StreamsConsumeParams, StreamsClient, StreamsCanonicalBlock, StreamsBatchContext, StreamsBatch, StackingWalkParams, StackingListParams, StackingEnvelope, SelectOfferOptions, SecondLayerOptions, SecondLayer, ScopedKeyProduct, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, Pox4CallsParams, PayAndRetryOptions, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStackingAction, IndexReorg, IndexPostCondition, IndexMempoolTransaction, IndexEventsResource, IndexEventTypeFilters, IndexEventType, IndexEvent, IndexDiscovery, IndexContractCall, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, DeliveryRow2 as DeliveryRow, DecodedStxTransferPayload, DecodedStxTransfer, DecodedStxMintPayload, DecodedStxMint, DecodedStxLockPayload, DecodedStxLock, DecodedStxBurnPayload, DecodedStxBurn, DecodedPrintValue, DecodedPrintPayload, DecodedPrint, DecodedNftTransferPayload, DecodedNftTransfer, DecodedNftMintPayload, DecodedNftMint, DecodedNftBurnPayload, DecodedNftBurn, DecodedFtTransferPayload, DecodedFtTransfer, DecodedFtMintPayload, DecodedFtMint, DecodedFtBurnPayload, DecodedFtBurn, DecodedEventRow, DecodedEventColumns, DeadRow2 as DeadRow, Datasets, DatasetRow, DEFAULT_PREFER_ASSETS, CursorListParams, CursorEnvelope, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, CreateProjectParams, CreateApiKeyResponse, CreateApiKeyParams, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ChainTriggerType, ChainTrigger, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, CURSOR_SLUGS, ByoBreakingChangeError, ByoBreakingChangeDetails, BuildSignedX402PaymentOptions, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };