@kasufinance/kasu-sdk 2.15.0 → 2.17.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 +17 -1
- package/dist/bundle.cjs.js +1144 -221
- package/dist/bundle.esm.js +1141 -222
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.js +1 -1
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/yield-history.d.ts +25 -1
- package/dist/domain/yield-history.js +41 -11
- package/dist/domain/yield-history.js.map +1 -1
- package/dist/domain/yields.d.ts +200 -15
- package/dist/domain/yields.js +211 -14
- package/dist/domain/yields.js.map +1 -1
- package/dist/services/Locking/locking.d.ts +12 -0
- package/dist/services/Locking/locking.js +16 -0
- package/dist/services/Locking/locking.js.map +1 -1
- package/dist/services/Portfolio/portfolio.d.ts +54 -1
- package/dist/services/Portfolio/portfolio.js +357 -80
- package/dist/services/Portfolio/portfolio.js.map +1 -1
- package/dist/services/Portfolio/queries.d.ts +16 -0
- package/dist/services/Portfolio/queries.js +119 -2
- package/dist/services/Portfolio/queries.js.map +1 -1
- package/dist/services/Portfolio/types.d.ts +94 -6
- package/dist/services/Portfolio/yield-history.d.ts +148 -10
- package/dist/services/Portfolio/yield-history.js +241 -31
- package/dist/services/Portfolio/yield-history.js.map +1 -1
- package/dist/services/UserLending/user-lending.d.ts +16 -0
- package/dist/services/UserLending/user-lending.js +24 -0
- package/dist/services/UserLending/user-lending.js.map +1 -1
- package/dist/services/shared.d.ts +7 -0
- package/dist/services/shared.js +48 -0
- package/dist/services/shared.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/index.ts +5 -1
- package/src/domain/yield-history.ts +47 -11
- package/src/domain/yields.ts +257 -15
- package/src/services/Locking/locking.ts +17 -0
- package/src/services/Portfolio/portfolio.ts +559 -126
- package/src/services/Portfolio/queries.ts +119 -2
- package/src/services/Portfolio/types.ts +91 -6
- package/src/services/Portfolio/yield-history.ts +405 -56
- package/src/services/UserLending/user-lending.ts +46 -0
- package/src/services/shared.ts +48 -0
package/dist/bundle.esm.js
CHANGED
|
@@ -15949,6 +15949,54 @@ function isMissingEntityError(error) {
|
|
|
15949
15949
|
function isEmptyHistoryError(error, liteDeployment) {
|
|
15950
15950
|
return liteDeployment && isMissingEntityError(error);
|
|
15951
15951
|
}
|
|
15952
|
+
/**
|
|
15953
|
+
* What node implementations and RPC providers answer when they cannot serve
|
|
15954
|
+
* state at a requested block: pruned history, or a block they have not seen
|
|
15955
|
+
* yet. Matched on the error's text, lowercased.
|
|
15956
|
+
*/
|
|
15957
|
+
const BLOCK_UNAVAILABLE_PATTERNS = [
|
|
15958
|
+
'missing trie node',
|
|
15959
|
+
'header not found',
|
|
15960
|
+
'unknown block',
|
|
15961
|
+
'block not found',
|
|
15962
|
+
'pruned',
|
|
15963
|
+
'historical state',
|
|
15964
|
+
'state is not available',
|
|
15965
|
+
'state not available',
|
|
15966
|
+
'missing state',
|
|
15967
|
+
'state unavailable',
|
|
15968
|
+
'state histories',
|
|
15969
|
+
'block number out of range',
|
|
15970
|
+
'beyond current head',
|
|
15971
|
+
'is in the future',
|
|
15972
|
+
];
|
|
15973
|
+
function errorTexts(error, depth = 0) {
|
|
15974
|
+
if (depth > 4 || error === null || error === undefined)
|
|
15975
|
+
return [];
|
|
15976
|
+
if (typeof error === 'string')
|
|
15977
|
+
return [error];
|
|
15978
|
+
if (typeof error !== 'object')
|
|
15979
|
+
return [];
|
|
15980
|
+
const record = error;
|
|
15981
|
+
return [
|
|
15982
|
+
'message',
|
|
15983
|
+
'reason',
|
|
15984
|
+
'body',
|
|
15985
|
+
'error',
|
|
15986
|
+
'data',
|
|
15987
|
+
'serverError',
|
|
15988
|
+
].flatMap((key) => errorTexts(record[key], depth + 1));
|
|
15989
|
+
}
|
|
15990
|
+
/**
|
|
15991
|
+
* True when a failed RPC read says the node cannot serve state at the block
|
|
15992
|
+
* asked for (pruned, or not reached yet) — and ONLY then. A rate limit, a
|
|
15993
|
+
* timeout, a refused connection or a revert is not this, and must surface as
|
|
15994
|
+
* the error it is.
|
|
15995
|
+
*/
|
|
15996
|
+
function isBlockUnavailableError(error) {
|
|
15997
|
+
const text = errorTexts(error).join(' ').toLowerCase();
|
|
15998
|
+
return BLOCK_UNAVAILABLE_PATTERNS.some((pattern) => text.includes(pattern));
|
|
15999
|
+
}
|
|
15952
16000
|
|
|
15953
16001
|
/**
|
|
15954
16002
|
* The error a CMS-only call raises on a deployment configured without
|
|
@@ -18042,6 +18090,22 @@ class KSULocking {
|
|
|
18042
18090
|
return (yield this._systemVariablesAbi.nextEpochStartTimestamp()).toNumber();
|
|
18043
18091
|
});
|
|
18044
18092
|
}
|
|
18093
|
+
/**
|
|
18094
|
+
* Unix SECONDS at which epoch 0 started:
|
|
18095
|
+
* `SystemVariables.epochStartTimestamp(0)`. The contract writes this once,
|
|
18096
|
+
* at initialisation, so it never changes for a deployment and may be cached
|
|
18097
|
+
* for the life of the app. Every epoch boundary follows from it —
|
|
18098
|
+
* `epochEndTimestamp(initial, epoch)` and `epochAccrual` in the domain
|
|
18099
|
+
* layer.
|
|
18100
|
+
*
|
|
18101
|
+
* Available on every deployment, Full and Lite. A failed read rejects; the
|
|
18102
|
+
* caller validates the value (a positive integer) before using it.
|
|
18103
|
+
*/
|
|
18104
|
+
getInitialEpochStartTimestamp() {
|
|
18105
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18106
|
+
return (yield this._systemVariablesAbi.epochStartTimestamp(0)).toNumber();
|
|
18107
|
+
});
|
|
18108
|
+
}
|
|
18045
18109
|
getNextClearingPeriodDate() {
|
|
18046
18110
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18047
18111
|
const nextEpochDate = yield this.getNextEpochDate();
|
|
@@ -18078,101 +18142,6 @@ class KSULocking {
|
|
|
18078
18142
|
}
|
|
18079
18143
|
}
|
|
18080
18144
|
|
|
18081
|
-
/**
|
|
18082
|
-
* Settled interest per cycle (epoch): what a lender was credited at each close,
|
|
18083
|
-
* per pool and tranche, and the one formula that turns a tranche's credited
|
|
18084
|
-
* interest into one lender's share of it.
|
|
18085
|
-
*
|
|
18086
|
-
* **The figures are NET, and only net.** `LendingPool._applyTrancheInterest`
|
|
18087
|
-
* takes the performance fee off first and emits `InterestApplied` with the
|
|
18088
|
-
* lender side only (`interest × (1 − performanceFee)`); a fixed-term top-up
|
|
18089
|
-
* (`_applyFixedRateInterests`) is net of the fee the same way. So the figure
|
|
18090
|
-
* this module computes from those records IS what the lender was credited —
|
|
18091
|
-
* never take the fee off it again. No gross is offered: the subgraph keeps
|
|
18092
|
-
* only TODAY's fee, so a historical gross would be a guess.
|
|
18093
|
-
*
|
|
18094
|
-
* Units: amounts are display units of the DEPLOYMENT'S OWN stable token (USDC
|
|
18095
|
-
* on Base and XDC USDC, AUDD on XDC AUDD) — never converted to USD here;
|
|
18096
|
-
* shares are display units of tranche shares, as the subgraph's BigDecimals.
|
|
18097
|
-
*/
|
|
18098
|
-
/**
|
|
18099
|
-
* The ONE per-epoch formula. `Portfolio.getPortfolioLendingData` runs it for
|
|
18100
|
-
* the last settled epoch and `getYieldHistory` for every epoch of a window, so
|
|
18101
|
-
* the two figures cannot drift apart.
|
|
18102
|
-
*
|
|
18103
|
-
* ```
|
|
18104
|
-
* base = epochInterest × userShares / trancheShares
|
|
18105
|
-
* lockBase = base × lock.sharesBeforeEpoch / userShares (active locks)
|
|
18106
|
-
* topUp = (lock.sharesAtEpoch − lock.sharesBeforeEpoch) × trancheBalanceNow / trancheSharesNow
|
|
18107
|
-
* variable = base − Σ lockBase
|
|
18108
|
-
* total = variable + Σ (lockBase + topUp)
|
|
18109
|
-
* ```
|
|
18110
|
-
*
|
|
18111
|
-
* A zero denominator contributes 0 (a tranche or a lender with no shares
|
|
18112
|
-
* earned nothing at that close), never `NaN`.
|
|
18113
|
-
*/
|
|
18114
|
-
function epochTrancheYield(input) {
|
|
18115
|
-
const base = input.trancheShares === 0
|
|
18116
|
-
? 0
|
|
18117
|
-
: (input.epochInterest * input.userShares) / input.trancheShares;
|
|
18118
|
-
let variable = base;
|
|
18119
|
-
const locks = input.locks.map((lock) => {
|
|
18120
|
-
if (!lock.active)
|
|
18121
|
-
return 0;
|
|
18122
|
-
const topUp = input.trancheSharesNow === 0
|
|
18123
|
-
? 0
|
|
18124
|
-
: ((lock.sharesAtEpoch - lock.sharesBeforeEpoch) *
|
|
18125
|
-
input.trancheBalanceNow) /
|
|
18126
|
-
input.trancheSharesNow;
|
|
18127
|
-
const lockBase = input.userShares === 0
|
|
18128
|
-
? 0
|
|
18129
|
-
: (base * lock.sharesBeforeEpoch) / input.userShares;
|
|
18130
|
-
variable -= lockBase;
|
|
18131
|
-
return lockBase + topUp;
|
|
18132
|
-
});
|
|
18133
|
-
const total = locks.reduce((sum, lockYield) => sum + lockYield, variable);
|
|
18134
|
-
return { total, variable, locks };
|
|
18135
|
-
}
|
|
18136
|
-
/**
|
|
18137
|
-
* Pool/tranche entries → one point per epoch, ascending by `epochId`. With no
|
|
18138
|
-
* filter it sums every strategy (the Lend tab's bars); with `poolId` it is one
|
|
18139
|
-
* strategy (a strategy page's bars).
|
|
18140
|
-
*
|
|
18141
|
-
* An epoch appears only if a kept entry has it — there is no zero padding, so
|
|
18142
|
-
* an empty input (a new lender) is an empty output.
|
|
18143
|
-
*
|
|
18144
|
-
* For a fixed-term lock holder the bars can sum to slightly MORE than the
|
|
18145
|
-
* lender's lifetime interest (up to about 0.2 %): each top-up is valued at the
|
|
18146
|
-
* tranche's CURRENT share price, which has grown since. Show "earned to date"
|
|
18147
|
-
* from the lifetime figure, never from this sum.
|
|
18148
|
-
*/
|
|
18149
|
-
function aggregateYieldHistory(entries, filter = {}) {
|
|
18150
|
-
var _a, _b;
|
|
18151
|
-
const poolId = (_a = filter.poolId) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
18152
|
-
const trancheId = (_b = filter.trancheId) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
18153
|
-
const byEpoch = new Map();
|
|
18154
|
-
for (const entry of entries) {
|
|
18155
|
-
if (poolId !== undefined && entry.poolId.toLowerCase() !== poolId) {
|
|
18156
|
-
continue;
|
|
18157
|
-
}
|
|
18158
|
-
if (trancheId !== undefined &&
|
|
18159
|
-
entry.trancheId.toLowerCase() !== trancheId) {
|
|
18160
|
-
continue;
|
|
18161
|
-
}
|
|
18162
|
-
const point = byEpoch.get(entry.epochId);
|
|
18163
|
-
if (point) {
|
|
18164
|
-
point.netYield += entry.netYield;
|
|
18165
|
-
continue;
|
|
18166
|
-
}
|
|
18167
|
-
byEpoch.set(entry.epochId, {
|
|
18168
|
-
epochId: entry.epochId,
|
|
18169
|
-
epochEnd: entry.epochEnd,
|
|
18170
|
-
netYield: entry.netYield,
|
|
18171
|
-
});
|
|
18172
|
-
}
|
|
18173
|
-
return [...byEpoch.values()].sort((a, b) => a.epochId - b.epochId);
|
|
18174
|
-
}
|
|
18175
|
-
|
|
18176
18145
|
/**
|
|
18177
18146
|
* Check if the SDK is configured for a Lite deployment.
|
|
18178
18147
|
* Lite deployments don't have KSU token, locking, or loyalty features.
|
|
@@ -18850,6 +18819,30 @@ class UserLending {
|
|
|
18850
18819
|
});
|
|
18851
18820
|
});
|
|
18852
18821
|
}
|
|
18822
|
+
/**
|
|
18823
|
+
* The lender's ACTIVE assets in each tranche, read from the chain
|
|
18824
|
+
* (`LendingPoolTranche.userActiveAssets`), in the order of `trancheIds`,
|
|
18825
|
+
* in the stable token's base units. Active shares are the ones the lender
|
|
18826
|
+
* owns in the tranche — fixed-term-locked and withdrawal-pending shares
|
|
18827
|
+
* included — whatever path brought them there; `LendingPool.userBalance`
|
|
18828
|
+
* is their sum. One call per tranche.
|
|
18829
|
+
*/
|
|
18830
|
+
getUserTrancheActiveAssets(user, trancheIds, provider, blockTag) {
|
|
18831
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18832
|
+
return yield Promise.all(trancheIds.map((trancheId) => ILendingPoolTrancheAbi__factory.connect(trancheId, provider !== null && provider !== void 0 ? provider : this._signerOrProvider).userActiveAssets(user, { blockTag: blockTag !== null && blockTag !== void 0 ? blockTag : 'latest' })));
|
|
18833
|
+
});
|
|
18834
|
+
}
|
|
18835
|
+
/**
|
|
18836
|
+
* The lender's balance in each pool (`LendingPool.userBalance`, the sum
|
|
18837
|
+
* of its tranches' active assets), in the order of `poolIds`, in the
|
|
18838
|
+
* stable token's base units, at `blockTag` (default `latest`). One call
|
|
18839
|
+
* per pool.
|
|
18840
|
+
*/
|
|
18841
|
+
getUserPoolBalancesAt(user, poolIds, provider, blockTag) {
|
|
18842
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18843
|
+
return yield Promise.all(poolIds.map((poolId) => ILendingPoolAbi__factory.connect(poolId, provider !== null && provider !== void 0 ? provider : this._signerOrProvider).userBalance(user, { blockTag: blockTag !== null && blockTag !== void 0 ? blockTag : 'latest' })));
|
|
18844
|
+
});
|
|
18845
|
+
}
|
|
18853
18846
|
getPortfolioUserTrancheBalances(user) {
|
|
18854
18847
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18855
18848
|
const userDetails = yield this._graph.request(portfolioUserTrancheDetailsQuery, {
|
|
@@ -19001,20 +18994,47 @@ gql `
|
|
|
19001
18994
|
}
|
|
19002
18995
|
}
|
|
19003
18996
|
`;
|
|
18997
|
+
/**
|
|
18998
|
+
* The portfolio read. Its last-epoch figures pair each tranche's newest
|
|
18999
|
+
* interest (epoch E) with the shares in force when clearing E applied it —
|
|
19000
|
+
* the selection `getYieldHistory` makes (`positionEpochYield`). For that it
|
|
19001
|
+
* reads, per lender and tranche, the newest share snapshot tagged before
|
|
19002
|
+
* `$recentEpoch` and EVERY snapshot tagged from it on (with their times), and,
|
|
19003
|
+
* for the listed pools (`$poolIds`) and tranches (`$trancheIds`), the
|
|
19004
|
+
* clearings and share exits of those recent epochs. `$recentEpoch` is six
|
|
19005
|
+
* epochs back (`RECENT_PAIRING_EPOCHS`); a newest interest older than that (a
|
|
19006
|
+
* pool that clears rarely) is priced from a history read of its own. Lock
|
|
19007
|
+
* snapshots are read the same way from one epoch further back
|
|
19008
|
+
* (`$lockRecentEpoch`), since a top-up compares E with E − 1. Every list read
|
|
19009
|
+
* with `$first` must come back SHORT of it — a full one is refused, never
|
|
19010
|
+
* used truncated. `_meta` is the block the answer describes: the chain is
|
|
19011
|
+
* read at that same block.
|
|
19012
|
+
*/
|
|
19004
19013
|
const lendingPortfolioQuery = gql `
|
|
19005
19014
|
query LastEpochQuery(
|
|
19006
19015
|
$userAddress: ID!
|
|
19007
19016
|
$epochId: BigInt!
|
|
19008
19017
|
$lastEpochId: BigInt!
|
|
19018
|
+
$recentEpoch: BigInt!
|
|
19019
|
+
$lockRecentEpoch: BigInt!
|
|
19009
19020
|
$unusedPools: [String!]!
|
|
19021
|
+
$poolIds: [String!]!
|
|
19022
|
+
$trancheIds: [String!]!
|
|
19010
19023
|
$first: Int!
|
|
19011
19024
|
) {
|
|
19025
|
+
_meta {
|
|
19026
|
+
block {
|
|
19027
|
+
number
|
|
19028
|
+
}
|
|
19029
|
+
}
|
|
19012
19030
|
user(id: $userAddress) {
|
|
19013
19031
|
lendingPoolUserDetails(
|
|
19014
19032
|
first: $first
|
|
19015
19033
|
where: { lendingPool_not_in: $unusedPools }
|
|
19016
19034
|
) {
|
|
19017
19035
|
id
|
|
19036
|
+
totalAcceptedDeposits
|
|
19037
|
+
totalAcceptedWithdrawnAmount
|
|
19018
19038
|
lendingPool {
|
|
19019
19039
|
id
|
|
19020
19040
|
name
|
|
@@ -19024,16 +19044,34 @@ const lendingPortfolioQuery = gql `
|
|
|
19024
19044
|
}
|
|
19025
19045
|
}
|
|
19026
19046
|
lendingPoolTrancheUserDetails(first: $first) {
|
|
19047
|
+
id
|
|
19027
19048
|
shares
|
|
19049
|
+
totalAcceptedDeposits
|
|
19050
|
+
totalAcceptedWithdrawnAmount
|
|
19028
19051
|
lendingPoolTrancheUserEpochSharesUpdates(
|
|
19029
19052
|
orderDirection: desc
|
|
19030
19053
|
orderBy: shareUpdatesIndex
|
|
19031
|
-
where: { epochId_lt: $
|
|
19054
|
+
where: { epochId_lt: $recentEpoch }
|
|
19032
19055
|
first: 1
|
|
19033
19056
|
) {
|
|
19057
|
+
epochId
|
|
19058
|
+
shareUpdatesIndex
|
|
19034
19059
|
shares
|
|
19060
|
+
timestamp
|
|
19061
|
+
}
|
|
19062
|
+
recentUserShareUpdates: lendingPoolTrancheUserEpochSharesUpdates(
|
|
19063
|
+
orderDirection: desc
|
|
19064
|
+
orderBy: shareUpdatesIndex
|
|
19065
|
+
where: { epochId_gte: $recentEpoch }
|
|
19066
|
+
first: $first
|
|
19067
|
+
) {
|
|
19068
|
+
epochId
|
|
19069
|
+
shareUpdatesIndex
|
|
19070
|
+
shares
|
|
19071
|
+
timestamp
|
|
19035
19072
|
}
|
|
19036
19073
|
userLendingPoolTrancheFixedTermDepositLocks(first: $first) {
|
|
19074
|
+
id
|
|
19037
19075
|
isLocked
|
|
19038
19076
|
unlockAmount
|
|
19039
19077
|
initialAmount
|
|
@@ -19065,6 +19103,26 @@ const lendingPortfolioQuery = gql `
|
|
|
19065
19103
|
) {
|
|
19066
19104
|
shares
|
|
19067
19105
|
}
|
|
19106
|
+
lockSharesBase: userLendingPoolTrancheFixedTermDepositLockShareUpdate(
|
|
19107
|
+
orderBy: shareUpdatesIndex
|
|
19108
|
+
orderDirection: desc
|
|
19109
|
+
first: 1
|
|
19110
|
+
where: { epochId_lt: $lockRecentEpoch }
|
|
19111
|
+
) {
|
|
19112
|
+
epochId
|
|
19113
|
+
shareUpdatesIndex
|
|
19114
|
+
shares
|
|
19115
|
+
}
|
|
19116
|
+
lockSharesRecent: userLendingPoolTrancheFixedTermDepositLockShareUpdate(
|
|
19117
|
+
orderBy: shareUpdatesIndex
|
|
19118
|
+
orderDirection: desc
|
|
19119
|
+
first: $first
|
|
19120
|
+
where: { epochId_gte: $lockRecentEpoch }
|
|
19121
|
+
) {
|
|
19122
|
+
epochId
|
|
19123
|
+
shareUpdatesIndex
|
|
19124
|
+
shares
|
|
19125
|
+
}
|
|
19068
19126
|
}
|
|
19069
19127
|
tranche {
|
|
19070
19128
|
id
|
|
@@ -19074,9 +19132,23 @@ const lendingPortfolioQuery = gql `
|
|
|
19074
19132
|
first: 1
|
|
19075
19133
|
orderBy: shareUpdatesIndex
|
|
19076
19134
|
orderDirection: desc
|
|
19077
|
-
where: { epochId_lt: $
|
|
19135
|
+
where: { epochId_lt: $recentEpoch }
|
|
19078
19136
|
) {
|
|
19137
|
+
epochId
|
|
19138
|
+
shareUpdatesIndex
|
|
19079
19139
|
shares
|
|
19140
|
+
timestamp
|
|
19141
|
+
}
|
|
19142
|
+
recentTrancheShareUpdates: lendingPoolTrancheShareUpdates(
|
|
19143
|
+
first: $first
|
|
19144
|
+
orderBy: shareUpdatesIndex
|
|
19145
|
+
orderDirection: desc
|
|
19146
|
+
where: { epochId_gte: $recentEpoch }
|
|
19147
|
+
) {
|
|
19148
|
+
epochId
|
|
19149
|
+
shareUpdatesIndex
|
|
19150
|
+
shares
|
|
19151
|
+
timestamp
|
|
19080
19152
|
}
|
|
19081
19153
|
lendingPoolTrancheEpochInterest(
|
|
19082
19154
|
first: 1
|
|
@@ -19084,12 +19156,50 @@ const lendingPortfolioQuery = gql `
|
|
|
19084
19156
|
orderDirection: desc
|
|
19085
19157
|
where: { epochId_lt: $epochId }
|
|
19086
19158
|
) {
|
|
19159
|
+
epochId
|
|
19087
19160
|
epochInterestAmount
|
|
19088
19161
|
}
|
|
19089
19162
|
}
|
|
19090
19163
|
}
|
|
19091
19164
|
}
|
|
19092
19165
|
}
|
|
19166
|
+
lendingPoolClearings(
|
|
19167
|
+
first: $first
|
|
19168
|
+
orderBy: id
|
|
19169
|
+
orderDirection: asc
|
|
19170
|
+
where: {
|
|
19171
|
+
lendingPool_in: $poolIds
|
|
19172
|
+
epochId_gte: $recentEpoch
|
|
19173
|
+
epochId_lt: $epochId
|
|
19174
|
+
}
|
|
19175
|
+
) {
|
|
19176
|
+
id
|
|
19177
|
+
epochId
|
|
19178
|
+
startTimestamp
|
|
19179
|
+
lendingPool {
|
|
19180
|
+
id
|
|
19181
|
+
}
|
|
19182
|
+
}
|
|
19183
|
+
recentWithdrawalsAccepted: userRequestEvents(
|
|
19184
|
+
first: $first
|
|
19185
|
+
orderBy: id
|
|
19186
|
+
orderDirection: asc
|
|
19187
|
+
where: {
|
|
19188
|
+
type_in: [WithdrawalAccepted, ImmediateWithdrawalExecuted]
|
|
19189
|
+
tranche_in: $trancheIds
|
|
19190
|
+
epochId_gte: $recentEpoch
|
|
19191
|
+
epochId_lt: $epochId
|
|
19192
|
+
}
|
|
19193
|
+
) {
|
|
19194
|
+
id
|
|
19195
|
+
type
|
|
19196
|
+
epochId
|
|
19197
|
+
createdOn
|
|
19198
|
+
sharesAmount
|
|
19199
|
+
tranche {
|
|
19200
|
+
id
|
|
19201
|
+
}
|
|
19202
|
+
}
|
|
19093
19203
|
userRequests(
|
|
19094
19204
|
first: $first
|
|
19095
19205
|
where: {
|
|
@@ -19117,6 +19227,131 @@ const lendingPortfolioQuery = gql `
|
|
|
19117
19227
|
}
|
|
19118
19228
|
`;
|
|
19119
19229
|
|
|
19230
|
+
/**
|
|
19231
|
+
* Settled interest per cycle (epoch): what a lender was credited at each close,
|
|
19232
|
+
* per pool and tranche, and the one formula that turns a tranche's credited
|
|
19233
|
+
* interest into one lender's share of it.
|
|
19234
|
+
*
|
|
19235
|
+
* **The figures are NET, and only net.** `LendingPool._applyTrancheInterest`
|
|
19236
|
+
* takes the performance fee off first and emits `InterestApplied` with the
|
|
19237
|
+
* lender side only (`interest × (1 − performanceFee)`); a fixed-term top-up
|
|
19238
|
+
* (`_applyFixedRateInterests`) is net of the fee the same way. So the figure
|
|
19239
|
+
* this module computes from those records IS what the lender was credited —
|
|
19240
|
+
* never take the fee off it again. No gross is offered: the subgraph keeps
|
|
19241
|
+
* only TODAY's fee, so a historical gross would be a guess.
|
|
19242
|
+
*
|
|
19243
|
+
* Units: amounts are display units of the DEPLOYMENT'S OWN stable token (USDC
|
|
19244
|
+
* on Base and XDC USDC, AUDD on XDC AUDD) — never converted to USD here;
|
|
19245
|
+
* shares are display units of tranche shares, as the subgraph's BigDecimals.
|
|
19246
|
+
*/
|
|
19247
|
+
/**
|
|
19248
|
+
* The largest change of a lock's shares, as a fraction of its shares before
|
|
19249
|
+
* the epoch, that one clearing's fixed-term top-up can make. The top-up is
|
|
19250
|
+
* the fixed rate's difference from the variable one on one week's balance
|
|
19251
|
+
* (`LendingPool._applyFixedRateInterests`) — a fraction of a percent at any
|
|
19252
|
+
* real rate — so 5 % is far above every genuine top-up and far below any
|
|
19253
|
+
* accounting fault. A lock-share change outside it is NOT interest: it is
|
|
19254
|
+
* left out of the yield (a share movement is never booked as yield). The one
|
|
19255
|
+
* seen on chain is a lock whose recorded shares were set to zero at a
|
|
19256
|
+
* clearing while its shares stayed in the fixed-term contract.
|
|
19257
|
+
*/
|
|
19258
|
+
const MAX_TOP_UP_SHARE_FRACTION = 0.05;
|
|
19259
|
+
/**
|
|
19260
|
+
* True when `sharesBefore → sharesAt` is a change one clearing's fixed-term
|
|
19261
|
+
* top-up can make (`MAX_TOP_UP_SHARE_FRACTION`). A lock with no shares
|
|
19262
|
+
* before has no top-up at all.
|
|
19263
|
+
*/
|
|
19264
|
+
function isPlausibleTopUp(sharesBefore, sharesAt) {
|
|
19265
|
+
if (!(sharesBefore > 0))
|
|
19266
|
+
return sharesAt === sharesBefore;
|
|
19267
|
+
return (Math.abs(sharesAt - sharesBefore) <=
|
|
19268
|
+
sharesBefore * MAX_TOP_UP_SHARE_FRACTION);
|
|
19269
|
+
}
|
|
19270
|
+
/**
|
|
19271
|
+
* The ONE per-epoch formula. `Portfolio.getPortfolioLendingData` runs it for
|
|
19272
|
+
* the last settled epoch and `getYieldHistory` for every epoch of a window, so
|
|
19273
|
+
* the two figures cannot drift apart.
|
|
19274
|
+
*
|
|
19275
|
+
* ```
|
|
19276
|
+
* base = epochInterest × userShares / trancheShares
|
|
19277
|
+
* lockBase = base × lock.sharesBeforeEpoch / userShares (active locks)
|
|
19278
|
+
* topUp = (lock.sharesAtEpoch − lock.sharesBeforeEpoch) × trancheBalanceNow / trancheSharesNow
|
|
19279
|
+
* variable = base − Σ lockBase
|
|
19280
|
+
* total = variable + Σ (lockBase + topUp)
|
|
19281
|
+
* ```
|
|
19282
|
+
*
|
|
19283
|
+
* A zero denominator contributes 0 (a tranche or a lender with no shares
|
|
19284
|
+
* earned nothing at that close), never `NaN`. So does a NEGATIVE share count:
|
|
19285
|
+
* the subgraph's per-lender shares are a ledger of accepted deposits and
|
|
19286
|
+
* withdrawals, and a wallet whose shares arrived some other way (moved to it
|
|
19287
|
+
* from another wallet) withdraws more than the ledger ever credited it. That
|
|
19288
|
+
* position is not one the ledger can describe, and its negative count is not
|
|
19289
|
+
* a negative yield. A lock-share change no top-up can make
|
|
19290
|
+
* (`isPlausibleTopUp`) contributes no top-up.
|
|
19291
|
+
*/
|
|
19292
|
+
function epochTrancheYield(input) {
|
|
19293
|
+
const base = input.trancheShares > 0 && input.userShares > 0
|
|
19294
|
+
? (input.epochInterest * input.userShares) / input.trancheShares
|
|
19295
|
+
: 0;
|
|
19296
|
+
let variable = base;
|
|
19297
|
+
const locks = input.locks.map((lock) => {
|
|
19298
|
+
if (!lock.active)
|
|
19299
|
+
return 0;
|
|
19300
|
+
const topUp = input.trancheSharesNow > 0 &&
|
|
19301
|
+
isPlausibleTopUp(lock.sharesBeforeEpoch, lock.sharesAtEpoch)
|
|
19302
|
+
? ((lock.sharesAtEpoch - lock.sharesBeforeEpoch) *
|
|
19303
|
+
input.trancheBalanceNow) /
|
|
19304
|
+
input.trancheSharesNow
|
|
19305
|
+
: 0;
|
|
19306
|
+
const lockBase = input.userShares > 0
|
|
19307
|
+
? (base * lock.sharesBeforeEpoch) / input.userShares
|
|
19308
|
+
: 0;
|
|
19309
|
+
variable -= lockBase;
|
|
19310
|
+
return lockBase + topUp;
|
|
19311
|
+
});
|
|
19312
|
+
const total = locks.reduce((sum, lockYield) => sum + lockYield, variable);
|
|
19313
|
+
return { total, variable, locks };
|
|
19314
|
+
}
|
|
19315
|
+
/**
|
|
19316
|
+
* Pool/tranche entries → one point per epoch, ascending by `epochId`. With no
|
|
19317
|
+
* filter it sums every strategy (the Lend tab's bars); with `poolId` it is one
|
|
19318
|
+
* strategy (a strategy page's bars).
|
|
19319
|
+
*
|
|
19320
|
+
* An epoch appears only if a kept entry has it — there is no zero padding, so
|
|
19321
|
+
* an empty input (a new lender) is an empty output.
|
|
19322
|
+
*
|
|
19323
|
+
* For a fixed-term lock holder the bars can sum to slightly MORE than the
|
|
19324
|
+
* lender's lifetime interest (up to about 0.2 %): each top-up is valued at the
|
|
19325
|
+
* tranche's CURRENT share price, which has grown since. Show "earned to date"
|
|
19326
|
+
* from the lifetime figure, never from this sum.
|
|
19327
|
+
*/
|
|
19328
|
+
function aggregateYieldHistory(entries, filter = {}) {
|
|
19329
|
+
var _a, _b;
|
|
19330
|
+
const poolId = (_a = filter.poolId) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
19331
|
+
const trancheId = (_b = filter.trancheId) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
19332
|
+
const byEpoch = new Map();
|
|
19333
|
+
for (const entry of entries) {
|
|
19334
|
+
if (poolId !== undefined && entry.poolId.toLowerCase() !== poolId) {
|
|
19335
|
+
continue;
|
|
19336
|
+
}
|
|
19337
|
+
if (trancheId !== undefined &&
|
|
19338
|
+
entry.trancheId.toLowerCase() !== trancheId) {
|
|
19339
|
+
continue;
|
|
19340
|
+
}
|
|
19341
|
+
const point = byEpoch.get(entry.epochId);
|
|
19342
|
+
if (point) {
|
|
19343
|
+
point.netYield += entry.netYield;
|
|
19344
|
+
continue;
|
|
19345
|
+
}
|
|
19346
|
+
byEpoch.set(entry.epochId, {
|
|
19347
|
+
epochId: entry.epochId,
|
|
19348
|
+
epochEnd: entry.epochEnd,
|
|
19349
|
+
netYield: entry.netYield,
|
|
19350
|
+
});
|
|
19351
|
+
}
|
|
19352
|
+
return [...byEpoch.values()].sort((a, b) => a.epochId - b.epochId);
|
|
19353
|
+
}
|
|
19354
|
+
|
|
19120
19355
|
/** The subgraph returns at most this many rows per collection per request. */
|
|
19121
19356
|
const YIELD_HISTORY_PAGE_SIZE = 1000;
|
|
19122
19357
|
/**
|
|
@@ -19180,6 +19415,7 @@ const yieldHistoryPositionsQuery = gql `
|
|
|
19180
19415
|
}
|
|
19181
19416
|
lendingPoolTrancheUserDetails(first: $first) {
|
|
19182
19417
|
id
|
|
19418
|
+
shares
|
|
19183
19419
|
tranche {
|
|
19184
19420
|
id
|
|
19185
19421
|
balance
|
|
@@ -19194,32 +19430,50 @@ const yieldHistoryPositionsQuery = gql `
|
|
|
19194
19430
|
}
|
|
19195
19431
|
}
|
|
19196
19432
|
}
|
|
19433
|
+
_meta {
|
|
19434
|
+
block {
|
|
19435
|
+
number
|
|
19436
|
+
}
|
|
19437
|
+
}
|
|
19197
19438
|
}
|
|
19198
19439
|
`;
|
|
19199
19440
|
/**
|
|
19200
|
-
* Round trip 2 onwards: the
|
|
19441
|
+
* Round trip 2 onwards: the six per-epoch series, one page of each per
|
|
19201
19442
|
* request, cursor-paginated by `id`. A series that is exhausted is skipped with
|
|
19202
19443
|
* `@include`, so a history costs as many requests as its LONGEST series has
|
|
19203
19444
|
* pages — normally one — never one per epoch.
|
|
19204
19445
|
*
|
|
19205
19446
|
* Share snapshots are read up to the window's end with no lower bound: the
|
|
19206
|
-
* value AS OF the first epoch may come from an update long before it.
|
|
19447
|
+
* value AS OF the first epoch may come from an update long before it. Each
|
|
19448
|
+
* carries its `timestamp`, and the window's clearings their start, because a
|
|
19449
|
+
* cycle's interest is paired with the shares in force when the clearing
|
|
19450
|
+
* APPLIED it (`sharesAtInterest`), which the epoch tag alone gets wrong for a
|
|
19451
|
+
* withdrawal accepted between clearings — so the lender's updates are read one
|
|
19452
|
+
* tag past the window (`$userSharesToEpoch`), where the subgraph puts it.
|
|
19453
|
+
* Every share exit between clearings is read too (`trancheSharesAtInterest`
|
|
19454
|
+
* rebuilds the tranche total from the previous clearing's snapshot).
|
|
19207
19455
|
*/
|
|
19208
19456
|
const yieldHistoryPageQuery = gql `
|
|
19209
19457
|
query YieldHistoryPage(
|
|
19458
|
+
$pools: [String!]!
|
|
19210
19459
|
$tranches: [String!]!
|
|
19211
19460
|
$userTranches: [String!]!
|
|
19212
19461
|
$locks: [String!]!
|
|
19213
19462
|
$fromEpoch: BigInt!
|
|
19214
19463
|
$toEpoch: BigInt!
|
|
19464
|
+
$userSharesToEpoch: BigInt!
|
|
19215
19465
|
$interestCursor: ID!
|
|
19216
19466
|
$trancheSharesCursor: ID!
|
|
19217
19467
|
$userSharesCursor: ID!
|
|
19218
19468
|
$lockSharesCursor: ID!
|
|
19469
|
+
$clearingsCursor: ID!
|
|
19470
|
+
$withdrawalsCursor: ID!
|
|
19219
19471
|
$withInterest: Boolean!
|
|
19220
19472
|
$withTrancheShares: Boolean!
|
|
19221
19473
|
$withUserShares: Boolean!
|
|
19222
19474
|
$withLockShares: Boolean!
|
|
19475
|
+
$withClearings: Boolean!
|
|
19476
|
+
$withWithdrawals: Boolean!
|
|
19223
19477
|
$first: Int!
|
|
19224
19478
|
) {
|
|
19225
19479
|
interest: lendingPoolTrancheEpochInterests(
|
|
@@ -19254,6 +19508,7 @@ const yieldHistoryPageQuery = gql `
|
|
|
19254
19508
|
epochId
|
|
19255
19509
|
shareUpdatesIndex
|
|
19256
19510
|
shares
|
|
19511
|
+
timestamp
|
|
19257
19512
|
lendingPoolTranche {
|
|
19258
19513
|
id
|
|
19259
19514
|
}
|
|
@@ -19265,13 +19520,14 @@ const yieldHistoryPageQuery = gql `
|
|
|
19265
19520
|
where: {
|
|
19266
19521
|
id_gt: $userSharesCursor
|
|
19267
19522
|
lendingPoolTrancheUserDetails_in: $userTranches
|
|
19268
|
-
epochId_lte: $
|
|
19523
|
+
epochId_lte: $userSharesToEpoch
|
|
19269
19524
|
}
|
|
19270
19525
|
) @include(if: $withUserShares) {
|
|
19271
19526
|
id
|
|
19272
19527
|
epochId
|
|
19273
19528
|
shareUpdatesIndex
|
|
19274
19529
|
shares
|
|
19530
|
+
timestamp
|
|
19275
19531
|
lendingPoolTrancheUserDetails {
|
|
19276
19532
|
id
|
|
19277
19533
|
}
|
|
@@ -19294,10 +19550,49 @@ const yieldHistoryPageQuery = gql `
|
|
|
19294
19550
|
id
|
|
19295
19551
|
}
|
|
19296
19552
|
}
|
|
19553
|
+
clearings: lendingPoolClearings(
|
|
19554
|
+
first: $first
|
|
19555
|
+
orderBy: id
|
|
19556
|
+
orderDirection: asc
|
|
19557
|
+
where: {
|
|
19558
|
+
id_gt: $clearingsCursor
|
|
19559
|
+
lendingPool_in: $pools
|
|
19560
|
+
epochId_gte: $fromEpoch
|
|
19561
|
+
epochId_lte: $toEpoch
|
|
19562
|
+
}
|
|
19563
|
+
) @include(if: $withClearings) {
|
|
19564
|
+
id
|
|
19565
|
+
epochId
|
|
19566
|
+
startTimestamp
|
|
19567
|
+
lendingPool {
|
|
19568
|
+
id
|
|
19569
|
+
}
|
|
19570
|
+
}
|
|
19571
|
+
withdrawals: userRequestEvents(
|
|
19572
|
+
first: $first
|
|
19573
|
+
orderBy: id
|
|
19574
|
+
orderDirection: asc
|
|
19575
|
+
where: {
|
|
19576
|
+
id_gt: $withdrawalsCursor
|
|
19577
|
+
type_in: [WithdrawalAccepted, ImmediateWithdrawalExecuted]
|
|
19578
|
+
tranche_in: $tranches
|
|
19579
|
+
epochId_gte: $fromEpoch
|
|
19580
|
+
epochId_lte: $toEpoch
|
|
19581
|
+
}
|
|
19582
|
+
) @include(if: $withWithdrawals) {
|
|
19583
|
+
id
|
|
19584
|
+
type
|
|
19585
|
+
epochId
|
|
19586
|
+
createdOn
|
|
19587
|
+
sharesAmount
|
|
19588
|
+
tranche {
|
|
19589
|
+
id
|
|
19590
|
+
}
|
|
19591
|
+
}
|
|
19297
19592
|
}
|
|
19298
19593
|
`;
|
|
19299
19594
|
/**
|
|
19300
|
-
* Fetch the
|
|
19595
|
+
* Fetch the six series for the window, paginating each by `id` until a short
|
|
19301
19596
|
* page. Returns the rows and how many requests it took.
|
|
19302
19597
|
*/
|
|
19303
19598
|
function fetchYieldHistorySeries(request, ids, window) {
|
|
@@ -19308,6 +19603,8 @@ function fetchYieldHistorySeries(request, ids, window) {
|
|
|
19308
19603
|
trancheShares: [],
|
|
19309
19604
|
userShares: [],
|
|
19310
19605
|
lockShares: [],
|
|
19606
|
+
clearings: [],
|
|
19607
|
+
withdrawals: [],
|
|
19311
19608
|
};
|
|
19312
19609
|
const series = [
|
|
19313
19610
|
{ key: 'interest', flag: 'withInterest', cursor: 'interestCursor' },
|
|
@@ -19326,18 +19623,32 @@ function fetchYieldHistorySeries(request, ids, window) {
|
|
|
19326
19623
|
flag: 'withLockShares',
|
|
19327
19624
|
cursor: 'lockSharesCursor',
|
|
19328
19625
|
},
|
|
19626
|
+
{
|
|
19627
|
+
key: 'clearings',
|
|
19628
|
+
flag: 'withClearings',
|
|
19629
|
+
cursor: 'clearingsCursor',
|
|
19630
|
+
},
|
|
19631
|
+
{
|
|
19632
|
+
key: 'withdrawals',
|
|
19633
|
+
flag: 'withWithdrawals',
|
|
19634
|
+
cursor: 'withdrawalsCursor',
|
|
19635
|
+
},
|
|
19329
19636
|
];
|
|
19330
19637
|
const cursors = {
|
|
19331
19638
|
interest: '',
|
|
19332
19639
|
trancheShares: '',
|
|
19333
19640
|
userShares: '',
|
|
19334
19641
|
lockShares: '',
|
|
19642
|
+
clearings: '',
|
|
19643
|
+
withdrawals: '',
|
|
19335
19644
|
};
|
|
19336
19645
|
const open = {
|
|
19337
19646
|
interest: ids.tranches.length > 0,
|
|
19338
19647
|
trancheShares: ids.tranches.length > 0,
|
|
19339
19648
|
userShares: ids.userTranches.length > 0,
|
|
19340
19649
|
lockShares: ids.locks.length > 0,
|
|
19650
|
+
clearings: ids.pools.length > 0,
|
|
19651
|
+
withdrawals: ids.tranches.length > 0,
|
|
19341
19652
|
};
|
|
19342
19653
|
let requests = 0;
|
|
19343
19654
|
while (series.some(({ key }) => open[key])) {
|
|
@@ -19345,11 +19656,15 @@ function fetchYieldHistorySeries(request, ids, window) {
|
|
|
19345
19656
|
throw new Error(`getYieldHistory: more than ${String(YIELD_HISTORY_MAX_PAGES)} pages for one lender`);
|
|
19346
19657
|
}
|
|
19347
19658
|
const variables = {
|
|
19659
|
+
pools: ids.pools,
|
|
19348
19660
|
tranches: ids.tranches,
|
|
19349
19661
|
userTranches: ids.userTranches,
|
|
19350
19662
|
locks: ids.locks,
|
|
19351
19663
|
fromEpoch: String(window.fromEpoch),
|
|
19352
19664
|
toEpoch: String(window.toEpoch),
|
|
19665
|
+
// One tag further for the lender: a withdrawal accepted between
|
|
19666
|
+
// clearings is tagged with the epoch AFTER the one it counts in.
|
|
19667
|
+
userSharesToEpoch: String(window.toEpoch + 1),
|
|
19353
19668
|
first: YIELD_HISTORY_PAGE_SIZE,
|
|
19354
19669
|
};
|
|
19355
19670
|
for (const { key, flag, cursor } of series) {
|
|
@@ -19394,6 +19709,144 @@ function sharesAsOf(updates, epoch) {
|
|
|
19394
19709
|
}
|
|
19395
19710
|
return found;
|
|
19396
19711
|
}
|
|
19712
|
+
/**
|
|
19713
|
+
* The snapshot in force when the clearing of `epoch` APPLIED that epoch's
|
|
19714
|
+
* interest — the shares the interest was actually spread over.
|
|
19715
|
+
*
|
|
19716
|
+
* A clearing applies interest FIRST (`ClearingCoordinator.doClearing`: the
|
|
19717
|
+
* `applyInterests` call before steps 1–5), then accepts deposits and
|
|
19718
|
+
* withdrawals. So an update is in force for epoch E's interest when it is
|
|
19719
|
+
* tagged `≤ E` (the subgraph tags every update written during clearing E, or
|
|
19720
|
+
* after it, `E + 1` or later), OR when it was written before clearing E began
|
|
19721
|
+
* (`timestamp < clearingStart`). The second test is the one that matters: a
|
|
19722
|
+
* withdrawal the pool manager accepts BETWEEN clearings
|
|
19723
|
+
* (`forceAcceptWithdrawalRequest`) is tagged `E + 1` by the subgraph, as if a
|
|
19724
|
+
* clearing had accepted it, yet the shares were gone before clearing E.
|
|
19725
|
+
*
|
|
19726
|
+
* Without a clearing start (none recorded) it is `sharesAsOf` — the tag alone.
|
|
19727
|
+
*/
|
|
19728
|
+
function sharesAtInterest(updates, epoch, clearingStart) {
|
|
19729
|
+
let found;
|
|
19730
|
+
for (const update of updates) {
|
|
19731
|
+
const inForce = Number(update.epochId) <= epoch ||
|
|
19732
|
+
(clearingStart !== undefined &&
|
|
19733
|
+
Number(update.timestamp) < clearingStart);
|
|
19734
|
+
if (!inForce)
|
|
19735
|
+
continue;
|
|
19736
|
+
if (!found || update.shareUpdatesIndex > found.shareUpdatesIndex) {
|
|
19737
|
+
found = update;
|
|
19738
|
+
}
|
|
19739
|
+
}
|
|
19740
|
+
return found;
|
|
19741
|
+
}
|
|
19742
|
+
/**
|
|
19743
|
+
* The tranche's total shares when the clearing of `epoch` applied its
|
|
19744
|
+
* interest.
|
|
19745
|
+
*
|
|
19746
|
+
* The subgraph writes a tranche snapshot when a clearing ENDS (tagged with
|
|
19747
|
+
* the next epoch) and at each immediate withdrawal, but none when the manager
|
|
19748
|
+
* accepts a withdrawal between clearings — so the newest snapshot can predate
|
|
19749
|
+
* shares that had already left. Instead of guessing the order of events in a
|
|
19750
|
+
* block, the total is rebuilt from the one snapshot whose place is certain:
|
|
19751
|
+
* the FIRST one tagged `epoch`, written when clearing `epoch − 1` ended (the
|
|
19752
|
+
* tag itself starts there). Every share exit between that and clearing
|
|
19753
|
+
* `epoch` is tagged `epoch` (the pool's clearing epoch at the time), and none
|
|
19754
|
+
* can happen during a clearing (`notPendingClearing`,
|
|
19755
|
+
* `verifyClearingNotPending`), while deposits and top-ups only happen inside
|
|
19756
|
+
* one. So: that snapshot less every exit tagged `epoch` before the clearing's
|
|
19757
|
+
* start (the clearing's own acceptances come at or after it).
|
|
19758
|
+
*
|
|
19759
|
+
* Without a clearing start, or without a snapshot tagged `epoch` (a tranche's
|
|
19760
|
+
* first clearing), it is the snapshot in force by tag alone.
|
|
19761
|
+
*/
|
|
19762
|
+
function trancheSharesAtInterest(snapshots, exits, epoch, clearingStart) {
|
|
19763
|
+
var _a, _b, _c;
|
|
19764
|
+
let base;
|
|
19765
|
+
if (clearingStart !== undefined) {
|
|
19766
|
+
for (const snapshot of snapshots) {
|
|
19767
|
+
if (Number(snapshot.epochId) !== epoch)
|
|
19768
|
+
continue;
|
|
19769
|
+
if (!base || snapshot.shareUpdatesIndex < base.shareUpdatesIndex) {
|
|
19770
|
+
base = snapshot;
|
|
19771
|
+
}
|
|
19772
|
+
}
|
|
19773
|
+
}
|
|
19774
|
+
if (clearingStart === undefined || !base) {
|
|
19775
|
+
return parseFloat((_b = (_a = sharesAsOf(snapshots, epoch)) === null || _a === void 0 ? void 0 : _a.shares) !== null && _b !== void 0 ? _b : '0');
|
|
19776
|
+
}
|
|
19777
|
+
let shares = parseFloat(base.shares);
|
|
19778
|
+
for (const exit of exits) {
|
|
19779
|
+
if (Number(exit.epochId) === epoch &&
|
|
19780
|
+
Number(exit.createdOn) < clearingStart) {
|
|
19781
|
+
shares -= parseFloat((_c = exit.sharesAmount) !== null && _c !== void 0 ? _c : '0');
|
|
19782
|
+
}
|
|
19783
|
+
}
|
|
19784
|
+
return shares;
|
|
19785
|
+
}
|
|
19786
|
+
/**
|
|
19787
|
+
* THE per-position, per-epoch selection both `getYieldHistory` and
|
|
19788
|
+
* `getPortfolioLendingData` run: the shares in force when clearing `epoch`
|
|
19789
|
+
* applied its interest (`sharesAtInterest`, `trancheSharesAtInterest`), each
|
|
19790
|
+
* lock's snapshots as of `epoch` and `epoch − 1`, then `epochTrancheYield`.
|
|
19791
|
+
*/
|
|
19792
|
+
function positionEpochYield(series, epoch, epochInterest, clearingStart) {
|
|
19793
|
+
var _a;
|
|
19794
|
+
const userSnapshot = sharesAtInterest(series.userUpdates, epoch, clearingStart);
|
|
19795
|
+
const userShares = parseFloat((_a = userSnapshot === null || userSnapshot === void 0 ? void 0 : userSnapshot.shares) !== null && _a !== void 0 ? _a : '0');
|
|
19796
|
+
const locks = series.locks.map((lock) => {
|
|
19797
|
+
var _a, _b, _c, _d;
|
|
19798
|
+
return ({
|
|
19799
|
+
active: parseFloat(lock.epochLockStart) < epoch &&
|
|
19800
|
+
parseFloat(lock.epochLockEnd) >= epoch &&
|
|
19801
|
+
userSnapshot !== undefined,
|
|
19802
|
+
// No snapshot yet = the lock's opening shares: a lock made after
|
|
19803
|
+
// clearing E starts at E but its first update is tagged E + 1, and
|
|
19804
|
+
// reading that gap as 0 would book its principal as a top-up.
|
|
19805
|
+
sharesAtEpoch: parseFloat((_b = (_a = sharesAsOf(lock.updates, epoch)) === null || _a === void 0 ? void 0 : _a.shares) !== null && _b !== void 0 ? _b : lock.initialTrancheShares),
|
|
19806
|
+
sharesBeforeEpoch: parseFloat((_d = (_c = sharesAsOf(lock.updates, epoch - 1)) === null || _c === void 0 ? void 0 : _c.shares) !== null && _d !== void 0 ? _d : lock.initialTrancheShares),
|
|
19807
|
+
});
|
|
19808
|
+
});
|
|
19809
|
+
return {
|
|
19810
|
+
yield: epochTrancheYield({
|
|
19811
|
+
epochInterest,
|
|
19812
|
+
userShares,
|
|
19813
|
+
trancheShares: trancheSharesAtInterest(series.trancheUpdates, series.exits, epoch, clearingStart),
|
|
19814
|
+
trancheBalanceNow: series.trancheBalanceNow,
|
|
19815
|
+
trancheSharesNow: series.trancheSharesNow,
|
|
19816
|
+
locks,
|
|
19817
|
+
}),
|
|
19818
|
+
userShares,
|
|
19819
|
+
};
|
|
19820
|
+
}
|
|
19821
|
+
/** A position's `PositionSeries` out of the fetched history series. */
|
|
19822
|
+
function positionSeriesFrom(rows, position) {
|
|
19823
|
+
const trancheId = position.tranche.id;
|
|
19824
|
+
return {
|
|
19825
|
+
trancheBalanceNow: parseFloat(position.tranche.balance),
|
|
19826
|
+
trancheSharesNow: parseFloat(position.tranche.shares),
|
|
19827
|
+
userUpdates: rows.userShares.filter((row) => row.lendingPoolTrancheUserDetails.id === position.id),
|
|
19828
|
+
trancheUpdates: rows.trancheShares.filter((row) => row.lendingPoolTranche.id === trancheId),
|
|
19829
|
+
exits: rows.withdrawals.filter((row) => row.tranche.id === trancheId),
|
|
19830
|
+
locks: position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => (Object.assign(Object.assign({}, lock), { updates: rows.lockShares.filter((row) => row.userLendingPoolTrancheFixedTermDepositLock.id ===
|
|
19831
|
+
lock.id) }))),
|
|
19832
|
+
};
|
|
19833
|
+
}
|
|
19834
|
+
/** `pool → epoch → clearing start`, from the clearing rows. */
|
|
19835
|
+
function clearingStarts(clearings) {
|
|
19836
|
+
var _a;
|
|
19837
|
+
const starts = new Map();
|
|
19838
|
+
for (const clearing of clearings) {
|
|
19839
|
+
const start = Number(clearing.startTimestamp);
|
|
19840
|
+
// A clearing not yet started carries 0: no start to pair by.
|
|
19841
|
+
if (!(start > 0))
|
|
19842
|
+
continue;
|
|
19843
|
+
const pool = clearing.lendingPool.id.toLowerCase();
|
|
19844
|
+
const byEpoch = (_a = starts.get(pool)) !== null && _a !== void 0 ? _a : new Map();
|
|
19845
|
+
byEpoch.set(Number(clearing.epochId), start);
|
|
19846
|
+
starts.set(pool, byEpoch);
|
|
19847
|
+
}
|
|
19848
|
+
return starts;
|
|
19849
|
+
}
|
|
19397
19850
|
function groupBy(rows, key) {
|
|
19398
19851
|
const map = new Map();
|
|
19399
19852
|
for (const row of rows) {
|
|
@@ -19410,12 +19863,13 @@ function groupBy(rows, key) {
|
|
|
19410
19863
|
* Pure: the fetched series → one entry per pool, tranche and settled epoch in
|
|
19411
19864
|
* which the lender held shares (or a lock earned a top-up). Each entry runs the
|
|
19412
19865
|
* same `epochTrancheYield` as the portfolio's last-epoch figure, with the same
|
|
19413
|
-
* share selection, so the
|
|
19866
|
+
* share selection (`sharesAtInterest`, `trancheSharesAtInterest`), so the
|
|
19867
|
+
* newest entry equals that figure.
|
|
19414
19868
|
*
|
|
19415
19869
|
* Sorted by `epochId`, then `poolId`, then `trancheId`.
|
|
19416
19870
|
*/
|
|
19417
19871
|
function buildYieldHistory(read, window, clock) {
|
|
19418
|
-
var _a, _b, _c, _d
|
|
19872
|
+
var _a, _b, _c, _d;
|
|
19419
19873
|
const user = read.positions.user;
|
|
19420
19874
|
if (!user)
|
|
19421
19875
|
return [];
|
|
@@ -19423,45 +19877,36 @@ function buildYieldHistory(read, window, clock) {
|
|
|
19423
19877
|
const trancheSharesByTranche = groupBy(read.trancheShares, (row) => row.lendingPoolTranche.id);
|
|
19424
19878
|
const userSharesByPosition = groupBy(read.userShares, (row) => row.lendingPoolTrancheUserDetails.id);
|
|
19425
19879
|
const lockSharesByLock = groupBy(read.lockShares, (row) => row.userLendingPoolTrancheFixedTermDepositLock.id);
|
|
19880
|
+
const withdrawalsByTranche = groupBy(read.withdrawals, (row) => row.tranche.id);
|
|
19881
|
+
const starts = clearingStarts(read.clearings);
|
|
19426
19882
|
const entries = [];
|
|
19427
19883
|
for (const pool of user.lendingPoolUserDetails) {
|
|
19884
|
+
const poolStarts = starts.get(pool.lendingPool.id.toLowerCase());
|
|
19428
19885
|
for (const position of pool.lendingPoolTrancheUserDetails) {
|
|
19429
19886
|
const trancheId = position.tranche.id;
|
|
19430
19887
|
const trancheUpdates = (_a = trancheSharesByTranche.get(trancheId)) !== null && _a !== void 0 ? _a : [];
|
|
19431
19888
|
const userUpdates = (_b = userSharesByPosition.get(position.id)) !== null && _b !== void 0 ? _b : [];
|
|
19889
|
+
const trancheWithdrawals = (_c = withdrawalsByTranche.get(trancheId)) !== null && _c !== void 0 ? _c : [];
|
|
19432
19890
|
const trancheBalanceNow = parseFloat(position.tranche.balance);
|
|
19433
19891
|
const trancheSharesNow = parseFloat(position.tranche.shares);
|
|
19434
|
-
for (const record of (
|
|
19892
|
+
for (const record of (_d = interestByTranche.get(trancheId)) !== null && _d !== void 0 ? _d : []) {
|
|
19435
19893
|
const epoch = Number(record.epochId);
|
|
19436
19894
|
if (epoch < window.fromEpoch || epoch > window.toEpoch) {
|
|
19437
19895
|
continue;
|
|
19438
19896
|
}
|
|
19439
|
-
const
|
|
19440
|
-
const
|
|
19441
|
-
const locks = position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => {
|
|
19442
|
-
var _a, _b, _c, _d, _e;
|
|
19443
|
-
const lockUpdates = (_a = lockSharesByLock.get(lock.id)) !== null && _a !== void 0 ? _a : [];
|
|
19444
|
-
return {
|
|
19445
|
-
active: parseFloat(lock.epochLockStart) < epoch &&
|
|
19446
|
-
parseFloat(lock.epochLockEnd) >= epoch &&
|
|
19447
|
-
userSnapshot !== undefined,
|
|
19448
|
-
// No snapshot yet = the lock's opening
|
|
19449
|
-
// shares: a lock made after clearing E
|
|
19450
|
-
// starts at E but its first update is
|
|
19451
|
-
// tagged E + 1, and reading that gap as 0
|
|
19452
|
-
// would book its principal as a top-up.
|
|
19453
|
-
sharesAtEpoch: parseFloat((_c = (_b = sharesAsOf(lockUpdates, epoch)) === null || _b === void 0 ? void 0 : _b.shares) !== null && _c !== void 0 ? _c : lock.initialTrancheShares),
|
|
19454
|
-
sharesBeforeEpoch: parseFloat((_e = (_d = sharesAsOf(lockUpdates, epoch - 1)) === null || _d === void 0 ? void 0 : _d.shares) !== null && _e !== void 0 ? _e : lock.initialTrancheShares),
|
|
19455
|
-
};
|
|
19456
|
-
});
|
|
19457
|
-
const { total } = epochTrancheYield({
|
|
19458
|
-
epochInterest: parseFloat(record.epochInterestAmount),
|
|
19459
|
-
userShares,
|
|
19460
|
-
trancheShares: parseFloat((_f = (_e = sharesAsOf(trancheUpdates, epoch)) === null || _e === void 0 ? void 0 : _e.shares) !== null && _f !== void 0 ? _f : '0'),
|
|
19897
|
+
const clearingStart = poolStarts === null || poolStarts === void 0 ? void 0 : poolStarts.get(epoch);
|
|
19898
|
+
const { yield: epochYield, userShares } = positionEpochYield({
|
|
19461
19899
|
trancheBalanceNow,
|
|
19462
19900
|
trancheSharesNow,
|
|
19463
|
-
|
|
19464
|
-
|
|
19901
|
+
userUpdates,
|
|
19902
|
+
trancheUpdates,
|
|
19903
|
+
exits: trancheWithdrawals,
|
|
19904
|
+
locks: position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => {
|
|
19905
|
+
var _a;
|
|
19906
|
+
return (Object.assign(Object.assign({}, lock), { updates: (_a = lockSharesByLock.get(lock.id)) !== null && _a !== void 0 ? _a : [] }));
|
|
19907
|
+
}),
|
|
19908
|
+
}, epoch, parseFloat(record.epochInterestAmount), clearingStart);
|
|
19909
|
+
const total = epochYield.total;
|
|
19465
19910
|
// Nothing held and nothing topped up: not part of this
|
|
19466
19911
|
// lender's history (a new lender's history is empty).
|
|
19467
19912
|
if (userShares <= 0 && total === 0)
|
|
@@ -19482,6 +19927,57 @@ function buildYieldHistory(read, window, clock) {
|
|
|
19482
19927
|
a.trancheId.localeCompare(b.trancheId));
|
|
19483
19928
|
}
|
|
19484
19929
|
|
|
19930
|
+
/**
|
|
19931
|
+
* How many epochs back the portfolio read pairs a tranche's newest interest
|
|
19932
|
+
* with the shares in force at its clearing (`lendingPortfolioQuery`): the last
|
|
19933
|
+
* six settled epochs, so a pool whose clearings run late or lag a few weeks
|
|
19934
|
+
* behind the others (Base has one) is paired too. A pool whose newest
|
|
19935
|
+
* interest is older (pools clear independently; some only when the
|
|
19936
|
+
* originator repays) is priced from a history read of its own, at that
|
|
19937
|
+
* epoch. The extra rows are a few per lender and tranche.
|
|
19938
|
+
*/
|
|
19939
|
+
const RECENT_PAIRING_EPOCHS = 6;
|
|
19940
|
+
/**
|
|
19941
|
+
* The ledger (subgraph) and the chain agree on a balance AT THE SAME BLOCK
|
|
19942
|
+
* within a cent, or a millionth of it — the rounding of two share-price
|
|
19943
|
+
* conversions.
|
|
19944
|
+
*/
|
|
19945
|
+
const BALANCE_RECONCILE_TOLERANCE = 0.01;
|
|
19946
|
+
const BALANCE_RECONCILE_RELATIVE = 1e-6;
|
|
19947
|
+
function ledgerAgrees(ledger, chain) {
|
|
19948
|
+
return (Math.abs(ledger - chain) <=
|
|
19949
|
+
Math.max(BALANCE_RECONCILE_TOLERANCE, Math.abs(chain) * BALANCE_RECONCILE_RELATIVE));
|
|
19950
|
+
}
|
|
19951
|
+
/**
|
|
19952
|
+
* A list read with `first: $first` that comes back FULL may have been cut:
|
|
19953
|
+
* refuse it rather than price from a truncated read.
|
|
19954
|
+
*/
|
|
19955
|
+
function refuseTruncated(data) {
|
|
19956
|
+
var _a, _b;
|
|
19957
|
+
const full = (rows) => { var _a; return ((_a = rows === null || rows === void 0 ? void 0 : rows.length) !== null && _a !== void 0 ? _a : 0) >= YIELD_HISTORY_PAGE_SIZE; };
|
|
19958
|
+
const lists = [
|
|
19959
|
+
['lendingPoolClearings', full(data.lendingPoolClearings)],
|
|
19960
|
+
['recentWithdrawalsAccepted', full(data.recentWithdrawalsAccepted)],
|
|
19961
|
+
];
|
|
19962
|
+
for (const pool of (_b = (_a = data.user) === null || _a === void 0 ? void 0 : _a.lendingPoolUserDetails) !== null && _b !== void 0 ? _b : []) {
|
|
19963
|
+
for (const position of pool.lendingPoolTrancheUserDetails) {
|
|
19964
|
+
lists.push([
|
|
19965
|
+
'recentUserShareUpdates',
|
|
19966
|
+
full(position.recentUserShareUpdates),
|
|
19967
|
+
], [
|
|
19968
|
+
'recentTrancheShareUpdates',
|
|
19969
|
+
full(position.tranche.recentTrancheShareUpdates),
|
|
19970
|
+
], ...position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => [
|
|
19971
|
+
'lockSharesRecent',
|
|
19972
|
+
full(lock.lockSharesRecent),
|
|
19973
|
+
]));
|
|
19974
|
+
}
|
|
19975
|
+
}
|
|
19976
|
+
const cut = lists.find(([, isFull]) => isFull);
|
|
19977
|
+
if (cut) {
|
|
19978
|
+
throw new Error(`getPortfolioLendingData: ${cut[0]} reached ${String(YIELD_HISTORY_PAGE_SIZE)} rows; refusing a possibly truncated read`);
|
|
19979
|
+
}
|
|
19980
|
+
}
|
|
19485
19981
|
class Portfolio {
|
|
19486
19982
|
constructor(_kasuConfig, signerOrProvider) {
|
|
19487
19983
|
this._kasuConfig = _kasuConfig;
|
|
@@ -19699,23 +20195,52 @@ class Portfolio {
|
|
|
19699
20195
|
}
|
|
19700
20196
|
getPortfolioLendingData(userAddress, poolOverviews, currentEpoch, provider) {
|
|
19701
20197
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19702
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
20198
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
19703
20199
|
const SECONDS_PER_EPOCH = 604800; // seconds in a week
|
|
19704
20200
|
const portfolioLendingPoolsPromise = [];
|
|
19705
20201
|
const previousEpoch = BigNumber.from(currentEpoch).sub(BigNumber.from(1));
|
|
19706
|
-
const
|
|
19707
|
-
|
|
19708
|
-
|
|
19709
|
-
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
this.
|
|
19716
|
-
|
|
20202
|
+
const recentEpoch = Math.max(0, previousEpoch.toNumber() - (RECENT_PAIRING_EPOCHS - 1));
|
|
20203
|
+
const unused = new Set(this._kasuConfig.UNUSED_LENDING_POOL_IDS.map((id) => id.toLowerCase()));
|
|
20204
|
+
const listedPools = poolOverviews.filter(({ id }) => !unused.has(id.toLowerCase()));
|
|
20205
|
+
const lastEpochData = yield this._graph.request(lendingPortfolioQuery, {
|
|
20206
|
+
userAddress: userAddress.toLowerCase(),
|
|
20207
|
+
epochId: parseFloat(currentEpoch),
|
|
20208
|
+
lastEpochId: previousEpoch.toNumber(),
|
|
20209
|
+
recentEpoch,
|
|
20210
|
+
lockRecentEpoch: Math.max(0, recentEpoch - 1),
|
|
20211
|
+
unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
|
|
20212
|
+
poolIds: listedPools.map(({ id }) => id.toLowerCase()),
|
|
20213
|
+
trancheIds: listedPools.flatMap(({ tranches }) => tranches.map(({ id }) => id.toLowerCase())),
|
|
20214
|
+
first: YIELD_HISTORY_PAGE_SIZE,
|
|
20215
|
+
});
|
|
19717
20216
|
if (!lastEpochData.user)
|
|
19718
20217
|
return [];
|
|
20218
|
+
refuseTruncated(lastEpochData);
|
|
20219
|
+
// The pools the lender has a ledger in AND that are listed: the only
|
|
20220
|
+
// ones read on chain, and the only ones reported.
|
|
20221
|
+
const userPools = listedPools.flatMap((overview) => {
|
|
20222
|
+
var _a;
|
|
20223
|
+
const details = (_a = lastEpochData.user) === null || _a === void 0 ? void 0 : _a.lendingPoolUserDetails.find(({ lendingPool }) => lendingPool.id.toLowerCase() === overview.id.toLowerCase());
|
|
20224
|
+
return details ? [{ overview, details }] : [];
|
|
20225
|
+
});
|
|
20226
|
+
const recentStarts = clearingStarts(lastEpochData.lendingPoolClearings);
|
|
20227
|
+
const recentExits = new Map();
|
|
20228
|
+
for (const exit of lastEpochData.recentWithdrawalsAccepted) {
|
|
20229
|
+
const list = (_a = recentExits.get(exit.tranche.id)) !== null && _a !== void 0 ? _a : [];
|
|
20230
|
+
list.push(exit);
|
|
20231
|
+
recentExits.set(exit.tranche.id, list);
|
|
20232
|
+
}
|
|
20233
|
+
const [chain, staleYields] = yield Promise.all([
|
|
20234
|
+
this.readChainAt((_b = lastEpochData._meta) === null || _b === void 0 ? void 0 : _b.block.number, (blockTag) => this._userLendingService.getUserPoolBalancesAt(userAddress, userPools.map(({ overview }) => overview.id), provider, blockTag)),
|
|
20235
|
+
this.staleLastEpochYields(userPools.flatMap(({ overview, details }) => details.lendingPoolTrancheUserDetails.map((position) => ({
|
|
20236
|
+
poolId: overview.id,
|
|
20237
|
+
position,
|
|
20238
|
+
}))), recentEpoch),
|
|
20239
|
+
]);
|
|
20240
|
+
const reconciled = yield Promise.all(userPools.map(({ overview, details }, index) => {
|
|
20241
|
+
var _a;
|
|
20242
|
+
return this.reconcilePool(userAddress, overview, details, (_a = chain.values[index]) !== null && _a !== void 0 ? _a : BigNumber.from(0), chain.blockTag, provider);
|
|
20243
|
+
}));
|
|
19719
20244
|
const userRequestsMap = new Map();
|
|
19720
20245
|
for (const userRequest of lastEpochData.userRequests) {
|
|
19721
20246
|
const trancheId = userRequest.tranche.id;
|
|
@@ -19741,28 +20266,22 @@ class Portfolio {
|
|
|
19741
20266
|
continue;
|
|
19742
20267
|
}
|
|
19743
20268
|
userRequestsMap.set(trancheId, Object.assign(Object.assign({}, mappedUserRequest), { [ftdId]: [
|
|
19744
|
-
...((
|
|
20269
|
+
...((_c = mappedUserRequest[ftdId]) !== null && _c !== void 0 ? _c : []),
|
|
19745
20270
|
userRequestFtdItem,
|
|
19746
20271
|
] }));
|
|
19747
20272
|
}
|
|
19748
20273
|
}
|
|
19749
|
-
|
|
19750
|
-
|
|
19751
|
-
const userPoolBalance = userPoolBalances.find(({ poolId }) => poolId === poolOverview.id);
|
|
19752
|
-
if (!userPoolBalance) {
|
|
19753
|
-
continue;
|
|
19754
|
-
}
|
|
19755
|
-
totalInvestments = userPoolBalance.balance.add(totalInvestments);
|
|
20274
|
+
for (const [poolIndex, { overview: poolOverview, details },] of userPools.entries()) {
|
|
20275
|
+
const pool = reconciled[poolIndex];
|
|
19756
20276
|
const tranches = [];
|
|
19757
20277
|
let poolYieldEarnedLastEpoch = 0;
|
|
19758
|
-
|
|
19759
|
-
|
|
19760
|
-
|
|
19761
|
-
const portfolioUserTrancheBalance = portfolioUserTrancheBalances.get(poolOverview.id);
|
|
20278
|
+
// A ledger crediting shares the wallet does not hold earns
|
|
20279
|
+
// nothing we can vouch for: its last-cycle figures are withheld.
|
|
20280
|
+
const withheld = ((_d = pool.mismatch) === null || _d === void 0 ? void 0 : _d.kind) === 'ledger-exceeds-chain';
|
|
19762
20281
|
for (const tranche of poolOverview.tranches) {
|
|
19763
|
-
const lastEpochUserTrancheDetails =
|
|
20282
|
+
const lastEpochUserTrancheDetails = details.lendingPoolTrancheUserDetails.find((lendingPool) => lendingPool.tranche.id === tranche.id);
|
|
19764
20283
|
const userRequest = userRequestsMap.get(tranche.id);
|
|
19765
|
-
const depositDetails = (
|
|
20284
|
+
const depositDetails = (_e = userRequest === null || userRequest === void 0 ? void 0 : userRequest['0']) !== null && _e !== void 0 ? _e : [];
|
|
19766
20285
|
if (!lastEpochUserTrancheDetails) {
|
|
19767
20286
|
tranches.push(Object.assign(Object.assign({}, tranche), { investedAmount: {
|
|
19768
20287
|
balance: '0',
|
|
@@ -19773,55 +20292,61 @@ class Portfolio {
|
|
|
19773
20292
|
}, depositDetails, fixedLoans: [] }));
|
|
19774
20293
|
continue;
|
|
19775
20294
|
}
|
|
19776
|
-
|
|
19777
|
-
|
|
19778
|
-
|
|
20295
|
+
// The tranche's newest interest (epoch E), priced with the
|
|
20296
|
+
// shares in force when clearing E applied it — the one
|
|
20297
|
+
// selection `getYieldHistory` makes (`positionEpochYield`).
|
|
20298
|
+
// Inside the recent window the candidates below are complete.
|
|
20299
|
+
// An older E (a pool that clears rarely — some only when the
|
|
20300
|
+
// originator repays) is priced from a history read of its own,
|
|
20301
|
+
// and is 0 for a lender who has left the tranche.
|
|
20302
|
+
const newestInterest = (_f = lastEpochUserTrancheDetails.tranche
|
|
20303
|
+
.lendingPoolTrancheEpochInterest) === null || _f === void 0 ? void 0 : _f[0];
|
|
20304
|
+
const interestEpoch = (newestInterest === null || newestInterest === void 0 ? void 0 : newestInterest.epochId) === undefined
|
|
20305
|
+
? undefined
|
|
20306
|
+
: Number(newestInterest.epochId);
|
|
19779
20307
|
const fixedTermDeposits = lastEpochUserTrancheDetails.userLendingPoolTrancheFixedTermDepositLocks;
|
|
19780
|
-
|
|
19781
|
-
|
|
19782
|
-
|
|
19783
|
-
|
|
19784
|
-
epochInterest: parseFloat((_f = (_e = (_d = lastEpochUserTrancheDetails.tranche
|
|
19785
|
-
.lendingPoolTrancheEpochInterest) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.epochInterestAmount) !== null && _f !== void 0 ? _f : '0'),
|
|
19786
|
-
userShares: parseFloat((_j = (_h = (_g = lastEpochUserTrancheDetails
|
|
19787
|
-
.lendingPoolTrancheUserEpochSharesUpdates) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.shares) !== null && _j !== void 0 ? _j : '0'),
|
|
19788
|
-
trancheShares: parseFloat((_m = (_l = (_k = lastEpochUserTrancheDetails.tranche
|
|
19789
|
-
.lendingPoolTrancheShareUpdates) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.shares) !== null && _m !== void 0 ? _m : '0'),
|
|
19790
|
-
trancheBalanceNow: parseFloat(lastEpochUserTrancheDetails.tranche.balance),
|
|
19791
|
-
trancheSharesNow: parseFloat(lastEpochUserTrancheDetails.tranche.shares),
|
|
19792
|
-
locks: fixedTermDeposits.map((fixedTermDeposit) => {
|
|
19793
|
-
var _a, _b, _c, _d, _e, _f;
|
|
19794
|
-
return ({
|
|
19795
|
-
active: parseFloat(fixedTermDeposit.epochLockStart) <
|
|
19796
|
-
lastEpoch &&
|
|
19797
|
-
parseFloat(fixedTermDeposit.epochLockEnd) >=
|
|
19798
|
-
lastEpoch &&
|
|
19799
|
-
userHasLastEpochShares,
|
|
19800
|
-
// No snapshot = the lock's opening shares, exactly
|
|
19801
|
-
// as `getYieldHistory` reads it: a lock made after
|
|
19802
|
-
// clearing E starts at E with its first update
|
|
19803
|
-
// tagged E + 1. Never the CURRENT shares, which
|
|
19804
|
-
// would carry a top-up from a clearing that ran
|
|
19805
|
-
// after the last settled epoch.
|
|
19806
|
-
sharesAtEpoch: parseFloat((_c = (_b = (_a = fixedTermDeposit.lockSharesAtLastEpoch) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.shares) !== null && _c !== void 0 ? _c : fixedTermDeposit.initialTrancheShares),
|
|
19807
|
-
sharesBeforeEpoch: parseFloat((_f = (_e = (_d = fixedTermDeposit
|
|
19808
|
-
.userLendingPoolTrancheFixedTermDepositLockShareUpdate) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.shares) !== null && _f !== void 0 ? _f : fixedTermDeposit.initialTrancheShares),
|
|
19809
|
-
});
|
|
19810
|
-
}),
|
|
19811
|
-
});
|
|
19812
|
-
const userTrancheBalance = {
|
|
19813
|
-
balance: '0',
|
|
19814
|
-
yieldEarned: 0,
|
|
20308
|
+
const noYield = {
|
|
20309
|
+
total: 0,
|
|
20310
|
+
variable: 0,
|
|
20311
|
+
locks: fixedTermDeposits.map(() => 0),
|
|
19815
20312
|
};
|
|
19816
|
-
|
|
19817
|
-
|
|
19818
|
-
|
|
19819
|
-
|
|
19820
|
-
|
|
19821
|
-
|
|
19822
|
-
|
|
19823
|
-
|
|
20313
|
+
let lastEpochYield = noYield;
|
|
20314
|
+
if (interestEpoch !== undefined &&
|
|
20315
|
+
interestEpoch < recentEpoch &&
|
|
20316
|
+
!withheld) {
|
|
20317
|
+
lastEpochYield =
|
|
20318
|
+
(_g = staleYields.get(lastEpochUserTrancheDetails.id)) !== null && _g !== void 0 ? _g : noYield;
|
|
20319
|
+
}
|
|
20320
|
+
else if (interestEpoch !== undefined && !withheld) {
|
|
20321
|
+
lastEpochYield = positionEpochYield({
|
|
20322
|
+
trancheBalanceNow: parseFloat(lastEpochUserTrancheDetails.tranche.balance),
|
|
20323
|
+
trancheSharesNow: parseFloat(lastEpochUserTrancheDetails.tranche.shares),
|
|
20324
|
+
userUpdates: [
|
|
20325
|
+
...((_h = lastEpochUserTrancheDetails.lendingPoolTrancheUserEpochSharesUpdates) !== null && _h !== void 0 ? _h : []),
|
|
20326
|
+
...((_j = lastEpochUserTrancheDetails.recentUserShareUpdates) !== null && _j !== void 0 ? _j : []),
|
|
20327
|
+
],
|
|
20328
|
+
trancheUpdates: [
|
|
20329
|
+
...((_k = lastEpochUserTrancheDetails.tranche
|
|
20330
|
+
.lendingPoolTrancheShareUpdates) !== null && _k !== void 0 ? _k : []),
|
|
20331
|
+
...((_l = lastEpochUserTrancheDetails.tranche
|
|
20332
|
+
.recentTrancheShareUpdates) !== null && _l !== void 0 ? _l : []),
|
|
20333
|
+
],
|
|
20334
|
+
exits: (_m = recentExits.get(tranche.id)) !== null && _m !== void 0 ? _m : [],
|
|
20335
|
+
locks: fixedTermDeposits.map((lock) => {
|
|
20336
|
+
var _a, _b;
|
|
20337
|
+
return (Object.assign(Object.assign({}, lock), { updates: [
|
|
20338
|
+
...((_a = lock.lockSharesBase) !== null && _a !== void 0 ? _a : []),
|
|
20339
|
+
...((_b = lock.lockSharesRecent) !== null && _b !== void 0 ? _b : []),
|
|
20340
|
+
] }));
|
|
20341
|
+
}),
|
|
20342
|
+
}, interestEpoch, parseFloat((_o = newestInterest === null || newestInterest === void 0 ? void 0 : newestInterest.epochInterestAmount) !== null && _o !== void 0 ? _o : '0'), (_p = recentStarts
|
|
20343
|
+
.get(poolOverview.id.toLowerCase())) === null || _p === void 0 ? void 0 : _p.get(interestEpoch)).yield;
|
|
19824
20344
|
}
|
|
20345
|
+
const ledger = pool.tranches.get(tranche.id);
|
|
20346
|
+
const userTrancheBalance = {
|
|
20347
|
+
balance: (_q = ledger === null || ledger === void 0 ? void 0 : ledger.balance) !== null && _q !== void 0 ? _q : '0',
|
|
20348
|
+
yieldEarned: (_r = ledger === null || ledger === void 0 ? void 0 : ledger.yieldEarned) !== null && _r !== void 0 ? _r : 0,
|
|
20349
|
+
};
|
|
19825
20350
|
let totalLifetimeFtdYield = 0;
|
|
19826
20351
|
const fixedLoans = fixedTermDeposits.map((fixedTermDeposit, lockIndex) => {
|
|
19827
20352
|
var _a, _b;
|
|
@@ -19869,7 +20394,9 @@ class Portfolio {
|
|
|
19869
20394
|
}, fixedLoans,
|
|
19870
20395
|
depositDetails }));
|
|
19871
20396
|
}
|
|
19872
|
-
portfolioLendingPoolsPromise.push(Object.assign(Object.assign({}, poolOverview), { totalYieldEarningsLastEpoch: this.precisionToString(poolYieldEarnedLastEpoch), totalInvestedAmount:
|
|
20397
|
+
portfolioLendingPoolsPromise.push(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, poolOverview), { totalYieldEarningsLastEpoch: this.precisionToString(poolYieldEarnedLastEpoch), totalInvestedAmount: pool.chainBalance.toString(), totalYieldEarningsLifetime: pool.lifetime.toString() }), (pool.mismatch ? { ledgerMismatch: pool.mismatch } : {})), (chain.blockTag === undefined
|
|
20398
|
+
? { chainPinned: false }
|
|
20399
|
+
: {})), { tranches }));
|
|
19873
20400
|
}
|
|
19874
20401
|
const portfolioLendingPools = portfolioLendingPoolsPromise.map((pool) => (Object.assign(Object.assign({}, pool), { tranches: pool.tranches.map((tranche) => {
|
|
19875
20402
|
const trancheBalance = tranche.investedAmount;
|
|
@@ -19880,7 +20407,14 @@ class Portfolio {
|
|
|
19880
20407
|
}, BigNumber.from(0));
|
|
19881
20408
|
const totalTrancheYieldEarned = trancheBalance.yieldEarned.toFixed(6);
|
|
19882
20409
|
const totalTrancheFtdYieldEarned = parseFloat(tranche.yieldEarnings.lifetime).toFixed(6);
|
|
19883
|
-
|
|
20410
|
+
// Never negative: a variable balance below the locked
|
|
20411
|
+
// amount is a ledger the chain does not back (the pool
|
|
20412
|
+
// carries `ledgerMismatch`), not money owed — flagged.
|
|
20413
|
+
const variableBalance = parseEther(trancheBalance.balance).sub(lockedAmount);
|
|
20414
|
+
const floored = variableBalance.isNegative();
|
|
20415
|
+
return Object.assign(Object.assign(Object.assign(Object.assign({}, tranche), { investedAmount: formatEther(floored ? BigNumber.from(0) : variableBalance) }), (floored
|
|
20416
|
+
? { investedAmountFloored: true }
|
|
20417
|
+
: {})), { yieldEarnings: Object.assign(Object.assign({}, tranche.yieldEarnings), { lifetime: this.precisionToString(parseFloat(totalTrancheYieldEarned) -
|
|
19884
20418
|
parseFloat(totalTrancheFtdYieldEarned)) }) });
|
|
19885
20419
|
}) })));
|
|
19886
20420
|
return portfolioLendingPools.filter((pool) => !parseUnits(pool.totalInvestedAmount).isZero() ||
|
|
@@ -19906,7 +20440,12 @@ class Portfolio {
|
|
|
19906
20440
|
* Cost: three parallel `SystemVariables` reads and the positions query in
|
|
19907
20441
|
* one round, then one subgraph request per page of the longest series
|
|
19908
20442
|
* (1000 rows a page) — normally two subgraph round trips in all, never one
|
|
19909
|
-
* per epoch.
|
|
20443
|
+
* per epoch — alongside one `LendingPool.userBalance` call per pool at
|
|
20444
|
+
* the subgraph's block. A pool whose ledger credits more than the wallet
|
|
20445
|
+
* holds at that block (shares moved away outside a withdrawal) is left
|
|
20446
|
+
* out; if the node says it cannot serve that block, `latest` is read
|
|
20447
|
+
* and nothing is. Any other failure of those reads (a rate limit, a
|
|
20448
|
+
* network error) THROWS: the history needs a working RPC.
|
|
19910
20449
|
*
|
|
19911
20450
|
* On a LITE deployment, a subgraph that lacks the entities (a validation
|
|
19912
20451
|
* error naming them) yields `[]`; on a full deployment that error throws,
|
|
@@ -19917,6 +20456,7 @@ class Portfolio {
|
|
|
19917
20456
|
*/
|
|
19918
20457
|
getYieldHistory(userAddress_1) {
|
|
19919
20458
|
return __awaiter(this, arguments, void 0, function* (userAddress, options = {}) {
|
|
20459
|
+
var _a;
|
|
19920
20460
|
validateYieldHistoryOptions(options);
|
|
19921
20461
|
try {
|
|
19922
20462
|
const [currentEpoch, epochZeroStart, epochDuration, positions] = yield Promise.all([
|
|
@@ -19935,7 +20475,9 @@ class Portfolio {
|
|
|
19935
20475
|
const userTranches = [];
|
|
19936
20476
|
const tranches = new Set();
|
|
19937
20477
|
const locks = [];
|
|
20478
|
+
const pools = [];
|
|
19938
20479
|
for (const pool of positions.user.lendingPoolUserDetails) {
|
|
20480
|
+
pools.push(pool.lendingPool.id);
|
|
19939
20481
|
for (const position of pool.lendingPoolTrancheUserDetails) {
|
|
19940
20482
|
userTranches.push(position.id);
|
|
19941
20483
|
tranches.add(position.tranche.id);
|
|
@@ -19946,11 +20488,33 @@ class Portfolio {
|
|
|
19946
20488
|
}
|
|
19947
20489
|
if (userTranches.length === 0)
|
|
19948
20490
|
return [];
|
|
19949
|
-
const { rows } = yield
|
|
20491
|
+
const [{ rows }, chain] = yield Promise.all([
|
|
20492
|
+
fetchYieldHistorySeries((variables) => this._graph.request(yieldHistoryPageQuery, variables), { pools, tranches: [...tranches], userTranches, locks }, window),
|
|
20493
|
+
this.readChainAt((_a = positions._meta) === null || _a === void 0 ? void 0 : _a.block.number, (blockTag) => this._userLendingService.getUserPoolBalancesAt(userAddress, pools, undefined, blockTag)),
|
|
20494
|
+
]);
|
|
20495
|
+
// A pool whose ledger credits shares the wallet does not hold at
|
|
20496
|
+
// the same block (shares moved away outside a withdrawal) has no
|
|
20497
|
+
// history we can vouch for: it is left out. Unpinned, nothing is.
|
|
20498
|
+
const decimals = this._kasuConfig.stableAssetDecimals;
|
|
20499
|
+
const withheld = new Set();
|
|
20500
|
+
if (chain.blockTag !== undefined) {
|
|
20501
|
+
positions.user.lendingPoolUserDetails.forEach((pool, index) => {
|
|
20502
|
+
var _a;
|
|
20503
|
+
const ledger = pool.lendingPoolTrancheUserDetails.reduce((sum, position) => {
|
|
20504
|
+
var _a;
|
|
20505
|
+
return sum +
|
|
20506
|
+
parseFloat(this._userLendingService.convertSharesToAssets((_a = position.shares) !== null && _a !== void 0 ? _a : '0', position.tranche.balance, position.tranche.shares));
|
|
20507
|
+
}, 0);
|
|
20508
|
+
const held = parseFloat(formatUnits((_a = chain.values[index]) !== null && _a !== void 0 ? _a : BigNumber.from(0), decimals));
|
|
20509
|
+
if (ledger > held && !ledgerAgrees(ledger, held)) {
|
|
20510
|
+
withheld.add(pool.lendingPool.id.toLowerCase());
|
|
20511
|
+
}
|
|
20512
|
+
});
|
|
20513
|
+
}
|
|
19950
20514
|
return buildYieldHistory(Object.assign({ positions }, rows), window, {
|
|
19951
20515
|
epochZeroStart: epochZeroStart.toNumber(),
|
|
19952
20516
|
epochDuration: epochDuration.toNumber(),
|
|
19953
|
-
});
|
|
20517
|
+
}).filter((entry) => !withheld.has(entry.poolId.toLowerCase()));
|
|
19954
20518
|
}
|
|
19955
20519
|
catch (error) {
|
|
19956
20520
|
if (isEmptyHistoryError(error, this._isLiteDeployment))
|
|
@@ -19959,6 +20523,164 @@ class Portfolio {
|
|
|
19959
20523
|
}
|
|
19960
20524
|
});
|
|
19961
20525
|
}
|
|
20526
|
+
/**
|
|
20527
|
+
* Read the chain at the subgraph's block, so the chain and the ledger
|
|
20528
|
+
* describe the same state: after every clearing the subgraph runs a few
|
|
20529
|
+
* blocks behind, and a `latest` read would then disagree with an
|
|
20530
|
+
* honest ledger (interest moved every balance, deposits were accepted)
|
|
20531
|
+
* and book that difference as a ledger fault.
|
|
20532
|
+
*
|
|
20533
|
+
* Only when the node says it cannot serve that block (pruned, or behind
|
|
20534
|
+
* the subgraph: `isBlockUnavailableError`) does it fall back to `latest`,
|
|
20535
|
+
* and it says so (`blockTag: undefined`): unpinned figures are never
|
|
20536
|
+
* compared with the ledger, and `getPortfolioLendingData` marks the pools
|
|
20537
|
+
* `chainPinned: false`. Any other failure — a rate limit, a timeout, a
|
|
20538
|
+
* network error — is thrown, never turned into an unpinned read.
|
|
20539
|
+
*/
|
|
20540
|
+
readChainAt(block, read) {
|
|
20541
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20542
|
+
if (block !== undefined) {
|
|
20543
|
+
try {
|
|
20544
|
+
return { values: yield read(block), blockTag: block };
|
|
20545
|
+
}
|
|
20546
|
+
catch (error) {
|
|
20547
|
+
if (!isBlockUnavailableError(error))
|
|
20548
|
+
throw error;
|
|
20549
|
+
}
|
|
20550
|
+
}
|
|
20551
|
+
return { values: yield read(undefined), blockTag: undefined };
|
|
20552
|
+
});
|
|
20553
|
+
}
|
|
20554
|
+
/**
|
|
20555
|
+
* One pool's balances: the ledger's (the subgraph counts a lender's
|
|
20556
|
+
* shares as accepted deposits − accepted withdrawals ± top-ups) checked
|
|
20557
|
+
* against the chain's `LendingPool.userBalance` at the SAME block.
|
|
20558
|
+
*
|
|
20559
|
+
* The ledger does not follow shares that move between wallets any other
|
|
20560
|
+
* way (an administrative move of a position is the case seen on chain):
|
|
20561
|
+
* the receiving wallet goes negative as it withdraws, the sending one
|
|
20562
|
+
* keeps shares it no longer holds. Where the two disagree at that block —
|
|
20563
|
+
* or any ledger balance is negative — the tranche balances are read from
|
|
20564
|
+
* the chain at that block (`userActiveAssets`, one call per tranche), the
|
|
20565
|
+
* tranche's ledger `yieldEarned` moves by the same difference, and the
|
|
20566
|
+
* pool carries `ledgerMismatch`. Unpinned (the node could not serve the
|
|
20567
|
+
* block), only a negative ledger balance is corrected. A pool that agrees
|
|
20568
|
+
* — every ordinary lender — costs nothing extra.
|
|
20569
|
+
*
|
|
20570
|
+
* Lifetime figures stay ledger figures: they cannot tell moved principal
|
|
20571
|
+
* from interest.
|
|
20572
|
+
*/
|
|
20573
|
+
reconcilePool(userAddress, overview, details, chainBalance, blockTag, provider) {
|
|
20574
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20575
|
+
var _a, _b, _c;
|
|
20576
|
+
const decimals = this._kasuConfig.stableAssetDecimals;
|
|
20577
|
+
const chainTotal = parseFloat(formatUnits(chainBalance, decimals));
|
|
20578
|
+
const lifetime = chainTotal -
|
|
20579
|
+
parseFloat(details.totalAcceptedDeposits) +
|
|
20580
|
+
parseFloat(details.totalAcceptedWithdrawnAmount);
|
|
20581
|
+
const tranches = new Map();
|
|
20582
|
+
for (const position of details.lendingPoolTrancheUserDetails) {
|
|
20583
|
+
const balance = this._userLendingService.convertSharesToAssets(position.shares, position.tranche.balance, position.tranche.shares);
|
|
20584
|
+
tranches.set(position.tranche.id, {
|
|
20585
|
+
balance,
|
|
20586
|
+
yieldEarned: parseFloat(balance) -
|
|
20587
|
+
parseFloat(position.totalAcceptedDeposits) +
|
|
20588
|
+
parseFloat(position.totalAcceptedWithdrawnAmount),
|
|
20589
|
+
});
|
|
20590
|
+
}
|
|
20591
|
+
const ledgerTotal = [...tranches.values()].reduce((sum, { balance }) => sum + parseFloat(balance), 0);
|
|
20592
|
+
const negative = [...tranches.values()].some(({ balance }) => parseFloat(balance) < 0);
|
|
20593
|
+
const disagrees = blockTag !== undefined && !ledgerAgrees(ledgerTotal, chainTotal);
|
|
20594
|
+
if (!negative && !disagrees) {
|
|
20595
|
+
return { chainBalance, lifetime, tranches };
|
|
20596
|
+
}
|
|
20597
|
+
const trancheIds = [
|
|
20598
|
+
...new Set([
|
|
20599
|
+
...overview.tranches.map(({ id }) => id),
|
|
20600
|
+
...tranches.keys(),
|
|
20601
|
+
]),
|
|
20602
|
+
];
|
|
20603
|
+
const onChain = yield this._userLendingService.getUserTrancheActiveAssets(userAddress, trancheIds, provider, blockTag);
|
|
20604
|
+
let phantom = false;
|
|
20605
|
+
const reconciled = new Map();
|
|
20606
|
+
for (const [index, trancheId] of trancheIds.entries()) {
|
|
20607
|
+
const fromLedger = tranches.get(trancheId);
|
|
20608
|
+
const ledgerBalance = parseFloat((_a = fromLedger === null || fromLedger === void 0 ? void 0 : fromLedger.balance) !== null && _a !== void 0 ? _a : '0');
|
|
20609
|
+
const balance = formatUnits((_b = onChain[index]) !== null && _b !== void 0 ? _b : BigNumber.from(0), decimals);
|
|
20610
|
+
if (blockTag !== undefined &&
|
|
20611
|
+
ledgerBalance > parseFloat(balance) &&
|
|
20612
|
+
!ledgerAgrees(ledgerBalance, parseFloat(balance))) {
|
|
20613
|
+
phantom = true;
|
|
20614
|
+
}
|
|
20615
|
+
reconciled.set(trancheId, {
|
|
20616
|
+
balance,
|
|
20617
|
+
yieldEarned: ((_c = fromLedger === null || fromLedger === void 0 ? void 0 : fromLedger.yieldEarned) !== null && _c !== void 0 ? _c : 0) +
|
|
20618
|
+
parseFloat(balance) -
|
|
20619
|
+
ledgerBalance,
|
|
20620
|
+
});
|
|
20621
|
+
}
|
|
20622
|
+
return {
|
|
20623
|
+
chainBalance,
|
|
20624
|
+
lifetime,
|
|
20625
|
+
tranches: reconciled,
|
|
20626
|
+
mismatch: {
|
|
20627
|
+
kind: phantom ? 'ledger-exceeds-chain' : 'chain-exceeds-ledger',
|
|
20628
|
+
ledgerBalance: String(ledgerTotal),
|
|
20629
|
+
chainBalance: String(chainTotal),
|
|
20630
|
+
},
|
|
20631
|
+
};
|
|
20632
|
+
});
|
|
20633
|
+
}
|
|
20634
|
+
/**
|
|
20635
|
+
* The last-epoch figures of positions whose newest interest is OLDER than
|
|
20636
|
+
* the recent window. Pools clear independently, and some clear only when
|
|
20637
|
+
* the originator repays, so a pool's last cycle can be weeks back: it is
|
|
20638
|
+
* priced at THAT epoch, from a history read of just those positions over
|
|
20639
|
+
* just those epochs, through the same `positionEpochYield` — so it equals
|
|
20640
|
+
* the history's newest bar.
|
|
20641
|
+
*
|
|
20642
|
+
* A lender who has since left the tranche (no ledger shares now) gets no
|
|
20643
|
+
* figure: an old pool's last cycle is not theirs to show. Costs nothing
|
|
20644
|
+
* when no position qualifies.
|
|
20645
|
+
*/
|
|
20646
|
+
staleLastEpochYields(positions, recentEpoch) {
|
|
20647
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20648
|
+
var _a;
|
|
20649
|
+
const stale = positions.flatMap(({ poolId, position }) => {
|
|
20650
|
+
var _a;
|
|
20651
|
+
const interest = (_a = position.tranche.lendingPoolTrancheEpochInterest) === null || _a === void 0 ? void 0 : _a[0];
|
|
20652
|
+
if ((interest === null || interest === void 0 ? void 0 : interest.epochId) === undefined)
|
|
20653
|
+
return [];
|
|
20654
|
+
if (!(parseFloat(position.shares) > 0))
|
|
20655
|
+
return [];
|
|
20656
|
+
const epoch = Number(interest.epochId);
|
|
20657
|
+
return epoch < recentEpoch
|
|
20658
|
+
? [{ poolId, position, epoch, interest }]
|
|
20659
|
+
: [];
|
|
20660
|
+
});
|
|
20661
|
+
const yields = new Map();
|
|
20662
|
+
if (stale.length === 0)
|
|
20663
|
+
return yields;
|
|
20664
|
+
const lockId = (poolId, lock) => { var _a; return (_a = lock.id) !== null && _a !== void 0 ? _a : `${poolId.toLowerCase()}-${lock.lockId}`; };
|
|
20665
|
+
const { rows } = yield fetchYieldHistorySeries((variables) => this._graph.request(yieldHistoryPageQuery, variables), {
|
|
20666
|
+
pools: [...new Set(stale.map(({ poolId }) => poolId))].map((id) => id.toLowerCase()),
|
|
20667
|
+
tranches: [
|
|
20668
|
+
...new Set(stale.map(({ position }) => position.tranche.id)),
|
|
20669
|
+
],
|
|
20670
|
+
userTranches: stale.map(({ position }) => position.id),
|
|
20671
|
+
locks: stale.flatMap(({ poolId, position }) => position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => lockId(poolId, lock))),
|
|
20672
|
+
}, {
|
|
20673
|
+
fromEpoch: Math.min(...stale.map(({ epoch }) => epoch)),
|
|
20674
|
+
toEpoch: Math.max(...stale.map(({ epoch }) => epoch)),
|
|
20675
|
+
});
|
|
20676
|
+
const starts = clearingStarts(rows.clearings);
|
|
20677
|
+
for (const { poolId, position, epoch, interest } of stale) {
|
|
20678
|
+
const series = positionSeriesFrom(rows, Object.assign(Object.assign({}, position), { userLendingPoolTrancheFixedTermDepositLocks: position.userLendingPoolTrancheFixedTermDepositLocks.map((lock) => (Object.assign(Object.assign({}, lock), { id: lockId(poolId, lock) }))) }));
|
|
20679
|
+
yields.set(position.id, positionEpochYield(series, epoch, parseFloat(interest.epochInterestAmount), (_a = starts.get(poolId.toLowerCase())) === null || _a === void 0 ? void 0 : _a.get(epoch)).yield);
|
|
20680
|
+
}
|
|
20681
|
+
return yields;
|
|
20682
|
+
});
|
|
20683
|
+
}
|
|
19962
20684
|
/**
|
|
19963
20685
|
* A money figure as a plain decimal string. Below a millionth of a token
|
|
19964
20686
|
* (the stable asset's own precision) is float noise, never money, so it
|
|
@@ -31534,6 +32256,16 @@ function getTrancheDisplayName(trancheName, pool) {
|
|
|
31534
32256
|
* window, and the accrual spreads an epoch's interest across it.
|
|
31535
32257
|
*/
|
|
31536
32258
|
const SECONDS_PER_WEEK = 604800;
|
|
32259
|
+
/**
|
|
32260
|
+
* The most unpaid interest {@link accruedInterestSince} shows for one pool:
|
|
32261
|
+
* this many epochs of its weekly figure (owner ruling 2026-11-07).
|
|
32262
|
+
*
|
|
32263
|
+
* A pool can stop being cleared without being flagged stopped. On Base, one
|
|
32264
|
+
* pool is more than six epochs behind and another more than a hundred.
|
|
32265
|
+
* Uncapped, the figure would show interest that may never be credited. Four
|
|
32266
|
+
* epochs covers any ordinary late clearing.
|
|
32267
|
+
*/
|
|
32268
|
+
const MAX_ACCRUAL_EPOCHS = 4;
|
|
31537
32269
|
function isUsableFeePercent(feePercent) {
|
|
31538
32270
|
return (feePercent !== null &&
|
|
31539
32271
|
Number.isFinite(feePercent) &&
|
|
@@ -31587,28 +32319,40 @@ function dailyInterest(weekly) {
|
|
|
31587
32319
|
return weekly / 7;
|
|
31588
32320
|
}
|
|
31589
32321
|
/**
|
|
31590
|
-
* Interest accrued since each pool's OWN last
|
|
31591
|
-
*
|
|
32322
|
+
* Interest accrued since each pool's OWN last clearing transaction, capped at
|
|
32323
|
+
* one epoch per pool.
|
|
31592
32324
|
*
|
|
31593
32325
|
* ```
|
|
31594
32326
|
* accrued = Σ_pool weekly_pool × clamp(now − clearing_pool, 0, 604 800) / 604 800
|
|
31595
32327
|
* ```
|
|
31596
32328
|
*
|
|
31597
|
-
*
|
|
31598
|
-
*
|
|
31599
|
-
*
|
|
31600
|
-
*
|
|
31601
|
-
*
|
|
31602
|
-
*
|
|
31603
|
-
*
|
|
31604
|
-
*
|
|
31605
|
-
*
|
|
31606
|
-
*
|
|
31607
|
-
*
|
|
31608
|
-
*
|
|
32329
|
+
* Per pool, because pools clear independently: one shared anchor accrues a
|
|
32330
|
+
* stale pool's share from a close it never had, and when another pool clears
|
|
32331
|
+
* it drops the total by the stale pool's whole weekly share.
|
|
32332
|
+
*
|
|
32333
|
+
* **The one-epoch cap rested on a wrong premise.** It assumed a late
|
|
32334
|
+
* clearing credits only one epoch, so accruing past seven days would promise
|
|
32335
|
+
* interest no close pays. The contracts say otherwise. `ClearingCoordinator`
|
|
32336
|
+
* states that clearing "must be executed once per epoch for each lending
|
|
32337
|
+
* pool" and that "clearing epochs must be executed in order"; `doClearing`
|
|
32338
|
+
* reverts unless the target epoch is the pool's `nextLendingPoolClearingEpoch`,
|
|
32339
|
+
* and it calls `LendingPool.applyInterests(targetEpoch)` on every clearing,
|
|
32340
|
+
* late or not ("if clearing for the epoch is executed only after the clearing
|
|
32341
|
+
* period, only yield will be applied"). Every missed epoch's interest is
|
|
32342
|
+
* therefore credited when the clearings catch up — on Base, one pool cleared
|
|
32343
|
+
* epochs 116 to 119 in the same block, four weeks credited at once.
|
|
32344
|
+
* Capped, the figure freezes as soon as a clearing is a week late; anchored
|
|
32345
|
+
* on the transaction, it also DIPS on a catch-up (elapsed resets to zero
|
|
32346
|
+
* while only one week is credited per clearing).
|
|
32347
|
+
*
|
|
32348
|
+
* The low clamp makes a close ahead of the local clock zero, never negative.
|
|
31609
32349
|
* A non-finite term contributes nothing; a non-finite `nowSeconds` accrues
|
|
31610
|
-
* nothing.
|
|
31611
|
-
*
|
|
32350
|
+
* nothing.
|
|
32351
|
+
*
|
|
32352
|
+
* @deprecated Use {@link accruedInterestSince} with {@link epochAccrual}:
|
|
32353
|
+
* identical while clearings run on time, and it keeps accruing, up to four
|
|
32354
|
+
* epochs, when they run late. Kept, behaviour-identical, for existing
|
|
32355
|
+
* callers.
|
|
31612
32356
|
*/
|
|
31613
32357
|
function accruedInterest(accruals, nowSeconds) {
|
|
31614
32358
|
if (!Number.isFinite(nowSeconds))
|
|
@@ -31623,6 +32367,181 @@ function accruedInterest(accruals, nowSeconds) {
|
|
|
31623
32367
|
}
|
|
31624
32368
|
return accrued;
|
|
31625
32369
|
}
|
|
32370
|
+
/**
|
|
32371
|
+
* Unix SECONDS at which `epoch` ENDS — the start of the next one:
|
|
32372
|
+
*
|
|
32373
|
+
* ```
|
|
32374
|
+
* epochEnd(e) = initialEpochStart + (e + 1) × 604 800
|
|
32375
|
+
* ```
|
|
32376
|
+
*
|
|
32377
|
+
* `SystemVariables.epochStartTimestamp(e)` is `initial + e × EPOCH_DURATION`,
|
|
32378
|
+
* and the initial start is written once, at initialisation, so the end of any
|
|
32379
|
+
* epoch follows from `epochStartTimestamp(0)` with no further read.
|
|
32380
|
+
*
|
|
32381
|
+
* FAILS CLOSED with `NaN`: a non-integer, non-finite or negative epoch, an
|
|
32382
|
+
* initial start that is not a positive integer, or a result past
|
|
32383
|
+
* `Number.MAX_SAFE_INTEGER`.
|
|
32384
|
+
*
|
|
32385
|
+
* @param initialEpochStart unix seconds, `epochStartTimestamp(0)`.
|
|
32386
|
+
* @param epoch the epoch number, 0-based.
|
|
32387
|
+
*/
|
|
32388
|
+
function epochEndTimestamp(initialEpochStart, epoch) {
|
|
32389
|
+
if (!Number.isSafeInteger(initialEpochStart) || initialEpochStart <= 0) {
|
|
32390
|
+
return NaN;
|
|
32391
|
+
}
|
|
32392
|
+
if (!Number.isSafeInteger(epoch) || epoch < 0)
|
|
32393
|
+
return NaN;
|
|
32394
|
+
const end = initialEpochStart + (epoch + 1) * SECONDS_PER_WEEK;
|
|
32395
|
+
return Number.isSafeInteger(end) ? end : NaN;
|
|
32396
|
+
}
|
|
32397
|
+
/**
|
|
32398
|
+
* Builds one pool's {@link EpochAccrual} from what the chain and the subgraph
|
|
32399
|
+
* say about its last clearing:
|
|
32400
|
+
*
|
|
32401
|
+
* ```
|
|
32402
|
+
* epochEnd = epochEndTimestamp(initialEpochStart, lastClearedEpoch)
|
|
32403
|
+
* accruesFrom = min(clearingStartedAt, epochEnd)
|
|
32404
|
+
* ```
|
|
32405
|
+
*
|
|
32406
|
+
* - **On time** (the clearing started inside its window, before its epoch
|
|
32407
|
+
* ended): `accruesFrom` is the clearing's start. Clearing applies the
|
|
32408
|
+
* epoch's interest first and only then accepts requests, so today's
|
|
32409
|
+
* balance — which includes a deposit that clearing accepted — is never
|
|
32410
|
+
* charged for time before it: a new lender starts at exactly 0.
|
|
32411
|
+
* - **Late** (it started at or after its epoch end): `accruesFrom` is the
|
|
32412
|
+
* epoch end. A late clearing accepts no requests and credits exactly one
|
|
32413
|
+
* epoch, so the time it did not credit is kept.
|
|
32414
|
+
*
|
|
32415
|
+
* `lastClearedEpoch` is the newest epoch whose clearing has STARTED (the
|
|
32416
|
+
* subgraph has a `LendingPoolClearing` for it), not the newest that has
|
|
32417
|
+
* finished, and `clearingStartedAt` is that clearing's `startTimestamp`.
|
|
32418
|
+
* `ClearingCoordinator.doClearing` mints the epoch's interest in its FIRST
|
|
32419
|
+
* transaction (`applyInterests`), while `nextLendingPoolClearingEpoch` only
|
|
32420
|
+
* advances when the clearing ENDS, so it is the wrong source.
|
|
32421
|
+
*
|
|
32422
|
+
* FAILS CLOSED with `null`: whatever {@link epochEndTimestamp} rejects, a
|
|
32423
|
+
* `clearingStartedAt` that is not a finite positive number, or a
|
|
32424
|
+
* `weeklyInterest` that is not finite or is negative. The caller then offers
|
|
32425
|
+
* no term for that pool.
|
|
32426
|
+
*
|
|
32427
|
+
* @param input.weeklyInterest the pool's net interest for one epoch.
|
|
32428
|
+
* @param input.initialEpochStart unix seconds, `epochStartTimestamp(0)`.
|
|
32429
|
+
* @param input.lastClearedEpoch the newest epoch whose clearing has started.
|
|
32430
|
+
* @param input.clearingStartedAt unix seconds, that clearing's start.
|
|
32431
|
+
*/
|
|
32432
|
+
function epochAccrual(input) {
|
|
32433
|
+
const { weeklyInterest: weekly, clearingStartedAt } = input;
|
|
32434
|
+
if (!Number.isFinite(weekly) || weekly < 0)
|
|
32435
|
+
return null;
|
|
32436
|
+
if (!Number.isFinite(clearingStartedAt) || clearingStartedAt <= 0) {
|
|
32437
|
+
return null;
|
|
32438
|
+
}
|
|
32439
|
+
const epochEnd = epochEndTimestamp(input.initialEpochStart, input.lastClearedEpoch);
|
|
32440
|
+
if (Number.isNaN(epochEnd))
|
|
32441
|
+
return null;
|
|
32442
|
+
return {
|
|
32443
|
+
weeklyInterest: weekly,
|
|
32444
|
+
accruesFrom: Math.min(clearingStartedAt, epochEnd),
|
|
32445
|
+
epochEnd,
|
|
32446
|
+
};
|
|
32447
|
+
}
|
|
32448
|
+
/**
|
|
32449
|
+
* Interest accrued and not yet credited — the moving part of lifetime
|
|
32450
|
+
* interest (lifetime = settled on chain + this). Per term, with
|
|
32451
|
+
* `W` = 604 800 s:
|
|
32452
|
+
*
|
|
32453
|
+
* ```
|
|
32454
|
+
* accrued = min( weekly × ( min(max(now − accruesFrom, 0), W)
|
|
32455
|
+
* + max(now − (epochEnd + W), 0) ) / W,
|
|
32456
|
+
* MAX_ACCRUAL_EPOCHS × weekly )
|
|
32457
|
+
* ```
|
|
32458
|
+
*
|
|
32459
|
+
* Read along the clock, for one pool:
|
|
32460
|
+
* 1. from `accruesFrom`, one epoch of interest accrues linearly;
|
|
32461
|
+
* 2. it then HOLDS from `accruesFrom + W` until `epochEnd + W`, the end of
|
|
32462
|
+
* the next epoch — at most 48 h after an on-time clearing (its clearing
|
|
32463
|
+
* window), no time at all after a late one (`accruesFrom == epochEnd`);
|
|
32464
|
+
* 3. then it resumes, up to {@link MAX_ACCRUAL_EPOCHS} (4) epochs of
|
|
32465
|
+
* `weekly` in all, and stops there.
|
|
32466
|
+
*
|
|
32467
|
+
* **Why it keeps accruing past one epoch.** Clearing must run once per
|
|
32468
|
+
* epoch for each pool, in order (`ClearingCoordinator.doClearing` reverts
|
|
32469
|
+
* unless the target epoch is the pool's `nextLendingPoolClearingEpoch`), and
|
|
32470
|
+
* every clearing, on time or late, starts with
|
|
32471
|
+
* `LendingPool.applyInterests(targetEpoch)`. A missed epoch is therefore
|
|
32472
|
+
* credited when the clearings catch up (on Base, one pool cleared epochs 116
|
|
32473
|
+
* to 119 in the same block).
|
|
32474
|
+
*
|
|
32475
|
+
* **Why it stops at four epochs** (owner ruling 2026-11-07). A pool can stop
|
|
32476
|
+
* being cleared without being flagged stopped. On Base today one pool is
|
|
32477
|
+
* more than six epochs behind and another more than a hundred. Past four
|
|
32478
|
+
* epochs the figure would show interest that may never be credited. Four
|
|
32479
|
+
* covers any ordinary late clearing.
|
|
32480
|
+
*
|
|
32481
|
+
* **Why the hold.** Without it an on-time anchor accrues past one epoch
|
|
32482
|
+
* while the next on-time clearing — which credits exactly one — is still to
|
|
32483
|
+
* come, and the total steps DOWN when it lands. With it, at a constant
|
|
32484
|
+
* balance, `settled + accrued` never steps down at a clearing (`t` = the
|
|
32485
|
+
* NEW clearing's start, `E` = the end of the epoch it clears):
|
|
32486
|
+
* - on time after on time: identical to the deprecated `accruedInterest`
|
|
32487
|
+
* at every instant. With `gap` = `t` − the previous clearing's start, it
|
|
32488
|
+
* steps UP by `weekly × (W − gap) / W` when `gap < W` (at most 2/7 of one
|
|
32489
|
+
* weekly, as before), and not at all when `gap ≥ W`;
|
|
32490
|
+
* - late after on time, and late after late: exactly continuous;
|
|
32491
|
+
* - on time after late: steps UP by `weekly × (E − t) / W`, at most 2/7 of
|
|
32492
|
+
* one weekly.
|
|
32493
|
+
* A deposit or top-up accepted at an on-time clearing starts at 0, so it
|
|
32494
|
+
* never dips the total either.
|
|
32495
|
+
*
|
|
32496
|
+
* **At the cap.** All of the above holds for a pool below the cap, where
|
|
32497
|
+
* the cap changes nothing. A pool AT the cap shows `4 × weekly` before a
|
|
32498
|
+
* catch-up clearing; after it, one more `weekly` is settled and the new term
|
|
32499
|
+
* shows `min(elapsed′, 4 × weekly)`, so `after = min(elapsed′ + weekly,
|
|
32500
|
+
* 5 × weekly) ≥ before`. Each clearing steps the total UP by at most one
|
|
32501
|
+
* weekly until the pool is back under the cap. Never down, and never above
|
|
32502
|
+
* settled plus `4 × weekly` per pool.
|
|
32503
|
+
*
|
|
32504
|
+
* **Never negative**, and non-decreasing in `now`. A term is skipped — it
|
|
32505
|
+
* contributes nothing — when `weeklyInterest` is not finite or is negative,
|
|
32506
|
+
* when `accruesFrom` or `epochEnd` is not finite, when `accruesFrom >
|
|
32507
|
+
* epochEnd` (inconsistent: the anchor is never after the epoch end), or when
|
|
32508
|
+
* an elapsed time overflows. A non-finite `nowSeconds` accrues nothing.
|
|
32509
|
+
*
|
|
32510
|
+
* **Per pool, because pools clear independently.** One shared anchor accrues
|
|
32511
|
+
* a stale pool's share from a close it never had.
|
|
32512
|
+
*
|
|
32513
|
+
* **Accepted approximation.** `weekly` is today's balance at today's epoch
|
|
32514
|
+
* rate. Over a multi-week gap the chain compounds weekly and may apply other
|
|
32515
|
+
* epochs' rates, so a long accrual reads slightly LOW. It is a ticking
|
|
32516
|
+
* estimate, not a ledger.
|
|
32517
|
+
*
|
|
32518
|
+
* Callers fail closed upstream: no term for a pool whose weekly interest or
|
|
32519
|
+
* clearing is unknown (`epochAccrual` returns `null`), and none for a pool
|
|
32520
|
+
* that has stopped — it will never clear again.
|
|
32521
|
+
*/
|
|
32522
|
+
function accruedInterestSince(accruals, nowSeconds) {
|
|
32523
|
+
if (!Number.isFinite(nowSeconds))
|
|
32524
|
+
return 0;
|
|
32525
|
+
let accrued = 0;
|
|
32526
|
+
for (const { weeklyInterest: weekly, accruesFrom, epochEnd } of accruals) {
|
|
32527
|
+
if (!Number.isFinite(weekly) || weekly < 0)
|
|
32528
|
+
continue;
|
|
32529
|
+
if (!Number.isFinite(accruesFrom) || !Number.isFinite(epochEnd)) {
|
|
32530
|
+
continue;
|
|
32531
|
+
}
|
|
32532
|
+
if (accruesFrom > epochEnd)
|
|
32533
|
+
continue;
|
|
32534
|
+
const sinceAnchor = nowSeconds - accruesFrom;
|
|
32535
|
+
const sinceHoldEnd = nowSeconds - (epochEnd + SECONDS_PER_WEEK);
|
|
32536
|
+
if (!Number.isFinite(sinceAnchor) || !Number.isFinite(sinceHoldEnd)) {
|
|
32537
|
+
continue;
|
|
32538
|
+
}
|
|
32539
|
+
const elapsed = Math.min(Math.max(sinceAnchor, 0), SECONDS_PER_WEEK) +
|
|
32540
|
+
Math.max(sinceHoldEnd, 0);
|
|
32541
|
+
accrued += Math.min((weekly * elapsed) / SECONDS_PER_WEEK, MAX_ACCRUAL_EPOCHS * weekly);
|
|
32542
|
+
}
|
|
32543
|
+
return accrued;
|
|
32544
|
+
}
|
|
31626
32545
|
/**
|
|
31627
32546
|
* What `amount` earns in a year at a NET rate — the "≈ $Y a year" line.
|
|
31628
32547
|
* Feed it `netEffectiveApy(...)`, never a gross APY: the result is a lender's
|
|
@@ -31665,4 +32584,4 @@ function weightedAverageApy(slices) {
|
|
|
31665
32584
|
return weighted / totalBalance;
|
|
31666
32585
|
}
|
|
31667
32586
|
|
|
31668
|
-
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, RISK_GROUP_ORDER, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, StrategyDeploymentInputError, StrategyTotalsInputError, TvlHistoryInputError, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, aggregateYieldHistory, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, checkSponsoredCallOutcome, classifyWalletFailure, combineTvlHistories, 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, groupRiskManagementItems, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFacility, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, pickShortDescription, poolAllTranchesFull, poolMaxApy, poolTvl, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, readCmsStartDate, resolveBoundShortcuts, resolveDepositBounds, securityStructureOf, selectVisiblePools, splitBusinessTypes, splitNumberedClauses, strategyDeployments, strategyTotalsUsd, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|
|
32587
|
+
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_ACCRUAL_EPOCHS, 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, RISK_GROUP_ORDER, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, StrategyDeploymentInputError, StrategyTotalsInputError, TvlHistoryInputError, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, accruedInterestSince, aggregateYieldHistory, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, checkSponsoredCallOutcome, classifyWalletFailure, combineTvlHistories, compareTrancheSeniority, computeSettlementWindow, countSubmissions, dailyInterest, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeDepositData, encodeRequestWithdrawalCall, encodeStableTransfer, encodeWithdrawAtExpiryCall, epochAccrual, epochEndTimestamp, epochRateToApy, epochTrancheYield, explorerAddressUrl, explorerTxUrl, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getStrategyRegion, getTrancheDisplayName, groupRiskManagementItems, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFacility, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, pickShortDescription, poolAllTranchesFull, poolMaxApy, poolTvl, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, readCmsStartDate, resolveBoundShortcuts, resolveDepositBounds, securityStructureOf, selectVisiblePools, splitBusinessTypes, splitNumberedClauses, strategyDeployments, strategyTotalsUsd, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|