/** * Epochs in a year — the single source of truth for every rate conversion in * the SDK and in every consumer that undoes one. * * The subgraph carries a per-epoch `interestRate`; `epochRateToApy` compounds * it into an APY and `apyToEpochRate` inverts exactly that. A second copy of * this number anywhere would recover a different weekly rate and every derived * figure — displayed APYs, net rates, projected interest — would be wrong, so * `DataService.calculateApyForTranche` and `KSULocking.calculateApy` both read * it from here rather than declaring their own. */ export declare const EPOCHS_IN_YEAR = 52.17857; /** * A per-epoch interest rate compounded into an annual rate. * * ``` * apy = (1 + r)^E − 1 * ``` * * This is the exact expression `DataService.calculateApyForTranche` has always * used, kept in its literal `**` form rather than rewritten through * `expm1`/`log1p`: it is the SDK's OWN definition of `tranche.apy`, so its * float behaviour is part of the contract every consumer already calibrated * against. `apyToEpochRate` is the one that must be numerically careful, * because it runs on the result. * * @param epochRate the per-epoch rate as a 0..1 fraction (e.g. `0.003`). * @returns the compounded annual rate as a 0..1 fraction. */ export declare function epochRateToApy(epochRate: number): number; /** * The inverse of `epochRateToApy` — the per-epoch rate an APY was compounded * from. * * `expm1`/`log1p` rather than the literal `(1 + apy) ** (1 / E) - 1`. * Algebraically identical, but the direct form computes a double just above 1 * and subtracts 1 from it, discarding the low bits of a result that is itself * ~1e-3 for a realistic rate. These two never form the intermediate near-1 * value. * * @param apy the compounded annual rate as a 0..1 fraction. * @returns the per-epoch rate as a 0..1 fraction. */ export declare function apyToEpochRate(apy: number): number; /** * The NET Effective Interest Rate — the compounded annual rate a lender * actually earns, after the platform performance fee. * * ``` * r = (1 + grossApy)^(1/E) − 1 // the gross per-epoch rate * net = (1 + r · (1 − feePercent/100))^E − 1 // fee taken each epoch, then compounded * ``` * * `LendingPool._applyTrancheInterest` mints the lender * `interest × (1 − performanceFee)` at every epoch close, and it is that NET * amount which capitalises and earns interest in the following epoch. So the * fee is applied per epoch and the result is re-compounded — not deducted from * the annual figure. * * ⚠️ UNITS — the one thing that must not be got wrong. * `feePercent` is a PERCENTAGE IN 0..100, **not** a 0..1 fraction. * `DataService.getPerformanceFee()` (and `StrategiesFacade.getPerformanceFeePercent()`) * returns the subgraph's `integerToPercentage2(1000)` = `10`, meaning **ten * percent**. It is NOT `0.10`. Treating it as a fraction computes * `r · (1 − 10)` = `−9r` and yields a nonsense negative rate that would render * as a plausible-looking `-…%`, which is why `feePercent > 100` and * `feePercent < 0` both return `NaN` and why the parameter is named * `feePercent` and never `fee`. * * This returns a NUMBER and nothing else. Rendering it — the 2dp convention, * the ` p.a.` suffix, and the fail-closed em-dash for a `NaN` or non-positive * result — is the consumer's job: kasu-ui does it in * `src/features/lending/lib/interest-rate.ts` (`formatEffectiveRate`, * `RATE_UNAVAILABLE`), which now wraps this function instead of restating it. * * @param grossApy compounded GROSS APY as a 0..1 fraction (e.g. `0.22` for * 22%), exactly as the SDK carries it on `tranche.apy` / `tranche.maxApy`. * @param feePercent the chain's performance fee as a percentage, `0..100` * (e.g. `10` for the live 10% fee). * @returns the net compounded annual rate as a 0..1 fraction, or `NaN` when * either input is outside its domain. Callers render `NaN` as "—". */ export declare function netEffectiveApy(grossApy: number, feePercent: number): number;