@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/domain/index.d.ts
CHANGED
|
@@ -64,5 +64,5 @@ export { combineTvlHistories, poolTvl, TvlHistoryInputError } from './pool-tvl';
|
|
|
64
64
|
export type { PoolTvlHistoryEntry, StrategyTvlHistoryEntry, TvlHistoryInputErrorCode, TvlHistoryLeg, } from './pool-tvl';
|
|
65
65
|
export { aggregateYieldHistory, epochTrancheYield } from './yield-history';
|
|
66
66
|
export type { EpochLockShares, EpochTrancheYield, EpochTrancheYieldInput, YieldHistoryEntry, YieldHistoryFilter, YieldHistoryPoint, } from './yield-history';
|
|
67
|
-
export { accruedInterest, dailyInterest, projectedAnnualEarnings, SECONDS_PER_WEEK, weeklyInterest, weightedAverageApy, } from './yields';
|
|
68
|
-
export type { InterestSlice, PoolAccrual } from './yields';
|
|
67
|
+
export { accruedInterest, accruedInterestSince, dailyInterest, epochAccrual, epochEndTimestamp, MAX_ACCRUAL_EPOCHS, projectedAnnualEarnings, SECONDS_PER_WEEK, weeklyInterest, weightedAverageApy, } from './yields';
|
|
68
|
+
export type { EpochAccrual, InterestSlice, PoolAccrual } from './yields';
|
package/dist/domain/index.js
CHANGED
|
@@ -46,5 +46,5 @@ export { compareTrancheSeniority, derivePoolStatus, MIN_TRANCHE_CAPACITY, netTra
|
|
|
46
46
|
export { classifyWalletFailure, isUnpredictableGas, isUserRejected, } from './wallet-errors';
|
|
47
47
|
export { combineTvlHistories, poolTvl, TvlHistoryInputError } from './pool-tvl';
|
|
48
48
|
export { aggregateYieldHistory, epochTrancheYield } from './yield-history';
|
|
49
|
-
export { accruedInterest, dailyInterest, projectedAnnualEarnings, SECONDS_PER_WEEK, weeklyInterest, weightedAverageApy, } from './yields';
|
|
49
|
+
export { accruedInterest, accruedInterestSince, dailyInterest, epochAccrual, epochEndTimestamp, MAX_ACCRUAL_EPOCHS, projectedAnnualEarnings, SECONDS_PER_WEEK, weeklyInterest, weightedAverageApy, } from './yields';
|
|
50
50
|
//# sourceMappingURL=index.js.map
|
package/dist/domain/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,24 @@
|
|
|
15
15
|
* on Base and XDC USDC, AUDD on XDC AUDD) — never converted to USD here;
|
|
16
16
|
* shares are display units of tranche shares, as the subgraph's BigDecimals.
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* The largest change of a lock's shares, as a fraction of its shares before
|
|
20
|
+
* the epoch, that one clearing's fixed-term top-up can make. The top-up is
|
|
21
|
+
* the fixed rate's difference from the variable one on one week's balance
|
|
22
|
+
* (`LendingPool._applyFixedRateInterests`) — a fraction of a percent at any
|
|
23
|
+
* real rate — so 5 % is far above every genuine top-up and far below any
|
|
24
|
+
* accounting fault. A lock-share change outside it is NOT interest: it is
|
|
25
|
+
* left out of the yield (a share movement is never booked as yield). The one
|
|
26
|
+
* seen on chain is a lock whose recorded shares were set to zero at a
|
|
27
|
+
* clearing while its shares stayed in the fixed-term contract.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MAX_TOP_UP_SHARE_FRACTION = 0.05;
|
|
30
|
+
/**
|
|
31
|
+
* True when `sharesBefore → sharesAt` is a change one clearing's fixed-term
|
|
32
|
+
* top-up can make (`MAX_TOP_UP_SHARE_FRACTION`). A lock with no shares
|
|
33
|
+
* before has no top-up at all.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isPlausibleTopUp(sharesBefore: number, sharesAt: number): boolean;
|
|
18
36
|
/** One fixed-term lock inside a tranche position, at one epoch. */
|
|
19
37
|
export interface EpochLockShares {
|
|
20
38
|
/**
|
|
@@ -68,7 +86,13 @@ export interface EpochTrancheYield {
|
|
|
68
86
|
* ```
|
|
69
87
|
*
|
|
70
88
|
* A zero denominator contributes 0 (a tranche or a lender with no shares
|
|
71
|
-
* earned nothing at that close), never `NaN`.
|
|
89
|
+
* earned nothing at that close), never `NaN`. So does a NEGATIVE share count:
|
|
90
|
+
* the subgraph's per-lender shares are a ledger of accepted deposits and
|
|
91
|
+
* withdrawals, and a wallet whose shares arrived some other way (moved to it
|
|
92
|
+
* from another wallet) withdraws more than the ledger ever credited it. That
|
|
93
|
+
* position is not one the ledger can describe, and its negative count is not
|
|
94
|
+
* a negative yield. A lock-share change no top-up can make
|
|
95
|
+
* (`isPlausibleTopUp`) contributes no top-up.
|
|
72
96
|
*/
|
|
73
97
|
export declare function epochTrancheYield(input: EpochTrancheYieldInput): EpochTrancheYield;
|
|
74
98
|
/** One lender's settled yield in one tranche at one epoch. */
|
|
@@ -15,6 +15,29 @@
|
|
|
15
15
|
* on Base and XDC USDC, AUDD on XDC AUDD) — never converted to USD here;
|
|
16
16
|
* shares are display units of tranche shares, as the subgraph's BigDecimals.
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* The largest change of a lock's shares, as a fraction of its shares before
|
|
20
|
+
* the epoch, that one clearing's fixed-term top-up can make. The top-up is
|
|
21
|
+
* the fixed rate's difference from the variable one on one week's balance
|
|
22
|
+
* (`LendingPool._applyFixedRateInterests`) — a fraction of a percent at any
|
|
23
|
+
* real rate — so 5 % is far above every genuine top-up and far below any
|
|
24
|
+
* accounting fault. A lock-share change outside it is NOT interest: it is
|
|
25
|
+
* left out of the yield (a share movement is never booked as yield). The one
|
|
26
|
+
* seen on chain is a lock whose recorded shares were set to zero at a
|
|
27
|
+
* clearing while its shares stayed in the fixed-term contract.
|
|
28
|
+
*/
|
|
29
|
+
export const MAX_TOP_UP_SHARE_FRACTION = 0.05;
|
|
30
|
+
/**
|
|
31
|
+
* True when `sharesBefore → sharesAt` is a change one clearing's fixed-term
|
|
32
|
+
* top-up can make (`MAX_TOP_UP_SHARE_FRACTION`). A lock with no shares
|
|
33
|
+
* before has no top-up at all.
|
|
34
|
+
*/
|
|
35
|
+
export function isPlausibleTopUp(sharesBefore, sharesAt) {
|
|
36
|
+
if (!(sharesBefore > 0))
|
|
37
|
+
return sharesAt === sharesBefore;
|
|
38
|
+
return (Math.abs(sharesAt - sharesBefore) <=
|
|
39
|
+
sharesBefore * MAX_TOP_UP_SHARE_FRACTION);
|
|
40
|
+
}
|
|
18
41
|
/**
|
|
19
42
|
* The ONE per-epoch formula. `Portfolio.getPortfolioLendingData` runs it for
|
|
20
43
|
* the last settled epoch and `getYieldHistory` for every epoch of a window, so
|
|
@@ -29,24 +52,31 @@
|
|
|
29
52
|
* ```
|
|
30
53
|
*
|
|
31
54
|
* A zero denominator contributes 0 (a tranche or a lender with no shares
|
|
32
|
-
* earned nothing at that close), never `NaN`.
|
|
55
|
+
* earned nothing at that close), never `NaN`. So does a NEGATIVE share count:
|
|
56
|
+
* the subgraph's per-lender shares are a ledger of accepted deposits and
|
|
57
|
+
* withdrawals, and a wallet whose shares arrived some other way (moved to it
|
|
58
|
+
* from another wallet) withdraws more than the ledger ever credited it. That
|
|
59
|
+
* position is not one the ledger can describe, and its negative count is not
|
|
60
|
+
* a negative yield. A lock-share change no top-up can make
|
|
61
|
+
* (`isPlausibleTopUp`) contributes no top-up.
|
|
33
62
|
*/
|
|
34
63
|
export function epochTrancheYield(input) {
|
|
35
|
-
const base = input.trancheShares
|
|
36
|
-
?
|
|
37
|
-
:
|
|
64
|
+
const base = input.trancheShares > 0 && input.userShares > 0
|
|
65
|
+
? (input.epochInterest * input.userShares) / input.trancheShares
|
|
66
|
+
: 0;
|
|
38
67
|
let variable = base;
|
|
39
68
|
const locks = input.locks.map((lock) => {
|
|
40
69
|
if (!lock.active)
|
|
41
70
|
return 0;
|
|
42
|
-
const topUp = input.trancheSharesNow
|
|
43
|
-
|
|
44
|
-
|
|
71
|
+
const topUp = input.trancheSharesNow > 0 &&
|
|
72
|
+
isPlausibleTopUp(lock.sharesBeforeEpoch, lock.sharesAtEpoch)
|
|
73
|
+
? ((lock.sharesAtEpoch - lock.sharesBeforeEpoch) *
|
|
45
74
|
input.trancheBalanceNow) /
|
|
46
|
-
input.trancheSharesNow
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
75
|
+
input.trancheSharesNow
|
|
76
|
+
: 0;
|
|
77
|
+
const lockBase = input.userShares > 0
|
|
78
|
+
? (base * lock.sharesBeforeEpoch) / input.userShares
|
|
79
|
+
: 0;
|
|
50
80
|
variable -= lockBase;
|
|
51
81
|
return lockBase + topUp;
|
|
52
82
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yield-history.js","sourceRoot":"","sources":["../../src/domain/yield-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"yield-history.js","sourceRoot":"","sources":["../../src/domain/yield-history.ts"],"names":[],"mappings":"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"}
|
package/dist/domain/yields.d.ts
CHANGED
|
@@ -18,6 +18,16 @@
|
|
|
18
18
|
* window, and the accrual spreads an epoch's interest across it.
|
|
19
19
|
*/
|
|
20
20
|
export declare const SECONDS_PER_WEEK = 604800;
|
|
21
|
+
/**
|
|
22
|
+
* The most unpaid interest {@link accruedInterestSince} shows for one pool:
|
|
23
|
+
* this many epochs of its weekly figure (owner ruling 2026-11-07).
|
|
24
|
+
*
|
|
25
|
+
* A pool can stop being cleared without being flagged stopped. On Base, one
|
|
26
|
+
* pool is more than six epochs behind and another more than a hundred.
|
|
27
|
+
* Uncapped, the figure would show interest that may never be credited. Four
|
|
28
|
+
* epochs covers any ordinary late clearing.
|
|
29
|
+
*/
|
|
30
|
+
export declare const MAX_ACCRUAL_EPOCHS = 4;
|
|
21
31
|
/** One slice of a position that earns at a single rate. */
|
|
22
32
|
export interface InterestSlice {
|
|
23
33
|
/** The lender's current balance in this slice, in stable display units. */
|
|
@@ -34,13 +44,41 @@ export interface InterestSlice {
|
|
|
34
44
|
*/
|
|
35
45
|
epochRate: number;
|
|
36
46
|
}
|
|
37
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* One pool's contribution to the current cycle's accrual, anchored on its
|
|
49
|
+
* last clearing TRANSACTION.
|
|
50
|
+
*
|
|
51
|
+
* @deprecated Use {@link EpochAccrual} with {@link accruedInterestSince}. A
|
|
52
|
+
* clearing transaction's timestamp is the wrong anchor: see `accruedInterest`.
|
|
53
|
+
*/
|
|
38
54
|
export interface PoolAccrual {
|
|
39
55
|
/** That pool's projected net interest for one epoch (`weeklyInterest`). */
|
|
40
56
|
weeklyInterest: number;
|
|
41
57
|
/** Unix SECONDS at which THAT pool last cleared a cycle. */
|
|
42
58
|
clearingTimestamp: number;
|
|
43
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* One pool's contribution to the unpaid interest — the input of
|
|
62
|
+
* {@link accruedInterestSince}. Build it with {@link epochAccrual}, which
|
|
63
|
+
* validates every field and derives the two timestamps; do not assemble one
|
|
64
|
+
* by hand.
|
|
65
|
+
*/
|
|
66
|
+
export interface EpochAccrual {
|
|
67
|
+
/** That pool's projected net interest for one epoch (`weeklyInterest`). */
|
|
68
|
+
weeklyInterest: number;
|
|
69
|
+
/**
|
|
70
|
+
* Unix SECONDS from which the pool's unpaid interest accrues: the earlier
|
|
71
|
+
* of the moment its last clearing STARTED and `epochEnd`. Never after
|
|
72
|
+
* `epochEnd`.
|
|
73
|
+
*/
|
|
74
|
+
accruesFrom: number;
|
|
75
|
+
/**
|
|
76
|
+
* Unix SECONDS at which the pool's last cleared epoch ENDS
|
|
77
|
+
* (`epochEndTimestamp(initialEpochStart, lastClearedEpoch)`). The accrual
|
|
78
|
+
* holds from `accruesFrom + 604 800` until `epochEnd + 604 800`.
|
|
79
|
+
*/
|
|
80
|
+
epochEnd: number;
|
|
81
|
+
}
|
|
44
82
|
/**
|
|
45
83
|
* Interest the slices accrue over ONE epoch, net of the fee.
|
|
46
84
|
*
|
|
@@ -72,30 +110,177 @@ export declare function weeklyInterest(slices: readonly InterestSlice[], feePerc
|
|
|
72
110
|
*/
|
|
73
111
|
export declare function dailyInterest(weekly: number | null): number | null;
|
|
74
112
|
/**
|
|
75
|
-
* Interest accrued since each pool's OWN last
|
|
76
|
-
*
|
|
113
|
+
* Interest accrued since each pool's OWN last clearing transaction, capped at
|
|
114
|
+
* one epoch per pool.
|
|
77
115
|
*
|
|
78
116
|
* ```
|
|
79
117
|
* accrued = Σ_pool weekly_pool × clamp(now − clearing_pool, 0, 604 800) / 604 800
|
|
80
118
|
* ```
|
|
81
119
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* per pool, the total is monotonic across any single pool's clearing: that
|
|
86
|
-
* pool swaps its accrued share for a capitalised one, and no other term moves.
|
|
120
|
+
* Per pool, because pools clear independently: one shared anchor accrues a
|
|
121
|
+
* stale pool's share from a close it never had, and when another pool clears
|
|
122
|
+
* it drops the total by the stale pool's whole weekly share.
|
|
87
123
|
*
|
|
88
|
-
* **The one-epoch cap
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
124
|
+
* **The one-epoch cap rested on a wrong premise.** It assumed a late
|
|
125
|
+
* clearing credits only one epoch, so accruing past seven days would promise
|
|
126
|
+
* interest no close pays. The contracts say otherwise. `ClearingCoordinator`
|
|
127
|
+
* states that clearing "must be executed once per epoch for each lending
|
|
128
|
+
* pool" and that "clearing epochs must be executed in order"; `doClearing`
|
|
129
|
+
* reverts unless the target epoch is the pool's `nextLendingPoolClearingEpoch`,
|
|
130
|
+
* and it calls `LendingPool.applyInterests(targetEpoch)` on every clearing,
|
|
131
|
+
* late or not ("if clearing for the epoch is executed only after the clearing
|
|
132
|
+
* period, only yield will be applied"). Every missed epoch's interest is
|
|
133
|
+
* therefore credited when the clearings catch up — on Base, one pool cleared
|
|
134
|
+
* epochs 116 to 119 in the same block, four weeks credited at once.
|
|
135
|
+
* Capped, the figure freezes as soon as a clearing is a week late; anchored
|
|
136
|
+
* on the transaction, it also DIPS on a catch-up (elapsed resets to zero
|
|
137
|
+
* while only one week is credited per clearing).
|
|
93
138
|
*
|
|
139
|
+
* The low clamp makes a close ahead of the local clock zero, never negative.
|
|
94
140
|
* A non-finite term contributes nothing; a non-finite `nowSeconds` accrues
|
|
95
|
-
* nothing.
|
|
96
|
-
*
|
|
141
|
+
* nothing.
|
|
142
|
+
*
|
|
143
|
+
* @deprecated Use {@link accruedInterestSince} with {@link epochAccrual}:
|
|
144
|
+
* identical while clearings run on time, and it keeps accruing, up to four
|
|
145
|
+
* epochs, when they run late. Kept, behaviour-identical, for existing
|
|
146
|
+
* callers.
|
|
97
147
|
*/
|
|
98
148
|
export declare function accruedInterest(accruals: readonly PoolAccrual[], nowSeconds: number): number;
|
|
149
|
+
/**
|
|
150
|
+
* Unix SECONDS at which `epoch` ENDS — the start of the next one:
|
|
151
|
+
*
|
|
152
|
+
* ```
|
|
153
|
+
* epochEnd(e) = initialEpochStart + (e + 1) × 604 800
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* `SystemVariables.epochStartTimestamp(e)` is `initial + e × EPOCH_DURATION`,
|
|
157
|
+
* and the initial start is written once, at initialisation, so the end of any
|
|
158
|
+
* epoch follows from `epochStartTimestamp(0)` with no further read.
|
|
159
|
+
*
|
|
160
|
+
* FAILS CLOSED with `NaN`: a non-integer, non-finite or negative epoch, an
|
|
161
|
+
* initial start that is not a positive integer, or a result past
|
|
162
|
+
* `Number.MAX_SAFE_INTEGER`.
|
|
163
|
+
*
|
|
164
|
+
* @param initialEpochStart unix seconds, `epochStartTimestamp(0)`.
|
|
165
|
+
* @param epoch the epoch number, 0-based.
|
|
166
|
+
*/
|
|
167
|
+
export declare function epochEndTimestamp(initialEpochStart: number, epoch: number): number;
|
|
168
|
+
/**
|
|
169
|
+
* Builds one pool's {@link EpochAccrual} from what the chain and the subgraph
|
|
170
|
+
* say about its last clearing:
|
|
171
|
+
*
|
|
172
|
+
* ```
|
|
173
|
+
* epochEnd = epochEndTimestamp(initialEpochStart, lastClearedEpoch)
|
|
174
|
+
* accruesFrom = min(clearingStartedAt, epochEnd)
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* - **On time** (the clearing started inside its window, before its epoch
|
|
178
|
+
* ended): `accruesFrom` is the clearing's start. Clearing applies the
|
|
179
|
+
* epoch's interest first and only then accepts requests, so today's
|
|
180
|
+
* balance — which includes a deposit that clearing accepted — is never
|
|
181
|
+
* charged for time before it: a new lender starts at exactly 0.
|
|
182
|
+
* - **Late** (it started at or after its epoch end): `accruesFrom` is the
|
|
183
|
+
* epoch end. A late clearing accepts no requests and credits exactly one
|
|
184
|
+
* epoch, so the time it did not credit is kept.
|
|
185
|
+
*
|
|
186
|
+
* `lastClearedEpoch` is the newest epoch whose clearing has STARTED (the
|
|
187
|
+
* subgraph has a `LendingPoolClearing` for it), not the newest that has
|
|
188
|
+
* finished, and `clearingStartedAt` is that clearing's `startTimestamp`.
|
|
189
|
+
* `ClearingCoordinator.doClearing` mints the epoch's interest in its FIRST
|
|
190
|
+
* transaction (`applyInterests`), while `nextLendingPoolClearingEpoch` only
|
|
191
|
+
* advances when the clearing ENDS, so it is the wrong source.
|
|
192
|
+
*
|
|
193
|
+
* FAILS CLOSED with `null`: whatever {@link epochEndTimestamp} rejects, a
|
|
194
|
+
* `clearingStartedAt` that is not a finite positive number, or a
|
|
195
|
+
* `weeklyInterest` that is not finite or is negative. The caller then offers
|
|
196
|
+
* no term for that pool.
|
|
197
|
+
*
|
|
198
|
+
* @param input.weeklyInterest the pool's net interest for one epoch.
|
|
199
|
+
* @param input.initialEpochStart unix seconds, `epochStartTimestamp(0)`.
|
|
200
|
+
* @param input.lastClearedEpoch the newest epoch whose clearing has started.
|
|
201
|
+
* @param input.clearingStartedAt unix seconds, that clearing's start.
|
|
202
|
+
*/
|
|
203
|
+
export declare function epochAccrual(input: {
|
|
204
|
+
weeklyInterest: number;
|
|
205
|
+
initialEpochStart: number;
|
|
206
|
+
lastClearedEpoch: number;
|
|
207
|
+
clearingStartedAt: number;
|
|
208
|
+
}): EpochAccrual | null;
|
|
209
|
+
/**
|
|
210
|
+
* Interest accrued and not yet credited — the moving part of lifetime
|
|
211
|
+
* interest (lifetime = settled on chain + this). Per term, with
|
|
212
|
+
* `W` = 604 800 s:
|
|
213
|
+
*
|
|
214
|
+
* ```
|
|
215
|
+
* accrued = min( weekly × ( min(max(now − accruesFrom, 0), W)
|
|
216
|
+
* + max(now − (epochEnd + W), 0) ) / W,
|
|
217
|
+
* MAX_ACCRUAL_EPOCHS × weekly )
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* Read along the clock, for one pool:
|
|
221
|
+
* 1. from `accruesFrom`, one epoch of interest accrues linearly;
|
|
222
|
+
* 2. it then HOLDS from `accruesFrom + W` until `epochEnd + W`, the end of
|
|
223
|
+
* the next epoch — at most 48 h after an on-time clearing (its clearing
|
|
224
|
+
* window), no time at all after a late one (`accruesFrom == epochEnd`);
|
|
225
|
+
* 3. then it resumes, up to {@link MAX_ACCRUAL_EPOCHS} (4) epochs of
|
|
226
|
+
* `weekly` in all, and stops there.
|
|
227
|
+
*
|
|
228
|
+
* **Why it keeps accruing past one epoch.** Clearing must run once per
|
|
229
|
+
* epoch for each pool, in order (`ClearingCoordinator.doClearing` reverts
|
|
230
|
+
* unless the target epoch is the pool's `nextLendingPoolClearingEpoch`), and
|
|
231
|
+
* every clearing, on time or late, starts with
|
|
232
|
+
* `LendingPool.applyInterests(targetEpoch)`. A missed epoch is therefore
|
|
233
|
+
* credited when the clearings catch up (on Base, one pool cleared epochs 116
|
|
234
|
+
* to 119 in the same block).
|
|
235
|
+
*
|
|
236
|
+
* **Why it stops at four epochs** (owner ruling 2026-11-07). A pool can stop
|
|
237
|
+
* being cleared without being flagged stopped. On Base today one pool is
|
|
238
|
+
* more than six epochs behind and another more than a hundred. Past four
|
|
239
|
+
* epochs the figure would show interest that may never be credited. Four
|
|
240
|
+
* covers any ordinary late clearing.
|
|
241
|
+
*
|
|
242
|
+
* **Why the hold.** Without it an on-time anchor accrues past one epoch
|
|
243
|
+
* while the next on-time clearing — which credits exactly one — is still to
|
|
244
|
+
* come, and the total steps DOWN when it lands. With it, at a constant
|
|
245
|
+
* balance, `settled + accrued` never steps down at a clearing (`t` = the
|
|
246
|
+
* NEW clearing's start, `E` = the end of the epoch it clears):
|
|
247
|
+
* - on time after on time: identical to the deprecated `accruedInterest`
|
|
248
|
+
* at every instant. With `gap` = `t` − the previous clearing's start, it
|
|
249
|
+
* steps UP by `weekly × (W − gap) / W` when `gap < W` (at most 2/7 of one
|
|
250
|
+
* weekly, as before), and not at all when `gap ≥ W`;
|
|
251
|
+
* - late after on time, and late after late: exactly continuous;
|
|
252
|
+
* - on time after late: steps UP by `weekly × (E − t) / W`, at most 2/7 of
|
|
253
|
+
* one weekly.
|
|
254
|
+
* A deposit or top-up accepted at an on-time clearing starts at 0, so it
|
|
255
|
+
* never dips the total either.
|
|
256
|
+
*
|
|
257
|
+
* **At the cap.** All of the above holds for a pool below the cap, where
|
|
258
|
+
* the cap changes nothing. A pool AT the cap shows `4 × weekly` before a
|
|
259
|
+
* catch-up clearing; after it, one more `weekly` is settled and the new term
|
|
260
|
+
* shows `min(elapsed′, 4 × weekly)`, so `after = min(elapsed′ + weekly,
|
|
261
|
+
* 5 × weekly) ≥ before`. Each clearing steps the total UP by at most one
|
|
262
|
+
* weekly until the pool is back under the cap. Never down, and never above
|
|
263
|
+
* settled plus `4 × weekly` per pool.
|
|
264
|
+
*
|
|
265
|
+
* **Never negative**, and non-decreasing in `now`. A term is skipped — it
|
|
266
|
+
* contributes nothing — when `weeklyInterest` is not finite or is negative,
|
|
267
|
+
* when `accruesFrom` or `epochEnd` is not finite, when `accruesFrom >
|
|
268
|
+
* epochEnd` (inconsistent: the anchor is never after the epoch end), or when
|
|
269
|
+
* an elapsed time overflows. A non-finite `nowSeconds` accrues nothing.
|
|
270
|
+
*
|
|
271
|
+
* **Per pool, because pools clear independently.** One shared anchor accrues
|
|
272
|
+
* a stale pool's share from a close it never had.
|
|
273
|
+
*
|
|
274
|
+
* **Accepted approximation.** `weekly` is today's balance at today's epoch
|
|
275
|
+
* rate. Over a multi-week gap the chain compounds weekly and may apply other
|
|
276
|
+
* epochs' rates, so a long accrual reads slightly LOW. It is a ticking
|
|
277
|
+
* estimate, not a ledger.
|
|
278
|
+
*
|
|
279
|
+
* Callers fail closed upstream: no term for a pool whose weekly interest or
|
|
280
|
+
* clearing is unknown (`epochAccrual` returns `null`), and none for a pool
|
|
281
|
+
* that has stopped — it will never clear again.
|
|
282
|
+
*/
|
|
283
|
+
export declare function accruedInterestSince(accruals: readonly EpochAccrual[], nowSeconds: number): number;
|
|
99
284
|
/**
|
|
100
285
|
* What `amount` earns in a year at a NET rate — the "≈ $Y a year" line.
|
|
101
286
|
* Feed it `netEffectiveApy(...)`, never a gross APY: the result is a lender's
|