@kasufinance/kasu-sdk 2.12.0 → 2.13.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 +26 -1
- package/dist/bundle.cjs.js +871 -41
- package/dist/bundle.esm.js +868 -43
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.js +1 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/pool-tvl.d.ts +62 -0
- package/dist/domain/pool-tvl.js +22 -0
- package/dist/domain/pool-tvl.js.map +1 -0
- package/dist/facade/chain-configs.js +24 -0
- package/dist/facade/chain-configs.js.map +1 -1
- package/dist/facade/kasu.d.ts +2 -0
- package/dist/facade/kasu.js +13 -5
- package/dist/facade/kasu.js.map +1 -1
- package/dist/facade/strategies.d.ts +20 -0
- package/dist/facade/strategies.js +22 -0
- package/dist/facade/strategies.js.map +1 -1
- package/dist/facade/types.d.ts +20 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/kasu-sdk.d.ts +9 -1
- package/dist/kasu-sdk.js +2 -2
- package/dist/kasu-sdk.js.map +1 -1
- package/dist/sdk-config.d.ts +20 -0
- package/dist/sdk-config.js +3 -1
- package/dist/sdk-config.js.map +1 -1
- package/dist/services/DataService/data-service.d.ts +81 -1
- package/dist/services/DataService/data-service.js +211 -6
- package/dist/services/DataService/data-service.js.map +1 -1
- package/dist/services/DataService/tvl-history.d.ts +296 -0
- package/dist/services/DataService/tvl-history.js +558 -0
- package/dist/services/DataService/tvl-history.js.map +1 -0
- package/dist/services/Portfolio/yield-history.d.ts +1 -16
- package/dist/services/Portfolio/yield-history.js +2 -29
- package/dist/services/Portfolio/yield-history.js.map +1 -1
- package/dist/services/shared.d.ts +16 -0
- package/dist/services/shared.js +30 -0
- package/dist/services/shared.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/index.ts +3 -0
- package/src/domain/pool-tvl.ts +66 -0
- package/src/facade/chain-configs.ts +26 -0
- package/src/facade/kasu.ts +20 -2
- package/src/facade/strategies.ts +26 -0
- package/src/facade/types.ts +20 -0
- package/src/index.ts +9 -0
- package/src/kasu-sdk.ts +19 -2
- package/src/sdk-config.ts +22 -0
- package/src/services/DataService/data-service.ts +296 -6
- package/src/services/DataService/tvl-history.ts +853 -0
- package/src/services/Portfolio/yield-history.ts +2 -35
- 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[];
|