@johannc-dev/zyrk 0.0.0-stage → 0.2.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/dist/sdk.d.ts ADDED
@@ -0,0 +1,1129 @@
1
+ /**
2
+ * `@johannc-dev/zyrk` 0.2: what a hosted program imports.
3
+ *
4
+ * This module is bundled into the program: it has no dependency and its
5
+ * runtime part is a handful of small, neutral helpers (reading a row of an
6
+ * {@link HourBatch}, building a trade id). It ships tooling, never a strategy.
7
+ */
8
+ export type Json = null | boolean | number | string | Json[] | {
9
+ [key: string]: Json;
10
+ };
11
+ /**
12
+ * What a program sends (results, state, job arguments, logs, emits): JSON,
13
+ * read-only arrays accepted, `undefined` properties dropped as by
14
+ * `JSON.stringify`.
15
+ */
16
+ export type JsonInput = null | boolean | number | string | readonly JsonInput[] | {
17
+ readonly [key: string]: JsonInput | undefined;
18
+ };
19
+ /** A base58 Solana address (mint, wallet, pool). */
20
+ export type Address = string;
21
+ /**
22
+ * A history window, `[sinceMs, untilMs)` in milliseconds since the epoch,
23
+ * at most 31 days long.
24
+ */
25
+ export interface Window {
26
+ readonly sinceMs: number;
27
+ readonly untilMs: number;
28
+ /**
29
+ * Accept hours with gaps or rejected operations instead of failing with
30
+ * `partial_coverage`. Such batches have `complete: false`.
31
+ */
32
+ readonly allowPartial?: boolean;
33
+ /** Fill `HourBatch.signatures` (88 characters per trade: ask only if needed). */
34
+ readonly withSignatures?: boolean;
35
+ /**
36
+ * Fill `HourBatch.market`: pool reserves, fee rates, signer, priority fee
37
+ * and flags of each trade (75 more bytes per trade, counted in the read
38
+ * limit). Without it these fields are neither read nor sent.
39
+ */
40
+ readonly withMarket?: boolean;
41
+ /**
42
+ * Also return pool events as rows with `side` {@link Side.event} and their
43
+ * kind in `market.event` (implies `withMarket`). Token reads: every event of
44
+ * the mint (creation, migration, pool creation, liquidity added or
45
+ * removed). Wallet reads: the tokens the wallet created. Event rows have
46
+ * `op` 65535; skip them (`side[i] === Side.event`) when you sum trades.
47
+ */
48
+ readonly withEvents?: boolean;
49
+ /**
50
+ * Fill `HourBatch.order` (on-chain order: transaction index, event rank,
51
+ * block time) and deliver each batch in on-chain order instead of provider
52
+ * order. 15 bytes per trade.
53
+ */
54
+ readonly withOrder?: boolean;
55
+ /**
56
+ * Fill `HourBatch.tx`: the transaction of each trade (an id shared by the
57
+ * trades of one transaction, kept after signatures are dropped) and its
58
+ * place in it. Does not change the batch order. 7 bytes per trade.
59
+ */
60
+ readonly withTx?: boolean;
61
+ }
62
+ /** Options of `ctx.data.walletTrades` and `ctx.data.tokenTrades`. */
63
+ export interface TradeQuery extends Window {
64
+ /** Only buys or only sells. Default: both. */
65
+ readonly side?: "buy" | "sell";
66
+ }
67
+ /** `HourBatch.side` values. */
68
+ export declare const Side: {
69
+ readonly buy: 0;
70
+ readonly sell: 1;
71
+ readonly event: 2;
72
+ };
73
+ /** `HourBatch.protocol` values. */
74
+ export declare const Protocol: {
75
+ readonly pumpfun: 0;
76
+ readonly pumpswap: 1;
77
+ };
78
+ /** Bits of `HourBatch.order.flags`. A trade has `known` or one `unknown*` reason. */
79
+ export declare const OrderFlag: {
80
+ /** `txIndex` and `eventIndex` are set. */
81
+ readonly known: 1;
82
+ /** Joined by the trade's signature. */
83
+ readonly bySignature: 2;
84
+ /**
85
+ * An identical trade (same slot, pool, trader and amounts) sits in another
86
+ * transaction of the slot: which of the two is which is not certain.
87
+ */
88
+ readonly ambiguous: 4;
89
+ /** An amount of the trade equals none of its chain event's. */
90
+ readonly amountDiffers: 8;
91
+ /** The slot's block was searched; no transaction fits the trade. */
92
+ readonly unknownNoMatch: 16;
93
+ /** Order not known yet: open hour, hour not ordered yet, slot not covered. */
94
+ readonly unknownNotCovered: 32;
95
+ /** Nothing to join (no slot, or no operation with a chain event). */
96
+ readonly unknownNoKey: 64;
97
+ /**
98
+ * The finalized chain has no block at the trade's slot (skipped slot,
99
+ * abandoned fork): the provider published a trade that did not happen.
100
+ * Drop it from a backtest.
101
+ */
102
+ readonly notFinalized: 128;
103
+ };
104
+ /** `order.txIndex` value when unknown. */
105
+ export declare const NO_TX_INDEX = 4294967295;
106
+ /** `order.eventIndex` value when unknown. */
107
+ export declare const NO_EVENT_INDEX = 65535;
108
+ /**
109
+ * On-chain order of each trade of a batch (`withOrder: true`). With it, the
110
+ * batch is sorted by `(slot, txIndex, eventIndex)`, trades of unknown order
111
+ * last within their slot. `(slot, txIndex)` names the transaction.
112
+ */
113
+ export interface OrderColumns {
114
+ /** Index of the transaction in its block (votes included, as `getBlock`); {@link NO_TX_INDEX} when unknown. */
115
+ readonly txIndex: Uint32Array;
116
+ /**
117
+ * Rank of the trade's event among the Pump.fun/PumpSwap events of its
118
+ * transaction, in execution order; {@link NO_EVENT_INDEX} when unknown.
119
+ */
120
+ readonly eventIndex: Uint16Array;
121
+ /** Block time from the chain in ms (1 s resolution); `NaN` when unknown. */
122
+ readonly blockTimeMs: Float64Array;
123
+ /** {@link OrderFlag} bits. */
124
+ readonly flags: Uint8Array;
125
+ }
126
+ /** `tx.id` value when the transaction is unknown. */
127
+ export declare const NO_TX_ID = 4294967295;
128
+ /**
129
+ * Bits of `HourBatch.tx.flags`. A trade has one grouping bit
130
+ * (`bySignature`, `byChain` or `unknown`) and, when grouped, one index bit
131
+ * (`chainIndex` or `providerIndex`).
132
+ */
133
+ export declare const TxFlag: {
134
+ /** Grouped by its signature (live, sealing or provider archive). */
135
+ readonly bySignature: 1;
136
+ /** Grouped by its on-chain `(slot, txIndex)`, for an hour stored without signatures. */
137
+ readonly byChain: 2;
138
+ /** `index` is the on-chain event rank: exact execution order. */
139
+ readonly chainIndex: 4;
140
+ /**
141
+ * `index` is the provider's order. The provider groups the events of a
142
+ * transaction by type (transfers, trades, liquidity, fees): not exact,
143
+ * though it matched the chain for 99.9 % of the pairs of trades measured.
144
+ */
145
+ readonly providerIndex: 8;
146
+ /** No transaction known: `id` is {@link NO_TX_ID}. */
147
+ readonly unknown: 16;
148
+ };
149
+ /**
150
+ * The transaction of each trade of a batch (`withTx: true`). Trades of one
151
+ * batch with the same `id` are in the same transaction (a route through
152
+ * several pools, a bundle-like multi-operation transaction): `id` is unique
153
+ * within the hour (the provider line of the transaction's first row), so
154
+ * `(hour, id)` names it. Order the trades of one transaction by `index`
155
+ * when they share the same index bit of `flags`, else by `(line, op)`.
156
+ */
157
+ export interface TxColumns {
158
+ /** Transaction id within the hour; {@link NO_TX_ID} when unknown. */
159
+ readonly id: Uint32Array;
160
+ /** Place of the trade in its transaction (see {@link TxFlag}); 65535 when unknown. */
161
+ readonly index: Uint16Array;
162
+ /** {@link TxFlag} bits. */
163
+ readonly flags: Uint8Array;
164
+ }
165
+ /** Value of an address column (`pool`, `trader`) when the address is absent. */
166
+ export declare const NO_ADDRESS = -1;
167
+ export declare const HOUR_MS = 3600000;
168
+ /** Wrapped SOL, the usual quote mint. */
169
+ export declare const SOL_MINT: Address;
170
+ /**
171
+ * The trades of one hour of a window, as columns: entry `i` of every array
172
+ * describes trade `i`. Rows are in provider order `(hour, line, op)`, or in
173
+ * on-chain order with `withOrder: true` (see {@link OrderColumns}).
174
+ *
175
+ * Arrays are read-only views of server memory, valid for the whole
176
+ * execution. Copy what you keep (`Array.from`, `slice`) only if you need to
177
+ * modify it. Floats use `NaN` for an absent value.
178
+ */
179
+ export interface HourBatch {
180
+ /**
181
+ * Hour of the file the trades are stored in: `hour * 3_600_000` is its
182
+ * first millisecond. The provider files a trade by its reception, so a few
183
+ * trades may carry a `timeMs` just outside this hour (still in the window).
184
+ */
185
+ readonly hour: number;
186
+ /** `sealed`: final. `live`: the open hour, may still change once sealed. */
187
+ readonly source: "sealed" | "live";
188
+ /**
189
+ * No gap and no rejected operation in this hour for this read. With
190
+ * `allowPartial`, an hour of the window with a coverage gap and no trade
191
+ * still comes, empty (`length: 0`) and `complete: false`.
192
+ */
193
+ readonly complete: boolean;
194
+ /** Operations of this hour that could not be normalized (not in the batch). */
195
+ readonly skipped: number;
196
+ /** Number of trades: the length of every column. */
197
+ readonly length: number;
198
+ /** Dictionary of this batch. `mint`, `pool`, `trader`, `quoteMint` index it. */
199
+ readonly addresses: readonly Address[];
200
+ readonly line: Uint32Array;
201
+ readonly op: Uint16Array;
202
+ readonly slot: Float64Array;
203
+ readonly timeMs: Float64Array;
204
+ /** Reception time for live trades; `NaN` when unknown. */
205
+ readonly receivedMs: Float64Array;
206
+ /** `0` buy, `1` sell (see {@link Side}). */
207
+ readonly side: Uint8Array;
208
+ /** `0` pumpfun (bonding curve), `1` pumpswap (AMM) (see {@link Protocol}). */
209
+ readonly protocol: Uint8Array;
210
+ readonly mint: Uint32Array;
211
+ /** `-1` when absent. */
212
+ readonly pool: Int32Array;
213
+ /** `-1` when absent. */
214
+ readonly trader: Int32Array;
215
+ readonly quoteMint: Uint32Array;
216
+ readonly tokenRaw: BigUint64Array;
217
+ readonly tokenDecimals: Uint8Array;
218
+ readonly quoteRaw: BigUint64Array;
219
+ readonly quoteDecimals: Uint8Array;
220
+ readonly tokenAmount: Float64Array;
221
+ readonly quoteAmount: Float64Array;
222
+ /** Raw provider price (quote per token). Often the only price present. */
223
+ readonly price: Float64Array;
224
+ readonly priceSol: Float64Array;
225
+ readonly priceUsd: Float64Array;
226
+ readonly quotePriceUsd: Float64Array;
227
+ readonly usdValue: Float64Array;
228
+ /** Only with `withSignatures: true`; `null` when not stored for a trade. */
229
+ readonly signatures?: readonly (string | null)[];
230
+ /** Only with `withMarket: true`. */
231
+ readonly market?: MarketColumns;
232
+ /** Only with `withOrder: true`; the batch is then in on-chain order. */
233
+ readonly order?: OrderColumns;
234
+ /** Only with `withTx: true`. */
235
+ readonly tx?: TxColumns;
236
+ }
237
+ /** `MarketColumns.event` values. */
238
+ export declare const MarketEvent: {
239
+ /** A trade. */
240
+ readonly none: 0;
241
+ /** The token left its bonding curve: `pool` is the new pumpswap pool, reserves are its own. */
242
+ readonly migrate: 1;
243
+ readonly createPool: 2;
244
+ /** Liquidity added by `trader`: amounts added, reserves after. */
245
+ readonly add: 3;
246
+ /** Liquidity removed by `trader`: amounts removed, reserves after. */
247
+ readonly remove: 4;
248
+ /**
249
+ * The token was created: `market.signer` signed it, `market.creatorFeeRecipient`
250
+ * is the creator named by the bonding curve (they differ for 17 % of
251
+ * creations). The creator's initial buy, if any, is the trade of the same
252
+ * `line`, flagged {@link MarketFlag.creatorInitialBuy}.
253
+ */
254
+ readonly create: 5;
255
+ /**
256
+ * Fee distributions (provider `distributeFees` rows, `withEvents` token
257
+ * reads). `quoteMint` is the mint paid (`feeMint`; SOL for `sol`),
258
+ * `quoteRaw` the total paid by the row (at `quoteDecimals`: the mint's
259
+ * decimals when known, else those the amounts are written with),
260
+ * `tokenRaw` 0, `trader` the recipient when the row has a single one
261
+ * ({@link NO_ADDRESS} otherwise). Fees to the token's holders, up to 8
262
+ * recipients per row.
263
+ */
264
+ readonly feeHolders: 6;
265
+ /** Creator fees paid to the shareholders of a fee-sharing token. */
266
+ readonly feeShareholders: 7;
267
+ /**
268
+ * Creator fees collected by the creator. Usually without token
269
+ * ({@link MarketFlag.feeWithoutToken}): such rows are in no token read.
270
+ */
271
+ readonly feeCreator: 8;
272
+ /** Fees claimed by a social account. */
273
+ readonly feeSocial: 9;
274
+ /** A fee distribution of another type. */
275
+ readonly feeOther: 10;
276
+ };
277
+ /** Bits of `MarketColumns.flags`. */
278
+ export declare const MarketFlag: {
279
+ /** `tokenReserve` and `quoteReserve` are set. */
280
+ readonly reserves: 1;
281
+ /** `virtualTokenReserve` and `virtualQuoteReserve` are set. */
282
+ readonly virtualReserves: 2;
283
+ /**
284
+ * The provider row holds several operations on this pool (e.g. a buy and
285
+ * a sell in one transaction): its reserves are the state after the whole
286
+ * row, not after this operation.
287
+ */
288
+ readonly multiOpRow: 4;
289
+ /**
290
+ * Token reads only: the previous trade of this pool in the batch, with
291
+ * this trade's token amount, does not give this trade's token reserve. An
292
+ * event between them is missing (liquidity, migration, a row the provider
293
+ * did not send) or the provider order differs from the chain order.
294
+ */
295
+ readonly chainBreak: 8;
296
+ /** No earlier trade of this pool in the batch to check against. */
297
+ readonly chainUnchecked: 16;
298
+ /** The creator's initial buy, made by the `create` of the token. */
299
+ readonly creatorInitialBuy: 32;
300
+ /** `cashbackEnabled` of the provider row. */
301
+ readonly cashback: 64;
302
+ /** `mayhemMode` of the provider row. */
303
+ readonly mayhem: 128;
304
+ /**
305
+ * A fee distribution that names no token (`mint` is the empty address):
306
+ * creator fees collected from the creator's vault, which pools the fees
307
+ * of all the creator's tokens. No read returns such rows today (they are
308
+ * in no token read): reserved for a read of fee recipients.
309
+ */
310
+ readonly feeWithoutToken: 256;
311
+ /**
312
+ * PumpSwap pool inverted on-chain (token is the on-chain quote): fees are
313
+ * taken in tokens. The reserve is the provider's, which leaves them out: a
314
+ * buy of X leaves `ceil(X * 25 / 10000)` more tokens in the pool, and the
315
+ * trader receives 0.30 % less than `tokenRaw`. `chainBreak` accounts for it.
316
+ */
317
+ readonly invertedPool: 512;
318
+ };
319
+ /**
320
+ * Pool state and fees of each trade (`withMarket: true`), entry `i` for
321
+ * trade `i`. Reserves are raw integers (token at `tokenDecimals`, quote at
322
+ * `quoteDecimals`): the state of the pool **after** the provider row of the
323
+ * trade. `0` when absent (see `flags`). Rates in basis points, `NaN` when
324
+ * absent.
325
+ */
326
+ export interface MarketColumns {
327
+ /** Real reserves (provider `tokensInPool`, `quoteInPool`). */
328
+ readonly tokenReserve: BigUint64Array;
329
+ readonly quoteReserve: BigUint64Array;
330
+ /**
331
+ * Pumpfun: the virtual reserves of the bonding curve, the ones its
332
+ * constant product uses. Pumpswap: the provider's virtual reserves, when
333
+ * it gives them.
334
+ */
335
+ readonly virtualTokenReserve: BigUint64Array;
336
+ readonly virtualQuoteReserve: BigUint64Array;
337
+ /** Provider `poolFeeRate` × 10 000. */
338
+ readonly poolFeeBps: Float64Array;
339
+ /** Provider `solRouteFeeRate` × 10 000. */
340
+ readonly routeFeeBps: Float64Array;
341
+ /** Provider `holderRewardsRate` × 10 000. */
342
+ readonly holderRewardsBps: Float64Array;
343
+ /** Index in `addresses` of the creator fee recipient; `-1` when absent. */
344
+ readonly creatorFeeRecipient: Int32Array;
345
+ /** Index in `addresses` of the transaction signer; `-1` when absent. */
346
+ readonly signer: Int32Array;
347
+ /** Priority fee of the transaction in lamports; `2n ** 64n - 1n` when absent. */
348
+ readonly priorityFeeRaw: BigUint64Array;
349
+ /** {@link MarketFlag} bits. */
350
+ readonly flags: Uint16Array;
351
+ /** {@link MarketEvent}: `0` for a trade. */
352
+ readonly event: Uint8Array;
353
+ }
354
+ /**
355
+ * Latest known token metadata (`/v1/tokens/{mint}/info`, also `metadata` of
356
+ * `tokenTotals`): provider values copied verbatim from the newest row of the
357
+ * mint that is cheap to reach, `null` when the row lacks them. `name`,
358
+ * `symbol` and `uri` of stored hours come from the hour's `tokens.t2` (the
359
+ * newest hour that has them), cut at 128, 64 and 512 UTF-8 bytes.
360
+ */
361
+ export type TokenMetadata = {
362
+ readonly name: string | null;
363
+ readonly symbol: string | null;
364
+ readonly uri: string | null;
365
+ /** Provider value in token units (may be fractional). */
366
+ readonly supply: number | null;
367
+ readonly decimals: number | null;
368
+ readonly tokenProgram: string | null;
369
+ readonly mintAuthority: string | null;
370
+ readonly freezeAuthority: string | null;
371
+ readonly quoteMint: string | null;
372
+ readonly quoteName: string | null;
373
+ readonly quoteSymbol: string | null;
374
+ readonly quoteUri: string | null;
375
+ /** Time, slot and signature of the row the values come from. */
376
+ readonly asOfMs: number | null;
377
+ readonly slot: number | null;
378
+ readonly signature: string | null;
379
+ /** `"open"`: the hour being written; `"sealed"`: a stored hour. */
380
+ readonly source: "sealed" | "open";
381
+ /** Time of the row `name`/`symbol`/`uri` come from (absent: no names known). */
382
+ readonly namesAsOfMs?: number | null;
383
+ /** One of `name`/`symbol`/`uri` was longer than its limit and was cut. */
384
+ readonly namesTruncated?: boolean;
385
+ };
386
+ /** `ctx.data.tokenInfo`: metadata and creation, no volumes. */
387
+ export type TokenInfo = {
388
+ readonly mint: Address;
389
+ readonly known: boolean;
390
+ /** `null` when the creation is not in the first retained block. */
391
+ readonly createdMs: number | null;
392
+ readonly creation: Json;
393
+ readonly metadata: TokenMetadata | null;
394
+ };
395
+ /**
396
+ * Parameters of `/v1/volume/search`, with the same names and units
397
+ * (`since`/`until` in **seconds**, multiples of 60). Paging is handled by
398
+ * `ctx.data.volumeSearch`: there is no `cursor`.
399
+ */
400
+ export interface VolumeSearchParams {
401
+ readonly since: number;
402
+ readonly until: number;
403
+ /** Decimal amounts of the quote, as strings (e.g. `"10.5"`). */
404
+ readonly min?: string;
405
+ readonly max?: string;
406
+ /** Quote mint. Default: SOL. */
407
+ readonly quote?: Address;
408
+ readonly currency?: "quote";
409
+ /** Page size. */
410
+ readonly limit?: number;
411
+ readonly allow_partial?: boolean;
412
+ }
413
+ export type JobStatus = "queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired" | "acknowledged";
414
+ /** Why an execution failed. `kind` is stable; test `code`, not `message`. */
415
+ export interface JobFailure {
416
+ readonly kind: "program" | "limit" | "infrastructure" | "permission";
417
+ readonly code: string;
418
+ readonly message: string;
419
+ }
420
+ /**
421
+ * Where a job stands. Continuations are followed: `id` is the id you asked
422
+ * for, the status is that of the last execution of its chain.
423
+ */
424
+ export type JobResult = {
425
+ readonly id: string;
426
+ readonly status: "queued" | "running";
427
+ } | {
428
+ readonly id: string;
429
+ readonly status: "succeeded";
430
+ readonly result: Json;
431
+ } | {
432
+ readonly id: string;
433
+ readonly status: "failed";
434
+ readonly error: JobFailure;
435
+ } | {
436
+ readonly id: string;
437
+ readonly status: "cancelled" | "expired" | "acknowledged";
438
+ };
439
+ /** The job is over: its status will not change any more. */
440
+ export declare function isFinal(result: JobResult): boolean;
441
+ export interface StartJob {
442
+ /** A function of this program. */
443
+ readonly function: string;
444
+ readonly args: JsonInput;
445
+ /** Called with {@link CompletionArgs} when the job ends. */
446
+ readonly onComplete?: string;
447
+ }
448
+ export type Trigger = {
449
+ readonly kind: "trade";
450
+ readonly mint?: Address;
451
+ readonly wallet?: Address;
452
+ } | {
453
+ readonly kind: "volume";
454
+ /**
455
+ * Quote volume threshold, raw units, decimal string: volume since
456
+ * creation, or over the last `windowMs` when given.
457
+ */
458
+ readonly thresholdRaw: string;
459
+ readonly mint?: Address;
460
+ readonly quote?: Address;
461
+ /**
462
+ * Sliding window, 1 000 to 3 600 000 ms: fires on the trade that brings
463
+ * the token's volume of the last `windowMs` from below the threshold to
464
+ * at least it; again only after it fell back below.
465
+ */
466
+ readonly windowMs?: number;
467
+ } | {
468
+ readonly kind: "priceVariation";
469
+ readonly mint?: Address;
470
+ readonly mode: "rise" | "fall" | "both";
471
+ /**
472
+ * 1.01 to 11, at most four decimals: `rise` is end ≥ start × factor,
473
+ * `fall` end ≤ start ÷ factor. See {@link priceFactor} for percents.
474
+ */
475
+ readonly factor: number;
476
+ /** 15 000 to 3 600 000. */
477
+ readonly durationMs: number;
478
+ } | {
479
+ readonly kind: "interval";
480
+ /** 1 000 to 86 400 000. */
481
+ readonly everyMs: number;
482
+ } | {
483
+ /**
484
+ * Pool events of the live feed ({@link PoolEvent}): of `mint`, or of
485
+ * every token without it; of the listed kinds, or every kind.
486
+ */
487
+ readonly kind: "poolEvent";
488
+ readonly mint?: Address;
489
+ /** Non-empty, no duplicate. */
490
+ readonly events?: readonly PoolEventKind[];
491
+ };
492
+ /** Names of the pool events ({@link MarketEvent} keys other than `none`). */
493
+ export type PoolEventKind = Exclude<keyof typeof MarketEvent, "none">;
494
+ export interface Subscription {
495
+ /** Function called with a {@link Delivery}. */
496
+ readonly function: string;
497
+ readonly trigger: Trigger;
498
+ /** After an interruption: `latest` skips to now, `replay` catches up. */
499
+ readonly recovery: "latest" | "replay";
500
+ /** 1 to 10 000, default 1 000 (the runtime caps replay at 1 000). */
501
+ readonly maxReplayEvents?: number;
502
+ }
503
+ /**
504
+ * A trade as published by the live feed, in the JSON shape of the public API
505
+ * (`/v1/tokens/{mint}/operations`). Only the fields most programs read are
506
+ * typed; the others are kept as they come.
507
+ */
508
+ export interface MarketOperation {
509
+ readonly id: string;
510
+ readonly mint: Address;
511
+ readonly trader: Address | null;
512
+ readonly pool: Address | null;
513
+ readonly side: "buy" | "sell";
514
+ readonly protocol: "pumpfun" | "pumpswap";
515
+ readonly token: {
516
+ readonly raw: string;
517
+ readonly amount: string;
518
+ readonly decimals: number;
519
+ };
520
+ readonly quote: {
521
+ readonly mint: Address;
522
+ readonly raw: string;
523
+ readonly amount: string;
524
+ readonly decimals: number;
525
+ };
526
+ readonly time: {
527
+ readonly ms: number;
528
+ readonly receivedMs: number | null;
529
+ };
530
+ /** `ord` is `"hour:line:op"`, the id used by {@link HourBatch}. */
531
+ readonly order: {
532
+ readonly ord: string;
533
+ readonly slot: number;
534
+ } | null;
535
+ /** The trade's transaction, as {@link TxColumns} (absent from older servers). */
536
+ readonly tx?: OperationTx;
537
+ readonly publishSeq: number | null;
538
+ readonly cumulativeQuoteRawAfter: string | null;
539
+ readonly [field: string]: unknown;
540
+ }
541
+ /**
542
+ * A pool event as published by the live feed: the same values as the
543
+ * `withEvents` row of {@link HourBatch} for the same provider row (`order.ord`
544
+ * is its `"hour:line:65535"` id, `code` its `market.event`).
545
+ */
546
+ export interface PoolEvent {
547
+ readonly type: "poolEvent";
548
+ readonly kind: PoolEventKind;
549
+ /** {@link MarketEvent} value. */
550
+ readonly code: number;
551
+ readonly id: string;
552
+ readonly mint: Address;
553
+ /** For a migration, the new pumpswap pool. */
554
+ readonly pool: Address;
555
+ readonly protocol: "pumpfun" | "pumpswap";
556
+ /** The liquidity provider of `add` / `remove`; `null` otherwise. */
557
+ readonly trader: Address | null;
558
+ readonly signature: string | null;
559
+ /** Amounts added or removed; `"0"` for other kinds. */
560
+ readonly token: {
561
+ readonly raw: string;
562
+ readonly amount: string;
563
+ readonly decimals: number;
564
+ };
565
+ readonly quote: {
566
+ readonly mint: Address;
567
+ readonly raw: string;
568
+ readonly amount: string;
569
+ readonly decimals: number;
570
+ };
571
+ readonly time: {
572
+ readonly ms: number;
573
+ readonly receivedMs: number | null;
574
+ };
575
+ readonly order: {
576
+ readonly ord: string;
577
+ readonly slot: number;
578
+ };
579
+ /** The event's transaction, as {@link TxColumns} (absent from older servers). */
580
+ readonly tx?: OperationTx;
581
+ readonly publishSeq: number;
582
+ /** The pool after the row: raw reserves (decimal strings), fees, signer. */
583
+ readonly market: {
584
+ readonly tokenReserveRaw: string | null;
585
+ readonly quoteReserveRaw: string | null;
586
+ readonly virtualTokenReserveRaw: string | null;
587
+ readonly virtualQuoteReserveRaw: string | null;
588
+ readonly signer: Address | null;
589
+ readonly [field: string]: unknown;
590
+ };
591
+ readonly [field: string]: unknown;
592
+ }
593
+ /**
594
+ * The transaction of a published operation: `(hour, id)` names it, as
595
+ * {@link TxColumns}. `id` and `index` are `null` when unknown; `flags` are
596
+ * the {@link TxFlag} names.
597
+ */
598
+ export interface OperationTx {
599
+ readonly id: number | null;
600
+ readonly index: number | null;
601
+ readonly flags: readonly (keyof typeof TxFlag)[];
602
+ }
603
+ /** Names of {@link TxFlag} bits, in bit order (the `tx.flags` of an operation). */
604
+ export declare function txFlagNames(flags: number): (keyof typeof TxFlag)[];
605
+ /**
606
+ * Same transaction: trades `i` and `j` of batches read `withTx: true`
607
+ * (possibly two batches of the same hour).
608
+ */
609
+ export declare function sameTransaction(a: HourBatch, i: number, b: HourBatch, j: number): boolean;
610
+ export type SubscriptionEvent = {
611
+ readonly kind: "trade";
612
+ readonly operation: MarketOperation;
613
+ /** Replays only: the chain position is unknown, provider order used. */
614
+ readonly orderFallback?: true;
615
+ } | {
616
+ readonly kind: "poolEvent";
617
+ readonly event: PoolEvent;
618
+ readonly orderFallback?: true;
619
+ } | {
620
+ readonly kind: "volume";
621
+ readonly operation: MarketOperation;
622
+ /** With `windowMs` only: the window and its volume after this trade. */
623
+ readonly windowMs?: number;
624
+ readonly windowQuoteRaw?: string;
625
+ readonly orderFallback?: true;
626
+ } | {
627
+ readonly kind: "interval";
628
+ readonly scheduledAt: number;
629
+ } | {
630
+ readonly kind: "priceVariation";
631
+ readonly signal: Json;
632
+ } | {
633
+ readonly kind: "priceStatus";
634
+ readonly status: Json;
635
+ } | {
636
+ readonly kind: "gap";
637
+ /**
638
+ * `retention`, `replay_limit`, `missing_events`, `source_reset`,
639
+ * `price_coverage`, `window_not_observed` (windowed `volume`: trades
640
+ * whose window was not observed)…; replays: `history_gap`,
641
+ * `not_sealed` (with `fromMs`, `toMs`).
642
+ */
643
+ readonly reason: string;
644
+ readonly [field: string]: unknown;
645
+ };
646
+ /** Arguments of a subscription handler. */
647
+ export interface Delivery {
648
+ readonly kind: "events";
649
+ readonly subscription: string;
650
+ readonly events: readonly SubscriptionEvent[];
651
+ /** Present only in a replay: the simulated clock and the replay. */
652
+ readonly replay?: ReplayInfo;
653
+ }
654
+ /** `Delivery.replay`: what a replayed delivery adds. */
655
+ export interface ReplayInfo {
656
+ readonly id: string;
657
+ /** 1 for the first delivery of the replay. */
658
+ readonly delivery: number;
659
+ /** Simulated time: the time of the last event of this delivery. */
660
+ readonly clockMs: number;
661
+ readonly sinceMs: number;
662
+ readonly untilMs: number;
663
+ readonly simulated: true;
664
+ }
665
+ /** The time a handler should use: simulated in a replay, real in live. */
666
+ export declare function deliveryNow(delivery: Delivery): number;
667
+ /** Body of `ctx.subscriptions.replay` and `POST programs/{p}/replay`. */
668
+ export interface ReplayRequest {
669
+ /** The same spec as a live subscription (`recovery` is optional here). */
670
+ readonly subscription: Omit<Subscription, "recovery"> & {
671
+ readonly recovery?: Subscription["recovery"];
672
+ };
673
+ readonly sinceMs: number;
674
+ /** In the past; window up to 24 h with tokens, 1 h for every token. */
675
+ readonly untilMs: number;
676
+ /**
677
+ * Up to 100 tokens when the trigger names none; neither: every token.
678
+ */
679
+ readonly mints?: readonly Address[];
680
+ /** `subscription` of the deliveries (default `"replay"`). */
681
+ readonly name?: string;
682
+ readonly speed?: "max";
683
+ /**
684
+ * Events per delivery, 1 to 1,000 (default: 32, as live). Larger batches
685
+ * make a replay faster; the function then receives up to `batchSize`
686
+ * events per call, which live never sends. The argument, output and op
687
+ * limits of these deliveries are multiplied by ⌈batchSize / 32⌉ (CPU,
688
+ * wall time and memory stay live's). Not for `interval` (one tick per
689
+ * delivery).
690
+ *
691
+ * Use it for long replays or many tokens where speed matters, with a
692
+ * function that handles each event quickly and independently: up to ~2×
693
+ * faster (every token × 1 h, copy-trading function: 108 s → 53 s with
694
+ * 1000). A heavy function keeps smaller batches (per-delivery CPU, wall and
695
+ * memory do not grow). Decisions are the same whatever the batch size.
696
+ */
697
+ readonly batchSize?: number;
698
+ /**
699
+ * `ctx.storage` of a replay is its own space (empty at start, in the
700
+ * account's `short` quota, deleted at the end). `keepStorage` copies, at
701
+ * the end of a successful replay, the objects of its area `from` (default:
702
+ * `to`), or only `keys` (up to 1000), to the account's area `to`, within
703
+ * that area's quota (refused as a whole: see `ReplayRecord.keptStorage`).
704
+ */
705
+ readonly keepStorage?: {
706
+ readonly to: "long" | "durable";
707
+ readonly from?: "short" | "long" | "durable";
708
+ readonly keys?: readonly string[];
709
+ };
710
+ }
711
+ /**
712
+ * One item of a replay's live feed (`GET replays/{id}/emits?after_seq=N`,
713
+ * `client.replayEmits`): a `ctx.emit`, or the final record of an execution
714
+ * (after its emits). Reading after `seq` N frees 1..N.
715
+ */
716
+ export type ReplayFeedItem = {
717
+ readonly seq: number;
718
+ readonly kind: "emitted";
719
+ readonly executionId: string;
720
+ readonly function: string;
721
+ readonly attempt: number;
722
+ readonly createdAt: number;
723
+ readonly data: Json;
724
+ } | {
725
+ readonly seq: number;
726
+ readonly kind: "execution";
727
+ readonly execution: {
728
+ readonly id: string;
729
+ readonly status: JobStatus;
730
+ readonly result?: Json;
731
+ readonly error?: {
732
+ readonly code: string;
733
+ readonly message: string;
734
+ };
735
+ readonly logs: readonly Json[];
736
+ readonly [field: string]: unknown;
737
+ };
738
+ };
739
+ export interface ReplayRecord {
740
+ readonly id: string;
741
+ readonly program: string;
742
+ readonly status: "running" | "cancelling" | "succeeded" | "failed" | "cancelled";
743
+ readonly sinceMs: number;
744
+ readonly untilMs: number;
745
+ readonly progress: {
746
+ readonly simulatedMs: number;
747
+ /** 0 to 1. */
748
+ readonly fraction: number;
749
+ readonly eventsRead: number;
750
+ readonly eventsDelivered: number;
751
+ readonly deliveries: number;
752
+ readonly gaps: number;
753
+ readonly orderFallbacks: number;
754
+ readonly historyReadBytes: number;
755
+ };
756
+ readonly usage: {
757
+ readonly cpuMs: number;
758
+ readonly readBytes: number;
759
+ readonly attempts: number;
760
+ };
761
+ readonly error: {
762
+ readonly code: string;
763
+ readonly message: string;
764
+ } | null;
765
+ readonly lastExecution: string | null;
766
+ /** What `keepStorage` copied at the end, or why nothing was. */
767
+ readonly keptStorage?: {
768
+ readonly copied: true;
769
+ readonly objects: number;
770
+ readonly bytes: number;
771
+ } | {
772
+ readonly copied: false;
773
+ readonly error: {
774
+ readonly code: string;
775
+ readonly message: string;
776
+ };
777
+ };
778
+ readonly [field: string]: unknown;
779
+ }
780
+ /** Arguments of an `onComplete` handler. */
781
+ export interface CompletionArgs {
782
+ readonly kind: "completion";
783
+ readonly executionId: string;
784
+ readonly status: JobStatus;
785
+ }
786
+ export declare function isDelivery(args: unknown): args is Delivery;
787
+ export declare function isCompletion(args: unknown): args is CompletionArgs;
788
+ export interface ExecutionInfo {
789
+ readonly id: string;
790
+ /** Shared by an execution, its continuations, children and retries. */
791
+ readonly workflow: string;
792
+ readonly program: string;
793
+ /** SHA-256 of the bundle. */
794
+ readonly version: string;
795
+ /** 1 for the first attempt. */
796
+ readonly attempt: number;
797
+ }
798
+ /** Lakebed's `StoragePutOptions` (every field optional here). */
799
+ export interface StoragePutOptions {
800
+ /** `type/subtype`; parameters are dropped. Default: `text/plain` for a string, else `application/octet-stream`. */
801
+ readonly contentType?: string;
802
+ /** Up to 16 entries; names `[a-z0-9-]{1,64}`, values printable ASCII (≤ 1024). Served as `x-meta-<name>` over HTTP. */
803
+ readonly metadata?: Readonly<Record<string, string>>;
804
+ /** Fail with `already_exists` instead of replacing an object. */
805
+ readonly ifAbsent?: boolean;
806
+ /**
807
+ * Write only if the object still has this etag (`"*"`: any existing
808
+ * object), else `precondition_failed`. Checked atomically with the write.
809
+ */
810
+ readonly ifMatch?: string;
811
+ }
812
+ /** Lakebed's `StorageObjectHead`, plus where the object stands in time. */
813
+ export interface StorageObjectHead {
814
+ readonly key: string;
815
+ readonly size: number;
816
+ readonly contentType: string;
817
+ readonly metadata: Readonly<Record<string, string>>;
818
+ /** ISO 8601 of the last write. */
819
+ readonly lastModified: string;
820
+ /** Last write (ms since epoch). Reads do not change it. */
821
+ readonly writtenAt: number;
822
+ /** `writtenAt` + the area's lifetime: the object is gone after it. `null` in `durable`. */
823
+ readonly expiresAt: number | null;
824
+ /** Changes at every write (HTTP `ETag`). */
825
+ readonly etag: string;
826
+ }
827
+ /** Lakebed's `StorageReadResult`. With a range, `body` is that range and `size` the whole object's. */
828
+ export interface StorageReadResult extends StorageObjectHead {
829
+ readonly body: Uint8Array;
830
+ }
831
+ /** Lakebed's `StorageObjectSummary` (what `list` answers), plus expiry. */
832
+ export interface StorageObjectSummary {
833
+ readonly key: string;
834
+ readonly size: number;
835
+ readonly contentType: string;
836
+ readonly lastModified: string;
837
+ readonly expiresAt: number | null;
838
+ }
839
+ /**
840
+ * What `list` answers: Lakebed's array of summaries, plus `cursor` (pass it
841
+ * as `after` for the next page, `null` at the end) and `truncated`.
842
+ */
843
+ export type StorageListPage = StorageObjectSummary[] & {
844
+ readonly cursor: string | null;
845
+ readonly truncated: boolean;
846
+ };
847
+ /** Lakebed's `StorageLedgerUsage` for one area of the account, with its limits. */
848
+ export interface StorageUsage {
849
+ readonly area: "short" | "long" | "durable";
850
+ readonly initialized: boolean;
851
+ /** committed + reserved + uncertain + deleting: what the quota counts. */
852
+ readonly usedBytes: number;
853
+ readonly reservedBytes: number;
854
+ /** Uploads in progress. */
855
+ readonly uncertainBytes: number;
856
+ readonly committedBytes: number;
857
+ readonly deletingBytes: number;
858
+ readonly objects: number;
859
+ readonly reservations: readonly {
860
+ readonly key: string;
861
+ readonly size: number;
862
+ readonly state: "reserved" | "writing" | "deleting";
863
+ readonly updatedAt: string;
864
+ }[];
865
+ readonly quotaBytes: number;
866
+ /** Lifetime of an object after its last write; `null` in `durable` (never expires). */
867
+ readonly ttlMs: number | null;
868
+ readonly maxObjectBytes: number;
869
+ }
870
+ /** Bytes to store: a string is stored as UTF-8. */
871
+ export type StorageBody = Uint8Array | ArrayBuffer | ArrayBufferView | string;
872
+ /** Writes one object piece by piece; nothing is visible before `close()`. */
873
+ export interface StorageWriter {
874
+ write(chunk: StorageBody): Promise<void>;
875
+ /** Makes the object visible (replacing any previous one). */
876
+ close(): Promise<StorageObjectHead>;
877
+ /** Drops what was written (also done when the execution ends). */
878
+ abort(): Promise<void>;
879
+ }
880
+ /**
881
+ * One storage area of the account, shared by all its programs and readable
882
+ * over HTTP (`/v1/functions/storage/{area}/{key}`). Keys are 1 to 512 bytes
883
+ * of UTF-8 without control characters (`/` is an ordinary character: use it
884
+ * for prefixes). Each object expires a fixed time after its last write;
885
+ * reads do not extend it. Writes are immediate and not undone if the
886
+ * execution fails afterwards.
887
+ */
888
+ export interface StorageArea {
889
+ /** Lakebed's `put`. Answers the new head. */
890
+ put(key: string, body: StorageBody, options?: StoragePutOptions): Promise<StorageObjectHead>;
891
+ /** Lakebed's `get`; `range` reads part of a large object. `null` when absent or expired. */
892
+ get(key: string, range?: {
893
+ offset?: number;
894
+ length?: number;
895
+ }): Promise<StorageReadResult | null>;
896
+ head(key: string): Promise<StorageObjectHead | null>;
897
+ /** Idempotent. With `ifMatch`, only if the object still has that etag (`precondition_failed`). */
898
+ delete(key: string, options?: {
899
+ ifMatch?: string;
900
+ }): Promise<void>;
901
+ /**
902
+ * Lakebed's `list`: keys starting with `prefix`, in byte order, at most
903
+ * `maxObjects` (1000). For the next page, pass the last key as `after`.
904
+ */
905
+ list(prefix?: string, options?: {
906
+ maxObjects?: number;
907
+ after?: string;
908
+ }): Promise<StorageListPage>;
909
+ usage(): Promise<StorageUsage>;
910
+ /** Helpers. */
911
+ getText(key: string): Promise<string | null>;
912
+ getJSON(key: string): Promise<Json>;
913
+ /** Stored as `application/json`. */
914
+ putJSON(key: string, value: JsonInput, options?: Omit<StoragePutOptions, "contentType">): Promise<StorageObjectHead>;
915
+ writer(key: string, options?: StoragePutOptions): Promise<StorageWriter>;
916
+ }
917
+ export interface Context {
918
+ readonly execution: ExecutionInfo;
919
+ readonly data: {
920
+ /**
921
+ * Trades of a wallet, one hour per batch, oldest first. Each `next()` reads
922
+ * one hour: break out of the loop to stop reading.
923
+ */
924
+ walletTrades(wallet: Address, query: TradeQuery): AsyncIterable<HourBatch>;
925
+ /** Trades of a token, one hour per batch, oldest first. */
926
+ tokenTrades(mint: Address, query: TradeQuery): AsyncIterable<HourBatch>;
927
+ /** Same JSON as `/v1/tokens/{mint}/totals` (with `metadata`). */
928
+ tokenTotals(mint: Address, options?: {
929
+ quote?: Address;
930
+ }): Promise<Json>;
931
+ /**
932
+ * Same JSON as `/v1/tokens/{mint}/info`: latest known metadata and the
933
+ * creation, at most two blocks read (no volumes).
934
+ */
935
+ tokenInfo(mint: Address): Promise<TokenInfo>;
936
+ /** Pages of `/v1/volume/search`, in its JSON shape. */
937
+ volumeSearch(params: VolumeSearchParams): AsyncIterable<Json>;
938
+ };
939
+ /** Private JSON state of the program, kept between executions. */
940
+ readonly state: {
941
+ /** `null` when the key is absent. */
942
+ get(key: string): Promise<Json>;
943
+ set(key: string, value: JsonInput): Promise<void>;
944
+ delete(key: string): Promise<void>;
945
+ };
946
+ readonly jobs: {
947
+ /** Starts a function of this program in parallel; returns its id. */
948
+ start(job: StartJob): Promise<string>;
949
+ /**
950
+ * Waits until every listed job is final, or until `timeoutMs`. Results are
951
+ * in the order of `ids`; on timeout, some are still `queued`/`running`.
952
+ * Waiting costs no CPU but counts in the 60 s wall time.
953
+ */
954
+ wait(ids: string | readonly string[], options?: {
955
+ timeoutMs?: number;
956
+ }): Promise<JobResult[]>;
957
+ /** Current status of a job of this account, without waiting. */
958
+ result(id: string): Promise<JobResult>;
959
+ /**
960
+ * Ends this execution and schedules the same function again with `args`
961
+ * (same version, same workflow budget). Use as `return ctx.jobs.continue(…)`.
962
+ */
963
+ continue(args: JsonInput): Promise<string>;
964
+ };
965
+ /**
966
+ * Files of the account, kept between executions: `short` (1 GiB, 24 h
967
+ * after the last write), `long` (500 MiB, 7 days after the last write) and
968
+ * `durable` (50 MiB, never expires).
969
+ */
970
+ readonly storage: {
971
+ readonly short: StorageArea;
972
+ readonly long: StorageArea;
973
+ /** 50 MiB, never expires: open positions, order journals. */
974
+ readonly durable: StorageArea;
975
+ };
976
+ readonly subscriptions: {
977
+ set(name: string, subscription: Subscription): Promise<void>;
978
+ remove(name: string): Promise<void>;
979
+ /**
980
+ * Replays history to a function of this program, in the live delivery
981
+ * format. Refused inside a replay.
982
+ */
983
+ replay(request: ReplayRequest): Promise<ReplayRecord>;
984
+ };
985
+ /** Calls another function of this program now, in this execution and budget. */
986
+ invoke(name: string, args: JsonInput): Promise<Json>;
987
+ /** Adds a diagnostic to the execution record (counts in the output limit). */
988
+ log(value: JsonInput): Promise<void>;
989
+ /** Publishes a provisional event on the account stream (counts in the output limit). */
990
+ emit(value: JsonInput): Promise<void>;
991
+ readonly webhook: {
992
+ /**
993
+ * Sends `payload` to the account's webhook URL now (not when the
994
+ * execution ends). JSON, at most 16 KiB, counted in the output limit; at
995
+ * most 32 calls per execution. Rejects with `webhook_not_configured`,
996
+ * `webhook_limit` or `webhook_payload_too_large`, and with
997
+ * `webhook_queue_full` when 1000 messages wait, unless
998
+ * `{ onFull: "drop" }`: the message is then dropped (counted in
999
+ * `dropped` of the delivery log) and the call answers `dropped: true`.
1000
+ * A retried execution sends again: the message carries `executionId`,
1001
+ * `attempt` and `index` to tell.
1002
+ */
1003
+ send(payload: JsonInput, options?: {
1004
+ onFull?: "fail" | "drop";
1005
+ }): Promise<{
1006
+ id: string;
1007
+ seq: number;
1008
+ dropped: false;
1009
+ } | {
1010
+ id: null;
1011
+ seq: null;
1012
+ dropped: true;
1013
+ }>;
1014
+ };
1015
+ }
1016
+ type HandlerReturn = JsonInput | void | Promise<JsonInput | void>;
1017
+ /**
1018
+ * A function of the program. `args` can be annotated with a narrower type;
1019
+ * validate it anyway: callers send any JSON.
1020
+ */
1021
+ export type Handler = {
1022
+ bivarianceHack(ctx: Context, args: Json): HandlerReturn;
1023
+ }["bivarianceHack"];
1024
+ export interface Program {
1025
+ readonly functions: Readonly<Record<string, Handler>>;
1026
+ /** Bump it with a `migration` when the shape of the state changes. */
1027
+ readonly stateVersion?: number;
1028
+ /** Name of a function receiving `{ from, to, state }` and returning the new state. */
1029
+ readonly migration?: string;
1030
+ /** Declared at deploy; `ctx.subscriptions` can change them later. */
1031
+ readonly subscriptions?: Readonly<Record<string, Subscription>>;
1032
+ }
1033
+ /** Marker read by the sandbox at deploy: programs without it are refused. */
1034
+ export declare const SDK_MARKER = "__zyrkSdk";
1035
+ export declare const SDK_VERSION = "0.2";
1036
+ export declare function defineProgram<const T extends Program>(program: T): T;
1037
+ /** Id of trade `i`: `"{hour}:{line}:{op}"`, unique and stable. */
1038
+ export declare function tradeId(batch: HourBatch, i: number): string;
1039
+ export interface TradeKey {
1040
+ readonly hour: number;
1041
+ readonly line: number;
1042
+ readonly op: number;
1043
+ }
1044
+ /** Parses `"{hour}:{line}:{op}"`; throws a `RangeError` on anything else. */
1045
+ export declare function parseTradeId(id: string): TradeKey;
1046
+ /** Provider order of two trade ids, for `Array#sort`. */
1047
+ export declare function compareTradeIds(a: string, b: string): number;
1048
+ /**
1049
+ * Id of a live-feed operation, in the {@link tradeId} format (`operation.id`
1050
+ * as delivered by funrun, else `order.ord`); `null` without order.
1051
+ */
1052
+ export declare function operationTradeId(operation: MarketOperation): string | null;
1053
+ /**
1054
+ * `priceVariation` factor for a percent change: `priceFactor(20)` is 1.2
1055
+ * (rise of 20 %), `priceFactor(-10)` is 1.1111 (fall of 10 %: 1 / 0.9,
1056
+ * rounded down to four decimals so that an exact 10 % fall fires). Throws a
1057
+ * `RangeError` outside 1.01 to 11 (+1 % to +1 000 %, −1 % to −90.9 %).
1058
+ */
1059
+ export declare function priceFactor(percent: number): number;
1060
+ /** Entry `index` of the batch dictionary; `null` for {@link NO_ADDRESS}. */
1061
+ export declare function addressAt(batch: HourBatch, index: number): Address | null;
1062
+ /**
1063
+ * Index of `address` in the batch dictionary, or {@link NO_ADDRESS}. Compare
1064
+ * columns to it to test many rows without building strings.
1065
+ */
1066
+ export declare function addressIndex(batch: HourBatch, address: Address): number;
1067
+ export declare function mintOf(batch: HourBatch, i: number): Address;
1068
+ export declare function traderOf(batch: HourBatch, i: number): Address | null;
1069
+ export declare function poolOf(batch: HourBatch, i: number): Address | null;
1070
+ export declare function quoteMintOf(batch: HourBatch, i: number): Address;
1071
+ export declare function sideOf(batch: HourBatch, i: number): "buy" | "sell";
1072
+ export declare function protocolOf(batch: HourBatch, i: number): "pumpfun" | "pumpswap";
1073
+ /**
1074
+ * On-chain order of trades `i` and `j` of batches with `withOrder: true`
1075
+ * (possibly two batches), for `Array#sort`: slot, transaction, event; a
1076
+ * trade of unknown order after the known ones of its slot. Batches of
1077
+ * consecutive hours can overlap by a few slots (the provider files a trade
1078
+ * by its reception): sort across batches with this when that matters.
1079
+ */
1080
+ export declare function compareChainOrder(a: HourBatch, i: number, b: HourBatch, j: number): number;
1081
+ /** First millisecond of an hour number. */
1082
+ export declare function hourStartMs(hour: number): number;
1083
+ /** One trade as an object. Convenient, but slower than reading the columns. */
1084
+ export interface Trade {
1085
+ readonly id: string;
1086
+ readonly hour: number;
1087
+ readonly line: number;
1088
+ readonly op: number;
1089
+ readonly slot: number;
1090
+ readonly timeMs: number;
1091
+ readonly receivedMs: number | null;
1092
+ readonly side: "buy" | "sell";
1093
+ readonly protocol: "pumpfun" | "pumpswap";
1094
+ readonly mint: Address;
1095
+ readonly pool: Address | null;
1096
+ readonly trader: Address | null;
1097
+ readonly quoteMint: Address;
1098
+ readonly tokenRaw: bigint;
1099
+ readonly tokenDecimals: number;
1100
+ readonly quoteRaw: bigint;
1101
+ readonly quoteDecimals: number;
1102
+ readonly tokenAmount: number;
1103
+ readonly quoteAmount: number;
1104
+ readonly price: number | null;
1105
+ readonly priceSol: number | null;
1106
+ readonly priceUsd: number | null;
1107
+ readonly quotePriceUsd: number | null;
1108
+ readonly usdValue: number | null;
1109
+ readonly signature: string | null;
1110
+ }
1111
+ /** Row `i` of a batch as a {@link Trade} (`NaN` becomes `null`). */
1112
+ export declare function tradeAt(batch: HourBatch, i: number): Trade;
1113
+ /**
1114
+ * Stable codes of errors thrown inside a program by `ctx` calls. Test
1115
+ * `error.code`; `message` is for humans and may change.
1116
+ */
1117
+ export type SdkErrorCode = "invalid_window" | "partial_coverage" | "history_preparing" | "storage_busy" | "history_unavailable" | "read_limit" | "read_time_limit" | "invalid_argument" | "unknown_function" | "execution_not_found" | "state_value_too_large" | "state_limit" | "children_limit" | "subscription_limit" | "price_subscription_limit" | "output_limit" | StorageErrorCode | (string & {});
1118
+ /** Lakebed's `StorageErrorCode`, plus `already_exists`, `value_changed`, `io_limit`, `upload_limit`, `precondition_failed`. */
1119
+ export type StorageErrorCode = "quota_exceeded" | "too_large" | "not_found" | "invalid_request" | "forbidden" | "unavailable" | "blocked_type" | "already_exists" | "value_changed" | "io_limit" | "upload_limit" | "precondition_failed";
1120
+ /** HTTP status of each storage code (Lakebed's for its seven). */
1121
+ export declare const STORAGE_STATUS_BY_CODE: Readonly<Record<StorageErrorCode, number>>;
1122
+ /** Error thrown by a `ctx` call. `retryAfterMs` comes with `storage_busy`/`history_preparing`. */
1123
+ export interface SdkError extends Error {
1124
+ readonly code: SdkErrorCode;
1125
+ readonly retryAfterMs?: number;
1126
+ }
1127
+ /** `true` when `error` was thrown by a `ctx` call (optionally with this `code`). */
1128
+ export declare function isSdkError(error: unknown, code?: SdkErrorCode): error is SdkError;
1129
+ export {};