-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathuser_positions_est.ts
More file actions
143 lines (135 loc) · 5.28 KB
/
user_positions_est.ts
File metadata and controls
143 lines (135 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { Pool } from './pool.js';
import { PoolOracle } from './pool_oracle.js';
import { Positions } from './user_types.js';
export class PositionsEstimate {
constructor(
/**
* The total value of all tokens borrowed from the pool in the pool's oracle denomination
*/
public totalBorrowed: number,
/**
* The total value of all tokens supplied to the pool in the pool's oracle denomination
*/
public totalSupplied: number,
/**
* The total liabilities of the user in the pool's oracle denomination
*/
public totalEffectiveLiabilities: number,
/**
* The total collateral of the user in the pool's oracle denomination
*/
public totalEffectiveCollateral: number,
/**
* The maximum amount of liabilities the user can take on
*/
public borrowCap: number,
/**
* The ratio of liabilities to collateral
*/
public borrowLimit: number,
/**
* The net APY of the user's position
*/
public netApy: number,
/**
* The average estimated APY accrued by all supplied tokens
*/
public supplyApy: number,
/**
* The average estimated APY accrued by all borrowed tokens
*/
public borrowApy: number
) {}
public static build(pool: Pool, poolOracle: PoolOracle, positions: Positions): PositionsEstimate {
const reserve_list = Array.from(pool.reserves.keys());
const liabilities = new Map<string, number>();
const collateral = new Map<string, number>();
const supply = new Map<string, number>();
let totalBorrowed = 0;
let totalSupplied = 0;
let totalEffectiveLiabilities = 0;
let totalEffectiveCollateral = 0;
let supplyApy = 0;
let borrowApy = 0;
// translate ledger liabilities to floating point values
for (const [key, value] of positions.liabilities) {
const reserve = pool.reserves.get(reserve_list[key]);
if (reserve === undefined) {
throw new Error(`Unable to find reserve for liability balance: ${key}`);
}
const oraclePrice = poolOracle.getPriceFloat(reserve.assetId);
if (oraclePrice === undefined) {
throw new Error(
`Unable to find price for liability balance: ${key}, price: ${oraclePrice}`
);
}
const asset_liability = reserve.toAssetFromDTokenFloat(value);
const asset_e_liability = reserve.toEffectiveAssetFromDTokenFloat(value);
const base_liability = asset_liability * oraclePrice;
const base_e_liability = asset_e_liability * oraclePrice;
totalBorrowed += base_liability;
totalEffectiveLiabilities += base_e_liability;
borrowApy += base_liability * reserve.estBorrowApy;
liabilities.set(reserve.assetId, asset_liability);
}
// translate ledger collateral to floating point values
for (const [key, value] of positions.collateral) {
const reserve = pool.reserves.get(reserve_list[key]);
if (reserve === undefined) {
throw new Error(`Unable to find reserve for collateral balance: ${key}`);
}
const oraclePrice = poolOracle.getPriceFloat(reserve.assetId);
if (oraclePrice === undefined) {
throw new Error(
`Unable to find price for collateral balance: ${key}, price: ${oraclePrice}`
);
}
const asset_collateral = reserve.toAssetFromBTokenFloat(value);
const asset_e_collateral = reserve.toEffectiveAssetFromBTokenFloat(value);
const base_collateral = asset_collateral * oraclePrice;
const base_e_collateral = asset_e_collateral * oraclePrice;
totalSupplied += base_collateral;
totalEffectiveCollateral += base_e_collateral;
supplyApy += base_collateral * reserve.estSupplyApy;
collateral.set(reserve.assetId, asset_collateral);
}
// translate ledger supply to floating point values
for (const [key, value] of positions.supply) {
const reserve = pool.reserves.get(reserve_list[key]);
if (reserve === undefined) {
throw new Error(`Unable to find reserve for supply balance: ${key}`);
}
const oraclePrice = poolOracle.getPriceFloat(reserve.assetId);
if (oraclePrice === undefined) {
throw new Error(`Unable to find price for supply balance: ${key}, price: ${oraclePrice}`);
}
const asset_supply = reserve.toAssetFromBTokenFloat(value);
const base_supply = asset_supply * oraclePrice;
totalSupplied += base_supply;
supplyApy += base_supply * reserve.estSupplyApy;
supply.set(reserve.assetId, asset_supply);
}
const borrowCap = totalEffectiveCollateral - totalEffectiveLiabilities;
const borrowLimit =
totalEffectiveCollateral == 0 ? 0 : totalEffectiveLiabilities / totalEffectiveCollateral;
const netApy =
totalSupplied == 0
? // if user has no supplied funds and has borrowed funds (e.g. a bad debt position), the debt will
// be forgiven as bad debt so the net APY is still 0
0
: (supplyApy - borrowApy) / totalSupplied;
supplyApy = totalSupplied == 0 ? 0 : supplyApy / totalSupplied;
borrowApy = totalBorrowed == 0 ? 0 : borrowApy / totalBorrowed;
return new PositionsEstimate(
totalBorrowed,
totalSupplied,
totalEffectiveLiabilities,
totalEffectiveCollateral,
borrowCap,
borrowLimit,
netApy,
supplyApy,
borrowApy
);
}
}