@kasufinance/kasu-sdk 1.0.1

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.
Files changed (219) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.json +90 -0
  3. package/.github/workflows/ci.yml +0 -0
  4. package/.github/workflows/main.yml +43 -0
  5. package/.prettierignore +3 -0
  6. package/.prettierrc +28 -0
  7. package/abis/IClearingCoordinator.abi.json +410 -0
  8. package/abis/IERC20Metadata.abi.json +224 -0
  9. package/abis/IFeeManager.abi.json +66 -0
  10. package/abis/IKSULocking.abi.json +754 -0
  11. package/abis/IKasuAllowList.abi.json +455 -0
  12. package/abis/IKasuController.abi.json +423 -0
  13. package/abis/IKasuNFTs.abi.json +1523 -0
  14. package/abis/IKsuPrice.abi.json +15 -0
  15. package/abis/ILendingPool.abi.json +1431 -0
  16. package/abis/ILendingPoolFactory.abi.json +97 -0
  17. package/abis/ILendingPoolManager.abi.json +1347 -0
  18. package/abis/ILendingPoolTranche.abi.json +1317 -0
  19. package/abis/IPriceFeed.abi.json +1 -0
  20. package/abis/ISystemVariables.abi.json +431 -0
  21. package/abis/IUserLoyaltyRewards.abi.json +288 -0
  22. package/abis/IUserManager.abi.json +321 -0
  23. package/abis/KSULockBonus.abi.json +91 -0
  24. package/abis/KasuPoolExternalTVL.abi.json +812 -0
  25. package/abis/Swapper.abi.json +146 -0
  26. package/copy-abi.ps1 +15 -0
  27. package/dist/bundle.cjs.js +21646 -0
  28. package/dist/bundle.esm.js +21644 -0
  29. package/dist/contracts/IClearingCoordinatorAbi.d.ts +169 -0
  30. package/dist/contracts/IClearingCoordinatorAbi.js +1 -0
  31. package/dist/contracts/IERC20MetadataAbi.d.ts +162 -0
  32. package/dist/contracts/IERC20MetadataAbi.js +1 -0
  33. package/dist/contracts/IFeeManagerAbi.d.ts +96 -0
  34. package/dist/contracts/IFeeManagerAbi.js +1 -0
  35. package/dist/contracts/IKSULockingAbi.d.ts +466 -0
  36. package/dist/contracts/IKSULockingAbi.js +1 -0
  37. package/dist/contracts/IKasuAllowListAbi.d.ts +304 -0
  38. package/dist/contracts/IKasuAllowListAbi.js +1 -0
  39. package/dist/contracts/IKasuControllerAbi.d.ts +309 -0
  40. package/dist/contracts/IKasuControllerAbi.js +1 -0
  41. package/dist/contracts/IKasuNFTsAbi.d.ts +1121 -0
  42. package/dist/contracts/IKasuNFTsAbi.js +1 -0
  43. package/dist/contracts/IKsuPriceAbi.d.ts +42 -0
  44. package/dist/contracts/IKsuPriceAbi.js +1 -0
  45. package/dist/contracts/ILendingPoolAbi.d.ts +968 -0
  46. package/dist/contracts/ILendingPoolAbi.js +1 -0
  47. package/dist/contracts/ILendingPoolFactoryAbi.d.ts +103 -0
  48. package/dist/contracts/ILendingPoolFactoryAbi.js +1 -0
  49. package/dist/contracts/ILendingPoolManagerAbi.d.ts +779 -0
  50. package/dist/contracts/ILendingPoolManagerAbi.js +1 -0
  51. package/dist/contracts/ILendingPoolTrancheAbi.d.ts +752 -0
  52. package/dist/contracts/ILendingPoolTrancheAbi.js +1 -0
  53. package/dist/contracts/ISystemVariablesAbi.d.ts +378 -0
  54. package/dist/contracts/ISystemVariablesAbi.js +1 -0
  55. package/dist/contracts/IUserLoyaltyRewardsAbi.d.ts +248 -0
  56. package/dist/contracts/IUserLoyaltyRewardsAbi.js +1 -0
  57. package/dist/contracts/IUserManagerAbi.d.ts +270 -0
  58. package/dist/contracts/IUserManagerAbi.js +1 -0
  59. package/dist/contracts/KSULockBonusAbi.d.ts +61 -0
  60. package/dist/contracts/KSULockBonusAbi.js +1 -0
  61. package/dist/contracts/KasuPoolExternalTVLAbi.d.ts +411 -0
  62. package/dist/contracts/KasuPoolExternalTVLAbi.js +1 -0
  63. package/dist/contracts/SwapperAbi.d.ts +120 -0
  64. package/dist/contracts/SwapperAbi.js +1 -0
  65. package/dist/contracts/common.d.ts +21 -0
  66. package/dist/contracts/common.js +1 -0
  67. package/dist/contracts/factories/IClearingCoordinatorAbi__factory.d.ts +320 -0
  68. package/dist/contracts/factories/IClearingCoordinatorAbi__factory.js +423 -0
  69. package/dist/contracts/factories/IERC20MetadataAbi__factory.d.ts +178 -0
  70. package/dist/contracts/factories/IERC20MetadataAbi__factory.js +237 -0
  71. package/dist/contracts/factories/IFeeManagerAbi__factory.d.ts +59 -0
  72. package/dist/contracts/factories/IFeeManagerAbi__factory.js +79 -0
  73. package/dist/contracts/factories/IKSULockingAbi__factory.d.ts +588 -0
  74. package/dist/contracts/factories/IKSULockingAbi__factory.js +767 -0
  75. package/dist/contracts/factories/IKasuAllowListAbi__factory.d.ts +354 -0
  76. package/dist/contracts/factories/IKasuAllowListAbi__factory.js +468 -0
  77. package/dist/contracts/factories/IKasuControllerAbi__factory.d.ts +339 -0
  78. package/dist/contracts/factories/IKasuControllerAbi__factory.js +436 -0
  79. package/dist/contracts/factories/IKasuNFTsAbi__factory.d.ts +1629 -0
  80. package/dist/contracts/factories/IKasuNFTsAbi__factory.js +2108 -0
  81. package/dist/contracts/factories/IKsuPriceAbi__factory.d.ts +18 -0
  82. package/dist/contracts/factories/IKsuPriceAbi__factory.js +28 -0
  83. package/dist/contracts/factories/ILendingPoolAbi__factory.d.ts +1109 -0
  84. package/dist/contracts/factories/ILendingPoolAbi__factory.js +1444 -0
  85. package/dist/contracts/factories/ILendingPoolFactoryAbi__factory.d.ts +81 -0
  86. package/dist/contracts/factories/ILendingPoolFactoryAbi__factory.js +110 -0
  87. package/dist/contracts/factories/ILendingPoolManagerAbi__factory.d.ts +1045 -0
  88. package/dist/contracts/factories/ILendingPoolManagerAbi__factory.js +1360 -0
  89. package/dist/contracts/factories/ILendingPoolTrancheAbi__factory.d.ts +1015 -0
  90. package/dist/contracts/factories/ILendingPoolTrancheAbi__factory.js +1330 -0
  91. package/dist/contracts/factories/ISystemVariablesAbi__factory.d.ts +338 -0
  92. package/dist/contracts/factories/ISystemVariablesAbi__factory.js +444 -0
  93. package/dist/contracts/factories/IUserLoyaltyRewardsAbi__factory.d.ts +230 -0
  94. package/dist/contracts/factories/IUserLoyaltyRewardsAbi__factory.js +301 -0
  95. package/dist/contracts/factories/IUserManagerAbi__factory.d.ts +250 -0
  96. package/dist/contracts/factories/IUserManagerAbi__factory.js +334 -0
  97. package/dist/contracts/factories/KSULockBonusAbi__factory.d.ts +76 -0
  98. package/dist/contracts/factories/KSULockBonusAbi__factory.js +104 -0
  99. package/dist/contracts/factories/KasuPoolExternalTVLAbi__factory.d.ts +631 -0
  100. package/dist/contracts/factories/KasuPoolExternalTVLAbi__factory.js +825 -0
  101. package/dist/contracts/factories/SwapperAbi__factory.d.ts +120 -0
  102. package/dist/contracts/factories/SwapperAbi__factory.js +159 -0
  103. package/dist/contracts/factories/index.d.ts +18 -0
  104. package/dist/contracts/factories/index.js +21 -0
  105. package/dist/contracts/index.d.ts +37 -0
  106. package/dist/contracts/index.js +19 -0
  107. package/dist/index.d.ts +17 -0
  108. package/dist/index.js +16 -0
  109. package/dist/sdk-config.d.ts +22 -0
  110. package/dist/sdk-config.js +9 -0
  111. package/dist/services/DataService/data-service.d.ts +37 -0
  112. package/dist/services/DataService/data-service.js +586 -0
  113. package/dist/services/DataService/directus-types.d.ts +187 -0
  114. package/dist/services/DataService/directus-types.js +1 -0
  115. package/dist/services/DataService/queries.d.ts +7 -0
  116. package/dist/services/DataService/queries.js +158 -0
  117. package/dist/services/DataService/subgraph-types.d.ts +95 -0
  118. package/dist/services/DataService/subgraph-types.js +1 -0
  119. package/dist/services/DataService/types.d.ts +169 -0
  120. package/dist/services/DataService/types.js +1 -0
  121. package/dist/services/Locking/locking.d.ts +61 -0
  122. package/dist/services/Locking/locking.js +344 -0
  123. package/dist/services/Locking/queries.d.ts +10 -0
  124. package/dist/services/Locking/queries.js +108 -0
  125. package/dist/services/Locking/types.d.ts +117 -0
  126. package/dist/services/Locking/types.js +1 -0
  127. package/dist/services/Portfolio/portfolio.d.ts +22 -0
  128. package/dist/services/Portfolio/portfolio.js +325 -0
  129. package/dist/services/Portfolio/queries.d.ts +2 -0
  130. package/dist/services/Portfolio/queries.js +164 -0
  131. package/dist/services/Portfolio/types.d.ts +206 -0
  132. package/dist/services/Portfolio/types.js +1 -0
  133. package/dist/services/Swapper/swapper.d.ts +11 -0
  134. package/dist/services/Swapper/swapper.js +97 -0
  135. package/dist/services/Swapper/types.d.ts +51 -0
  136. package/dist/services/Swapper/types.js +1 -0
  137. package/dist/services/UserLending/helper.d.ts +2 -0
  138. package/dist/services/UserLending/helper.js +16 -0
  139. package/dist/services/UserLending/queries.d.ts +8 -0
  140. package/dist/services/UserLending/queries.js +188 -0
  141. package/dist/services/UserLending/subgraph-types.d.ts +147 -0
  142. package/dist/services/UserLending/subgraph-types.js +6 -0
  143. package/dist/services/UserLending/types.d.ts +102 -0
  144. package/dist/services/UserLending/types.js +13 -0
  145. package/dist/services/UserLending/user-lending.d.ts +55 -0
  146. package/dist/services/UserLending/user-lending.js +490 -0
  147. package/dist/services/shared.d.ts +1 -0
  148. package/dist/services/shared.js +11 -0
  149. package/dist/tests/sample.test.d.ts +1 -0
  150. package/dist/tests/sample.test.js +32 -0
  151. package/index.ts +2 -0
  152. package/jest-config.ts +9 -0
  153. package/jest.config.js +8 -0
  154. package/package.json +49 -0
  155. package/rollup.config.js +45 -0
  156. package/src/contracts/IClearingCoordinatorAbi.ts +406 -0
  157. package/src/contracts/IERC20MetadataAbi.ts +364 -0
  158. package/src/contracts/IFeeManagerAbi.ts +182 -0
  159. package/src/contracts/IKSULockingAbi.ts +965 -0
  160. package/src/contracts/IKasuAllowListAbi.ts +605 -0
  161. package/src/contracts/IKasuControllerAbi.ts +703 -0
  162. package/src/contracts/IKasuNFTsAbi.ts +2744 -0
  163. package/src/contracts/IKsuPriceAbi.ts +87 -0
  164. package/src/contracts/ILendingPoolAbi.ts +2081 -0
  165. package/src/contracts/ILendingPoolFactoryAbi.ts +161 -0
  166. package/src/contracts/ILendingPoolManagerAbi.ts +1917 -0
  167. package/src/contracts/ILendingPoolTrancheAbi.ts +1911 -0
  168. package/src/contracts/ISystemVariablesAbi.ts +908 -0
  169. package/src/contracts/IUserLoyaltyRewardsAbi.ts +544 -0
  170. package/src/contracts/IUserManagerAbi.ts +612 -0
  171. package/src/contracts/KSULockBonusAbi.ts +124 -0
  172. package/src/contracts/KasuPoolExternalTVLAbi.ts +1071 -0
  173. package/src/contracts/SwapperAbi.ts +266 -0
  174. package/src/contracts/common.ts +44 -0
  175. package/src/contracts/factories/IClearingCoordinatorAbi__factory.ts +438 -0
  176. package/src/contracts/factories/IERC20MetadataAbi__factory.ts +248 -0
  177. package/src/contracts/factories/IFeeManagerAbi__factory.ts +90 -0
  178. package/src/contracts/factories/IKSULockingAbi__factory.ts +778 -0
  179. package/src/contracts/factories/IKasuAllowListAbi__factory.ts +479 -0
  180. package/src/contracts/factories/IKasuControllerAbi__factory.ts +447 -0
  181. package/src/contracts/factories/IKasuNFTsAbi__factory.ts +2116 -0
  182. package/src/contracts/factories/IKsuPriceAbi__factory.ts +36 -0
  183. package/src/contracts/factories/ILendingPoolAbi__factory.ts +1455 -0
  184. package/src/contracts/factories/ILendingPoolFactoryAbi__factory.ts +125 -0
  185. package/src/contracts/factories/ILendingPoolManagerAbi__factory.ts +1375 -0
  186. package/src/contracts/factories/ILendingPoolTrancheAbi__factory.ts +1345 -0
  187. package/src/contracts/factories/ISystemVariablesAbi__factory.ts +455 -0
  188. package/src/contracts/factories/IUserLoyaltyRewardsAbi__factory.ts +316 -0
  189. package/src/contracts/factories/IUserManagerAbi__factory.ts +345 -0
  190. package/src/contracts/factories/KSULockBonusAbi__factory.ts +115 -0
  191. package/src/contracts/factories/KasuPoolExternalTVLAbi__factory.ts +840 -0
  192. package/src/contracts/factories/SwapperAbi__factory.ts +167 -0
  193. package/src/contracts/factories/index.ts +21 -0
  194. package/src/contracts/index.ts +40 -0
  195. package/src/index.ts +27 -0
  196. package/src/sdk-config.ts +35 -0
  197. package/src/services/DataService/data-service.ts +1017 -0
  198. package/src/services/DataService/directus-types.ts +199 -0
  199. package/src/services/DataService/queries.ts +165 -0
  200. package/src/services/DataService/subgraph-types.ts +104 -0
  201. package/src/services/DataService/types.ts +184 -0
  202. package/src/services/Locking/locking.ts +541 -0
  203. package/src/services/Locking/queries.ts +118 -0
  204. package/src/services/Locking/types.ts +141 -0
  205. package/src/services/Portfolio/portfolio.ts +593 -0
  206. package/src/services/Portfolio/queries.ts +166 -0
  207. package/src/services/Portfolio/types.ts +220 -0
  208. package/src/services/Swapper/swapper.ts +158 -0
  209. package/src/services/Swapper/types.ts +54 -0
  210. package/src/services/UserLending/helper.ts +28 -0
  211. package/src/services/UserLending/queries.ts +196 -0
  212. package/src/services/UserLending/subgraph-types.ts +173 -0
  213. package/src/services/UserLending/types.ts +123 -0
  214. package/src/services/UserLending/user-lending.ts +933 -0
  215. package/src/services/shared.ts +11 -0
  216. package/src/tests/sample.test.ts +44 -0
  217. package/tsconfig.json +27 -0
  218. package/tsconfig.tsbuildinfo +1 -0
  219. package/versioner.sh +6 -0
