@raac/rpc 1.2.0-beta.13 → 1.2.0-beta.14
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.
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const ethers_1 = require("ethers");
|
|
7
|
+
const chains_1 = __importDefault(require("../../configs/chains"));
|
|
4
8
|
const _helpers_1 = require("./_helpers");
|
|
5
9
|
const artifacts_1 = require("../../utils/artifacts");
|
|
10
|
+
const getContractAddress_1 = __importDefault(require("../../contracts/getContractAddress"));
|
|
11
|
+
const RAY = 10n ** 27n;
|
|
12
|
+
const HALF_RAY = RAY / 2n;
|
|
13
|
+
/** Mirrors WadRayMath.rayMul (half-up rounding). */
|
|
14
|
+
const rayMul = (a, b) => (a * b + HALF_RAY) / RAY;
|
|
15
|
+
/** A RAY-denominated annual rate as a percentage string, e.g. 5e25 -> "5.00". */
|
|
16
|
+
const asPercent = (rate) => (Number(rate) / 1e25).toFixed(2);
|
|
17
|
+
/** A RAY-denominated value as a unit decimal string, e.g. RAY -> "1.000000". */
|
|
18
|
+
const asDecimal = (value) => (Number(value) / 1e27).toFixed(6);
|
|
19
|
+
/**
|
|
20
|
+
* Effective yearly cost of a nominal RAY borrow rate: e^r - 1.
|
|
21
|
+
* The usage index compounds (ReserveLibrary.calculateCompoundedInterest), so the
|
|
22
|
+
* borrow side's effective rate exceeds its nominal rate. The liquidity index
|
|
23
|
+
* accrues linearly, so the supply side has no equivalent gap.
|
|
24
|
+
*/
|
|
25
|
+
const toCompoundedApy = (rate) => Math.expm1(Number(rate) / 1e27);
|
|
6
26
|
async function getLendingPoolInfo(chainId, userAddress, provider) {
|
|
7
27
|
try {
|
|
28
|
+
if (!provider) {
|
|
29
|
+
const rpc = chains_1.default[chainId].rpcs[0];
|
|
30
|
+
provider = new ethers_1.ethers.JsonRpcProvider(rpc);
|
|
31
|
+
}
|
|
8
32
|
const lendingPoolContract = await (0, _helpers_1.getLendingPoolContract)(chainId, provider);
|
|
9
33
|
const handleError = (operation, returnType) => (error) => {
|
|
10
34
|
if (error.code === "BAD_DATA") {
|
|
11
|
-
console.log(`BAD_DATA from ${operation} - Pool empty?`, error.
|
|
35
|
+
console.log(`BAD_DATA from ${operation} - Pool empty?`, error.message);
|
|
12
36
|
return returnType || null;
|
|
13
37
|
}
|
|
14
38
|
throw error;
|
|
@@ -19,85 +43,93 @@ async function getLendingPoolInfo(chainId, userAddress, provider) {
|
|
|
19
43
|
lendingPoolContract.getNormalizedIncome().catch(handleError("getNormalizedIncome", 0n)),
|
|
20
44
|
lendingPoolContract.getNormalizedDebt().catch(handleError("getNormalizedDebt", 0n)),
|
|
21
45
|
]);
|
|
22
|
-
//
|
|
46
|
+
// Reserve state
|
|
23
47
|
const totalLiquidity = reserve?.totalLiquidity ?? 0n;
|
|
24
48
|
const totalUsage = reserve?.totalUsage ?? 0n;
|
|
25
49
|
const liquidityIndex = reserve?.liquidityIndex ?? 0n;
|
|
26
50
|
const usageIndex = reserve?.usageIndex ?? 0n;
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
//
|
|
51
|
+
// Rates as maintained by the pool. These are written by
|
|
52
|
+
// ReserveLibrary.updateInterestRatesAndLiquidity on every operation that moves
|
|
53
|
+
// liquidity or debt, and interest accrues at them until the next one, so they
|
|
54
|
+
// are the rates actually in effect - not a stale snapshot to be recomputed.
|
|
55
|
+
const supplyRate = rateData?.currentLiquidityRate ?? 0n;
|
|
56
|
+
const borrowRate = rateData?.currentUsageRate ?? 0n;
|
|
57
|
+
const utilization = rateData?.currentUtilizationRate ?? 0n;
|
|
58
|
+
const currentProtocolFeeRate = rateData?.currentProtocolFeeRate ?? 0n;
|
|
59
|
+
// Rate curve parameters
|
|
36
60
|
const primeRate = rateData?.primeRate ?? 0n;
|
|
37
61
|
const baseRate = rateData?.baseRate ?? 0n;
|
|
38
62
|
const optimalRate = rateData?.optimalRate ?? 0n;
|
|
39
63
|
const maxRate = rateData?.maxRate ?? 0n;
|
|
40
64
|
const optimalUtilizationRate = rateData?.optimalUtilizationRate ?? 0n;
|
|
41
65
|
const protocolFeeRate = rateData?.protocolFeeRate ?? 0n;
|
|
42
|
-
const pendingProtocolFeeAmount = reserve
|
|
43
|
-
// Compute APY
|
|
44
|
-
let apr;
|
|
45
|
-
if (utilization <= optimalUtilizationRate && optimalUtilizationRate > 0) {
|
|
46
|
-
apr = optimalRate;
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
const excessUtilization = utilization - optimalUtilizationRate;
|
|
50
|
-
const maxExcessUtilization = BigInt(1e27) - optimalUtilizationRate;
|
|
51
|
-
const rateSlope = maxRate - optimalRate;
|
|
52
|
-
const rateIncrease = (excessUtilization * rateSlope) / maxExcessUtilization;
|
|
53
|
-
apr = primeRate + rateIncrease;
|
|
54
|
-
apr = apr > maxRate ? maxRate : apr;
|
|
55
|
-
}
|
|
56
|
-
// compute the APY
|
|
57
|
-
// FIXME: This is not correct
|
|
58
|
-
let apy;
|
|
59
|
-
const grossLiquidityRate = utilization * currentUsageRate / BigInt(1e27);
|
|
60
|
-
const protocolFeeAmount = grossLiquidityRate * protocolFeeRate / BigInt(1e27);
|
|
61
|
-
apy = grossLiquidityRate - protocolFeeAmount;
|
|
62
|
-
console.log("apr", apy);
|
|
66
|
+
const pendingProtocolFeeAmount = await getPendingProtocolFee(chainId, provider, reserve, normalizedIncome);
|
|
63
67
|
let userRedeemable = 0n;
|
|
64
68
|
if (userAddress) {
|
|
65
|
-
//
|
|
69
|
+
// RToken.balanceOf already applies the liquidity index, so it is the
|
|
70
|
+
// redeemable underlying amount - do not scale it again.
|
|
66
71
|
const rTokenAddress = reserve?.reserveRTokenAddress;
|
|
67
72
|
const rTokenABI = (0, artifacts_1.getABI)("rtoken");
|
|
68
73
|
const rTokenContract = new ethers_1.ethers.Contract(rTokenAddress, rTokenABI, provider);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
userRedeemable = (userScaledBalance * liquidityIndex) / BigInt(1e27);
|
|
74
|
+
userRedeemable =
|
|
75
|
+
(await rTokenContract
|
|
76
|
+
.balanceOf(userAddress)
|
|
77
|
+
.catch(handleError("rToken balanceOf", 0n))) ?? 0n;
|
|
74
78
|
}
|
|
75
|
-
|
|
79
|
+
return {
|
|
76
80
|
totalLiquidity: ethers_1.ethers.formatEther(totalLiquidity),
|
|
77
81
|
totalBorrow: ethers_1.ethers.formatEther(totalUsage),
|
|
78
|
-
utilization: (
|
|
79
|
-
liquidityIndex: (
|
|
80
|
-
usageIndex: (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
utilization: asDecimal(utilization),
|
|
83
|
+
liquidityIndex: asDecimal(liquidityIndex),
|
|
84
|
+
usageIndex: asDecimal(usageIndex),
|
|
85
|
+
supplyRate: asPercent(supplyRate),
|
|
86
|
+
borrowRate: asPercent(borrowRate),
|
|
87
|
+
supplyApy: asPercent(supplyRate),
|
|
88
|
+
borrowApy: (toCompoundedApy(borrowRate) * 100).toFixed(2),
|
|
89
|
+
primeRate: asPercent(primeRate),
|
|
90
|
+
baseRate: asPercent(baseRate),
|
|
91
|
+
optimalRate: asPercent(optimalRate),
|
|
92
|
+
maxRate: asPercent(maxRate),
|
|
93
|
+
optimalUtilizationRate: asDecimal(optimalUtilizationRate),
|
|
94
|
+
protocolFeeRate: asPercent(protocolFeeRate),
|
|
95
|
+
currentProtocolFeeRate: asPercent(currentProtocolFeeRate),
|
|
96
|
+
normalizedIncome: asDecimal(normalizedIncome),
|
|
97
|
+
normalizedDebt: asDecimal(normalizedDebt),
|
|
98
|
+
userRedeemable: ethers_1.ethers.formatEther(userRedeemable),
|
|
94
99
|
pendingProtocolFeeAmount: ethers_1.ethers.formatEther(pendingProtocolFeeAmount),
|
|
100
|
+
/** @deprecated use `supplyRate` */
|
|
101
|
+
currentLiquidityRate: asPercent(supplyRate),
|
|
102
|
+
/** @deprecated use `borrowRate` */
|
|
103
|
+
currentUsageRate: asPercent(borrowRate),
|
|
104
|
+
/** @deprecated use `borrowRate` */
|
|
105
|
+
apr: asPercent(borrowRate),
|
|
106
|
+
/** @deprecated use `supplyRate` */
|
|
107
|
+
apy: asPercent(supplyRate),
|
|
95
108
|
};
|
|
96
|
-
return result;
|
|
97
109
|
}
|
|
98
110
|
catch (error) {
|
|
99
111
|
console.error("Error fetching lending pool info:", error);
|
|
100
112
|
throw error;
|
|
101
113
|
}
|
|
102
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolves the protocol fee owed in underlying asset units.
|
|
117
|
+
*
|
|
118
|
+
* Newer pools bank the fee scaled by the liquidity index and expose
|
|
119
|
+
* `getPendingProtocolFee()`, which re-values it at the current index. Older pools
|
|
120
|
+
* store the unscaled amount in the reserve's ninth slot and have no getter, so
|
|
121
|
+
* fall back to reading it directly.
|
|
122
|
+
*/
|
|
123
|
+
async function getPendingProtocolFee(chainId, provider, reserve, normalizedIncome) {
|
|
124
|
+
const stored = reserve?.[8] ?? 0n;
|
|
125
|
+
if (stored === 0n)
|
|
126
|
+
return 0n;
|
|
127
|
+
try {
|
|
128
|
+
const pool = new ethers_1.ethers.Contract((0, getContractAddress_1.default)(chainId, "lendingpool"), ["function getPendingProtocolFee() view returns (uint256)"], provider);
|
|
129
|
+
return await pool.getPendingProtocolFee();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return normalizedIncome > 0n ? rayMul(stored, normalizedIncome) : stored;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
103
135
|
exports.default = getLendingPoolInfo;
|
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
import { Provider } from "ethers";
|
|
2
2
|
import { ChainId } from "../../configs/chains";
|
|
3
|
-
declare function getLendingPoolInfo(chainId: ChainId, userAddress
|
|
3
|
+
declare function getLendingPoolInfo(chainId: ChainId, userAddress?: string, provider?: Provider): Promise<{
|
|
4
4
|
totalLiquidity: string;
|
|
5
5
|
totalBorrow: string;
|
|
6
6
|
utilization: string;
|
|
7
7
|
liquidityIndex: string;
|
|
8
8
|
usageIndex: string;
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
supplyRate: string;
|
|
10
|
+
borrowRate: string;
|
|
11
|
+
supplyApy: string;
|
|
12
|
+
borrowApy: string;
|
|
11
13
|
primeRate: string;
|
|
12
14
|
baseRate: string;
|
|
13
15
|
optimalRate: string;
|
|
14
16
|
maxRate: string;
|
|
15
17
|
optimalUtilizationRate: string;
|
|
16
18
|
protocolFeeRate: string;
|
|
19
|
+
currentProtocolFeeRate: string;
|
|
17
20
|
normalizedIncome: string;
|
|
18
21
|
normalizedDebt: string;
|
|
19
|
-
apy: string;
|
|
20
22
|
userRedeemable: string;
|
|
21
|
-
apr: string;
|
|
22
23
|
pendingProtocolFeeAmount: string;
|
|
24
|
+
/** @deprecated use `supplyRate` */
|
|
25
|
+
currentLiquidityRate: string;
|
|
26
|
+
/** @deprecated use `borrowRate` */
|
|
27
|
+
currentUsageRate: string;
|
|
28
|
+
/** @deprecated use `borrowRate` */
|
|
29
|
+
apr: string;
|
|
30
|
+
/** @deprecated use `supplyRate` */
|
|
31
|
+
apy: string;
|
|
23
32
|
}>;
|
|
24
33
|
export default getLendingPoolInfo;
|