@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,593 @@
1
+ import { Provider } from '@ethersproject/providers';
2
+ import { BigNumber, Signer } from 'ethers';
3
+ import { formatEther, parseEther, parseUnits } from 'ethers/lib/utils';
4
+ import { GraphQLClient } from 'graphql-request';
5
+
6
+ import {
7
+ IKasuNFTsAbi,
8
+ IKasuNFTsAbi__factory,
9
+ ISystemVariablesAbi,
10
+ ISystemVariablesAbi__factory,
11
+ } from '../../contracts';
12
+ import { SdkConfig } from '../../sdk-config';
13
+ import { DataService } from '../DataService/data-service';
14
+ import { PoolOverview } from '../DataService/types';
15
+ import { KSULocking } from '../Locking/locking';
16
+ import { UserLending } from '../UserLending/user-lending';
17
+
18
+ import { lendingPortfolioQuery } from './queries';
19
+ import {
20
+ LendingPortfolioQueryResult,
21
+ PortfolioLendingPool,
22
+ PortfolioRewards,
23
+ PortfolioSummary,
24
+ PortfolioTranche,
25
+ PortfolioTrancheDepositDetails,
26
+ UserLendingPoolTrancheFixedTermDepositLock,
27
+ } from './types';
28
+
29
+ export class Portfolio {
30
+ private _lockingService: KSULocking;
31
+ private _dataService: DataService;
32
+ private _userLendingService: UserLending;
33
+ private readonly _graph: GraphQLClient;
34
+
35
+ private _systemVariablesAbi: ISystemVariablesAbi;
36
+ private _kasuNftContract: IKasuNFTsAbi;
37
+ readonly _signerOrProvider: Signer | Provider;
38
+
39
+ constructor(
40
+ private _kasuConfig: SdkConfig,
41
+ signerOrProvider: Signer | Provider,
42
+ ) {
43
+ this._signerOrProvider = signerOrProvider;
44
+ this._lockingService = new KSULocking(_kasuConfig, signerOrProvider);
45
+ this._dataService = new DataService(_kasuConfig, signerOrProvider);
46
+ this._systemVariablesAbi = ISystemVariablesAbi__factory.connect(
47
+ _kasuConfig.contracts.SystemVariables,
48
+ signerOrProvider,
49
+ );
50
+ this._userLendingService = new UserLending(
51
+ _kasuConfig,
52
+ signerOrProvider,
53
+ );
54
+ this._kasuNftContract = IKasuNFTsAbi__factory.connect(
55
+ _kasuConfig.contracts.KasuNFTs,
56
+ signerOrProvider,
57
+ );
58
+ this._graph = new GraphQLClient(_kasuConfig.subgraphUrl);
59
+ }
60
+
61
+ async getPortfolioRewards(userAddress: string): Promise<PortfolioRewards> {
62
+ const userLockingData =
63
+ await this._lockingService.getUserBonusData(userAddress);
64
+ const lockingRewards =
65
+ await this._lockingService.getLockingRewards(userAddress);
66
+ const ksuLaunchBonus =
67
+ await this._lockingService.getUserTotalBonusAmount(userAddress);
68
+ return {
69
+ bonusYieldEarnings: {
70
+ claimableBalance: {
71
+ ksuAmount: userLockingData.ksuBonusAndRewards,
72
+ },
73
+ lifeTime: {
74
+ ksuAmount: userLockingData.ksuBonusAndRewardsLifetime,
75
+ },
76
+ },
77
+ protocolFees: {
78
+ claimableBalance: {
79
+ usdcAmount: lockingRewards.claimableRewards,
80
+ },
81
+ lifeTime: { usdcAmount: lockingRewards.lifeTimeRewards },
82
+ },
83
+ ksuLaunchBonus: { lifeTime: { ksuAmount: ksuLaunchBonus } },
84
+ };
85
+ }
86
+
87
+ async getUserNfts(userAddress: string): Promise<number[]> {
88
+ const usernfts = await this._kasuNftContract.tokensOfOwner(userAddress);
89
+
90
+ return usernfts.map((nft) => nft.toNumber());
91
+ }
92
+
93
+ async getPortfolioSummary(
94
+ userAddress: string,
95
+ portfolioLendingPools: PortfolioLendingPool[],
96
+ ): Promise<PortfolioSummary> {
97
+ const userLockingData =
98
+ await this._lockingService.getUserBonusData(userAddress);
99
+ let totalInvestments = 0;
100
+
101
+ let weightedApy = 0;
102
+ let totalYieldEarned = 0;
103
+
104
+ let weeklyYieldEarnings = 0;
105
+
106
+ for (const pool of portfolioLendingPools) {
107
+ for (const tranche of pool.tranches) {
108
+ const investedAmount = parseFloat(tranche.investedAmount);
109
+
110
+ totalInvestments += investedAmount;
111
+ totalYieldEarned += parseFloat(tranche.yieldEarnings.lifetime);
112
+
113
+ weightedApy += parseFloat(tranche.apy) * investedAmount;
114
+
115
+ weeklyYieldEarnings +=
116
+ investedAmount * parseFloat(tranche.interestRate);
117
+
118
+ for (const fixedDeposits of tranche.fixedLoans) {
119
+ const ftdConfig = tranche.fixedTermConfig.find(
120
+ (ftd) => ftd.configId === fixedDeposits.configId,
121
+ );
122
+
123
+ if (!ftdConfig) continue;
124
+
125
+ const ftdInvestedAmount = parseFloat(fixedDeposits.amount);
126
+
127
+ totalInvestments += ftdInvestedAmount;
128
+ totalYieldEarned += parseFloat(
129
+ fixedDeposits.yieldEarnings.lifetime,
130
+ );
131
+
132
+ weeklyYieldEarnings +=
133
+ ftdInvestedAmount *
134
+ parseFloat(ftdConfig.epochInterestRate);
135
+
136
+ weightedApy +=
137
+ parseFloat(ftdConfig.apy) * ftdInvestedAmount;
138
+ }
139
+ }
140
+ }
141
+
142
+ return {
143
+ current: {
144
+ totalKsuLocked: userLockingData.totalLockedAmount,
145
+ totalLendingPoolInvestments: totalInvestments.toString(),
146
+ weightedAverageApy:
147
+ totalInvestments === 0
148
+ ? '0'
149
+ : (weightedApy / totalInvestments).toString(),
150
+ },
151
+ daily: {
152
+ yieldEarnings: (weeklyYieldEarnings / 7).toString(),
153
+ },
154
+ weekly: {
155
+ yieldEarnings: weeklyYieldEarnings.toString(),
156
+ protocolFeesEarned: '0',
157
+ ksuBonusRewards: '0',
158
+ },
159
+ lifetime: {
160
+ yieldEarnings: totalYieldEarned.toString(),
161
+ ksuBonusRewards: userLockingData.ksuBonusAndRewards,
162
+ protocolFeesEarned: userLockingData.protocolFeesEarned,
163
+ },
164
+ };
165
+ }
166
+
167
+ async getPortfolioLendingData(
168
+ userAddress: string,
169
+ poolOverviews: PoolOverview[],
170
+ currentEpoch: string,
171
+ provider?: Provider,
172
+ ): Promise<PortfolioLendingPool[]> {
173
+ const SECONDS_PER_EPOCH = 604_800; // seconds in a week
174
+
175
+ const portfolioLendingPoolsPromise: (Omit<
176
+ PortfolioLendingPool,
177
+ 'tranches'
178
+ > & {
179
+ tranches: (Omit<PortfolioTranche, 'investedAmount'> & {
180
+ investedAmount: {
181
+ balance: string;
182
+ yieldEarned: number;
183
+ };
184
+ })[];
185
+ })[] = [];
186
+
187
+ const previousEpoch = BigNumber.from(currentEpoch).sub(
188
+ BigNumber.from(1),
189
+ );
190
+
191
+ const [lastEpochData, portfolioUserTrancheBalances, userPoolBalances] =
192
+ await Promise.all([
193
+ this._graph.request<LendingPortfolioQueryResult>(
194
+ lendingPortfolioQuery,
195
+ {
196
+ userAddress: userAddress.toLowerCase(),
197
+ epochId: parseFloat(currentEpoch),
198
+ lastEpochId: previousEpoch.toNumber(),
199
+ unusedPools: this._kasuConfig.UNUSED_LENDING_POOL_IDS,
200
+ },
201
+ ),
202
+ this._userLendingService.getPortfolioUserTrancheBalances(
203
+ userAddress,
204
+ ),
205
+ this._userLendingService.getUserPoolBalance(
206
+ userAddress,
207
+ poolOverviews.map(({ id }) => id),
208
+ provider,
209
+ ),
210
+ ]);
211
+
212
+ if (!lastEpochData.user) return [];
213
+
214
+ const userRequestsMap = new Map<
215
+ string,
216
+ Record<string, PortfolioTrancheDepositDetails[] | undefined>
217
+ >();
218
+
219
+ for (const userRequest of lastEpochData.userRequests) {
220
+ const trancheId = userRequest.tranche.id;
221
+
222
+ const ftdId = userRequest.fixedTermConfigId;
223
+
224
+ let remainingAcceptedAmount = parseFloat(
225
+ userRequest.amountAccepted,
226
+ );
227
+
228
+ for (const userRequestEvent of userRequest.userRequestEvents) {
229
+ const mappedUserRequest = userRequestsMap.get(trancheId);
230
+
231
+ const assetAmount = parseFloat(userRequestEvent.assetAmount);
232
+
233
+ const acceptedAmount =
234
+ remainingAcceptedAmount > assetAmount
235
+ ? assetAmount
236
+ : remainingAcceptedAmount;
237
+
238
+ remainingAcceptedAmount -= acceptedAmount;
239
+
240
+ const userRequestFtdItem: PortfolioTrancheDepositDetails = {
241
+ id: userRequestEvent.id,
242
+ depositAmount: userRequestEvent.assetAmount,
243
+ acceptedAmount: acceptedAmount.toString(),
244
+ timestamp: parseInt(userRequest.createdOn),
245
+ };
246
+
247
+ if (!mappedUserRequest) {
248
+ userRequestsMap.set(trancheId, {
249
+ [ftdId]: [userRequestFtdItem],
250
+ });
251
+ continue;
252
+ }
253
+
254
+ userRequestsMap.set(trancheId, {
255
+ ...mappedUserRequest,
256
+ [ftdId]: [
257
+ ...(mappedUserRequest[ftdId] ?? []),
258
+ userRequestFtdItem,
259
+ ],
260
+ });
261
+ }
262
+ }
263
+
264
+ let totalInvestments = BigNumber.from(0);
265
+ let totalYieldEarnedLastEpoch = 0;
266
+
267
+ for (const poolOverview of poolOverviews) {
268
+ const userPoolBalance = userPoolBalances.find(
269
+ ({ poolId }) => poolId === poolOverview.id,
270
+ );
271
+ if (!userPoolBalance) {
272
+ console.warn(
273
+ `Could not find user pool balance for ${poolOverview.id}`,
274
+ );
275
+ continue;
276
+ }
277
+ totalInvestments = userPoolBalance.balance.add(totalInvestments);
278
+ const tranches: (Omit<PortfolioTranche, 'investedAmount'> & {
279
+ investedAmount: {
280
+ balance: string;
281
+ yieldEarned: number;
282
+ };
283
+ })[] = [];
284
+
285
+ const lendingPoolUserDetails =
286
+ lastEpochData.user.lendingPoolUserDetails.find(
287
+ ({ lendingPool }) => lendingPool.id === poolOverview.id,
288
+ );
289
+
290
+ if (!lendingPoolUserDetails) continue;
291
+
292
+ const portfolioUserTrancheBalance =
293
+ portfolioUserTrancheBalances.get(poolOverview.id);
294
+
295
+ for (const tranche of poolOverview.tranches) {
296
+ const lastEpochUserTrancheDetails =
297
+ lendingPoolUserDetails.lendingPoolTrancheUserDetails.find(
298
+ (lendingPool) => lendingPool.tranche.id === tranche.id,
299
+ );
300
+
301
+ const userRequest = userRequestsMap.get(tranche.id);
302
+
303
+ const depositDetails = userRequest?.['0'] ?? [];
304
+
305
+ if (!lastEpochUserTrancheDetails) {
306
+ tranches.push({
307
+ ...tranche,
308
+ investedAmount: {
309
+ balance: '0',
310
+ yieldEarned: 0,
311
+ },
312
+ yieldEarnings: {
313
+ lastEpoch: '0',
314
+ lifetime: '0',
315
+ },
316
+ depositDetails,
317
+ fixedLoans: [],
318
+ });
319
+ continue;
320
+ }
321
+ const lastEpochTotalYield = parseFloat(
322
+ lastEpochUserTrancheDetails.tranche
323
+ .lendingPoolTrancheEpochInterest?.[0]
324
+ ?.epochInterestAmount ?? '0',
325
+ );
326
+
327
+ const lastEpochUserShares = parseFloat(
328
+ lastEpochUserTrancheDetails
329
+ .lendingPoolTrancheUserEpochSharesUpdates?.[0]
330
+ ?.shares ?? '0',
331
+ );
332
+
333
+ const lastEpochTotalShares = parseFloat(
334
+ lastEpochUserTrancheDetails.tranche
335
+ .lendingPoolTrancheShareUpdates?.[0]?.shares ?? '0',
336
+ );
337
+
338
+ const currentTotalAmount = parseFloat(
339
+ lastEpochUserTrancheDetails.tranche.balance,
340
+ );
341
+ const currentTotalShares = parseFloat(
342
+ lastEpochUserTrancheDetails.tranche.shares,
343
+ );
344
+
345
+ const lastEpochTotalBaseYield =
346
+ lastEpochTotalShares === 0
347
+ ? 0
348
+ : (lastEpochTotalYield * lastEpochUserShares) /
349
+ lastEpochTotalShares;
350
+
351
+ const userTrancheBalance = {
352
+ balance: '0',
353
+ yieldEarned: 0,
354
+ };
355
+
356
+ if (portfolioUserTrancheBalance) {
357
+ const portfolioUserTranche =
358
+ portfolioUserTrancheBalance.find(
359
+ ({ trancheId }) => trancheId === tranche.id,
360
+ );
361
+
362
+ if (portfolioUserTranche) {
363
+ userTrancheBalance.balance =
364
+ portfolioUserTranche.userBalance;
365
+ userTrancheBalance.yieldEarned =
366
+ portfolioUserTranche.yieldEarned;
367
+ }
368
+ }
369
+
370
+ let totalLifetimeFtdYield = 0;
371
+
372
+ let lastEpochVariableBaseYield = lastEpochTotalBaseYield;
373
+
374
+ const fixedLoans: PortfolioTranche['fixedLoans'] =
375
+ lastEpochUserTrancheDetails.userLendingPoolTrancheFixedTermDepositLocks.map(
376
+ (fixedTermDeposit) => {
377
+ const fixedLoanDepositDetails =
378
+ userRequest?.[
379
+ fixedTermDeposit
380
+ .lendingPoolTrancheFixedTermConfig
381
+ .configId
382
+ ] ?? [];
383
+
384
+ let lastEpochYieldEarned = 0;
385
+ let lifetimeYieldEarned = 0;
386
+
387
+ if (
388
+ parseFloat(fixedTermDeposit.epochLockStart) <
389
+ previousEpoch.toNumber() &&
390
+ parseFloat(fixedTermDeposit.epochLockEnd) >=
391
+ previousEpoch.toNumber() &&
392
+ Boolean(
393
+ lastEpochUserTrancheDetails
394
+ .lendingPoolTrancheUserEpochSharesUpdates
395
+ ?.length,
396
+ )
397
+ ) {
398
+ const currentEpochFtdShares = parseFloat(
399
+ fixedTermDeposit.trancheShares,
400
+ );
401
+
402
+ const lastEpochFtdShares = parseFloat(
403
+ fixedTermDeposit
404
+ .userLendingPoolTrancheFixedTermDepositLockShareUpdate?.[0]
405
+ ?.shares ?? '0',
406
+ );
407
+
408
+ const additionalFtdYield =
409
+ ((currentEpochFtdShares -
410
+ lastEpochFtdShares) *
411
+ currentTotalAmount) /
412
+ currentTotalShares;
413
+
414
+ const lastEpochFtdBaseYield =
415
+ (lastEpochTotalBaseYield *
416
+ lastEpochFtdShares) /
417
+ lastEpochUserShares;
418
+
419
+ lastEpochVariableBaseYield -=
420
+ lastEpochFtdBaseYield;
421
+
422
+ lastEpochYieldEarned =
423
+ lastEpochFtdBaseYield + additionalFtdYield;
424
+ }
425
+
426
+ lifetimeYieldEarned =
427
+ this.calculateFixedTermDepositEarnings(
428
+ fixedTermDeposit,
429
+ lastEpochUserTrancheDetails.tranche.balance,
430
+ lastEpochUserTrancheDetails.tranche.shares,
431
+ );
432
+
433
+ totalLifetimeFtdYield += lifetimeYieldEarned;
434
+
435
+ totalYieldEarnedLastEpoch += lastEpochYieldEarned;
436
+
437
+ const lockDuration =
438
+ parseFloat(
439
+ fixedTermDeposit
440
+ .lendingPoolTrancheFixedTermConfig
441
+ .epochLockDuration,
442
+ ) * SECONDS_PER_EPOCH;
443
+
444
+ return {
445
+ lockId: fixedTermDeposit.lockId,
446
+ configId:
447
+ fixedTermDeposit
448
+ .lendingPoolTrancheFixedTermConfig
449
+ .configId,
450
+ epochLockDuration:
451
+ fixedTermDeposit
452
+ .lendingPoolTrancheFixedTermConfig
453
+ .epochLockDuration,
454
+ epochLockEnd: fixedTermDeposit.epochLockEnd,
455
+ epochInterestRate:
456
+ fixedTermDeposit
457
+ .lendingPoolTrancheFixedTermConfig
458
+ .epochInterestRate,
459
+ epochLockStart: fixedTermDeposit.epochLockStart,
460
+ amount: this._userLendingService
461
+ .convertSharesToAssets(
462
+ fixedTermDeposit.trancheShares,
463
+ lastEpochUserTrancheDetails.tranche
464
+ .balance,
465
+ lastEpochUserTrancheDetails.tranche
466
+ .shares,
467
+ )
468
+ .toString(),
469
+ endTime:
470
+ parseInt(fixedTermDeposit.createdOn) +
471
+ lockDuration,
472
+ isLocked: fixedTermDeposit.isLocked,
473
+ isWithdrawalRequested:
474
+ fixedTermDeposit.isWithdrawalRequested,
475
+ startTime: parseInt(fixedTermDeposit.createdOn),
476
+ yieldEarnings: {
477
+ lastEpoch: lastEpochYieldEarned.toString(),
478
+ lifetime:
479
+ this.precisionToString(
480
+ lifetimeYieldEarned,
481
+ ),
482
+ },
483
+ depositDetails: fixedLoanDepositDetails,
484
+ };
485
+ },
486
+ );
487
+
488
+ totalYieldEarnedLastEpoch += lastEpochTotalBaseYield;
489
+
490
+ tranches.push({
491
+ ...tranche,
492
+ investedAmount: userTrancheBalance,
493
+ yieldEarnings: {
494
+ lastEpoch: lastEpochVariableBaseYield.toString(),
495
+ lifetime: this.precisionToString(totalLifetimeFtdYield), // passing in total FTD yield to be subtracted by total trache lifetime later down
496
+ },
497
+ fixedLoans,
498
+ depositDetails,
499
+ });
500
+ }
501
+
502
+ portfolioLendingPoolsPromise.push({
503
+ ...poolOverview,
504
+ totalYieldEarningsLastEpoch:
505
+ totalYieldEarnedLastEpoch.toString(),
506
+ totalInvestedAmount: userPoolBalance.balance.toString(),
507
+ totalYieldEarningsLifetime:
508
+ userPoolBalance.yieldEarned.toString(),
509
+ tranches,
510
+ });
511
+ }
512
+
513
+ const portfolioLendingPools: PortfolioLendingPool[] =
514
+ portfolioLendingPoolsPromise.map((pool) => ({
515
+ ...pool,
516
+ tranches: pool.tranches.map((tranche) => {
517
+ const trancheBalance = tranche.investedAmount;
518
+
519
+ const lockedAmount = tranche.fixedLoans.reduce(
520
+ (total, cur) => {
521
+ if (!cur.isLocked) return total;
522
+
523
+ return total.add(parseEther(cur.amount));
524
+ },
525
+ BigNumber.from(0),
526
+ );
527
+
528
+ const totalTrancheYieldEarned =
529
+ trancheBalance.yieldEarned.toFixed(6);
530
+ const totalTrancheFtdYieldEarned = parseFloat(
531
+ tranche.yieldEarnings.lifetime,
532
+ ).toFixed(6);
533
+
534
+ return {
535
+ ...tranche,
536
+ investedAmount: formatEther(
537
+ parseEther(trancheBalance.balance).sub(
538
+ lockedAmount,
539
+ ),
540
+ ),
541
+ yieldEarnings: {
542
+ ...tranche.yieldEarnings,
543
+ lifetime: this.precisionToString(
544
+ parseFloat(totalTrancheYieldEarned) -
545
+ parseFloat(totalTrancheFtdYieldEarned),
546
+ ),
547
+ },
548
+ };
549
+ }),
550
+ }));
551
+
552
+ return portfolioLendingPools.filter(
553
+ (pool) =>
554
+ !parseUnits(pool.totalInvestedAmount).isZero() ||
555
+ !parseUnits(pool.totalYieldEarningsLifetime).isZero(),
556
+ );
557
+ }
558
+
559
+ precisionToString(val: number): string {
560
+ if (val < 0 && val > -0.0001) {
561
+ return '0';
562
+ }
563
+
564
+ return val.toString();
565
+ }
566
+
567
+ calculateFixedTermDepositEarnings(
568
+ fixedTermDepositLock: UserLendingPoolTrancheFixedTermDepositLock,
569
+ totalTrancheBalance: string,
570
+ totalTrancheShares: string,
571
+ ): number {
572
+ const { isLocked, unlockAmount, initialAmount, trancheShares } =
573
+ fixedTermDepositLock;
574
+
575
+ let yieldEarned = 0;
576
+
577
+ if (!isLocked && unlockAmount) {
578
+ yieldEarned = parseFloat(unlockAmount) - parseFloat(initialAmount);
579
+ } else {
580
+ const currentUsdAmount =
581
+ this._userLendingService.convertSharesToAssets(
582
+ trancheShares,
583
+ totalTrancheBalance,
584
+ totalTrancheShares,
585
+ );
586
+
587
+ yieldEarned =
588
+ parseFloat(currentUsdAmount) - parseFloat(initialAmount);
589
+ }
590
+
591
+ return yieldEarned;
592
+ }
593
+ }