@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.
- package/README.md +26 -1
- package/dist/bundle.cjs.js +974 -83
- package/dist/bundle.esm.js +971 -85
- 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/domain/requests.d.ts +11 -10
- 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/UserLending/subgraph-types.d.ts +2 -8
- package/dist/services/UserLending/types.d.ts +10 -0
- package/dist/services/UserLending/user-lending.d.ts +14 -0
- 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/domain/requests.ts +37 -23
- 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/UserLending/queries.ts +2 -7
- package/src/services/UserLending/subgraph-types.ts +2 -8
- package/src/services/UserLending/types.ts +10 -0
- package/src/services/UserLending/user-lending.ts +98 -40
- package/src/services/shared.ts +38 -1
package/dist/bundle.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { utils as utils$2, Contract, BigNumber, providers, ethers, constants, Signer } from 'ethers';
|
|
2
|
+
import { Interface, formatUnits, isAddress, parseUnits, formatEther, defaultAbiCoder, parseEther } from 'ethers/lib/utils';
|
|
3
3
|
|
|
4
4
|
const defaultJsonSerializer = JSON;
|
|
5
5
|
|
|
@@ -15479,6 +15479,28 @@ class KasuPoolExternalTVLAbi__factory {
|
|
|
15479
15479
|
}
|
|
15480
15480
|
KasuPoolExternalTVLAbi__factory.abi = _abi;
|
|
15481
15481
|
|
|
15482
|
+
/**
|
|
15483
|
+
* A pool's TVL — the total lent into it by everyone — and the shape of its
|
|
15484
|
+
* history. Pure: the reads live in `services/DataService/tvl-history.ts`.
|
|
15485
|
+
*/
|
|
15486
|
+
/**
|
|
15487
|
+
* The ONE definition of a pool's TVL: what lenders have lent on chain
|
|
15488
|
+
* (`lendingPool.balance` in the subgraph) plus the off-chain amount the
|
|
15489
|
+
* pool's `ExternalTVL` contract records (`externalTVLOfPool`).
|
|
15490
|
+
*
|
|
15491
|
+
* Both inputs, and the result, are in DISPLAY units of the deployment's own
|
|
15492
|
+
* stable token (USDC on Base and XDC USDC, AUDD on XDC AUDD) — `'1.5'` is
|
|
15493
|
+
* one and a half tokens, not 1.5 minor units. Convert before formatting as
|
|
15494
|
+
* USD.
|
|
15495
|
+
*
|
|
15496
|
+
* `getPoolOverview` (its `totalValueLocked.total`) and `getPoolTvlHistory`
|
|
15497
|
+
* (every point) both call this, so the chart and the figure above it cannot
|
|
15498
|
+
* be computed two ways.
|
|
15499
|
+
*/
|
|
15500
|
+
function poolTvl(onChainBalance, offChainTvl) {
|
|
15501
|
+
return parseFloat(onChainBalance) + parseFloat(offChainTvl);
|
|
15502
|
+
}
|
|
15503
|
+
|
|
15482
15504
|
/**
|
|
15483
15505
|
* Epochs in a year — the single source of truth for every rate conversion in
|
|
15484
15506
|
* the SDK and in every consumer that undoes one.
|
|
@@ -15718,6 +15740,36 @@ function filterArray(array, id_in) {
|
|
|
15718
15740
|
});
|
|
15719
15741
|
}
|
|
15720
15742
|
}
|
|
15743
|
+
/**
|
|
15744
|
+
* A GraphQL VALIDATION error naming an entity, field or argument this
|
|
15745
|
+
* deployment's subgraph does not have. A network error, a timeout or an
|
|
15746
|
+
* indexing error is not one.
|
|
15747
|
+
*/
|
|
15748
|
+
function isMissingEntityError(error) {
|
|
15749
|
+
if (typeof error !== 'object' || error === null)
|
|
15750
|
+
return false;
|
|
15751
|
+
const response = error.response;
|
|
15752
|
+
const errors = response === null || response === void 0 ? void 0 : response.errors;
|
|
15753
|
+
if (!Array.isArray(errors) || errors.length === 0)
|
|
15754
|
+
return false;
|
|
15755
|
+
return errors.every((e) => {
|
|
15756
|
+
const message = e === null || e === void 0 ? void 0 : e.message;
|
|
15757
|
+
return (typeof message === 'string' &&
|
|
15758
|
+
/has no field|cannot query field|unknown (type|field|argument)|no such (type|field)/i.test(message));
|
|
15759
|
+
});
|
|
15760
|
+
}
|
|
15761
|
+
/**
|
|
15762
|
+
* The only failure a history read (`getYieldHistory`, `getPoolTvlHistory`)
|
|
15763
|
+
* turns into `[]`: a missing-schema error
|
|
15764
|
+
* on a LITE deployment, whose subgraph may predate the entities. On a full
|
|
15765
|
+
* deployment the entities are part of the schema, so the same error means a
|
|
15766
|
+
* broken query or subgraph and THROWS — an empty chart there would hide it.
|
|
15767
|
+
* Everything else (network, timeout, indexing) throws on every deployment, so
|
|
15768
|
+
* a consumer can tell "no history here" from "history unavailable".
|
|
15769
|
+
*/
|
|
15770
|
+
function isEmptyHistoryError(error, liteDeployment) {
|
|
15771
|
+
return liteDeployment && isMissingEntityError(error);
|
|
15772
|
+
}
|
|
15721
15773
|
|
|
15722
15774
|
/**
|
|
15723
15775
|
* The error a CMS-only call raises on a deployment configured without
|
|
@@ -15907,11 +15959,569 @@ const getLendingPoolWithdrawalAndDepositsQuery = gql `
|
|
|
15907
15959
|
}
|
|
15908
15960
|
`;
|
|
15909
15961
|
|
|
15962
|
+
/** Clearings per subgraph page (the subgraph's own row cap). */
|
|
15963
|
+
const TVL_HISTORY_PAGE_SIZE = 1000;
|
|
15964
|
+
/**
|
|
15965
|
+
* A runaway guard on the clearings pagination, not a working limit: a pool
|
|
15966
|
+
* clears once per epoch, so 20 pages would be twenty thousand cycles.
|
|
15967
|
+
*/
|
|
15968
|
+
const TVL_HISTORY_MAX_PAGES = 20;
|
|
15969
|
+
/**
|
|
15970
|
+
* How many past blocks one time-travel request reads, as GraphQL aliases. A
|
|
15971
|
+
* pool with ~120 clearings costs two such requests.
|
|
15972
|
+
*/
|
|
15973
|
+
const TVL_HISTORY_BLOCKS_PER_REQUEST = 100;
|
|
15974
|
+
/** At most this many past-state RPC reads are in flight at once. */
|
|
15975
|
+
const TVL_HISTORY_RPC_CONCURRENCY = 8;
|
|
15976
|
+
/** Attempts per past-state RPC read (each over every history RPC in turn). */
|
|
15977
|
+
const TVL_HISTORY_RPC_ATTEMPTS = 3;
|
|
15978
|
+
/** Back-off before the second attempt; doubled for each one after. */
|
|
15979
|
+
const TVL_HISTORY_RPC_RETRY_DELAY_MS = 500;
|
|
15980
|
+
/** Per-call timeout of the history providers the SDK builds itself. */
|
|
15981
|
+
const TVL_HISTORY_RPC_TIMEOUT_MS = 10000;
|
|
15982
|
+
/** Default `timeoutMs` of a whole `getPoolTvlHistory` call. */
|
|
15983
|
+
const TVL_HISTORY_DEFAULT_TIMEOUT_MS = 30000;
|
|
15984
|
+
/**
|
|
15985
|
+
* Blocks at least this far below the subgraph's head are treated as final
|
|
15986
|
+
* and their reads are cached; nearer ones are read again every time.
|
|
15987
|
+
*/
|
|
15988
|
+
const TVL_HISTORY_CACHE_DEPTH = 64;
|
|
15989
|
+
/** Entries per SDK instance before the cache starts again from empty. */
|
|
15990
|
+
const TVL_HISTORY_CACHE_LIMIT = 20000;
|
|
15991
|
+
/** `getPoolTvlHistory` took longer than its `timeoutMs`. */
|
|
15992
|
+
class PoolTvlHistoryTimeoutError extends Error {
|
|
15993
|
+
constructor(timeoutMs) {
|
|
15994
|
+
super(`getPoolTvlHistory: timed out after ${String(timeoutMs)} ms`);
|
|
15995
|
+
this.timeoutMs = timeoutMs;
|
|
15996
|
+
this.name = 'PoolTvlHistoryTimeoutError';
|
|
15997
|
+
}
|
|
15998
|
+
}
|
|
15999
|
+
/** `getPoolTvlHistory` was abandoned through its `signal`. */
|
|
16000
|
+
class PoolTvlHistoryAbortedError extends Error {
|
|
16001
|
+
constructor() {
|
|
16002
|
+
super('getPoolTvlHistory: aborted');
|
|
16003
|
+
this.name = 'PoolTvlHistoryAbortedError';
|
|
16004
|
+
}
|
|
16005
|
+
}
|
|
16006
|
+
/**
|
|
16007
|
+
* A history provider answered a past block as if nothing were deployed — no
|
|
16008
|
+
* code even for the pool, which cleared in that very block. A pruned node
|
|
16009
|
+
* does that; trusting it would draw the off-chain TVL as 0.
|
|
16010
|
+
*/
|
|
16011
|
+
class PastStateUnavailableError extends Error {
|
|
16012
|
+
constructor(block) {
|
|
16013
|
+
super(`getPoolTvlHistory: history provider does not serve past state (no code for the pool at block ${String(block)}, where it cleared)`);
|
|
16014
|
+
this.block = block;
|
|
16015
|
+
this.name = 'PastStateUnavailableError';
|
|
16016
|
+
}
|
|
16017
|
+
}
|
|
16018
|
+
/**
|
|
16019
|
+
* Throws `RangeError` / `TypeError` on a malformed option.
|
|
16020
|
+
* `getPoolTvlHistory` calls it ONCE, BEFORE any network read;
|
|
16021
|
+
* `resolvePoolTvlHistoryWindow` assumes it has run.
|
|
16022
|
+
*/
|
|
16023
|
+
function validatePoolTvlHistoryOptions(options) {
|
|
16024
|
+
const { fromEpoch, count, timeoutMs, signal } = options;
|
|
16025
|
+
if (fromEpoch !== undefined &&
|
|
16026
|
+
(!Number.isSafeInteger(fromEpoch) || fromEpoch < 0)) {
|
|
16027
|
+
throw new RangeError(`getPoolTvlHistory: fromEpoch must be a non-negative integer, got ${String(fromEpoch)}`);
|
|
16028
|
+
}
|
|
16029
|
+
if (count !== undefined && (!Number.isSafeInteger(count) || count < 1)) {
|
|
16030
|
+
throw new RangeError(`getPoolTvlHistory: count must be a positive integer, got ${String(count)}`);
|
|
16031
|
+
}
|
|
16032
|
+
if (timeoutMs !== undefined &&
|
|
16033
|
+
(typeof timeoutMs !== 'number' ||
|
|
16034
|
+
!Number.isFinite(timeoutMs) ||
|
|
16035
|
+
timeoutMs <= 0)) {
|
|
16036
|
+
throw new RangeError(`getPoolTvlHistory: timeoutMs must be a positive number, got ${String(timeoutMs)}`);
|
|
16037
|
+
}
|
|
16038
|
+
if (signal !== undefined &&
|
|
16039
|
+
(typeof signal !== 'object' ||
|
|
16040
|
+
typeof signal.aborted !== 'boolean')) {
|
|
16041
|
+
throw new TypeError('getPoolTvlHistory: signal must be an AbortSignal');
|
|
16042
|
+
}
|
|
16043
|
+
}
|
|
16044
|
+
/** The epoch window. Options must already have passed validation. */
|
|
16045
|
+
function resolvePoolTvlHistoryWindow(options, currentEpoch) {
|
|
16046
|
+
const { fromEpoch, count } = options;
|
|
16047
|
+
let from;
|
|
16048
|
+
let to = currentEpoch;
|
|
16049
|
+
if (fromEpoch !== undefined) {
|
|
16050
|
+
from = fromEpoch;
|
|
16051
|
+
if (count !== undefined) {
|
|
16052
|
+
to = Math.min(currentEpoch, fromEpoch + count - 1);
|
|
16053
|
+
}
|
|
16054
|
+
}
|
|
16055
|
+
else {
|
|
16056
|
+
from = count !== undefined ? Math.max(0, currentEpoch - count + 1) : 0;
|
|
16057
|
+
}
|
|
16058
|
+
return from > to ? null : { fromEpoch: from, toEpoch: to };
|
|
16059
|
+
}
|
|
16060
|
+
/**
|
|
16061
|
+
* Runs `work` under a deadline and an optional caller signal. Whichever comes
|
|
16062
|
+
* first rejects the returned promise with its typed error at once, aborts
|
|
16063
|
+
* `cancellation.signal` (cancelling in-flight subgraph requests) and makes
|
|
16064
|
+
* every later `throwIfCancelled()` throw, so no new read starts. An RPC call
|
|
16065
|
+
* already sent cannot be recalled; its answer is dropped.
|
|
16066
|
+
*/
|
|
16067
|
+
function runCancellable(timeoutMs, external, work) {
|
|
16068
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16069
|
+
if (external === null || external === void 0 ? void 0 : external.aborted)
|
|
16070
|
+
throw new PoolTvlHistoryAbortedError();
|
|
16071
|
+
const controller = new AbortController();
|
|
16072
|
+
let reason;
|
|
16073
|
+
let rejectCancelled = () => undefined;
|
|
16074
|
+
const cancelled = new Promise((_, reject) => {
|
|
16075
|
+
rejectCancelled = reject;
|
|
16076
|
+
});
|
|
16077
|
+
const cancel = (error) => {
|
|
16078
|
+
if (reason)
|
|
16079
|
+
return;
|
|
16080
|
+
reason = error;
|
|
16081
|
+
controller.abort();
|
|
16082
|
+
rejectCancelled(error);
|
|
16083
|
+
};
|
|
16084
|
+
const timer = setTimeout(() => {
|
|
16085
|
+
cancel(new PoolTvlHistoryTimeoutError(timeoutMs));
|
|
16086
|
+
}, timeoutMs);
|
|
16087
|
+
const onAbort = () => {
|
|
16088
|
+
cancel(new PoolTvlHistoryAbortedError());
|
|
16089
|
+
};
|
|
16090
|
+
external === null || external === void 0 ? void 0 : external.addEventListener('abort', onAbort);
|
|
16091
|
+
const cancellation = {
|
|
16092
|
+
signal: controller.signal,
|
|
16093
|
+
throwIfCancelled: () => {
|
|
16094
|
+
if (reason)
|
|
16095
|
+
throw reason;
|
|
16096
|
+
},
|
|
16097
|
+
};
|
|
16098
|
+
try {
|
|
16099
|
+
const running = work(cancellation);
|
|
16100
|
+
// The losing side must never surface as an unhandled rejection.
|
|
16101
|
+
running.catch(() => undefined);
|
|
16102
|
+
return yield Promise.race([running, cancelled]);
|
|
16103
|
+
}
|
|
16104
|
+
finally {
|
|
16105
|
+
clearTimeout(timer);
|
|
16106
|
+
external === null || external === void 0 ? void 0 : external.removeEventListener('abort', onAbort);
|
|
16107
|
+
}
|
|
16108
|
+
});
|
|
16109
|
+
}
|
|
16110
|
+
// ---------------------------------------------------------------------------
|
|
16111
|
+
// Subgraph reads
|
|
16112
|
+
// ---------------------------------------------------------------------------
|
|
16113
|
+
/** Above any epoch number: "no upper bound" for the clearings query. */
|
|
16114
|
+
const NO_EPOCH_BOUND = '1000000000000';
|
|
16115
|
+
/**
|
|
16116
|
+
* The pool's FINISHED clearings, plus — on the first page only — its balance
|
|
16117
|
+
* now and the subgraph's latest block.
|
|
16118
|
+
*
|
|
16119
|
+
* Two modes over one document: ascending from `$epochGte` (a `fromEpoch`
|
|
16120
|
+
* window, or everything), or descending below `$epochLt` (the newest N, for
|
|
16121
|
+
* a `count`-only window, so it never pages through the whole history).
|
|
16122
|
+
*/
|
|
16123
|
+
const poolTvlClearingsQuery = gql `
|
|
16124
|
+
query PoolTvlClearings(
|
|
16125
|
+
$poolId: ID!
|
|
16126
|
+
$pool: String!
|
|
16127
|
+
$epochGte: BigInt!
|
|
16128
|
+
$epochLt: BigInt!
|
|
16129
|
+
$direction: OrderDirection!
|
|
16130
|
+
$first: Int!
|
|
16131
|
+
$withSnapshot: Boolean!
|
|
16132
|
+
) {
|
|
16133
|
+
clearings: lendingPoolClearings(
|
|
16134
|
+
first: $first
|
|
16135
|
+
orderBy: epochId
|
|
16136
|
+
orderDirection: $direction
|
|
16137
|
+
where: {
|
|
16138
|
+
lendingPool: $pool
|
|
16139
|
+
isFinished: true
|
|
16140
|
+
epochId_gte: $epochGte
|
|
16141
|
+
epochId_lt: $epochLt
|
|
16142
|
+
}
|
|
16143
|
+
) {
|
|
16144
|
+
epochId
|
|
16145
|
+
endBlockNumber
|
|
16146
|
+
endTimestamp
|
|
16147
|
+
}
|
|
16148
|
+
pool: lendingPool(id: $poolId) @include(if: $withSnapshot) {
|
|
16149
|
+
balance
|
|
16150
|
+
}
|
|
16151
|
+
meta: _meta @include(if: $withSnapshot) {
|
|
16152
|
+
block {
|
|
16153
|
+
number
|
|
16154
|
+
timestamp
|
|
16155
|
+
}
|
|
16156
|
+
}
|
|
16157
|
+
}
|
|
16158
|
+
`;
|
|
16159
|
+
/** The time-travel alias for one block: `b<block>`. */
|
|
16160
|
+
function blockAlias(block) {
|
|
16161
|
+
return `b${String(block)}`;
|
|
16162
|
+
}
|
|
16163
|
+
/**
|
|
16164
|
+
* One time-travel request: the pool's balance at the END of each block, one
|
|
16165
|
+
* alias per block. Block numbers are written into the document, so each must
|
|
16166
|
+
* be a positive safe integer — anything else throws rather than reaching the
|
|
16167
|
+
* query text. The pool id travels as a variable.
|
|
16168
|
+
*/
|
|
16169
|
+
function poolBalancesAtBlocksQuery(blocks) {
|
|
16170
|
+
const fields = blocks.map((block) => {
|
|
16171
|
+
if (!Number.isSafeInteger(block) || block <= 0) {
|
|
16172
|
+
throw new Error(`getPoolTvlHistory: refusing block number ${String(block)}`);
|
|
16173
|
+
}
|
|
16174
|
+
return `${blockAlias(block)}: lendingPool(id: $poolId, block: { number: ${String(block)} }) { balance }`;
|
|
16175
|
+
});
|
|
16176
|
+
return `query PoolTvlAtBlocks($poolId: ID!) { ${fields.join(' ')} }`;
|
|
16177
|
+
}
|
|
16178
|
+
function parseClearing(row) {
|
|
16179
|
+
const clearing = {
|
|
16180
|
+
epochId: Number(row.epochId),
|
|
16181
|
+
block: Number(row.endBlockNumber),
|
|
16182
|
+
timestamp: Number(row.endTimestamp),
|
|
16183
|
+
};
|
|
16184
|
+
if (!Number.isSafeInteger(clearing.epochId) ||
|
|
16185
|
+
clearing.epochId < 0 ||
|
|
16186
|
+
!Number.isSafeInteger(clearing.block) ||
|
|
16187
|
+
clearing.block <= 0 ||
|
|
16188
|
+
!Number.isSafeInteger(clearing.timestamp) ||
|
|
16189
|
+
clearing.timestamp <= 0) {
|
|
16190
|
+
throw new Error(`getPoolTvlHistory: malformed clearing row ${JSON.stringify(row)}`);
|
|
16191
|
+
}
|
|
16192
|
+
return clearing;
|
|
16193
|
+
}
|
|
16194
|
+
/**
|
|
16195
|
+
* The scope's finished clearings, ascending by epoch, and the snapshot from
|
|
16196
|
+
* the first page. Normally ONE request.
|
|
16197
|
+
*/
|
|
16198
|
+
function fetchPoolClearings(request, poolId, scope, cancellation) {
|
|
16199
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16200
|
+
const clearings = [];
|
|
16201
|
+
let snapshot = {};
|
|
16202
|
+
let gte = scope.kind === 'from' ? scope.fromEpoch : 0;
|
|
16203
|
+
let lt;
|
|
16204
|
+
let requests = 0;
|
|
16205
|
+
for (;;) {
|
|
16206
|
+
cancellation.throwIfCancelled();
|
|
16207
|
+
if (requests >= TVL_HISTORY_MAX_PAGES) {
|
|
16208
|
+
throw new Error(`getPoolTvlHistory: more than ${String(TVL_HISTORY_MAX_PAGES)} pages of clearings for one pool`);
|
|
16209
|
+
}
|
|
16210
|
+
const first = requests === 0;
|
|
16211
|
+
const remaining = scope.kind === 'newest'
|
|
16212
|
+
? scope.count - clearings.length
|
|
16213
|
+
: TVL_HISTORY_PAGE_SIZE;
|
|
16214
|
+
const pageSize = Math.min(TVL_HISTORY_PAGE_SIZE, remaining);
|
|
16215
|
+
const page = yield request(poolTvlClearingsQuery, {
|
|
16216
|
+
poolId,
|
|
16217
|
+
pool: poolId,
|
|
16218
|
+
epochGte: String(gte),
|
|
16219
|
+
epochLt: lt === undefined ? NO_EPOCH_BOUND : String(lt),
|
|
16220
|
+
direction: scope.kind === 'newest' ? 'desc' : 'asc',
|
|
16221
|
+
first: pageSize,
|
|
16222
|
+
withSnapshot: first,
|
|
16223
|
+
}, cancellation.signal);
|
|
16224
|
+
requests += 1;
|
|
16225
|
+
if (first)
|
|
16226
|
+
snapshot = { pool: page.pool, meta: page.meta };
|
|
16227
|
+
const rows = page.clearings.map(parseClearing);
|
|
16228
|
+
clearings.push(...rows);
|
|
16229
|
+
const last = rows.at(-1);
|
|
16230
|
+
if (rows.length < pageSize || last === undefined)
|
|
16231
|
+
break;
|
|
16232
|
+
if (scope.kind === 'newest') {
|
|
16233
|
+
if (clearings.length >= scope.count)
|
|
16234
|
+
break;
|
|
16235
|
+
if (lt !== undefined && last.epochId >= lt) {
|
|
16236
|
+
throw new Error('getPoolTvlHistory: the clearings cursor did not advance');
|
|
16237
|
+
}
|
|
16238
|
+
lt = last.epochId;
|
|
16239
|
+
}
|
|
16240
|
+
else {
|
|
16241
|
+
if (last.epochId < gte) {
|
|
16242
|
+
throw new Error('getPoolTvlHistory: the clearings cursor did not advance');
|
|
16243
|
+
}
|
|
16244
|
+
gte = last.epochId + 1;
|
|
16245
|
+
}
|
|
16246
|
+
}
|
|
16247
|
+
clearings.sort((a, b) => a.epochId - b.epochId);
|
|
16248
|
+
return { clearings, snapshot, requests };
|
|
16249
|
+
});
|
|
16250
|
+
}
|
|
16251
|
+
/**
|
|
16252
|
+
* The pool's balance (display units, the subgraph's decimal string) at the end
|
|
16253
|
+
* of each block, `TVL_HISTORY_BLOCKS_PER_REQUEST` blocks per request. A block
|
|
16254
|
+
* at which the subgraph has no such pool THROWS: a finished clearing of the
|
|
16255
|
+
* pool happened in it, so a missing pool means a broken read, not a zero.
|
|
16256
|
+
*/
|
|
16257
|
+
function fetchPoolBalancesAtBlocks(request, poolId, blocks, cancellation) {
|
|
16258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16259
|
+
const chunks = [];
|
|
16260
|
+
for (let i = 0; i < blocks.length; i += TVL_HISTORY_BLOCKS_PER_REQUEST) {
|
|
16261
|
+
chunks.push(blocks.slice(i, i + TVL_HISTORY_BLOCKS_PER_REQUEST));
|
|
16262
|
+
}
|
|
16263
|
+
cancellation.throwIfCancelled();
|
|
16264
|
+
const pages = yield Promise.all(chunks.map((chunk) => request(poolBalancesAtBlocksQuery(chunk), { poolId }, cancellation.signal).then((page) => ({ chunk, page }))));
|
|
16265
|
+
const balances = new Map();
|
|
16266
|
+
for (const { chunk, page } of pages) {
|
|
16267
|
+
for (const block of chunk) {
|
|
16268
|
+
const state = page[blockAlias(block)];
|
|
16269
|
+
if (!state) {
|
|
16270
|
+
throw new Error(`getPoolTvlHistory: the subgraph has no state for the pool at block ${String(block)}`);
|
|
16271
|
+
}
|
|
16272
|
+
balances.set(block, state.balance);
|
|
16273
|
+
}
|
|
16274
|
+
}
|
|
16275
|
+
return { balances, requests: chunks.length };
|
|
16276
|
+
});
|
|
16277
|
+
}
|
|
16278
|
+
const EXTERNAL_TVL_INTERFACE = new Interface(KasuPoolExternalTVLAbi__factory.abi);
|
|
16279
|
+
function hasCode(code) {
|
|
16280
|
+
if (typeof code !== 'string' || !/^0x[0-9a-fA-F]*$/.test(code)) {
|
|
16281
|
+
throw new Error(`getPoolTvlHistory: getCode returned ${String(code)}, not hex`);
|
|
16282
|
+
}
|
|
16283
|
+
return code !== '0x';
|
|
16284
|
+
}
|
|
16285
|
+
/**
|
|
16286
|
+
* The real reader: each read goes to the history RPCs IN ORDER until one
|
|
16287
|
+
* answers, and the whole chain is retried `attempts` times with back-off.
|
|
16288
|
+
* After the last attempt the last error propagates — never a value. Each
|
|
16289
|
+
* attempt first checks the cancellation, so a timed-out call stops here.
|
|
16290
|
+
*/
|
|
16291
|
+
function createOffChainTvlReader({ externalTvl, pool, rpcs, cancellation, attempts = TVL_HISTORY_RPC_ATTEMPTS, delayMs = TVL_HISTORY_RPC_RETRY_DELAY_MS, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), }) {
|
|
16292
|
+
if (rpcs.length === 0) {
|
|
16293
|
+
throw new Error('getPoolTvlHistory: no history RPC to read from');
|
|
16294
|
+
}
|
|
16295
|
+
const data = EXTERNAL_TVL_INTERFACE.encodeFunctionData('externalTVLOfPool', [pool]);
|
|
16296
|
+
const read = (op) => __awaiter(this, void 0, void 0, function* () {
|
|
16297
|
+
let lastError;
|
|
16298
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
16299
|
+
for (const rpc of rpcs) {
|
|
16300
|
+
cancellation.throwIfCancelled();
|
|
16301
|
+
try {
|
|
16302
|
+
return yield op(rpc);
|
|
16303
|
+
}
|
|
16304
|
+
catch (error) {
|
|
16305
|
+
lastError = error;
|
|
16306
|
+
}
|
|
16307
|
+
}
|
|
16308
|
+
if (attempt < attempts) {
|
|
16309
|
+
yield sleep(delayMs * Math.pow(2, (attempt - 1)));
|
|
16310
|
+
}
|
|
16311
|
+
}
|
|
16312
|
+
cancellation.throwIfCancelled();
|
|
16313
|
+
throw lastError;
|
|
16314
|
+
});
|
|
16315
|
+
return {
|
|
16316
|
+
readAt: (block) => read((rpc) => __awaiter(this, void 0, void 0, function* () {
|
|
16317
|
+
const result = yield rpc.call({ to: externalTvl, data }, block);
|
|
16318
|
+
const [value] = EXTERNAL_TVL_INTERFACE.decodeFunctionResult('externalTVLOfPool', result);
|
|
16319
|
+
return value;
|
|
16320
|
+
})),
|
|
16321
|
+
hasCodeAt: (block) => read((rpc) => __awaiter(this, void 0, void 0, function* () { return hasCode(yield rpc.getCode(externalTvl, block)); })),
|
|
16322
|
+
poolHasCodeAt: (block) => read((rpc) => __awaiter(this, void 0, void 0, function* () { return hasCode(yield rpc.getCode(pool, block)); })),
|
|
16323
|
+
};
|
|
16324
|
+
}
|
|
16325
|
+
/**
|
|
16326
|
+
* Index of the first block (of `blocks`, ascending) at which the contract has
|
|
16327
|
+
* code; `blocks.length` when it has code at none. A deployed contract keeps
|
|
16328
|
+
* its code (it is a proxy, never self-destructed), so the answer is a single
|
|
16329
|
+
* boundary and a binary search finds it: ONE `getCode` when the contract
|
|
16330
|
+
* already existed at the oldest clearing, about log2(n) otherwise.
|
|
16331
|
+
*/
|
|
16332
|
+
function firstBlockWithCode(blocks, hasCodeAt) {
|
|
16333
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16334
|
+
if (blocks.length === 0)
|
|
16335
|
+
return 0;
|
|
16336
|
+
if (yield hasCodeAt(blocks[0]))
|
|
16337
|
+
return 0;
|
|
16338
|
+
const last = blocks.length - 1;
|
|
16339
|
+
if (!(yield hasCodeAt(blocks[last])))
|
|
16340
|
+
return blocks.length;
|
|
16341
|
+
let lo = 0; // no code
|
|
16342
|
+
let hi = last; // code
|
|
16343
|
+
while (hi - lo > 1) {
|
|
16344
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
16345
|
+
if (yield hasCodeAt(blocks[mid]))
|
|
16346
|
+
hi = mid;
|
|
16347
|
+
else
|
|
16348
|
+
lo = mid;
|
|
16349
|
+
}
|
|
16350
|
+
return hi;
|
|
16351
|
+
});
|
|
16352
|
+
}
|
|
16353
|
+
/**
|
|
16354
|
+
* `fn` over `items`, at most `limit` in flight; rejects on the first failure
|
|
16355
|
+
* and starts nothing after it (or after `beforeEach` throws).
|
|
16356
|
+
*/
|
|
16357
|
+
function mapWithConcurrency(items_1, limit_1, fn_1) {
|
|
16358
|
+
return __awaiter(this, arguments, void 0, function* (items, limit, fn, beforeEach = () => undefined) {
|
|
16359
|
+
const results = new Array(items.length);
|
|
16360
|
+
let next = 0;
|
|
16361
|
+
let failed = false;
|
|
16362
|
+
const worker = () => __awaiter(this, void 0, void 0, function* () {
|
|
16363
|
+
while (!failed && next < items.length) {
|
|
16364
|
+
const index = next++;
|
|
16365
|
+
try {
|
|
16366
|
+
beforeEach();
|
|
16367
|
+
results[index] = yield fn(items[index]);
|
|
16368
|
+
}
|
|
16369
|
+
catch (error) {
|
|
16370
|
+
failed = true;
|
|
16371
|
+
throw error;
|
|
16372
|
+
}
|
|
16373
|
+
}
|
|
16374
|
+
});
|
|
16375
|
+
yield Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
|
|
16376
|
+
return results;
|
|
16377
|
+
});
|
|
16378
|
+
}
|
|
16379
|
+
/**
|
|
16380
|
+
* Immutable past-block reads, per SDK instance. Keys carry the contract (or
|
|
16381
|
+
* subgraph), the pool and the block, so two deployments never collide.
|
|
16382
|
+
*/
|
|
16383
|
+
class PastBlockCache {
|
|
16384
|
+
constructor() {
|
|
16385
|
+
this._entries = new Map();
|
|
16386
|
+
}
|
|
16387
|
+
get(key) {
|
|
16388
|
+
return this._entries.get(key);
|
|
16389
|
+
}
|
|
16390
|
+
set(key, value) {
|
|
16391
|
+
if (this._entries.size >= TVL_HISTORY_CACHE_LIMIT) {
|
|
16392
|
+
this._entries.clear();
|
|
16393
|
+
}
|
|
16394
|
+
this._entries.set(key, value);
|
|
16395
|
+
}
|
|
16396
|
+
get size() {
|
|
16397
|
+
return this._entries.size;
|
|
16398
|
+
}
|
|
16399
|
+
}
|
|
16400
|
+
/**
|
|
16401
|
+
* The off-chain TVL (BASE units) at each block, and — with `withLatest` — at
|
|
16402
|
+
* the latest block, all inside ONE bounded pool of reads.
|
|
16403
|
+
*
|
|
16404
|
+
* Before the contract existed there was nothing to record, so those blocks
|
|
16405
|
+
* are 0 — decided by `getCode`, never by catching a revert: an RPC that
|
|
16406
|
+
* refuses past state can surface that refusal as a "call exception". And a
|
|
16407
|
+
* "no code" answer is believed only if the same provider DOES show code for
|
|
16408
|
+
* the pool at the oldest and newest such block (it cleared there); otherwise
|
|
16409
|
+
* `PastStateUnavailableError`. Every other failed read throws.
|
|
16410
|
+
*
|
|
16411
|
+
* `cached` blocks (final, below the head) are answered from `cache` and
|
|
16412
|
+
* stored there after a successful read.
|
|
16413
|
+
*/
|
|
16414
|
+
function fetchOffChainTvlAtBlocks(reader_1, blocks_1, _a) {
|
|
16415
|
+
return __awaiter(this, arguments, void 0, function* (reader, blocks, { withLatest = false, cancellation, cache, cacheKey, cacheable = () => false, }) {
|
|
16416
|
+
let rpcReads = 0;
|
|
16417
|
+
const cached = (kind, block, load) => {
|
|
16418
|
+
const key = cache && cacheKey && cacheable(block)
|
|
16419
|
+
? cacheKey(kind, block)
|
|
16420
|
+
: undefined;
|
|
16421
|
+
const hit = key === undefined ? undefined : cache === null || cache === void 0 ? void 0 : cache.get(key);
|
|
16422
|
+
if (hit !== undefined)
|
|
16423
|
+
return Promise.resolve(hit);
|
|
16424
|
+
cancellation.throwIfCancelled();
|
|
16425
|
+
rpcReads += 1;
|
|
16426
|
+
return load().then((value) => {
|
|
16427
|
+
if (key !== undefined)
|
|
16428
|
+
cache === null || cache === void 0 ? void 0 : cache.set(key, value);
|
|
16429
|
+
return value;
|
|
16430
|
+
});
|
|
16431
|
+
};
|
|
16432
|
+
const deployedFrom = yield firstBlockWithCode(blocks, (block) => cached('code', block, () => reader.hasCodeAt(block)));
|
|
16433
|
+
if (deployedFrom > 0) {
|
|
16434
|
+
for (const block of new Set([blocks[0], blocks[deployedFrom - 1]])) {
|
|
16435
|
+
const poolDeployed = yield cached('pool', block, () => reader.poolHasCodeAt(block));
|
|
16436
|
+
if (!poolDeployed)
|
|
16437
|
+
throw new PastStateUnavailableError(block);
|
|
16438
|
+
}
|
|
16439
|
+
}
|
|
16440
|
+
const offChain = new Map();
|
|
16441
|
+
for (const block of blocks.slice(0, deployedFrom)) {
|
|
16442
|
+
offChain.set(block, BigNumber.from(0));
|
|
16443
|
+
}
|
|
16444
|
+
const targets = [...blocks.slice(deployedFrom)];
|
|
16445
|
+
if (withLatest)
|
|
16446
|
+
targets.push('latest');
|
|
16447
|
+
const values = yield mapWithConcurrency(targets, TVL_HISTORY_RPC_CONCURRENCY, (block) => {
|
|
16448
|
+
if (block !== 'latest') {
|
|
16449
|
+
return cached('tvl', block, () => reader.readAt(block));
|
|
16450
|
+
}
|
|
16451
|
+
// Never cached: "latest" moves.
|
|
16452
|
+
rpcReads += 1;
|
|
16453
|
+
return reader.readAt('latest');
|
|
16454
|
+
}, () => {
|
|
16455
|
+
cancellation.throwIfCancelled();
|
|
16456
|
+
});
|
|
16457
|
+
let latest = null;
|
|
16458
|
+
targets.forEach((block, i) => {
|
|
16459
|
+
if (block === 'latest')
|
|
16460
|
+
latest = values[i];
|
|
16461
|
+
else
|
|
16462
|
+
offChain.set(block, values[i]);
|
|
16463
|
+
});
|
|
16464
|
+
return { offChain, latest, rpcReads };
|
|
16465
|
+
});
|
|
16466
|
+
}
|
|
16467
|
+
/**
|
|
16468
|
+
* Pure: the reads → the history. One `clearing` point per clearing, ordered by
|
|
16469
|
+
* the block it finished in (then by epoch, for clearings that shared a block),
|
|
16470
|
+
* so the series is ascending in TIME even where epoch numbers jump; then the
|
|
16471
|
+
* `current` point. Each point is `poolTvl(onChain, offChain)` — the same
|
|
16472
|
+
* function `getPoolOverview` uses for `totalValueLocked.total`.
|
|
16473
|
+
*/
|
|
16474
|
+
function buildPoolTvlHistory(read) {
|
|
16475
|
+
const offChainDisplay = (value) => formatUnits(value, read.decimals);
|
|
16476
|
+
const entries = [...read.clearings]
|
|
16477
|
+
.sort((a, b) => a.block - b.block || a.epochId - b.epochId)
|
|
16478
|
+
.map((clearing) => {
|
|
16479
|
+
const balance = read.balances.get(clearing.block);
|
|
16480
|
+
const offChain = read.offChain.get(clearing.block);
|
|
16481
|
+
if (balance === undefined || offChain === undefined) {
|
|
16482
|
+
throw new Error(`getPoolTvlHistory: no reading at block ${String(clearing.block)}`);
|
|
16483
|
+
}
|
|
16484
|
+
return {
|
|
16485
|
+
epochId: clearing.epochId,
|
|
16486
|
+
timestamp: clearing.timestamp,
|
|
16487
|
+
tvl: poolTvl(balance, offChainDisplay(offChain)),
|
|
16488
|
+
kind: 'clearing',
|
|
16489
|
+
};
|
|
16490
|
+
});
|
|
16491
|
+
if (read.current) {
|
|
16492
|
+
entries.push({
|
|
16493
|
+
epochId: read.current.epochId,
|
|
16494
|
+
timestamp: read.current.timestamp,
|
|
16495
|
+
tvl: poolTvl(read.current.balance, offChainDisplay(read.current.offChain)),
|
|
16496
|
+
kind: 'current',
|
|
16497
|
+
});
|
|
16498
|
+
}
|
|
16499
|
+
return entries;
|
|
16500
|
+
}
|
|
16501
|
+
/** Ascending, de-duplicated clearing blocks: each past block is read ONCE. */
|
|
16502
|
+
function distinctBlocks(clearings) {
|
|
16503
|
+
return [...new Set(clearings.map((c) => c.block))].sort((a, b) => a - b);
|
|
16504
|
+
}
|
|
16505
|
+
|
|
16506
|
+
/** Thrown by `getPoolTvlHistory` when no provider that serves past state is configured. */
|
|
16507
|
+
const NO_HISTORY_PROVIDER_MESSAGE = 'getPoolTvlHistory: no history provider; pass historyProvider or set historyRpcUrls to RPCs that serve past state';
|
|
15910
16508
|
class DataService {
|
|
15911
|
-
|
|
16509
|
+
/**
|
|
16510
|
+
* @param historyProvider - a provider that SERVES PAST STATE (an archive
|
|
16511
|
+
* RPC), used only by `getPoolTvlHistory` for the off-chain TVL at old
|
|
16512
|
+
* blocks. Without one, providers are built on `SdkConfig.historyRpcUrls`
|
|
16513
|
+
* (tried in order); with neither, that one call throws
|
|
16514
|
+
* `NO_HISTORY_PROVIDER_MESSAGE`. Never the default provider: a pruned
|
|
16515
|
+
* node refuses old blocks.
|
|
16516
|
+
*/
|
|
16517
|
+
constructor(_kasuConfig, signerOrProvider, historyProvider) {
|
|
15912
16518
|
this._kasuConfig = _kasuConfig;
|
|
16519
|
+
/** Immutable past-block reads, kept for the life of this instance. */
|
|
16520
|
+
this._tvlHistoryCache = new PastBlockCache();
|
|
15913
16521
|
this._externalTvlAbi = KasuPoolExternalTVLAbi__factory.connect(_kasuConfig.contracts.ExternalTVL, signerOrProvider);
|
|
16522
|
+
this._systemVariablesAbi = ISystemVariablesAbi__factory.connect(_kasuConfig.contracts.SystemVariables, signerOrProvider);
|
|
15914
16523
|
this._graph = new GraphQLClient(_kasuConfig.subgraphUrl);
|
|
16524
|
+
this._explicitHistoryProvider = historyProvider;
|
|
15915
16525
|
this._directus = createDirectusClient(_kasuConfig.directusUrl);
|
|
15916
16526
|
}
|
|
15917
16527
|
getUrlFromFile(fileName) {
|
|
@@ -15991,6 +16601,194 @@ class DataService {
|
|
|
15991
16601
|
return tvlMap;
|
|
15992
16602
|
});
|
|
15993
16603
|
}
|
|
16604
|
+
/**
|
|
16605
|
+
* The pool's TVL — the total lent into it by everyone — at every cycle
|
|
16606
|
+
* boundary, then as of now: the data behind a TVL chart.
|
|
16607
|
+
*
|
|
16608
|
+
* One `clearing` point per FINISHED clearing, read at the block it
|
|
16609
|
+
* finished in (`LendingPoolClearing.endBlockNumber`), then one `current`
|
|
16610
|
+
* point. Every point is `poolTvl(onChain, offChain)`, the definition
|
|
16611
|
+
* `getPoolOverview` uses for `totalValueLocked.total`:
|
|
16612
|
+
*
|
|
16613
|
+
* - on-chain: `lendingPool.balance` from the subgraph, read with
|
|
16614
|
+
* time-travel queries (`block: { number }`);
|
|
16615
|
+
* - off-chain: `ExternalTVL.externalTVLOfPool(pool)` at the same block,
|
|
16616
|
+
* through the HISTORY providers (see the constructor). 0 before the
|
|
16617
|
+
* contract was deployed (decided by `getCode`, and only if the same
|
|
16618
|
+
* provider shows the pool's own code there); any failed read throws.
|
|
16619
|
+
*
|
|
16620
|
+
* The `current` point mixes two sources: the subgraph's latest balance
|
|
16621
|
+
* (and its latest block time) and `externalTVLOfPool` at `latest` on the
|
|
16622
|
+
* history provider. `getPoolOverview` reads the same two, the off-chain
|
|
16623
|
+
* one on the default provider, so the last point equals
|
|
16624
|
+
* `totalValueLocked.total` when both reads succeed. They can differ when
|
|
16625
|
+
* `getPoolOverview`'s off-chain read FAILS — it then falls back to 0 —
|
|
16626
|
+
* or when the figure moves between the two calls.
|
|
16627
|
+
*
|
|
16628
|
+
* Units: `tvl` in display units of the deployment's own stable token
|
|
16629
|
+
* (USDC on Base and XDC USDC, AUDD on XDC AUDD); `timestamp` in unix
|
|
16630
|
+
* seconds. Ascending in time. See `PoolTvlHistoryEntry`.
|
|
16631
|
+
*
|
|
16632
|
+
* Cost: one subgraph request for the clearings (per thousand), one per
|
|
16633
|
+
* hundred distinct uncached clearing blocks, a `currentEpochNumber` read;
|
|
16634
|
+
* then, on the history providers, one `externalTVLOfPool` per distinct
|
|
16635
|
+
* uncached block plus the latest, and one to about log2(n) `getCode`s —
|
|
16636
|
+
* at most `TVL_HISTORY_RPC_CONCURRENCY` in flight. Final blocks are
|
|
16637
|
+
* cached on this instance, so a second call reads only what is new.
|
|
16638
|
+
* `timeoutMs` (default 30 s) bounds the whole call.
|
|
16639
|
+
*
|
|
16640
|
+
* `[]` for a pool the subgraph does not know, for a window with no epoch
|
|
16641
|
+
* in it, and on a LITE deployment whose subgraph lacks the entities. On a
|
|
16642
|
+
* full deployment that schema error throws, like every network, indexing
|
|
16643
|
+
* or past-state failure.
|
|
16644
|
+
*
|
|
16645
|
+
* @throws RangeError / TypeError on a malformed option or a pool id that
|
|
16646
|
+
* is not an address, and `NO_HISTORY_PROVIDER_MESSAGE` when the
|
|
16647
|
+
* deployment has an `ExternalTVL` contract but no history provider — all
|
|
16648
|
+
* before any network read. `PoolTvlHistoryTimeoutError` /
|
|
16649
|
+
* `PoolTvlHistoryAbortedError` on the deadline or the signal,
|
|
16650
|
+
* `PastStateUnavailableError` from a pruned history provider.
|
|
16651
|
+
*/
|
|
16652
|
+
getPoolTvlHistory(poolId_1) {
|
|
16653
|
+
return __awaiter(this, arguments, void 0, function* (poolId, options = {}) {
|
|
16654
|
+
var _a;
|
|
16655
|
+
validatePoolTvlHistoryOptions(options);
|
|
16656
|
+
if (!isAddress(poolId)) {
|
|
16657
|
+
throw new TypeError(`getPoolTvlHistory: poolId must be an address, got ${String(poolId)}`);
|
|
16658
|
+
}
|
|
16659
|
+
const pool = poolId.toLowerCase();
|
|
16660
|
+
const externalTvl = this._externalTvlAddress();
|
|
16661
|
+
const rpcs = externalTvl ? this._historyRpcs() : [];
|
|
16662
|
+
if (externalTvl && rpcs.length === 0) {
|
|
16663
|
+
throw new Error(NO_HISTORY_PROVIDER_MESSAGE);
|
|
16664
|
+
}
|
|
16665
|
+
return yield runCancellable((_a = options.timeoutMs) !== null && _a !== void 0 ? _a : TVL_HISTORY_DEFAULT_TIMEOUT_MS, options.signal, (cancellation) => this._readPoolTvlHistory(pool, options, externalTvl
|
|
16666
|
+
? this._createOffChainTvlReader({
|
|
16667
|
+
externalTvl,
|
|
16668
|
+
pool,
|
|
16669
|
+
rpcs,
|
|
16670
|
+
cancellation,
|
|
16671
|
+
})
|
|
16672
|
+
: null, externalTvl !== null && externalTvl !== void 0 ? externalTvl : '', cancellation));
|
|
16673
|
+
});
|
|
16674
|
+
}
|
|
16675
|
+
_readPoolTvlHistory(pool, options, reader, externalTvl, cancellation) {
|
|
16676
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16677
|
+
var _a, _b, _c;
|
|
16678
|
+
const graph = (document, variables, signal) => this._graph.request({ document, variables, signal });
|
|
16679
|
+
const scope = options.fromEpoch === undefined && options.count !== undefined
|
|
16680
|
+
? { kind: 'newest', count: options.count }
|
|
16681
|
+
: { kind: 'from', fromEpoch: (_a = options.fromEpoch) !== null && _a !== void 0 ? _a : 0 };
|
|
16682
|
+
try {
|
|
16683
|
+
const [currentEpochNumber, { clearings, snapshot }] = yield Promise.all([
|
|
16684
|
+
this._systemVariablesAbi.currentEpochNumber(),
|
|
16685
|
+
fetchPoolClearings(graph, pool, scope, cancellation),
|
|
16686
|
+
]);
|
|
16687
|
+
const currentEpoch = currentEpochNumber.toNumber();
|
|
16688
|
+
const window = resolvePoolTvlHistoryWindow(options, currentEpoch);
|
|
16689
|
+
const poolNow = snapshot.pool;
|
|
16690
|
+
if (!window || !poolNow)
|
|
16691
|
+
return [];
|
|
16692
|
+
const head = (_b = snapshot.meta) === null || _b === void 0 ? void 0 : _b.block;
|
|
16693
|
+
if (!head || typeof head.timestamp !== 'number') {
|
|
16694
|
+
throw new Error('getPoolTvlHistory: the subgraph returned no latest block time');
|
|
16695
|
+
}
|
|
16696
|
+
const inWindow = clearings.filter((c) => c.epochId >= window.fromEpoch &&
|
|
16697
|
+
c.epochId <= window.toEpoch);
|
|
16698
|
+
const blocks = distinctBlocks(inWindow);
|
|
16699
|
+
const withCurrent = window.toEpoch >= currentEpoch;
|
|
16700
|
+
const cacheable = (block) => block <= head.number - TVL_HISTORY_CACHE_DEPTH;
|
|
16701
|
+
const [balances, offChainRead] = yield Promise.all([
|
|
16702
|
+
this._balancesAtBlocks(graph, pool, blocks, cacheable, cancellation),
|
|
16703
|
+
reader
|
|
16704
|
+
? fetchOffChainTvlAtBlocks(reader, blocks, {
|
|
16705
|
+
withLatest: withCurrent,
|
|
16706
|
+
cancellation,
|
|
16707
|
+
cache: this._tvlHistoryCache,
|
|
16708
|
+
cacheKey: (kind, block) => `${kind}|${externalTvl}|${pool}|${String(block)}`,
|
|
16709
|
+
cacheable,
|
|
16710
|
+
})
|
|
16711
|
+
: {
|
|
16712
|
+
offChain: new Map(blocks.map((b) => [b, BigNumber.from(0)])),
|
|
16713
|
+
latest: null,
|
|
16714
|
+
},
|
|
16715
|
+
]);
|
|
16716
|
+
return buildPoolTvlHistory({
|
|
16717
|
+
clearings: inWindow,
|
|
16718
|
+
balances,
|
|
16719
|
+
offChain: offChainRead.offChain,
|
|
16720
|
+
current: withCurrent
|
|
16721
|
+
? {
|
|
16722
|
+
epochId: currentEpoch,
|
|
16723
|
+
timestamp: head.timestamp,
|
|
16724
|
+
balance: poolNow.balance,
|
|
16725
|
+
offChain: (_c = offChainRead.latest) !== null && _c !== void 0 ? _c : BigNumber.from(0),
|
|
16726
|
+
}
|
|
16727
|
+
: null,
|
|
16728
|
+
decimals: this._kasuConfig.stableAssetDecimals,
|
|
16729
|
+
});
|
|
16730
|
+
}
|
|
16731
|
+
catch (error) {
|
|
16732
|
+
if (isEmptyHistoryError(error, this._kasuConfig.isLiteDeployment)) {
|
|
16733
|
+
return [];
|
|
16734
|
+
}
|
|
16735
|
+
throw error;
|
|
16736
|
+
}
|
|
16737
|
+
});
|
|
16738
|
+
}
|
|
16739
|
+
/** The pool's balance at each block: cached final blocks, then one batch. */
|
|
16740
|
+
_balancesAtBlocks(graph, pool, blocks, cacheable, cancellation) {
|
|
16741
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16742
|
+
const key = (block) => `balance|${this._kasuConfig.subgraphUrl}|${pool}|${String(block)}`;
|
|
16743
|
+
const balances = new Map();
|
|
16744
|
+
const missing = [];
|
|
16745
|
+
for (const block of blocks) {
|
|
16746
|
+
const hit = cacheable(block)
|
|
16747
|
+
? this._tvlHistoryCache.get(key(block))
|
|
16748
|
+
: undefined;
|
|
16749
|
+
if (hit === undefined)
|
|
16750
|
+
missing.push(block);
|
|
16751
|
+
else
|
|
16752
|
+
balances.set(block, hit);
|
|
16753
|
+
}
|
|
16754
|
+
if (missing.length > 0) {
|
|
16755
|
+
const read = yield fetchPoolBalancesAtBlocks(graph, pool, missing, cancellation);
|
|
16756
|
+
for (const [block, balance] of read.balances) {
|
|
16757
|
+
balances.set(block, balance);
|
|
16758
|
+
if (cacheable(block))
|
|
16759
|
+
this._tvlHistoryCache.set(key(block), balance);
|
|
16760
|
+
}
|
|
16761
|
+
}
|
|
16762
|
+
return balances;
|
|
16763
|
+
});
|
|
16764
|
+
}
|
|
16765
|
+
/** `null` when the deployment has no `ExternalTVL` contract. */
|
|
16766
|
+
_externalTvlAddress() {
|
|
16767
|
+
const address = this._kasuConfig.contracts.ExternalTVL;
|
|
16768
|
+
if (!address || /^0x0{40}$/i.test(address))
|
|
16769
|
+
return null;
|
|
16770
|
+
return address.toLowerCase();
|
|
16771
|
+
}
|
|
16772
|
+
/** Seam for tests: the real reader over the history RPCs. */
|
|
16773
|
+
_createOffChainTvlReader(args) {
|
|
16774
|
+
return createOffChainTvlReader(args);
|
|
16775
|
+
}
|
|
16776
|
+
/**
|
|
16777
|
+
* The history RPCs, in fallback order: the explicit provider, else ONE
|
|
16778
|
+
* provider per `historyRpcUrls` entry — built here and nowhere else,
|
|
16779
|
+
* pinned to `SdkConfig.chainId` when known, each with a per-call timeout.
|
|
16780
|
+
* Built once per instance.
|
|
16781
|
+
*/
|
|
16782
|
+
_historyRpcs() {
|
|
16783
|
+
if (this._explicitHistoryProvider)
|
|
16784
|
+
return [this._explicitHistoryProvider];
|
|
16785
|
+
if (!this._builtHistoryProviders) {
|
|
16786
|
+
// Through the `ethers` namespace, so the consumer's own build
|
|
16787
|
+
// (Node or browser) is used — see `defaultProvider` in the facade.
|
|
16788
|
+
this._builtHistoryProviders = this._kasuConfig.historyRpcUrls.map((url) => new providers.StaticJsonRpcProvider({ url, timeout: TVL_HISTORY_RPC_TIMEOUT_MS }, this._kasuConfig.chainId));
|
|
16789
|
+
}
|
|
16790
|
+
return this._builtHistoryProviders;
|
|
16791
|
+
}
|
|
15994
16792
|
getPoolOverview(epochId, id_in) {
|
|
15995
16793
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15996
16794
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
@@ -16131,8 +16929,8 @@ class DataService {
|
|
|
16131
16929
|
subheading: lendingPoolDirectus === null || lendingPoolDirectus === void 0 ? void 0 : lendingPoolDirectus.subheading,
|
|
16132
16930
|
operatingSince: lendingPoolDirectus === null || lendingPoolDirectus === void 0 ? void 0 : lendingPoolDirectus.operatingSince,
|
|
16133
16931
|
totalValueLocked: {
|
|
16134
|
-
|
|
16135
|
-
|
|
16932
|
+
// The one TVL definition, shared with getPoolTvlHistory.
|
|
16933
|
+
total: poolTvl(lendingPoolSubgraph.balance, offChainTvl).toString(),
|
|
16136
16934
|
offchain: offChainTvl,
|
|
16137
16935
|
},
|
|
16138
16936
|
loansUnderManagement: (_q = lendingPoolDirectus === null || lendingPoolDirectus === void 0 ? void 0 : lendingPoolDirectus.loansUnderManagement) !== null && _q !== void 0 ? _q : '0',
|
|
@@ -17215,14 +18013,13 @@ const currentEpochFtdAmountQuery = gql `
|
|
|
17215
18013
|
user: $userId
|
|
17216
18014
|
lendingPool_in: $poolIds
|
|
17217
18015
|
epochId: $currentEpoch
|
|
18016
|
+
type: DepositRequest
|
|
17218
18017
|
}
|
|
17219
18018
|
) {
|
|
17220
18019
|
fixedTermConfigId
|
|
17221
18020
|
amountRequested
|
|
17222
18021
|
tranche {
|
|
17223
18022
|
id
|
|
17224
|
-
balance
|
|
17225
|
-
shares
|
|
17226
18023
|
}
|
|
17227
18024
|
}
|
|
17228
18025
|
}
|
|
@@ -17237,11 +18034,7 @@ const currentFtdBalanceQuery = gql `
|
|
|
17237
18034
|
configId
|
|
17238
18035
|
lendingPoolTranche {
|
|
17239
18036
|
id
|
|
17240
|
-
|
|
17241
|
-
}
|
|
17242
|
-
lendingPool {
|
|
17243
|
-
balance
|
|
17244
|
-
tranches {
|
|
18037
|
+
balance
|
|
17245
18038
|
shares
|
|
17246
18039
|
}
|
|
17247
18040
|
}
|
|
@@ -17249,6 +18042,13 @@ const currentFtdBalanceQuery = gql `
|
|
|
17249
18042
|
}
|
|
17250
18043
|
`;
|
|
17251
18044
|
|
|
18045
|
+
/** Thrown when the subgraph reports a request type with no known unit. */
|
|
18046
|
+
const UNKNOWN_REQUEST_TYPE_MESSAGE = 'UserLending: unknown request type, its amount unit is unknown';
|
|
18047
|
+
const KNOWN_REQUEST_TYPES = [
|
|
18048
|
+
'DepositRequest',
|
|
18049
|
+
'WithdrawalRequest',
|
|
18050
|
+
];
|
|
18051
|
+
const isKnownRequestType = (type) => typeof type === 'string' && KNOWN_REQUEST_TYPES.includes(type);
|
|
17252
18052
|
class UserLending {
|
|
17253
18053
|
constructor(_kasuConfig, signerOrProvider) {
|
|
17254
18054
|
this._kasuConfig = _kasuConfig;
|
|
@@ -17410,6 +18210,14 @@ class UserLending {
|
|
|
17410
18210
|
]);
|
|
17411
18211
|
const retn = [];
|
|
17412
18212
|
for (const userRequest of subgraphResult.userRequests) {
|
|
18213
|
+
// A request type this SDK does not know has no known amount unit
|
|
18214
|
+
// (the schema also declares types no live deployment emits yet).
|
|
18215
|
+
// Skip that ONE row before anything is priced or read on chain,
|
|
18216
|
+
// rather than failing — and blanking — the lender's whole list.
|
|
18217
|
+
if (!isKnownRequestType(userRequest.type)) {
|
|
18218
|
+
console.error(`${UNKNOWN_REQUEST_TYPE_MESSAGE}: ${String(userRequest.type)} (request ${userRequest.id}); row skipped`);
|
|
18219
|
+
continue;
|
|
18220
|
+
}
|
|
17413
18221
|
const directusPool = directusResult.find(({ id }) => id === userRequest.lendingPool.id);
|
|
17414
18222
|
const trancheName = trancheNames[userRequest.lendingPool.tranches.length - 1][parseInt(userRequest.tranche.orderId)];
|
|
17415
18223
|
const events = [];
|
|
@@ -17505,9 +18313,7 @@ class UserLending {
|
|
|
17505
18313
|
: 'Withdrawal',
|
|
17506
18314
|
trancheName: trancheName,
|
|
17507
18315
|
trancheId: userRequest.tranche.id,
|
|
17508
|
-
requestedAmount:
|
|
17509
|
-
? userRequest.amountRequested
|
|
17510
|
-
: this.convertSharesToAssets(userRequest.amountRequested, userRequest.tranche.balance, userRequest.tranche.shares).toString(),
|
|
18316
|
+
requestedAmount: this.requestedAmountInAssets(userRequest),
|
|
17511
18317
|
acceptedAmount: userRequest.amountAccepted,
|
|
17512
18318
|
rejectedAmount: userRequest.amountRejected,
|
|
17513
18319
|
status: userRequest.status,
|
|
@@ -17540,8 +18346,11 @@ class UserLending {
|
|
|
17540
18346
|
for (const userFTD of currentFtdBalance.userLendingPoolTrancheFixedTermDepositLocks) {
|
|
17541
18347
|
const ftdID = parseFloat(userFTD.lendingPoolTrancheFixedTermConfig.configId);
|
|
17542
18348
|
const trancheID = userFTD.lendingPoolTrancheFixedTermConfig.lendingPoolTranche.id.toLowerCase();
|
|
17543
|
-
|
|
17544
|
-
|
|
18349
|
+
// The lock holds shares of ONE tranche, so they are worth that
|
|
18350
|
+
// tranche's share price — not the pool's average across tranches,
|
|
18351
|
+
// which differs whenever the tranches have earned differently.
|
|
18352
|
+
const lockTranche = userFTD.lendingPoolTrancheFixedTermConfig.lendingPoolTranche;
|
|
18353
|
+
const amount = this.convertSharesToAssets(userFTD.trancheShares, lockTranche.balance, lockTranche.shares);
|
|
17545
18354
|
const item = (_a = trancheMap.get(trancheID)) !== null && _a !== void 0 ? _a : [];
|
|
17546
18355
|
if (item[ftdID]) {
|
|
17547
18356
|
item[ftdID] += parseFloat(amount);
|
|
@@ -17556,25 +18365,40 @@ class UserLending {
|
|
|
17556
18365
|
}
|
|
17557
18366
|
getCurrentEpochFtdAmount(poolIds, userId, currentEpoch) {
|
|
17558
18367
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18368
|
+
var _a, _b;
|
|
17559
18369
|
const currentEpochFtdAmountRes = yield this._graph.request(currentEpochFtdAmountQuery, {
|
|
17560
18370
|
userId: userId.toLowerCase(),
|
|
17561
18371
|
poolIds: poolIds.map((id) => id.toLowerCase()),
|
|
17562
18372
|
currentEpoch: parseFloat(currentEpoch),
|
|
17563
18373
|
});
|
|
17564
|
-
|
|
18374
|
+
// Deposit requests only (the query filters on type): a deposit's
|
|
18375
|
+
// `amountRequested` is already an ASSET amount, so it is summed as it
|
|
18376
|
+
// is — never put through a share price. Summed, not assigned: a
|
|
18377
|
+
// cancelled request and its replacement share a tranche and a config
|
|
18378
|
+
// in one epoch, and the cancelled one's 0 must not overwrite the live
|
|
18379
|
+
// amount.
|
|
18380
|
+
const totals = new Map();
|
|
17565
18381
|
for (const userRequest of currentEpochFtdAmountRes.userRequests) {
|
|
17566
18382
|
const ftdID = parseFloat(userRequest.fixedTermConfigId);
|
|
17567
|
-
|
|
17568
|
-
const amountRequested = this.convertSharesToAssets(userRequest.amountRequested, userRequest.tranche.balance, userRequest.tranche.shares);
|
|
17569
|
-
if (item) {
|
|
17570
|
-
const clonedItem = [...item];
|
|
17571
|
-
clonedItem[ftdID] = amountRequested;
|
|
17572
|
-
currentEpochFtdAmounts.set(userRequest.tranche.id, clonedItem);
|
|
18383
|
+
if (!Number.isInteger(ftdID) || ftdID < 0)
|
|
17573
18384
|
continue;
|
|
17574
|
-
|
|
18385
|
+
const perConfig = (_a = totals.get(userRequest.tranche.id)) !== null && _a !== void 0 ? _a : new Map();
|
|
18386
|
+
perConfig.set(ftdID, ((_b = perConfig.get(ftdID)) !== null && _b !== void 0 ? _b : BigNumber.from(0)).add(parseUnits(userRequest.amountRequested)));
|
|
18387
|
+
totals.set(userRequest.tranche.id, perConfig);
|
|
18388
|
+
}
|
|
18389
|
+
// A slot whose total is zero is left out — `'0.0'` is a truthy
|
|
18390
|
+
// string, and a caller testing the slot would read it as an amount.
|
|
18391
|
+
// A tranche with no non-zero slot is left out entirely.
|
|
18392
|
+
const currentEpochFtdAmounts = new Map();
|
|
18393
|
+
for (const [trancheId, perConfig] of totals) {
|
|
17575
18394
|
const ftdAmounts = [];
|
|
17576
|
-
|
|
17577
|
-
|
|
18395
|
+
for (const [ftdID, total] of perConfig) {
|
|
18396
|
+
if (total.gt(0))
|
|
18397
|
+
ftdAmounts[ftdID] = formatUnits(total);
|
|
18398
|
+
}
|
|
18399
|
+
if (ftdAmounts.length) {
|
|
18400
|
+
currentEpochFtdAmounts.set(trancheId, ftdAmounts);
|
|
18401
|
+
}
|
|
17578
18402
|
}
|
|
17579
18403
|
return currentEpochFtdAmounts;
|
|
17580
18404
|
});
|
|
@@ -17595,6 +18419,31 @@ class UserLending {
|
|
|
17595
18419
|
return amountMap;
|
|
17596
18420
|
});
|
|
17597
18421
|
}
|
|
18422
|
+
/**
|
|
18423
|
+
* A request's outstanding amount in ASSETS (the deployment's stable token).
|
|
18424
|
+
*
|
|
18425
|
+
* The subgraph's `UserRequest.amountRequested` is denominated by request
|
|
18426
|
+
* type. A DEPOSIT request holds assets: the deposit NFT's `assetAmount`,
|
|
18427
|
+
* top-ups added, accepted and rejected amounts taken off. A WITHDRAWAL
|
|
18428
|
+
* request holds tranche SHARES: the withdrawal NFT's `sharesAmount`,
|
|
18429
|
+
* accepted shares taken off. So only a withdrawal is converted, at the
|
|
18430
|
+
* tranche's current share price; a deposit passes through unchanged —
|
|
18431
|
+
* pricing it as shares overstated it by the share price.
|
|
18432
|
+
*/
|
|
18433
|
+
requestedAmountInAssets(userRequest) {
|
|
18434
|
+
switch (userRequest.type) {
|
|
18435
|
+
case 'DepositRequest':
|
|
18436
|
+
return userRequest.amountRequested;
|
|
18437
|
+
case 'WithdrawalRequest':
|
|
18438
|
+
return this.convertSharesToAssets(userRequest.amountRequested, userRequest.tranche.balance, userRequest.tranche.shares);
|
|
18439
|
+
default: {
|
|
18440
|
+
// Fail closed: a type this SDK does not know has no known
|
|
18441
|
+
// unit, and pricing it either way would print a wrong figure.
|
|
18442
|
+
const unknownType = userRequest.type;
|
|
18443
|
+
throw new Error(`${UNKNOWN_REQUEST_TYPE_MESSAGE}: ${unknownType}`);
|
|
18444
|
+
}
|
|
18445
|
+
}
|
|
18446
|
+
}
|
|
17598
18447
|
convertSharesToAssets(sharesAmount, totalAssets, totalSupply) {
|
|
17599
18448
|
if (parseUnits(totalSupply).isZero())
|
|
17600
18449
|
return '0';
|
|
@@ -18293,35 +19142,6 @@ function buildYieldHistory(read, window, clock) {
|
|
|
18293
19142
|
a.poolId.localeCompare(b.poolId) ||
|
|
18294
19143
|
a.trancheId.localeCompare(b.trancheId));
|
|
18295
19144
|
}
|
|
18296
|
-
/**
|
|
18297
|
-
* A GraphQL VALIDATION error naming an entity, field or argument this
|
|
18298
|
-
* deployment's subgraph does not have. A network error, a timeout or an
|
|
18299
|
-
* indexing error is not one.
|
|
18300
|
-
*/
|
|
18301
|
-
function isMissingEntityError(error) {
|
|
18302
|
-
if (typeof error !== 'object' || error === null)
|
|
18303
|
-
return false;
|
|
18304
|
-
const response = error.response;
|
|
18305
|
-
const errors = response === null || response === void 0 ? void 0 : response.errors;
|
|
18306
|
-
if (!Array.isArray(errors) || errors.length === 0)
|
|
18307
|
-
return false;
|
|
18308
|
-
return errors.every((e) => {
|
|
18309
|
-
const message = e === null || e === void 0 ? void 0 : e.message;
|
|
18310
|
-
return (typeof message === 'string' &&
|
|
18311
|
-
/has no field|cannot query field|unknown (type|field|argument)|no such (type|field)/i.test(message));
|
|
18312
|
-
});
|
|
18313
|
-
}
|
|
18314
|
-
/**
|
|
18315
|
-
* The only failure `getYieldHistory` turns into `[]`: a missing-schema error
|
|
18316
|
-
* on a LITE deployment, whose subgraph may predate the entities. On a full
|
|
18317
|
-
* deployment the entities are part of the schema, so the same error means a
|
|
18318
|
-
* broken query or subgraph and THROWS — an empty chart there would hide it.
|
|
18319
|
-
* Everything else (network, timeout, indexing) throws on every deployment, so
|
|
18320
|
-
* a consumer can tell "no history here" from "history unavailable".
|
|
18321
|
-
*/
|
|
18322
|
-
function isEmptyHistoryError(error, liteDeployment) {
|
|
18323
|
-
return liteDeployment && isMissingEntityError(error);
|
|
18324
|
-
}
|
|
18325
19145
|
|
|
18326
19146
|
class Portfolio {
|
|
18327
19147
|
constructor(_kasuConfig, signerOrProvider) {
|
|
@@ -24765,11 +25585,11 @@ class Swapper {
|
|
|
24765
25585
|
}
|
|
24766
25586
|
|
|
24767
25587
|
class KasuSdk {
|
|
24768
|
-
constructor(config, signerOrProvider) {
|
|
25588
|
+
constructor(config, signerOrProvider, options = {}) {
|
|
24769
25589
|
this._graphClient = new GraphQLClient(config.subgraphUrl);
|
|
24770
25590
|
this.Locking = new KSULocking(config, signerOrProvider);
|
|
24771
25591
|
this.UserLending = new UserLending(config, signerOrProvider);
|
|
24772
|
-
this.DataService = new DataService(config, signerOrProvider);
|
|
25592
|
+
this.DataService = new DataService(config, signerOrProvider, options.historyProvider);
|
|
24773
25593
|
this.Portfolio = new Portfolio(config, signerOrProvider);
|
|
24774
25594
|
this.Swapper = new Swapper();
|
|
24775
25595
|
}
|
|
@@ -24777,7 +25597,7 @@ class KasuSdk {
|
|
|
24777
25597
|
|
|
24778
25598
|
class SdkConfig {
|
|
24779
25599
|
constructor(options) {
|
|
24780
|
-
var _a, _b, _c, _d;
|
|
25600
|
+
var _a, _b, _c, _d, _e;
|
|
24781
25601
|
this.subgraphUrl = options.subgraphUrl;
|
|
24782
25602
|
this.contracts = options.contracts;
|
|
24783
25603
|
this.directusUrl = (_a = options.directusUrl) !== null && _a !== void 0 ? _a : '';
|
|
@@ -24792,6 +25612,8 @@ class SdkConfig {
|
|
|
24792
25612
|
this.isLiteDeployment = (_b = options.isLiteDeployment) !== null && _b !== void 0 ? _b : false;
|
|
24793
25613
|
this.poolMetadataMapping = (_c = options.poolMetadataMapping) !== null && _c !== void 0 ? _c : {};
|
|
24794
25614
|
this.stableAssetDecimals = (_d = options.stableAssetDecimals) !== null && _d !== void 0 ? _d : 6;
|
|
25615
|
+
this.historyRpcUrls = [...((_e = options.historyRpcUrls) !== null && _e !== void 0 ? _e : [])];
|
|
25616
|
+
this.chainId = options.chainId;
|
|
24795
25617
|
}
|
|
24796
25618
|
}
|
|
24797
25619
|
|
|
@@ -25098,6 +25920,27 @@ const XDC_RPC_URLS = [
|
|
|
25098
25920
|
'https://rpc.xinfin.network',
|
|
25099
25921
|
'https://rpc.primenumbers.xyz/',
|
|
25100
25922
|
];
|
|
25923
|
+
/**
|
|
25924
|
+
* XDC RPCs that serve PAST state, for `getPoolTvlHistory` (each verified
|
|
25925
|
+
* with `externalTVLOfPool` at old blocks, CORS `*`), in fallback order. Not
|
|
25926
|
+
* `rpc.xdcrpc.com`, which refuses older blocks, and never `rpc.xdc.org` /
|
|
25927
|
+
* `erpc.xdc.org`. Public and rate-limited.
|
|
25928
|
+
*/
|
|
25929
|
+
const XDC_HISTORY_RPC_URLS = [
|
|
25930
|
+
'https://rpc.primenumbers.xyz/',
|
|
25931
|
+
'https://rpc.ankr.com/xdc',
|
|
25932
|
+
];
|
|
25933
|
+
/**
|
|
25934
|
+
* Base RPCs that serve PAST state, in fallback order (each verified with
|
|
25935
|
+
* `externalTVLOfPool` at old blocks; all answer CORS). Not
|
|
25936
|
+
* `base-rpc.publicnode.com`, the default read RPC, which refuses old state.
|
|
25937
|
+
* Public and rate-limited.
|
|
25938
|
+
*/
|
|
25939
|
+
const BASE_HISTORY_RPC_URLS = [
|
|
25940
|
+
'https://mainnet.base.org',
|
|
25941
|
+
'https://base.drpc.org',
|
|
25942
|
+
'https://1rpc.io/base',
|
|
25943
|
+
];
|
|
25101
25944
|
/**
|
|
25102
25945
|
* Built-in chain configurations for Kasu-supported networks.
|
|
25103
25946
|
*
|
|
@@ -25141,6 +25984,7 @@ const CHAIN_CONFIGS = {
|
|
|
25141
25984
|
'https://base-rpc.publicnode.com',
|
|
25142
25985
|
'https://mainnet.base.org',
|
|
25143
25986
|
],
|
|
25987
|
+
historyRpcUrls: BASE_HISTORY_RPC_URLS,
|
|
25144
25988
|
blockExplorerUrl: 'https://basescan.org',
|
|
25145
25989
|
},
|
|
25146
25990
|
xdc: {
|
|
@@ -25177,6 +26021,7 @@ const CHAIN_CONFIGS = {
|
|
|
25177
26021
|
currencyCode: 'AUD',
|
|
25178
26022
|
},
|
|
25179
26023
|
rpcUrls: XDC_RPC_URLS,
|
|
26024
|
+
historyRpcUrls: XDC_HISTORY_RPC_URLS,
|
|
25180
26025
|
blockExplorerUrl: 'https://xdcscan.com',
|
|
25181
26026
|
},
|
|
25182
26027
|
'xdc-usdc': {
|
|
@@ -25209,6 +26054,7 @@ const CHAIN_CONFIGS = {
|
|
|
25209
26054
|
currencyCode: 'USD',
|
|
25210
26055
|
},
|
|
25211
26056
|
rpcUrls: XDC_RPC_URLS,
|
|
26057
|
+
historyRpcUrls: XDC_HISTORY_RPC_URLS,
|
|
25212
26058
|
blockExplorerUrl: 'https://xdcscan.com',
|
|
25213
26059
|
},
|
|
25214
26060
|
plume: {
|
|
@@ -28320,6 +29166,28 @@ class StrategiesFacade {
|
|
|
28320
29166
|
return yield this._dataService.getPerformanceFee();
|
|
28321
29167
|
});
|
|
28322
29168
|
}
|
|
29169
|
+
/**
|
|
29170
|
+
* The strategy's TVL (total lent by everyone) at every cycle boundary,
|
|
29171
|
+
* then as of now — the data behind a TVL chart. Ascending in time; the
|
|
29172
|
+
* last point (`kind: 'current'`) equals `strategy.tvl.total` when both
|
|
29173
|
+
* calls' reads succeed (see `PoolTvlHistoryEntry`).
|
|
29174
|
+
*
|
|
29175
|
+
* `tvl` is in display units of the deployment's OWN stable token (USDC on
|
|
29176
|
+
* Base and XDC USDC, AUDD on XDC AUDD); `timestamp` is unix SECONDS.
|
|
29177
|
+
* `{ count }` = the newest `count` epochs, `{ fromEpoch }` = from that
|
|
29178
|
+
* epoch on; `timeoutMs` (default 30 s) and `signal` bound the call. A
|
|
29179
|
+
* malformed option throws before any network read. See
|
|
29180
|
+
* `DataService.getPoolTvlHistory` for the reads, the cost and the errors.
|
|
29181
|
+
*
|
|
29182
|
+
* ```ts
|
|
29183
|
+
* const points = await kasu.strategies.getPoolTvlHistory(poolId, { count: 52 });
|
|
29184
|
+
* ```
|
|
29185
|
+
*/
|
|
29186
|
+
getPoolTvlHistory(poolId_1) {
|
|
29187
|
+
return __awaiter(this, arguments, void 0, function* (poolId, options = {}) {
|
|
29188
|
+
return yield this._dataService.getPoolTvlHistory(poolId, options);
|
|
29189
|
+
});
|
|
29190
|
+
}
|
|
28323
29191
|
/**
|
|
28324
29192
|
* Fetch a single strategy by pool ID. Returns `null` if not found.
|
|
28325
29193
|
*/
|
|
@@ -28644,17 +29512,24 @@ function cancelDeadline(request, nextEpochStart, nowSeconds) {
|
|
|
28644
29512
|
const isCancelled = (events) => events.some((e) => e.requestType === 'Cancelled');
|
|
28645
29513
|
const isForced = (events) => events.some((e) => e.requestType === 'Forced');
|
|
28646
29514
|
const initiatedEvent = (events) => events.find((e) => e.requestType === 'Initiated');
|
|
28647
|
-
/**
|
|
28648
|
-
* Subgraph behaviour: when a request is cancelled, the on-request
|
|
28649
|
-
* `requestedAmount` field is reset to 0 (the lender's effective balance is
|
|
28650
|
-
* restored). The original amount survives on the `Initiated` event's
|
|
28651
|
-
* `assetAmount`. Recover from there so cancelled rows still carry the amount
|
|
28652
|
-
* the lender originally asked for.
|
|
28653
|
-
*/
|
|
29515
|
+
/** `assetAmount` of the `Initiated` event, or 0 when there is none. */
|
|
28654
29516
|
const initiatedAmountOf = (events) => {
|
|
28655
29517
|
const initiated = initiatedEvent(events);
|
|
28656
29518
|
return initiated ? Number(initiated.assetAmount || '0') : 0;
|
|
28657
29519
|
};
|
|
29520
|
+
/**
|
|
29521
|
+
* Subgraph behaviour: when a request is cancelled, the on-request
|
|
29522
|
+
* `requestedAmount` field is reset to 0 (the lender's effective balance is
|
|
29523
|
+
* restored). The amount cancelled survives on the `Cancelled` event's
|
|
29524
|
+
* `assetAmount` — everything still outstanding at the cancel, top-ups
|
|
29525
|
+
* included. Only when that event carries no figure does this fall back to the
|
|
29526
|
+
* `Initiated` event, which holds the FIRST submission alone and so misses
|
|
29527
|
+
* every top-up.
|
|
29528
|
+
*/
|
|
29529
|
+
const cancelledAmountOf = (events) => {
|
|
29530
|
+
const cancelledEvent = events.find((e) => e.requestType === 'Cancelled');
|
|
29531
|
+
return num(cancelledEvent === null || cancelledEvent === void 0 ? void 0 : cancelledEvent.assetAmount) || initiatedAmountOf(events);
|
|
29532
|
+
};
|
|
28658
29533
|
/**
|
|
28659
29534
|
* A deposit is REALLOCATED when the timeline carries a `Reallocated` event, or
|
|
28660
29535
|
* an `Accepted` event into a tranche other than the one requested.
|
|
@@ -28679,17 +29554,15 @@ const numOrNull = (str) => {
|
|
|
28679
29554
|
* Convert a `UserRequest` into a `RequestState`. Pure — no clock, no network,
|
|
28680
29555
|
* no copy.
|
|
28681
29556
|
*
|
|
28682
|
-
* BRANCH ORDER (this IS the behaviour
|
|
28683
|
-
* `deriveTransactionView` check for check):
|
|
29557
|
+
* BRANCH ORDER (this IS the behaviour):
|
|
28684
29558
|
*
|
|
28685
29559
|
* 1. a `Cancelled` event → `cancelled`, neutral, 0
|
|
28686
29560
|
* 2. a withdrawal with a `Forced` event → `forced`, outflow, −accepted
|
|
28687
29561
|
* 3. a reallocated deposit → `reallocated`, inflow, +accepted
|
|
28688
|
-
* 4. a withdrawal partly filled
|
|
28689
|
-
* remainder (cycle
|
|
29562
|
+
* 4. a withdrawal partly filled (paid > 0) with
|
|
29563
|
+
* a LIVE remainder (queued > 0, cycle open) → `partial`, outflow, −accepted
|
|
28690
29564
|
* 5. resolved (`status === 'Processed'`):
|
|
28691
|
-
* withdrawal
|
|
28692
|
-
* withdrawal, fully filled → `complete`, outflow, −accepted
|
|
29565
|
+
* withdrawal (nothing left queued) → `complete`, outflow, −accepted
|
|
28693
29566
|
* deposit, nothing accepted → `rejected`, neutral, 0
|
|
28694
29567
|
* deposit, part rejected → `partial`, inflow, +accepted
|
|
28695
29568
|
* deposit, fully accepted → `complete`, inflow, +accepted
|
|
@@ -28717,10 +29590,10 @@ function deriveRequestState(request) {
|
|
|
28717
29590
|
const isWithdrawal = request.requestType === 'Withdrawal';
|
|
28718
29591
|
const cancelled = isCancelled(request.events);
|
|
28719
29592
|
// Cancelled requests have `requestedAmount` zeroed on the request itself;
|
|
28720
|
-
//
|
|
28721
|
-
//
|
|
29593
|
+
// take the amount from the Cancelled event so the row still carries
|
|
29594
|
+
// "1500 cancelled" (1000 + a 500 top-up) instead of "0 cancelled".
|
|
28722
29595
|
const requested = cancelled
|
|
28723
|
-
? num(request.requestedAmount) ||
|
|
29596
|
+
? num(request.requestedAmount) || cancelledAmountOf(request.events)
|
|
28724
29597
|
: num(request.requestedAmount);
|
|
28725
29598
|
const accepted = num(request.acceptedAmount);
|
|
28726
29599
|
const rejected = num(request.rejectedAmount);
|
|
@@ -28771,18 +29644,23 @@ function deriveRequestState(request) {
|
|
|
28771
29644
|
}
|
|
28772
29645
|
// 4. Withdrawal partly filled with a LIVE remainder: the request returns
|
|
28773
29646
|
// to the queue with a live Cancel. Checked BEFORE the resolved branch and
|
|
28774
|
-
// via `isCycleClosed`, never via the sticky raw status.
|
|
29647
|
+
// via `isCycleClosed`, never via the sticky raw status. `requested` is
|
|
29648
|
+
// what is still OUTSTANDING, so "partly filled" is "something paid AND
|
|
29649
|
+
// something still queued" — never a comparison of the two, which would
|
|
29650
|
+
// turn on whether more was paid than is left.
|
|
28775
29651
|
if (isWithdrawal &&
|
|
28776
29652
|
accepted > 0 &&
|
|
28777
|
-
|
|
29653
|
+
requested > 0 &&
|
|
28778
29654
|
!isCycleClosed(request)) {
|
|
28779
29655
|
return Object.assign(Object.assign({}, base), { kind: 'outflow', amount: -accepted, statusCode: 'partial' });
|
|
28780
29656
|
}
|
|
28781
29657
|
// 5. Resolved — a rejection IS a resolution.
|
|
28782
29658
|
if (request.status === UserRequestStatus.PROCESSED) {
|
|
29659
|
+
// A withdrawal is resolved only once nothing is left queued — a
|
|
29660
|
+
// partly filled one returns to the queue (branch 4), and one cancelled
|
|
29661
|
+
// with a remainder is branch 1 — so a resolved withdrawal is complete.
|
|
28783
29662
|
if (isWithdrawal) {
|
|
28784
|
-
|
|
28785
|
-
return Object.assign(Object.assign({}, base), { kind: 'outflow', amount: -accepted, statusCode: partly ? 'partial' : 'complete' });
|
|
29663
|
+
return Object.assign(Object.assign({}, base), { kind: 'outflow', amount: -accepted, statusCode: 'complete' });
|
|
28786
29664
|
}
|
|
28787
29665
|
// Deposit: full reject vs partial vs full accept.
|
|
28788
29666
|
if (accepted === 0) {
|
|
@@ -28921,12 +29799,13 @@ class PortfolioFacade {
|
|
|
28921
29799
|
* ```
|
|
28922
29800
|
*/
|
|
28923
29801
|
class Kasu {
|
|
28924
|
-
constructor(sdk, chainConfig, signerOrProvider, configOverrides) {
|
|
29802
|
+
constructor(sdk, chainConfig, signerOrProvider, configOverrides, historyProvider) {
|
|
28925
29803
|
var _a, _b;
|
|
28926
29804
|
this._sdk = sdk;
|
|
28927
29805
|
this._chainConfig = chainConfig;
|
|
28928
29806
|
this._signerOrProvider = signerOrProvider;
|
|
28929
29807
|
this._configOverrides = configOverrides;
|
|
29808
|
+
this._historyProvider = historyProvider;
|
|
28930
29809
|
this.strategies = new StrategiesFacade(sdk.DataService, sdk.UserLending, normaliseMapping((_a = configOverrides.poolMetadataMapping) !== null && _a !== void 0 ? _a : chainConfig.poolMetadataMapping));
|
|
28931
29810
|
// Derived ONCE and handed to every facade that needs it. Each of them
|
|
28932
29811
|
// re-deriving `Signer.isSigner` is how two facades come to disagree
|
|
@@ -28964,7 +29843,7 @@ class Kasu {
|
|
|
28964
29843
|
* ```
|
|
28965
29844
|
*/
|
|
28966
29845
|
static create(options) {
|
|
28967
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
29846
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
28968
29847
|
const chainConfig = resolveChainConfig(options.chain);
|
|
28969
29848
|
const overrides = (_a = options.configOverrides) !== null && _a !== void 0 ? _a : {};
|
|
28970
29849
|
const sdkConfig = new SdkConfig({
|
|
@@ -28979,12 +29858,18 @@ class Kasu {
|
|
|
28979
29858
|
// of 6. Every live deployment happens to be 6dp today, so the
|
|
28980
29859
|
// default was right by luck; the next one need not be.
|
|
28981
29860
|
stableAssetDecimals: (_h = overrides.stableAssetDecimals) !== null && _h !== void 0 ? _h : (_j = stableAssetOf(chainConfig)) === null || _j === void 0 ? void 0 : _j.decimals,
|
|
29861
|
+
historyRpcUrls: (_k = overrides.historyRpcUrls) !== null && _k !== void 0 ? _k : chainConfig.historyRpcUrls,
|
|
29862
|
+
chainId: (_l = overrides.chainId) !== null && _l !== void 0 ? _l : chainConfig.chainId,
|
|
28982
29863
|
});
|
|
28983
|
-
const signerOrProvider = (
|
|
29864
|
+
const signerOrProvider = (_m = options.signerOrProvider) !== null && _m !== void 0 ? _m : defaultProvider(chainConfig, typeof options.chain === 'string'
|
|
28984
29865
|
? options.chain
|
|
28985
29866
|
: chainConfig.name);
|
|
28986
|
-
|
|
28987
|
-
|
|
29867
|
+
// An explicit history provider wins; otherwise DataService builds
|
|
29868
|
+
// them from `historyRpcUrls`, pinned to `chainId` (the one place).
|
|
29869
|
+
const sdk = new KasuSdk(sdkConfig, signerOrProvider, {
|
|
29870
|
+
historyProvider: options.historyProvider,
|
|
29871
|
+
});
|
|
29872
|
+
return new Kasu(sdk, chainConfig, signerOrProvider, overrides, options.historyProvider);
|
|
28988
29873
|
}
|
|
28989
29874
|
/**
|
|
28990
29875
|
* A NEW instance bound to `signer`, with the same chain config and the same
|
|
@@ -29004,6 +29889,7 @@ class Kasu {
|
|
|
29004
29889
|
chain: this._chainConfig,
|
|
29005
29890
|
signerOrProvider: signer,
|
|
29006
29891
|
configOverrides: this._configOverrides,
|
|
29892
|
+
historyProvider: this._historyProvider,
|
|
29007
29893
|
});
|
|
29008
29894
|
}
|
|
29009
29895
|
/**
|
|
@@ -29783,4 +30669,4 @@ function weightedAverageApy(slices) {
|
|
|
29783
30669
|
return weighted / totalBalance;
|
|
29784
30670
|
}
|
|
29785
30671
|
|
|
29786
|
-
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, BatchPendingError, BatchRevertedError, BatchSubmissionError, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, CallsFacade, DAYS_PER_EPOCH, DAYS_PER_MONTH, DEFAULT_BATCH_POLLING_POLICY, DepositBatchMismatchError, DepositFlow, DepositsFacade, ENTRY_POINT_V07, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_DAYS_FOR_MONTHS, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NOT_A_WITHDRAWAL_CALL_MESSAGE, NO_DIRECTUS_URL_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, NO_WITHDRAWAL_ENCODER_MESSAGE, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, aggregateYieldHistory, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, checkSponsoredCallOutcome, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, dailyInterest, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeDepositData, encodeRequestWithdrawalCall, encodeStableTransfer, encodeWithdrawAtExpiryCall, epochRateToApy, epochTrancheYield, explorerAddressUrl, explorerTxUrl, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getStrategyRegion, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, pickShortDescription, poolAllTranchesFull, poolMaxApy, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|
|
30672
|
+
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, BatchPendingError, BatchRevertedError, BatchSubmissionError, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, CallsFacade, DAYS_PER_EPOCH, DAYS_PER_MONTH, DEFAULT_BATCH_POLLING_POLICY, DepositBatchMismatchError, DepositFlow, DepositsFacade, ENTRY_POINT_V07, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_DAYS_FOR_MONTHS, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NOT_A_WITHDRAWAL_CALL_MESSAGE, NO_DIRECTUS_URL_MESSAGE, NO_HISTORY_PROVIDER_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, NO_WITHDRAWAL_ENCODER_MESSAGE, PastStateUnavailableError, PoolTvlHistoryAbortedError, PoolTvlHistoryTimeoutError, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, aggregateYieldHistory, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, checkSponsoredCallOutcome, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, dailyInterest, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeDepositData, encodeRequestWithdrawalCall, encodeStableTransfer, encodeWithdrawAtExpiryCall, epochRateToApy, epochTrancheYield, explorerAddressUrl, explorerTxUrl, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getStrategyRegion, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, pickShortDescription, poolAllTranchesFull, poolMaxApy, poolTvl, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|