@kasufinance/kasu-sdk 2.12.0 → 2.13.1

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.
Files changed (62) hide show
  1. package/README.md +26 -1
  2. package/dist/bundle.cjs.js +974 -83
  3. package/dist/bundle.esm.js +971 -85
  4. package/dist/domain/index.d.ts +2 -0
  5. package/dist/domain/index.js +1 -0
  6. package/dist/domain/index.js.map +1 -1
  7. package/dist/domain/pool-tvl.d.ts +62 -0
  8. package/dist/domain/pool-tvl.js +22 -0
  9. package/dist/domain/pool-tvl.js.map +1 -0
  10. package/dist/domain/requests.d.ts +11 -10
  11. package/dist/facade/chain-configs.js +24 -0
  12. package/dist/facade/chain-configs.js.map +1 -1
  13. package/dist/facade/kasu.d.ts +2 -0
  14. package/dist/facade/kasu.js +13 -5
  15. package/dist/facade/kasu.js.map +1 -1
  16. package/dist/facade/strategies.d.ts +20 -0
  17. package/dist/facade/strategies.js +22 -0
  18. package/dist/facade/strategies.js.map +1 -1
  19. package/dist/facade/types.d.ts +20 -0
  20. package/dist/index.d.ts +4 -0
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/kasu-sdk.d.ts +9 -1
  24. package/dist/kasu-sdk.js +2 -2
  25. package/dist/kasu-sdk.js.map +1 -1
  26. package/dist/sdk-config.d.ts +20 -0
  27. package/dist/sdk-config.js +3 -1
  28. package/dist/sdk-config.js.map +1 -1
  29. package/dist/services/DataService/data-service.d.ts +81 -1
  30. package/dist/services/DataService/data-service.js +211 -6
  31. package/dist/services/DataService/data-service.js.map +1 -1
  32. package/dist/services/DataService/tvl-history.d.ts +296 -0
  33. package/dist/services/DataService/tvl-history.js +558 -0
  34. package/dist/services/DataService/tvl-history.js.map +1 -0
  35. package/dist/services/Portfolio/yield-history.d.ts +1 -16
  36. package/dist/services/Portfolio/yield-history.js +2 -29
  37. package/dist/services/Portfolio/yield-history.js.map +1 -1
  38. package/dist/services/UserLending/subgraph-types.d.ts +2 -8
  39. package/dist/services/UserLending/types.d.ts +10 -0
  40. package/dist/services/UserLending/user-lending.d.ts +14 -0
  41. package/dist/services/shared.d.ts +16 -0
  42. package/dist/services/shared.js +30 -0
  43. package/dist/services/shared.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/domain/index.ts +3 -0
  46. package/src/domain/pool-tvl.ts +66 -0
  47. package/src/domain/requests.ts +37 -23
  48. package/src/facade/chain-configs.ts +26 -0
  49. package/src/facade/kasu.ts +20 -2
  50. package/src/facade/strategies.ts +26 -0
  51. package/src/facade/types.ts +20 -0
  52. package/src/index.ts +9 -0
  53. package/src/kasu-sdk.ts +19 -2
  54. package/src/sdk-config.ts +22 -0
  55. package/src/services/DataService/data-service.ts +296 -6
  56. package/src/services/DataService/tvl-history.ts +853 -0
  57. package/src/services/Portfolio/yield-history.ts +2 -35
  58. package/src/services/UserLending/queries.ts +2 -7
  59. package/src/services/UserLending/subgraph-types.ts +2 -8
  60. package/src/services/UserLending/types.ts +10 -0
  61. package/src/services/UserLending/user-lending.ts +98 -40
  62. package/src/services/shared.ts +38 -1