@@ -0,0 +1,1017 @@
1
+ import {
2
+ authentication,
3
+ AuthenticationClient,
4
+ createDirectus,
5
+ DirectusClient,
6
+ readItems,
7
+ readSingleton,
8
+ rest,
9
+ RestClient,
10
+ } from '@directus/sdk';
11
+ import { Provider } from '@ethersproject/abstract-provider';
12
+ import { Signer } from 'ethers';
13
+ import { formatUnits } from 'ethers/lib/utils';
14
+ import { GraphQLClient } from 'graphql-request';
15
+
16
+ import {
17
+ KasuPoolExternalTVLAbi,
18
+ KasuPoolExternalTVLAbi__factory,
19
+ } from '../../contracts';
20
+ import { SdkConfig } from '../../sdk-config';
21
+ import { getSystemVariablesQuery } from '../Locking/queries';
22
+ import { SystemVariables } from '../Locking/types';
23
+ import { filterArray } from '../shared';
24
+
25
+ import {
26
+ BadAndDoubtfulDebtsItems,
27
+ DirectusSchema,
28
+ FinancialReportingDocumentsItemsDirectus,
29
+ KeyCreditMetricsDirectus,
30
+ NftBoostDirectus,
31
+ PlatformOverviewDirectus,
32
+ PoolDelegateProfileAndHistoryDirectus,
33
+ PoolOverviewDirectus,
34
+ PoolRepaymentItemsDirectus,
35
+ RiskManagementGroupDirectus,
36
+ } from './directus-types';
37
+ import {
38
+ getAllTrancheConfigurationsQuery,
39
+ getAllTranchesQuery,
40
+ getLendingPoolWithdrawalAndDepositsQuery,
41
+ getPlumeTvl,
42
+ getPoolNameQuery,
43
+ getPoolOverviewQuery,
44
+ } from './queries';
45
+ import {
46
+ LendingPoolConfigurationSubgraph,
47
+ LendingPoolSubgraph,
48
+ LendingPoolSubgraphReturn,
49
+ LendingPoolWithdrawalAndDepositSubgraph,
50
+ PlumeSubgraphReturn,
51
+ TrancheConfigurationSubgraphResult,
52
+ TrancheSubgraphResult,
53
+ } from './subgraph-types';
54
+ import {
55
+ BadAndDoubtfulDebts,
56
+ FinancialReportingDocuments,
57
+ LendingTotals,
58
+ PoolCreditMetrics,
59
+ PoolDelegateProfileAndHistory,
60
+ PoolOverview,
61
+ PoolRepayment,
62
+ PoolTranche,
63
+ RiskManagement,
64
+ RiskManagementItem,
65
+ TrancheData,
66
+ } from './types';
67
+
68
+ export class DataService {
69
+ private readonly _graph: GraphQLClient;
70
+ private readonly _plumeGraph: GraphQLClient;
71
+ private readonly _externalTvlAbi: KasuPoolExternalTVLAbi;
72
+ private readonly _directus: DirectusClient<DirectusSchema> &
73
+ AuthenticationClient<DirectusSchema> &
74
+ RestClient<DirectusSchema>;
75
+ private _directusPoolOverview: PoolOverviewDirectus[] | undefined;
76
+ private _plumeTvl = new Map<string, string>();
77
+
78
+ constructor(
79
+ private _kasuConfig: SdkConfig,
80
+ signerOrProvider: Signer | Provider,
81
+ ) {
82
+ this._externalTvlAbi = KasuPoolExternalTVLAbi__factory.connect(
83
+ _kasuConfig.contracts.ExternalTVL,
84
+ signerOrProvider,
85
+ );
86
+ this._graph = new GraphQLClient(_kasuConfig.subgraphUrl);
87
+ this._plumeGraph = new GraphQLClient(_kasuConfig.plumeSubgraphUrl);
88
+
89
+ this._directus = createDirectus<DirectusSchema>(_kasuConfig.directusUrl)
90
+ .with(authentication())
91
+ .with(rest());
92
+ }
93
+
94
+ private getUrlFromFile(fileName: string): string {
95
+ return `${this._kasuConfig.directusUrl}assets/${fileName}`;
96
+ }
97
+
98
+ calculatePoolCapacity(
99
+ poolCapacities: number[],
100
+ poolCapacityPercentages: number[],
101
+ index: number,
102
+ spillOver: number,
103
+ lendingPoolSubgraph: LendingPoolSubgraph,
104
+ lendingPoolConfig: LendingPoolConfigurationSubgraph,
105
+ ): { poolCapacity: number[]; poolCapacityPercentage: number[] } {
106
+ const desiredDrawAmount = lendingPoolConfig.desiredDrawAmount; // subgraph
107
+ const desiredTrancheRatio =
108
+ lendingPoolConfig.tranchesConfig[index].desiredRatio;
109
+
110
+ const targetDrawAmount =
111
+ parseFloat(desiredDrawAmount) *
112
+ (parseFloat(desiredTrancheRatio) / 100);
113
+
114
+ const pendingDeposits =
115
+ parseFloat(
116
+ lendingPoolSubgraph.pendingPool.totalPendingDepositAmounts[
117
+ index
118
+ ],
119
+ ) - spillOver;
120
+
121
+ const balance = parseFloat(lendingPoolSubgraph.tranches[index].balance); // subgraph
122
+
123
+ const targetAmount = balance + targetDrawAmount;
124
+
125
+ const remainingCapacity = Math.max(
126
+ targetDrawAmount - pendingDeposits,
127
+ 0,
128
+ );
129
+
130
+ const remainingCapacityPercentage =
131
+ targetAmount != 0 ? remainingCapacity / targetAmount : 0;
132
+
133
+ const remainingCapacitySpillover = Math.min(
134
+ targetDrawAmount - pendingDeposits,
135
+ 0,
136
+ );
137
+
138
+ poolCapacities.push(remainingCapacity);
139
+ poolCapacityPercentages.push(remainingCapacityPercentage);
140
+ if (index === lendingPoolConfig.tranchesConfig.length - 1) {
141
+ return {
142
+ poolCapacity: poolCapacities,
143
+ poolCapacityPercentage: poolCapacityPercentages,
144
+ };
145
+ }
146
+ return this.calculatePoolCapacity(
147
+ poolCapacities,
148
+ poolCapacityPercentages,
149
+ index + 1,
150
+ remainingCapacitySpillover,
151
+ lendingPoolSubgraph,
152
+ lendingPoolConfig,
153
+ );
154
+ }
155
+
156
+ calculateApyForTranche(interestRate: string): number {
157
+ const EPOCHS_IN_YEAR = 52.17857;
158
+ return (1 + parseFloat(interestRate)) ** EPOCHS_IN_YEAR - 1;
159
+ }
160
+
161
+ async getPlatformOverview(): Promise<PlatformOverviewDirectus> {
162
+ return await this._directus.request(readSingleton('PlatformOverview'));
163
+ }
164
+
165
+ async getNftBoost(): Promise<Omit<NftBoostDirectus, 'id'>> {
166
+ return await this._directus.request(readSingleton('NftBoost'));
167
+ }
168
+
169
+ async getOffChainTvl(poolIds: string[]): Promise<Map<string, string>> {
170
+ const tvlMap = new Map<string, string>();
171
+
172
+ try {
173
+ const results = await Promise.all(
174
+ poolIds.map(
175
+ async (id) =>
176
+ [
177
+ id,
178
+ await this._externalTvlAbi.externalTVLOfPool(id),
179
+ ] as const,
180
+ ),
181
+ );
182
+
183
+ for (const [id, tvl] of results) {
184
+ tvlMap.set(id, formatUnits(tvl, 6));
185
+ }
186
+ } catch (error) {
187
+ console.error('getOffChainTvl :', error);
188
+ }
189
+
190
+ return tvlMap;
191
+ }
192
+
193
+ async getPoolOverview(
194
+ epochId: string,
195
+ id_in?: string[],
196
+ ): Promise<PoolOverview[]> {
197
+ const trancheNames: string[][] = [
198
+ ['Senior'],
199
+ ['Junior', 'Senior'],
200
+ ['Junior', 'Mezzanine', 'Senior'],
201
+ ];
202
+
203
+ const poolOverviewResults: LendingPoolSubgraphReturn =
204
+ await this._graph.request(getPoolOverviewQuery(id_in), {
205
+ unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
206
+ epochId,
207
+ });
208
+
209
+ if (!this._plumeTvl.size) {
210
+ const plumeResults: PlumeSubgraphReturn =
211
+ await this._plumeGraph.request(getPlumeTvl);
212
+
213
+ for (const pool of plumeResults.lendingPools) {
214
+ this._plumeTvl.set(pool.id, pool.balance);
215
+ }
216
+ }
217
+
218
+ if (!this._directusPoolOverview) {
219
+ this._directusPoolOverview = await this._directus.request(
220
+ readItems('PoolOverview', {
221
+ filter: {
222
+ enabled: {
223
+ _eq: true,
224
+ },
225
+ },
226
+ }),
227
+ );
228
+ }
229
+
230
+ const offchainTvlMap = await this.getOffChainTvl(
231
+ poolOverviewResults.lendingPools.map(({ id }) => id),
232
+ );
233
+
234
+ const retn: PoolOverview[] = [];
235
+ for (const lendingPoolSubgraph of poolOverviewResults.lendingPools) {
236
+ const lendingPoolDirectus: PoolOverviewDirectus | undefined =
237
+ this._directusPoolOverview.find(
238
+ (r) => r.id.toLowerCase() == lendingPoolSubgraph.id,
239
+ );
240
+
241
+ const lendingPoolConfig = lendingPoolSubgraph.configuration;
242
+
243
+ if (!lendingPoolDirectus) {
244
+ console.warn(
245
+ "Couldn't find directus pool for id: ",
246
+ lendingPoolSubgraph.id,
247
+ );
248
+ continue;
249
+ }
250
+ const poolCapacities = this.calculatePoolCapacity(
251
+ [],
252
+ [],
253
+ 0,
254
+ 0,
255
+ lendingPoolSubgraph,
256
+ lendingPoolConfig,
257
+ );
258
+ const tranches: TrancheData[] = lendingPoolSubgraph.tranches
259
+ .map((tranche) => {
260
+ const trancheConfig =
261
+ lendingPoolSubgraph.configuration.tranchesConfig.find(
262
+ (r) => r.id == tranche.id,
263
+ );
264
+ if (!trancheConfig) {
265
+ console.warn(
266
+ "Couldn't find tranche config for id: ",
267
+ tranche.id,
268
+ );
269
+ return null;
270
+ }
271
+
272
+ const interestUpdates =
273
+ trancheConfig.lendingPoolTrancheInterestRateUpdates;
274
+
275
+ const interestRate = interestUpdates.length
276
+ ? interestUpdates[0].epochInterestRate
277
+ : trancheConfig.interestRate;
278
+
279
+ const baseApy = this.calculateApyForTranche(interestRate);
280
+
281
+ let minApy = baseApy;
282
+ let maxApy = baseApy;
283
+
284
+ const fixedTermConfig =
285
+ trancheConfig.lendingPoolTrancheFixedTermConfigs.map(
286
+ (fixedTermConfig) => {
287
+ const fixedTermApy =
288
+ this.calculateApyForTranche(
289
+ fixedTermConfig.epochInterestRate,
290
+ );
291
+
292
+ minApy = Math.min(minApy, fixedTermApy);
293
+ maxApy = Math.max(maxApy, fixedTermApy);
294
+
295
+ return {
296
+ configId: fixedTermConfig.configId,
297
+ apy: fixedTermApy.toString(),
298
+ epochLockDuration:
299
+ fixedTermConfig.epochLockDuration,
300
+ epochInterestRate:
301
+ fixedTermConfig.epochInterestRate,
302
+ fixedTermDepositStatus:
303
+ fixedTermConfig.fixedTermDepositStatus,
304
+ fixedTermDepositAllowlist:
305
+ fixedTermConfig.fixedTermDepositAllowlist.map(
306
+ (allowList) => ({
307
+ isAllowlisted:
308
+ allowList.isAllowlisted,
309
+ userId: allowList.user.id,
310
+ }),
311
+ ),
312
+ };
313
+ },
314
+ );
315
+
316
+ const averageApy = fixedTermConfig.length
317
+ ? fixedTermConfig.reduce(
318
+ (total, cur) => (total += parseFloat(cur.apy)),
319
+ 0,
320
+ ) / fixedTermConfig.length
321
+ : baseApy;
322
+
323
+ return {
324
+ id: tranche.id,
325
+ apy: baseApy.toString(),
326
+ minApy: minApy.toString(),
327
+ maxApy: maxApy.toString(),
328
+ averageApy: averageApy.toString(),
329
+ interestRate,
330
+ maximumDeposit: trancheConfig.maxDepositAmount,
331
+ minimumDeposit: trancheConfig.minDepositAmount,
332
+ poolCapacityPercentage:
333
+ poolCapacities.poolCapacityPercentage[
334
+ parseInt(tranche.orderId)
335
+ ].toString(),
336
+ poolCapacity:
337
+ poolCapacities.poolCapacity[
338
+ parseInt(tranche.orderId)
339
+ ].toString(),
340
+ name: trancheNames[
341
+ lendingPoolSubgraph.tranches.length - 1
342
+ ][parseInt(tranche.orderId)],
343
+ fixedTermConfig,
344
+ };
345
+ })
346
+ .filter((tranche) => tranche !== null);
347
+
348
+ const poolCapacitySum = poolCapacities.poolCapacity.reduce(
349
+ (a, b) => a + b,
350
+ 0,
351
+ );
352
+
353
+ const poolCapacityPercentageSum =
354
+ poolCapacities.poolCapacityPercentage.reduce(
355
+ (a, b) => a + b,
356
+ 0,
357
+ ) / poolCapacities.poolCapacity.length;
358
+
359
+ const trancheBalanceSum = lendingPoolSubgraph.tranches.reduce(
360
+ (a, b) => a + parseFloat(b.balance),
361
+ 0,
362
+ );
363
+
364
+ let averageApy = 0;
365
+ for (const tranche of lendingPoolSubgraph.tranches) {
366
+ const trancheData = tranches.find(
367
+ (r) => r.id.toLowerCase() == tranche.id,
368
+ );
369
+ if (!trancheData) {
370
+ console.warn(
371
+ "Couldn't find tranche directus for id: ",
372
+ tranche.id,
373
+ );
374
+ continue;
375
+ }
376
+ const weight =
377
+ trancheBalanceSum == 0
378
+ ? 0
379
+ : parseFloat(tranche.balance) / trancheBalanceSum;
380
+ averageApy += parseFloat(trancheData.averageApy) * weight;
381
+ }
382
+
383
+ const plumeTvl =
384
+ lendingPoolDirectus.plumeStrategy &&
385
+ this._plumeTvl.has(lendingPoolDirectus.plumeStrategy)
386
+ ? this._plumeTvl.get(lendingPoolDirectus.plumeStrategy) ??
387
+ '0'
388
+ : '0';
389
+
390
+ const offChainTvl =
391
+ offchainTvlMap.get(lendingPoolSubgraph.id) ?? '0';
392
+
393
+ const poolOverview: PoolOverview = {
394
+ id: lendingPoolSubgraph.id,
395
+ security: lendingPoolDirectus.security,
396
+ enabled: lendingPoolDirectus.enabled,
397
+ isOversubscribed: lendingPoolDirectus.oversubscribed,
398
+ apy: averageApy,
399
+ description: lendingPoolDirectus.description,
400
+ liteDescription: lendingPoolDirectus.liteDescription,
401
+ thumbnailImageUrl: this.getUrlFromFile(
402
+ lendingPoolDirectus.thumbnailImage,
403
+ ),
404
+ bannerImageUrl: this.getUrlFromFile(
405
+ lendingPoolDirectus.bannerImage,
406
+ ),
407
+ strategyDeckUrl: this.getUrlFromFile(
408
+ lendingPoolDirectus.strategyDeck,
409
+ ),
410
+ assetClass: lendingPoolDirectus.assetClass,
411
+ industryExposure: lendingPoolDirectus.industryExposure,
412
+ poolApyStructure: lendingPoolDirectus.poolApyStructure,
413
+ apyExpiryDate: lendingPoolDirectus.apyExpiryDate,
414
+ poolInvestmentTerm: lendingPoolDirectus.poolInvestmentTerm,
415
+ loanStructure: lendingPoolDirectus.loanStructure,
416
+ poolName:
417
+ lendingPoolDirectus.poolName ?? lendingPoolSubgraph.name,
418
+ subheading: lendingPoolDirectus.subheading,
419
+ totalValueLocked: {
420
+ total: (
421
+ parseFloat(lendingPoolSubgraph.balance) +
422
+ parseFloat(plumeTvl) +
423
+ parseFloat(offChainTvl)
424
+ ).toString(),
425
+ offchain: offChainTvl,
426
+ plume: plumeTvl,
427
+ },
428
+ loansUnderManagement: lendingPoolDirectus.loansUnderManagement,
429
+ yieldEarned: lendingPoolSubgraph.totalUserInterestAmount,
430
+ poolCapacity: poolCapacitySum.toString(),
431
+ poolCapacityPercentage: poolCapacityPercentageSum.toString(),
432
+ activeLoans: lendingPoolDirectus.activeLoans,
433
+ loanFundsOriginated: lendingPoolDirectus.loanFundsOriginated,
434
+ tranches: tranches,
435
+ isActive: !lendingPoolSubgraph.isStopped,
436
+ requestEpochsInAdvance:
437
+ lendingPoolSubgraph.configuration
438
+ .lendingPoolWithdrawalConfig.requestEpochsInAdvance,
439
+ };
440
+
441
+ // show only enabled pools from cms
442
+ if (poolOverview.enabled) {
443
+ retn.push(poolOverview);
444
+ }
445
+ }
446
+
447
+ return retn;
448
+ }
449
+
450
+ async getPerformanceFee(): Promise<number> {
451
+ const systemVariables: SystemVariables = await this._graph.request(
452
+ getSystemVariablesQuery,
453
+ );
454
+
455
+ return parseFloat(systemVariables.systemVariables.performanceFee);
456
+ }
457
+
458
+ async getRiskManagement(id_in?: string[]): Promise<RiskManagement[]> {
459
+ const [
460
+ resultDirectusRiskManagement,
461
+ resultDirectusRiskManagementItem,
462
+ resultDirectusRiskManagementGroups,
463
+ ] = await Promise.all([
464
+ this._directus.request(readItems('RiskManagement')),
465
+ this._directus.request(readItems('RiskManagementItems')),
466
+ this._directus.request(readItems('RiskManagementGroups')),
467
+ ]);
468
+
469
+ const groupMapper: Partial<
470
+ Record<string, RiskManagementGroupDirectus>
471
+ > = resultDirectusRiskManagementGroups.reduce(
472
+ (acc, cur) => ({ ...acc, [cur.name]: cur }),
473
+ {},
474
+ );
475
+
476
+ const itemMapper: Partial<Record<string, RiskManagementItem>> =
477
+ resultDirectusRiskManagementItem.reduce((acc, cur) => {
478
+ const groupName = groupMapper[cur.group.key]?.name;
479
+
480
+ if (!groupName) return acc;
481
+
482
+ return {
483
+ ...acc,
484
+ [cur.name]: {
485
+ ...cur,
486
+ group: groupName,
487
+ },
488
+ };
489
+ }, {});
490
+
491
+ const riskManagement = resultDirectusRiskManagement.map((risk) => {
492
+ const items = risk.riskManagementItems
493
+ .map((data) => {
494
+ const { riskManagementItem, ...rest } = data;
495
+
496
+ const item = itemMapper[riskManagementItem.key];
497
+
498
+ if (!item) return null;
499
+
500
+ return {
501
+ ...rest,
502
+ ...item,
503
+ };
504
+ })
505
+ .filter((item) => item !== null);
506
+
507
+ return {
508
+ id: risk.id,
509
+ poolIdFK: risk.poolIdFK.toLowerCase(),
510
+ items,
511
+ riskPerformance: {
512
+ id: risk.id,
513
+ firstLossCapital: risk.firstLossCapital,
514
+ poolLossRate: risk.poolLossRate,
515
+ independentRiskScore: risk.independentRiskScore,
516
+ communityRating: risk.communityRating,
517
+ },
518
+ };
519
+ });
520
+
521
+ return filterArray(riskManagement, id_in);
522
+ }
523
+
524
+ async getPoolDelegateProfileAndHistory(
525
+ id_in?: string[],
526
+ ): Promise<PoolDelegateProfileAndHistory[]> {
527
+ const poolDelegateProfileAndHistoryDirectus: PoolDelegateProfileAndHistoryDirectus[] =
528
+ (await this._directus.request(
529
+ readItems('PoolDelegateProfileAndHistory', {
530
+ // @ts-expect-error this is correct and works
531
+ fields: ['*', { otherPools: ['*'] }],
532
+ }),
533
+ )) as unknown as PoolDelegateProfileAndHistoryDirectus[];
534
+
535
+ const [poolNames, directusPoolNames] = await Promise.all([
536
+ this._graph.request<{
537
+ lendingPools: Pick<
538
+ LendingPoolSubgraph,
539
+ 'name' | 'id' | 'isStopped'
540
+ >[];
541
+ }>(getPoolNameQuery, {
542
+ ids: poolDelegateProfileAndHistoryDirectus.flatMap((directus) =>
543
+ directus.otherPools.map(
544
+ (delegate) => delegate.PoolOverview_id,
545
+ ),
546
+ ),
547
+ unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
548
+ }),
549
+ this._directus.request(
550
+ readItems('PoolOverview', {
551
+ fields: ['id', 'poolName', 'subheading', 'oversubscribed'],
552
+ }),
553
+ ),
554
+ ]);
555
+
556
+ const retn: PoolDelegateProfileAndHistory[] = [];
557
+ for (const data of poolDelegateProfileAndHistoryDirectus) {
558
+ const otherKASUPools: PoolDelegateProfileAndHistory['otherKASUPools'] =
559
+ [];
560
+
561
+ for (const otherPool of data.otherPools) {
562
+ const found = poolNames.lendingPools.find(
563
+ ({ id }) => otherPool.PoolOverview_id === id,
564
+ );
565
+
566
+ if (!found) continue;
567
+
568
+ const directusName = directusPoolNames.find(
569
+ ({ id }) => id === found.id,
570
+ );
571
+
572
+ const poolName = directusName?.poolName ?? found.name;
573
+
574
+ otherKASUPools.push({
575
+ id: found.id,
576
+ name: directusName?.subheading
577
+ ? `${poolName} - ${directusName.subheading}`
578
+ : poolName,
579
+ isActive: !found.isStopped,
580
+ isOversubscribed: Boolean(directusName?.oversubscribed),
581
+ });
582
+ }
583
+
584
+ retn.push({
585
+ id: data.id,
586
+ delegateLendingHistory: data.delegateLendingHistory,
587
+ assetClasses: data.assetClasses,
588
+ otherKASUPools,
589
+ totalLoanFundsOriginated: data.totalLoanFundsOriginated,
590
+ totalLoansOriginated: data.totalLoansOriginated,
591
+ loansUnderManagement: data.loansUnderManagement,
592
+ historicLossRate: data.historicLossRate,
593
+ });
594
+ }
595
+ return filterArray(retn, id_in);
596
+ }
597
+
598
+ async getPoolTranches(
599
+ epochId: string,
600
+ id_in?: string[],
601
+ ): Promise<PoolTranche[]> {
602
+ const subgraphResults: TrancheSubgraphResult =
603
+ await this._graph.request(getAllTranchesQuery, {
604
+ unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
605
+ });
606
+ const subgraphConfigurationResults: TrancheConfigurationSubgraphResult =
607
+ await this._graph.request(getAllTrancheConfigurationsQuery, {
608
+ unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
609
+ epochId,
610
+ });
611
+ const retn: PoolTranche[] = [];
612
+ for (const trancheSubgraph of subgraphResults.lendingPoolTranches) {
613
+ const configuration =
614
+ subgraphConfigurationResults.lendingPoolTrancheConfigurations.find(
615
+ (r) => r.id == trancheSubgraph.id,
616
+ );
617
+ if (!configuration) {
618
+ console.warn(
619
+ "Couldn't find tranche configuration for id: ",
620
+ trancheSubgraph.id,
621
+ );
622
+ continue;
623
+ }
624
+
625
+ const interestUpdates =
626
+ configuration.lendingPoolTrancheInterestRateUpdates;
627
+
628
+ const interestRate = interestUpdates.length
629
+ ? interestUpdates[0].epochInterestRate
630
+ : configuration.interestRate;
631
+
632
+ const tranche: PoolTranche = {
633
+ id: trancheSubgraph.id,
634
+ poolIdFK: trancheSubgraph.lendingPool.id.toLowerCase(),
635
+ apy: this.calculateApyForTranche(interestRate).toString(),
636
+ minimalDepositThreshold: configuration.minDepositAmount,
637
+ maximalDepositThreshold: configuration.maxDepositAmount,
638
+ };
639
+ retn.push(tranche);
640
+ }
641
+ return filterArray(retn, id_in);
642
+ }
643
+
644
+ async getBadAndDoubtfulDebts(
645
+ id_in?: string[],
646
+ ): Promise<BadAndDoubtfulDebts[]> {
647
+ const [badAndDoubtfulDebtsItemsDirectus, badAndDoubtfulDebtsDirectus] =
648
+ await Promise.all([
649
+ this._directus.request(readItems('BadAndDoubtfulDebtsItems')),
650
+ this._directus.request(readItems('BadAndDoubtfulDebts')),
651
+ ]);
652
+
653
+ const itemsMapper: Partial<Record<string, BadAndDoubtfulDebtsItems>> =
654
+ badAndDoubtfulDebtsItemsDirectus.reduce(
655
+ (acc, cur) => ({ ...acc, [cur.id]: cur }),
656
+ {},
657
+ );
658
+
659
+ const test = badAndDoubtfulDebtsDirectus.map((debts) => {
660
+ const items = debts.items
661
+ .map((debtItem) => {
662
+ const { item, ...metric } = debtItem;
663
+
664
+ const itemMetric = itemsMapper[item.key];
665
+
666
+ if (!itemMetric) return null;
667
+
668
+ return {
669
+ ...metric,
670
+ item: itemMetric,
671
+ };
672
+ })
673
+ .filter((item) => item !== null);
674
+
675
+ return {
676
+ ...debts,
677
+ items,
678
+ };
679
+ });
680
+
681
+ return filterArray(test, id_in);
682
+ }
683
+
684
+ async getPoolCreditMetrics(id_in?: string[]): Promise<PoolCreditMetrics[]> {
685
+ const [keyCreditMetricsDirectus, poolCreditMetricsDirectus] =
686
+ await Promise.all([
687
+ this._directus.request(readItems('KeyCreditMetrics')),
688
+ this._directus.request(readItems('PoolCreditMetrics')),
689
+ ]);
690
+
691
+ const keyCreditMetricsMapper: Partial<
692
+ Record<string, KeyCreditMetricsDirectus>
693
+ > = keyCreditMetricsDirectus.reduce(
694
+ (acc, cur) => ({ ...acc, [cur.name]: cur }),
695
+ {},
696
+ );
697
+
698
+ const poolCreditMetrics = poolCreditMetricsDirectus.map((pool) => {
699
+ const metrics = pool.keyCreditMetrics
700
+ .map((data) => {
701
+ const { keyCreditMetric, ...metric } = data;
702
+
703
+ const keyMetric =
704
+ keyCreditMetricsMapper[keyCreditMetric.key];
705
+
706
+ if (!keyMetric) return null;
707
+
708
+ return {
709
+ ...metric,
710
+ keyCreditMetric: keyMetric,
711
+ };
712
+ })
713
+ .filter((metric) => metric !== null);
714
+
715
+ return {
716
+ ...pool,
717
+ keyCreditMetrics: metrics,
718
+ };
719
+ });
720
+
721
+ return filterArray(poolCreditMetrics, id_in);
722
+ }
723
+
724
+ async getFinancialReportingDocuments(
725
+ id_in?: string[],
726
+ ): Promise<FinancialReportingDocuments[]> {
727
+ const [
728
+ financialReportingDocumentsDirectus,
729
+ financialReportingDocumentsItemsDirectus,
730
+ ] = await Promise.all([
731
+ this._directus.request(readItems('FinancialReportingDocuments')),
732
+ this._directus.request(
733
+ readItems('FinancialReportingDocumentsItems'),
734
+ ),
735
+ ]);
736
+
737
+ const documentItemsMapper: Partial<
738
+ Record<number, FinancialReportingDocumentsItemsDirectus>
739
+ > = financialReportingDocumentsItemsDirectus.reduce(
740
+ (acc, cur) => ({ ...acc, [cur.id]: cur }),
741
+ {},
742
+ );
743
+
744
+ const mapDocumentFilePath = financialReportingDocumentsDirectus
745
+ .map((report) => {
746
+ if (!report.documents) return null;
747
+
748
+ const documents = report.documents
749
+ .map((documentId) => {
750
+ const document = documentItemsMapper[documentId];
751
+
752
+ if (!document) return null;
753
+
754
+ return {
755
+ ...document,
756
+ document: this.getUrlFromFile(document.document),
757
+ };
758
+ })
759
+ .filter((document) => document !== null);
760
+
761
+ return {
762
+ ...report,
763
+ documents,
764
+ };
765
+ })
766
+ .filter((report) => report !== null);
767
+
768
+ return filterArray(mapDocumentFilePath, id_in);
769
+ }
770
+
771
+ async getRepayments(id_in?: string[]): Promise<PoolRepayment[]> {
772
+ const [poolRepaymentDirectus, poolRepaymentItemsDirectus] =
773
+ await Promise.all([
774
+ this._directus.request(
775
+ readItems('PoolRepayments', {
776
+ filter: {
777
+ poolIdFK: {
778
+ _nin: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
779
+ },
780
+ },
781
+ }),
782
+ ),
783
+ this._directus.request(readItems('PoolRepaymentItems')),
784
+ ]);
785
+
786
+ const repaymentItemsMapper: Partial<
787
+ Record<string, PoolRepaymentItemsDirectus>
788
+ > = poolRepaymentItemsDirectus.reduce(
789
+ (acc, cur) => ({ ...acc, [cur.name]: cur }),
790
+ {},
791
+ );
792
+
793
+ const lendingPoolsWithdrawalsAndDepositsSubgraph: LendingPoolWithdrawalAndDepositSubgraph =
794
+ await this._graph.request(
795
+ getLendingPoolWithdrawalAndDepositsQuery,
796
+ { unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS },
797
+ );
798
+ const retn: PoolRepayment[] = [];
799
+ for (const data of poolRepaymentDirectus) {
800
+ const lendingPoolSubgraph =
801
+ lendingPoolsWithdrawalsAndDepositsSubgraph.lendingPools.find(
802
+ (pool) => pool.id == data.poolIdFK,
803
+ );
804
+
805
+ if (lendingPoolSubgraph === undefined) {
806
+ continue;
807
+ }
808
+
809
+ const currentDepositRequests = parseFloat(
810
+ lendingPoolSubgraph.pendingPool.totalPendingDepositsAmount,
811
+ );
812
+
813
+ let sumTotalPendingWithdrawalShares = 0.0;
814
+
815
+ lendingPoolSubgraph.pendingPool.totalPendingWithdrawalShares.forEach(
816
+ (shares) => {
817
+ sumTotalPendingWithdrawalShares += parseFloat(shares);
818
+ },
819
+ );
820
+
821
+ const cumulativeLendingAndWithdrawals =
822
+ data.CumulativeLendingAndWithdrawals.map((fund) => {
823
+ let calculatedValue = 0;
824
+
825
+ if (fund.key === 'netLendingWithdrawals') {
826
+ calculatedValue =
827
+ parseFloat(
828
+ lendingPoolSubgraph.totalDepositsAccepted,
829
+ ) -
830
+ parseFloat(
831
+ lendingPoolSubgraph.totalWithdrawalsAccepted,
832
+ );
833
+ }
834
+
835
+ if (fund.key === 'cumulativeLending') {
836
+ calculatedValue = parseFloat(
837
+ lendingPoolSubgraph.totalDepositsAccepted,
838
+ );
839
+ }
840
+
841
+ if (fund.key === 'cumulativeLendingWithdrawals') {
842
+ calculatedValue = parseFloat(
843
+ lendingPoolSubgraph.totalWithdrawalsAccepted,
844
+ );
845
+ }
846
+
847
+ const repaymentItem =
848
+ repaymentItemsMapper[fund.repaymentItem.key];
849
+
850
+ if (!repaymentItem) return null;
851
+
852
+ return {
853
+ value: fund.value ?? calculatedValue,
854
+ ...repaymentItem,
855
+ };
856
+ }).filter((item) => item !== null);
857
+
858
+ const lendingAndWithdrawalRequests =
859
+ data.LendingAndWithdrawalRequests.map((fund) => {
860
+ let calculatedValue = 0;
861
+
862
+ if (fund.key === 'netLendingWithdrawalRequests') {
863
+ calculatedValue =
864
+ currentDepositRequests -
865
+ sumTotalPendingWithdrawalShares;
866
+ }
867
+
868
+ if (fund.key === 'currentLendingRequests') {
869
+ calculatedValue = currentDepositRequests;
870
+ }
871
+
872
+ if (fund.key === 'currentLendingWithdrawalRequests') {
873
+ calculatedValue = sumTotalPendingWithdrawalShares;
874
+ }
875
+
876
+ const repaymentItem =
877
+ repaymentItemsMapper[fund.repaymentItem.key];
878
+
879
+ if (!repaymentItem) return null;
880
+
881
+ return {
882
+ value: fund.value ?? calculatedValue,
883
+ ...repaymentItem,
884
+ };
885
+ }).filter((item) => item !== null);
886
+
887
+ const poolRepayment: PoolRepayment = {
888
+ id: data.id,
889
+ poolIdFK: data.poolIdFK.toLowerCase(),
890
+ currentTotalEndBorrowers: data.currentTotalEndBorrowers,
891
+ repaymentsFileUrl: this.getUrlFromFile(data.repaymentsFile),
892
+ upcomingLendingFundsFlow: data.UpcomingLendingFundsFlow.map(
893
+ (fund) => {
894
+ const repaymentItem =
895
+ repaymentItemsMapper[fund.repaymentItem.key];
896
+
897
+ if (!repaymentItem) return null;
898
+
899
+ return {
900
+ value: fund.value,
901
+ ...repaymentItem,
902
+ };
903
+ },
904
+ ).filter((item) => item !== null),
905
+ cumulativeLendingFundsFlow: data.CumulativeLendingFundsFlow.map(
906
+ (fund) => {
907
+ const repaymentItem =
908
+ repaymentItemsMapper[fund.repaymentItem.key];
909
+
910
+ if (!repaymentItem) return null;
911
+
912
+ return {
913
+ value: fund.value,
914
+ ...repaymentItem,
915
+ };
916
+ },
917
+ ).filter((item) => item !== null),
918
+ cumulativeLendingAndWithdrawals,
919
+ lendingAndWithdrawalRequests,
920
+ };
921
+
922
+ retn.push(poolRepayment);
923
+ }
924
+ return filterArray(retn, id_in);
925
+ }
926
+
927
+ async getLendingTotals(
928
+ poolOverviews: PoolOverview[],
929
+ ): Promise<LendingTotals> {
930
+ const riskManagements: RiskManagement[] =
931
+ await this.getRiskManagement();
932
+ const retn: LendingTotals = {
933
+ totalValueLocked: 0,
934
+ loansUnderManagement: 0,
935
+ totalLoanFundsOriginated: 0,
936
+ totalLossRate: 0,
937
+ totalYieldEarned: 0,
938
+ };
939
+ for (const poolOverview of poolOverviews) {
940
+ retn.totalValueLocked += parseFloat(
941
+ poolOverview.totalValueLocked.total,
942
+ );
943
+ retn.loansUnderManagement += parseFloat(
944
+ poolOverview.loansUnderManagement,
945
+ );
946
+ retn.totalLoanFundsOriginated += parseFloat(
947
+ poolOverview.loanFundsOriginated,
948
+ );
949
+ retn.totalYieldEarned += parseFloat(poolOverview.yieldEarned);
950
+ }
951
+ for (const poolOverview of poolOverviews) {
952
+ const riskManagement = riskManagements.find(
953
+ (rm) =>
954
+ rm.poolIdFK.toLowerCase() === poolOverview.id.toLowerCase(),
955
+ );
956
+ if (!riskManagement) {
957
+ console.warn(
958
+ "Couldn't find risk management for id: ",
959
+ poolOverview.id,
960
+ );
961
+ continue;
962
+ }
963
+ const weight =
964
+ retn.totalLoanFundsOriginated === 0
965
+ ? 0
966
+ : parseFloat(poolOverview.loanFundsOriginated) /
967
+ retn.totalLoanFundsOriginated;
968
+ retn.totalLossRate +=
969
+ riskManagement.riskPerformance.poolLossRate * weight;
970
+ }
971
+ return retn;
972
+ }
973
+
974
+ calculateCompounding(
975
+ amount: number,
976
+ epochInterestRate: number,
977
+ daysInvested: number,
978
+ interestFee: number,
979
+ ): number[] {
980
+ const COMPOUNDING_PERIOD = 7;
981
+ const earnedAmount: number[] = [];
982
+
983
+ const epochInterestRateAfterFee = epochInterestRate * (1 - interestFee);
984
+
985
+ for (let i = 0; i < daysInvested + 1; i++) {
986
+ const investmentEpochs = i / COMPOUNDING_PERIOD;
987
+
988
+ const interestEarned =
989
+ amount *
990
+ (Math.pow(1 + epochInterestRateAfterFee, investmentEpochs) - 1);
991
+
992
+ earnedAmount.push(interestEarned);
993
+ }
994
+
995
+ return earnedAmount;
996
+ }
997
+
998
+ calculateBonusInterestEarnings(
999
+ earnedAmounts: number[],
1000
+ amount: number,
1001
+ bonusEpochInterest: number,
1002
+ ): number[] {
1003
+ const COMPOUNDING_PERIOD = 7;
1004
+ const dailyInterest = bonusEpochInterest / COMPOUNDING_PERIOD;
1005
+
1006
+ const bonusInterestEarned: number[] = [0];
1007
+
1008
+ for (let i = 1; i < earnedAmounts.length; i++) {
1009
+ const bonusInterest = (amount + earnedAmounts[i]) * dailyInterest;
1010
+ bonusInterestEarned.push(
1011
+ bonusInterestEarned[i - 1] + bonusInterest,
1012
+ );
1013
+ }
1014
+
1015
+ return bonusInterestEarned;
1016
+ }
1017
+ }