@@ -0,0 +1,296 @@
1
+ import { BigNumber } from 'ethers';
2
+ import { PoolTvlHistoryEntry } from '../../domain/pool-tvl';
3
+ /**
4
+ * Which part of a pool's TVL history to return, and how long to wait for it.
5
+ * Epochs are counted in the chain's numbering
6
+ * (`SystemVariables.currentEpochNumber`), and the newest epoch is the
7
+ * CURRENT one, which the closing `current` point carries.
8
+ *
9
+ * - neither field: every clearing, then the `current` point;
10
+ * - `count` only: the newest `count` epochs, up to and including the current
11
+ * one (a pool that did not clear in some of them has fewer points);
12
+ * - `fromEpoch` only: `fromEpoch` up to the current epoch;
13
+ * - both: `count` epochs starting at `fromEpoch`, capped at the current
14
+ * epoch. The `current` point is included only when the window reaches the
15
+ * current epoch.
16
+ */
17
+ export interface PoolTvlHistoryOptions {
18
+ /** First epoch included. A non-negative integer. */
19
+ fromEpoch?: number;
20
+ /** How many epochs. A positive integer. */
21
+ count?: number;
22
+ /**
23
+ * The whole call's time limit, in MILLISECONDS. On expiry it rejects with
24
+ * `PoolTvlHistoryTimeoutError` and starts no further request.
25
+ * @default 30_000
26
+ */
27
+ timeoutMs?: number;
28
+ /**
29
+ * Abandons the call: it rejects with `PoolTvlHistoryAbortedError` and
30
+ * starts no further request. Already aborted = rejected before any read.
31
+ */
32
+ signal?: AbortSignal;
33
+ }
34
+ /** The resolved, inclusive epoch range; `null` when it is empty. */
35
+ export interface PoolTvlHistoryWindow {
36
+ fromEpoch: number;
37
+ toEpoch: number;
38
+ }
39
+ /** Clearings per subgraph page (the subgraph's own row cap). */
40
+ export declare const TVL_HISTORY_PAGE_SIZE = 1000;
41
+ /**
42
+ * A runaway guard on the clearings pagination, not a working limit: a pool
43
+ * clears once per epoch, so 20 pages would be twenty thousand cycles.
44
+ */
45
+ export declare const TVL_HISTORY_MAX_PAGES = 20;
46
+ /**
47
+ * How many past blocks one time-travel request reads, as GraphQL aliases. A
48
+ * pool with ~120 clearings costs two such requests.
49
+ */
50
+ export declare const TVL_HISTORY_BLOCKS_PER_REQUEST = 100;
51
+ /** At most this many past-state RPC reads are in flight at once. */
52
+ export declare const TVL_HISTORY_RPC_CONCURRENCY = 8;
53
+ /** Attempts per past-state RPC read (each over every history RPC in turn). */
54
+ export declare const TVL_HISTORY_RPC_ATTEMPTS = 3;
55
+ /** Back-off before the second attempt; doubled for each one after. */
56
+ export declare const TVL_HISTORY_RPC_RETRY_DELAY_MS = 500;
57
+ /** Per-call timeout of the history providers the SDK builds itself. */
58
+ export declare const TVL_HISTORY_RPC_TIMEOUT_MS = 10000;
59
+ /** Default `timeoutMs` of a whole `getPoolTvlHistory` call. */
60
+ export declare const TVL_HISTORY_DEFAULT_TIMEOUT_MS = 30000;
61
+ /**
62
+ * Blocks at least this far below the subgraph's head are treated as final
63
+ * and their reads are cached; nearer ones are read again every time.
64
+ */
65
+ export declare const TVL_HISTORY_CACHE_DEPTH = 64;
66
+ /** Entries per SDK instance before the cache starts again from empty. */
67
+ export declare const TVL_HISTORY_CACHE_LIMIT = 20000;
68
+ /** `getPoolTvlHistory` took longer than its `timeoutMs`. */
69
+ export declare class PoolTvlHistoryTimeoutError extends Error {
70
+ readonly timeoutMs: number;
71
+ constructor(timeoutMs: number);
72
+ }
73
+ /** `getPoolTvlHistory` was abandoned through its `signal`. */
74
+ export declare class PoolTvlHistoryAbortedError extends Error {
75
+ constructor();
76
+ }
77
+ /**
78
+ * A history provider answered a past block as if nothing were deployed — no
79
+ * code even for the pool, which cleared in that very block. A pruned node
80
+ * does that; trusting it would draw the off-chain TVL as 0.
81
+ */
82
+ export declare class PastStateUnavailableError extends Error {
83
+ readonly block: number;
84
+ constructor(block: number);
85
+ }
86
+ /**
87
+ * Throws `RangeError` / `TypeError` on a malformed option.
88
+ * `getPoolTvlHistory` calls it ONCE, BEFORE any network read;
89
+ * `resolvePoolTvlHistoryWindow` assumes it has run.
90
+ */
91
+ export declare function validatePoolTvlHistoryOptions(options: PoolTvlHistoryOptions): void;
92
+ /** The epoch window. Options must already have passed validation. */
93
+ export declare function resolvePoolTvlHistoryWindow(options: Pick<PoolTvlHistoryOptions, 'fromEpoch' | 'count'>, currentEpoch: number): PoolTvlHistoryWindow | null;
94
+ /** What every stage checks before it starts more work. */
95
+ export interface Cancellation {
96
+ /** Aborted with the call; hand it to `fetch`-based clients. */
97
+ readonly signal: AbortSignal;
98
+ /** Throws the typed reason once the call is timed out or aborted. */
99
+ throwIfCancelled(): void;
100
+ }
101
+ /**
102
+ * Runs `work` under a deadline and an optional caller signal. Whichever comes
103
+ * first rejects the returned promise with its typed error at once, aborts
104
+ * `cancellation.signal` (cancelling in-flight subgraph requests) and makes
105
+ * every later `throwIfCancelled()` throw, so no new read starts. An RPC call
106
+ * already sent cannot be recalled; its answer is dropped.
107
+ */
108
+ export declare function runCancellable<T>(timeoutMs: number, external: AbortSignal | undefined, work: (cancellation: Cancellation) => Promise<T>): Promise<T>;
109
+ /**
110
+ * The pool's FINISHED clearings, plus — on the first page only — its balance
111
+ * now and the subgraph's latest block.
112
+ *
113
+ * Two modes over one document: ascending from `$epochGte` (a `fromEpoch`
114
+ * window, or everything), or descending below `$epochLt` (the newest N, for
115
+ * a `count`-only window, so it never pages through the whole history).
116
+ */
117
+ export declare const poolTvlClearingsQuery: string;
118
+ export interface ClearingRow {
119
+ epochId: string;
120
+ endBlockNumber: string;
121
+ endTimestamp: string;
122
+ }
123
+ export interface PoolTvlSnapshot {
124
+ pool?: {
125
+ balance: string;
126
+ } | null;
127
+ meta?: {
128
+ block: {
129
+ number: number;
130
+ timestamp: number | null;
131
+ };
132
+ } | null;
133
+ }
134
+ export interface PoolTvlClearingsResult extends PoolTvlSnapshot {
135
+ clearings: ClearingRow[];
136
+ }
137
+ /** The time-travel alias for one block: `b<block>`. */
138
+ export declare function blockAlias(block: number): string;
139
+ /**
140
+ * One time-travel request: the pool's balance at the END of each block, one
141
+ * alias per block. Block numbers are written into the document, so each must
142
+ * be a positive safe integer — anything else throws rather than reaching the
143
+ * query text. The pool id travels as a variable.
144
+ */
145
+ export declare function poolBalancesAtBlocksQuery(blocks: readonly number[]): string;
146
+ export type PoolBalancesAtBlocksResult = Record<string, {
147
+ balance: string;
148
+ } | null>;
149
+ /** One subgraph request; `signal` cancels it. */
150
+ export type GraphRequest = <T>(document: string, variables: Record<string, unknown>, signal?: AbortSignal) => Promise<T>;
151
+ /** A clearing row parsed and checked. */
152
+ export interface Clearing {
153
+ epochId: number;
154
+ block: number;
155
+ timestamp: number;
156
+ }
157
+ /** Which clearings to read: ascending from an epoch, or the newest N. */
158
+ export type ClearingsScope = {
159
+ kind: 'from';
160
+ fromEpoch: number;
161
+ } | {
162
+ kind: 'newest';
163
+ count: number;
164
+ };
165
+ /**
166
+ * The scope's finished clearings, ascending by epoch, and the snapshot from
167
+ * the first page. Normally ONE request.
168
+ */
169
+ export declare function fetchPoolClearings(request: GraphRequest, poolId: string, scope: ClearingsScope, cancellation: Cancellation): Promise<{
170
+ clearings: Clearing[];
171
+ snapshot: PoolTvlSnapshot;
172
+ requests: number;
173
+ }>;
174
+ /**
175
+ * The pool's balance (display units, the subgraph's decimal string) at the end
176
+ * of each block, `TVL_HISTORY_BLOCKS_PER_REQUEST` blocks per request. A block
177
+ * at which the subgraph has no such pool THROWS: a finished clearing of the
178
+ * pool happened in it, so a missing pool means a broken read, not a zero.
179
+ */
180
+ export declare function fetchPoolBalancesAtBlocks(request: GraphRequest, poolId: string, blocks: readonly number[], cancellation: Cancellation): Promise<{
181
+ balances: Map<number, string>;
182
+ requests: number;
183
+ }>;
184
+ /**
185
+ * What a history provider must answer: an `eth_call` and an `eth_getCode`
186
+ * at a block. Any ethers v5 `Provider` is one.
187
+ */
188
+ export interface HistoryRpc {
189
+ call(transaction: {
190
+ to: string;
191
+ data: string;
192
+ }, blockTag: number | 'latest'): Promise<string>;
193
+ getCode(address: string, blockTag: number): Promise<string>;
194
+ }
195
+ /**
196
+ * The past-state reads behind the off-chain TVL. Every method rejects on any
197
+ * failure; none may turn an error into a value.
198
+ */
199
+ export interface OffChainTvlReader {
200
+ /** `externalTVLOfPool(pool)` at `block`, in the stable token's BASE units. */
201
+ readAt(block: number | 'latest'): Promise<BigNumber>;
202
+ /** Whether the `ExternalTVL` contract has code at `block`. */
203
+ hasCodeAt(block: number): Promise<boolean>;
204
+ /** Whether the POOL contract has code at `block` (the pruned-node check). */
205
+ poolHasCodeAt(block: number): Promise<boolean>;
206
+ }
207
+ /**
208
+ * The real reader: each read goes to the history RPCs IN ORDER until one
209
+ * answers, and the whole chain is retried `attempts` times with back-off.
210
+ * After the last attempt the last error propagates — never a value. Each
211
+ * attempt first checks the cancellation, so a timed-out call stops here.
212
+ */
213
+ export declare function createOffChainTvlReader({ externalTvl, pool, rpcs, cancellation, attempts, delayMs, sleep, }: {
214
+ externalTvl: string;
215
+ pool: string;
216
+ rpcs: readonly HistoryRpc[];
217
+ cancellation: Cancellation;
218
+ attempts?: number;
219
+ delayMs?: number;
220
+ sleep?: (ms: number) => Promise<void>;
221
+ }): OffChainTvlReader;
222
+ /**
223
+ * Index of the first block (of `blocks`, ascending) at which the contract has
224
+ * code; `blocks.length` when it has code at none. A deployed contract keeps
225
+ * its code (it is a proxy, never self-destructed), so the answer is a single
226
+ * boundary and a binary search finds it: ONE `getCode` when the contract
227
+ * already existed at the oldest clearing, about log2(n) otherwise.
228
+ */
229
+ export declare function firstBlockWithCode(blocks: readonly number[], hasCodeAt: (block: number) => Promise<boolean>): Promise<number>;
230
+ /**
231
+ * `fn` over `items`, at most `limit` in flight; rejects on the first failure
232
+ * and starts nothing after it (or after `beforeEach` throws).
233
+ */
234
+ export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, fn: (item: T) => Promise<R>, beforeEach?: () => void): Promise<R[]>;
235
+ /**
236
+ * Immutable past-block reads, per SDK instance. Keys carry the contract (or
237
+ * subgraph), the pool and the block, so two deployments never collide.
238
+ */
239
+ export declare class PastBlockCache {
240
+ private readonly _entries;
241
+ get<T>(key: string): T | undefined;
242
+ set(key: string, value: unknown): void;
243
+ get size(): number;
244
+ }
245
+ /**
246
+ * The off-chain TVL (BASE units) at each block, and — with `withLatest` — at
247
+ * the latest block, all inside ONE bounded pool of reads.
248
+ *
249
+ * Before the contract existed there was nothing to record, so those blocks
250
+ * are 0 — decided by `getCode`, never by catching a revert: an RPC that
251
+ * refuses past state can surface that refusal as a "call exception". And a
252
+ * "no code" answer is believed only if the same provider DOES show code for
253
+ * the pool at the oldest and newest such block (it cleared there); otherwise
254
+ * `PastStateUnavailableError`. Every other failed read throws.
255
+ *
256
+ * `cached` blocks (final, below the head) are answered from `cache` and
257
+ * stored there after a successful read.
258
+ */
259
+ export declare function fetchOffChainTvlAtBlocks(reader: OffChainTvlReader, blocks: readonly number[], { withLatest, cancellation, cache, cacheKey, cacheable, }: {
260
+ withLatest?: boolean;
261
+ cancellation: Cancellation;
262
+ cache?: PastBlockCache;
263
+ cacheKey?: (kind: 'tvl' | 'code' | 'pool', block: number) => string;
264
+ cacheable?: (block: number) => boolean;
265
+ }): Promise<{
266
+ offChain: Map<number, BigNumber>;
267
+ latest: BigNumber | null;
268
+ rpcReads: number;
269
+ }>;
270
+ export interface PoolTvlHistoryRead {
271
+ /** Finished clearings inside the window. */
272
+ clearings: Clearing[];
273
+ /** On-chain balance (display units) at each distinct clearing block. */
274
+ balances: ReadonlyMap<number, string>;
275
+ /** Off-chain TVL (BASE units) at each distinct clearing block. */
276
+ offChain: ReadonlyMap<number, BigNumber>;
277
+ /** The closing point's inputs; `null` when the window stops short of now. */
278
+ current: {
279
+ epochId: number;
280
+ timestamp: number;
281
+ balance: string;
282
+ offChain: BigNumber;
283
+ } | null;
284
+ /** The stable token's decimals, for the off-chain BASE units. */
285
+ decimals: number;
286
+ }
287
+ /**
288
+ * Pure: the reads → the history. One `clearing` point per clearing, ordered by
289
+ * the block it finished in (then by epoch, for clearings that shared a block),
290
+ * so the series is ascending in TIME even where epoch numbers jump; then the
291
+ * `current` point. Each point is `poolTvl(onChain, offChain)` — the same
292
+ * function `getPoolOverview` uses for `totalValueLocked.total`.
293
+ */
294
+ export declare function buildPoolTvlHistory(read: PoolTvlHistoryRead): PoolTvlHistoryEntry[];
295
+ /** Ascending, de-duplicated clearing blocks: each past block is read ONCE. */
296
+ export declare function distinctBlocks(clearings: readonly Clearing[]): number[];