@hobba-io/core 0.1.0

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 (190) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +87 -0
  3. package/dist/amountUtils.d.ts +15 -0
  4. package/dist/amountUtils.d.ts.map +1 -0
  5. package/dist/amountUtils.js +59 -0
  6. package/dist/amountUtils.js.map +1 -0
  7. package/dist/constants.d.ts +148 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +231 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/errors.d.ts +7 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +29 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/executeAction.d.ts +36 -0
  16. package/dist/executeAction.d.ts.map +1 -0
  17. package/dist/executeAction.js +606 -0
  18. package/dist/executeAction.js.map +1 -0
  19. package/dist/executeDepositBorrow.d.ts +49 -0
  20. package/dist/executeDepositBorrow.d.ts.map +1 -0
  21. package/dist/executeDepositBorrow.js +444 -0
  22. package/dist/executeDepositBorrow.js.map +1 -0
  23. package/dist/idl/hobba.json +5072 -0
  24. package/dist/idl.d.ts +783 -0
  25. package/dist/idl.d.ts.map +1 -0
  26. package/dist/idl.js +7 -0
  27. package/dist/idl.js.map +1 -0
  28. package/dist/index.d.ts +17 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +22 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/juplend/accountResolvers.d.ts +106 -0
  33. package/dist/juplend/accountResolvers.d.ts.map +1 -0
  34. package/dist/juplend/accountResolvers.js +148 -0
  35. package/dist/juplend/accountResolvers.js.map +1 -0
  36. package/dist/juplend/operateRemaining.d.ts +11 -0
  37. package/dist/juplend/operateRemaining.d.ts.map +1 -0
  38. package/dist/juplend/operateRemaining.js +46 -0
  39. package/dist/juplend/operateRemaining.js.map +1 -0
  40. package/dist/juplend/positionInit.d.ts +34 -0
  41. package/dist/juplend/positionInit.d.ts.map +1 -0
  42. package/dist/juplend/positionInit.js +56 -0
  43. package/dist/juplend/positionInit.js.map +1 -0
  44. package/dist/juplend/positionParser.d.ts +8 -0
  45. package/dist/juplend/positionParser.d.ts.map +1 -0
  46. package/dist/juplend/positionParser.js +30 -0
  47. package/dist/juplend/positionParser.js.map +1 -0
  48. package/dist/juplend/sdkApi.d.ts +39 -0
  49. package/dist/juplend/sdkApi.d.ts.map +1 -0
  50. package/dist/juplend/sdkApi.js +68 -0
  51. package/dist/juplend/sdkApi.js.map +1 -0
  52. package/dist/juplend/tickMath.d.ts +19 -0
  53. package/dist/juplend/tickMath.d.ts.map +1 -0
  54. package/dist/juplend/tickMath.js +91 -0
  55. package/dist/juplend/tickMath.js.map +1 -0
  56. package/dist/juplend/tickUtils.d.ts +20 -0
  57. package/dist/juplend/tickUtils.d.ts.map +1 -0
  58. package/dist/juplend/tickUtils.js +115 -0
  59. package/dist/juplend/tickUtils.js.map +1 -0
  60. package/dist/juplend/vaultConfigParser.d.ts +25 -0
  61. package/dist/juplend/vaultConfigParser.d.ts.map +1 -0
  62. package/dist/juplend/vaultConfigParser.js +38 -0
  63. package/dist/juplend/vaultConfigParser.js.map +1 -0
  64. package/dist/kamino/accountResolvers.d.ts +110 -0
  65. package/dist/kamino/accountResolvers.d.ts.map +1 -0
  66. package/dist/kamino/accountResolvers.js +220 -0
  67. package/dist/kamino/accountResolvers.js.map +1 -0
  68. package/dist/kamino/obligationParser.d.ts +13 -0
  69. package/dist/kamino/obligationParser.d.ts.map +1 -0
  70. package/dist/kamino/obligationParser.js +92 -0
  71. package/dist/kamino/obligationParser.js.map +1 -0
  72. package/dist/kamino/refreshInstructions.d.ts +4 -0
  73. package/dist/kamino/refreshInstructions.d.ts.map +1 -0
  74. package/dist/kamino/refreshInstructions.js +32 -0
  75. package/dist/kamino/refreshInstructions.js.map +1 -0
  76. package/dist/limits.d.ts +87 -0
  77. package/dist/limits.d.ts.map +1 -0
  78. package/dist/limits.js +174 -0
  79. package/dist/limits.js.map +1 -0
  80. package/dist/marketConfig.d.ts +35 -0
  81. package/dist/marketConfig.d.ts.map +1 -0
  82. package/dist/marketConfig.js +85 -0
  83. package/dist/marketConfig.js.map +1 -0
  84. package/dist/oracle/scopePrice.d.ts +7 -0
  85. package/dist/oracle/scopePrice.d.ts.map +1 -0
  86. package/dist/oracle/scopePrice.js +31 -0
  87. package/dist/oracle/scopePrice.js.map +1 -0
  88. package/dist/pdas.d.ts +33 -0
  89. package/dist/pdas.d.ts.map +1 -0
  90. package/dist/pdas.js +116 -0
  91. package/dist/pdas.js.map +1 -0
  92. package/dist/position.d.ts +45 -0
  93. package/dist/position.d.ts.map +1 -0
  94. package/dist/position.js +68 -0
  95. package/dist/position.js.map +1 -0
  96. package/dist/positionMetrics.d.ts +108 -0
  97. package/dist/positionMetrics.d.ts.map +1 -0
  98. package/dist/positionMetrics.js +238 -0
  99. package/dist/positionMetrics.js.map +1 -0
  100. package/dist/program.d.ts +12 -0
  101. package/dist/program.d.ts.map +1 -0
  102. package/dist/program.js +24 -0
  103. package/dist/program.js.map +1 -0
  104. package/dist/quote.d.ts +90 -0
  105. package/dist/quote.d.ts.map +1 -0
  106. package/dist/quote.js +198 -0
  107. package/dist/quote.js.map +1 -0
  108. package/dist/rates/borrowRates.d.ts +44 -0
  109. package/dist/rates/borrowRates.d.ts.map +1 -0
  110. package/dist/rates/borrowRates.js +229 -0
  111. package/dist/rates/borrowRates.js.map +1 -0
  112. package/dist/rates/collateralInfo.d.ts +21 -0
  113. package/dist/rates/collateralInfo.d.ts.map +1 -0
  114. package/dist/rates/collateralInfo.js +104 -0
  115. package/dist/rates/collateralInfo.js.map +1 -0
  116. package/dist/rates/constants.d.ts +22 -0
  117. package/dist/rates/constants.d.ts.map +1 -0
  118. package/dist/rates/constants.js +70 -0
  119. package/dist/rates/constants.js.map +1 -0
  120. package/dist/rates/index.d.ts +11 -0
  121. package/dist/rates/index.d.ts.map +1 -0
  122. package/dist/rates/index.js +11 -0
  123. package/dist/rates/index.js.map +1 -0
  124. package/dist/rates/kaminoApi.d.ts +24 -0
  125. package/dist/rates/kaminoApi.d.ts.map +1 -0
  126. package/dist/rates/kaminoApi.js +98 -0
  127. package/dist/rates/kaminoApi.js.map +1 -0
  128. package/dist/rates/supplyRates.d.ts +23 -0
  129. package/dist/rates/supplyRates.d.ts.map +1 -0
  130. package/dist/rates/supplyRates.js +67 -0
  131. package/dist/rates/supplyRates.js.map +1 -0
  132. package/dist/transactionBuilder.d.ts +5 -0
  133. package/dist/transactionBuilder.d.ts.map +1 -0
  134. package/dist/transactionBuilder.js +287 -0
  135. package/dist/transactionBuilder.js.map +1 -0
  136. package/dist/txHelpers.d.ts +16 -0
  137. package/dist/txHelpers.d.ts.map +1 -0
  138. package/dist/txHelpers.js +82 -0
  139. package/dist/txHelpers.js.map +1 -0
  140. package/dist/userState.d.ts +21 -0
  141. package/dist/userState.d.ts.map +1 -0
  142. package/dist/userState.js +60 -0
  143. package/dist/userState.js.map +1 -0
  144. package/dist/vault/vaultAccounts.d.ts +82 -0
  145. package/dist/vault/vaultAccounts.d.ts.map +1 -0
  146. package/dist/vault/vaultAccounts.js +275 -0
  147. package/dist/vault/vaultAccounts.js.map +1 -0
  148. package/dist/wallet.d.ts +12 -0
  149. package/dist/wallet.d.ts.map +1 -0
  150. package/dist/wallet.js +2 -0
  151. package/dist/wallet.js.map +1 -0
  152. package/package.json +63 -0
  153. package/src/amountUtils.ts +69 -0
  154. package/src/constants.ts +263 -0
  155. package/src/errors.ts +33 -0
  156. package/src/executeAction.ts +884 -0
  157. package/src/executeDepositBorrow.ts +677 -0
  158. package/src/idl/hobba.json +5072 -0
  159. package/src/idl.ts +7 -0
  160. package/src/index.ts +21 -0
  161. package/src/juplend/accountResolvers.ts +207 -0
  162. package/src/juplend/operateRemaining.ts +81 -0
  163. package/src/juplend/positionInit.ts +86 -0
  164. package/src/juplend/positionParser.ts +41 -0
  165. package/src/juplend/sdkApi.ts +112 -0
  166. package/src/juplend/tickMath.ts +82 -0
  167. package/src/juplend/tickUtils.ts +163 -0
  168. package/src/juplend/vaultConfigParser.ts +45 -0
  169. package/src/kamino/accountResolvers.ts +299 -0
  170. package/src/kamino/obligationParser.ts +123 -0
  171. package/src/kamino/refreshInstructions.ts +45 -0
  172. package/src/limits.ts +222 -0
  173. package/src/marketConfig.ts +139 -0
  174. package/src/oracle/scopePrice.ts +31 -0
  175. package/src/pdas.ts +226 -0
  176. package/src/position.ts +131 -0
  177. package/src/positionMetrics.ts +387 -0
  178. package/src/program.ts +30 -0
  179. package/src/quote.ts +310 -0
  180. package/src/rates/borrowRates.ts +270 -0
  181. package/src/rates/collateralInfo.ts +136 -0
  182. package/src/rates/constants.ts +87 -0
  183. package/src/rates/index.ts +38 -0
  184. package/src/rates/kaminoApi.ts +134 -0
  185. package/src/rates/supplyRates.ts +102 -0
  186. package/src/transactionBuilder.ts +324 -0
  187. package/src/txHelpers.ts +107 -0
  188. package/src/userState.ts +91 -0
  189. package/src/vault/vaultAccounts.ts +365 -0
  190. package/src/wallet.ts +12 -0
package/dist/quote.js ADDED
@@ -0,0 +1,198 @@
1
+ import { collateralDecimals, collateralLabel } from "./amountUtils";
2
+ import { getPosition } from "./position";
3
+ import { bestMarketName, fetchCollateralPrice, fetchRatesPayload, fetchSupplyRatesPayload, } from "./positionMetrics";
4
+ /** Calculator defaults — same values the app falls back to when rates are empty. */
5
+ const FALLBACK_BORROW_APY = 5.6 / 100;
6
+ const FALLBACK_SUPPLY_APY = 21.59 / 100;
7
+ const SOL_STAKING_APY = 7 / 100;
8
+ const MAX_USER_LTV_PCT = 50;
9
+ function assessRisk(currentPrice, liquidationPrice) {
10
+ if (currentPrice <= 0 || liquidationPrice <= 0)
11
+ return { riskLabel: "—", riskLevel: "none" };
12
+ const fallPct = ((currentPrice - liquidationPrice) / currentPrice) * 100;
13
+ if (fallPct > 70)
14
+ return { riskLabel: "Very Safe", riskLevel: "safe" };
15
+ if (fallPct > 50)
16
+ return { riskLabel: "Safe", riskLevel: "safe" };
17
+ if (fallPct > 40)
18
+ return { riskLabel: "Moderate Risk", riskLevel: "moderate" };
19
+ if (fallPct > 30)
20
+ return { riskLabel: "Risky", riskLevel: "moderate" };
21
+ if (fallPct > 15)
22
+ return { riskLabel: "Very Risky", riskLevel: "risky" };
23
+ return { riskLabel: "Extremely Risky", riskLevel: "risky" };
24
+ }
25
+ function selfRepayDateFor(loanApyFraction) {
26
+ if (loanApyFraction >= 0)
27
+ return null;
28
+ const yearsToRepay = 1 / Math.abs(loanApyFraction);
29
+ if (yearsToRepay > 10)
30
+ return null;
31
+ const repayDate = new Date();
32
+ repayDate.setDate(repayDate.getDate() + Math.ceil(yearsToRepay * 365));
33
+ return `${repayDate.getDate().toString().padStart(2, "0")}/${(repayDate.getMonth() + 1)
34
+ .toString()
35
+ .padStart(2, "0")}/${repayDate.getFullYear()}`;
36
+ }
37
+ export async function getQuote(params) {
38
+ const { connection, collateralMint } = params;
39
+ const base = (params.apiBaseUrl ?? "").replace(/\/+$/, "");
40
+ const label = collateralLabel(collateralMint);
41
+ const [position, rates, supplyRates, price] = await Promise.all([
42
+ params.owner
43
+ ? getPosition({ connection, owner: params.owner, collateralMint, apiBaseUrl: base })
44
+ : Promise.resolve(null),
45
+ fetchRatesPayload(base),
46
+ fetchSupplyRatesPayload(base),
47
+ fetchCollateralPrice(base, label),
48
+ ]);
49
+ return computeQuote({
50
+ position,
51
+ rates,
52
+ supplyRates,
53
+ collateralPriceUsd: price,
54
+ collateralMint,
55
+ depositAmount: params.depositAmount,
56
+ borrowAmount: params.borrowAmount,
57
+ repayAmount: params.repayAmount,
58
+ withdrawAmount: params.withdrawAmount,
59
+ });
60
+ }
61
+ export function computeQuote(inputs) {
62
+ const { position, rates, supplyRates, collateralPriceUsd: price, collateralMint } = inputs;
63
+ const label = collateralLabel(collateralMint);
64
+ const decimals = collateralDecimals(collateralMint);
65
+ const divisor = Math.pow(10, decimals);
66
+ const isSol = label === "SOL";
67
+ const params = inputs;
68
+ // Best live rates with the app's hardcoded fallbacks (CalculatorSection).
69
+ const bestBorrowAPY = (() => {
70
+ if (rates.markets.length === 0)
71
+ return FALLBACK_BORROW_APY;
72
+ let best = Infinity;
73
+ for (const m of rates.markets)
74
+ if (m.borrowAPY < best)
75
+ best = m.borrowAPY;
76
+ return best < Infinity ? best / 100 : FALLBACK_BORROW_APY;
77
+ })();
78
+ const bestSupplyAPY = (() => {
79
+ if (supplyRates.vaults.length === 0)
80
+ return FALLBACK_SUPPLY_APY;
81
+ let best = -Infinity;
82
+ for (const v of supplyRates.vaults)
83
+ if (v.supplyAPY > best)
84
+ best = v.supplyAPY;
85
+ return best > -Infinity ? best / 100 : FALLBACK_SUPPLY_APY;
86
+ })();
87
+ const lender = position?.exists
88
+ ? position.lender
89
+ : bestMarketName(rates) === "JupLend"
90
+ ? "juplend"
91
+ : "kamino";
92
+ const isJuplendLender = lender === "juplend";
93
+ const ltvSource = isJuplendLender
94
+ ? rates.juplendCollateralLtvs[label]
95
+ : rates.collateralLtvs[label];
96
+ const liquidationLtvPct = ltvSource?.liquidationThresholdPct ?? (label === "cbBTC" ? 80 : 75);
97
+ // Current position in UI units
98
+ const curCollateralUi = position ? Number(position.collateral) / divisor : 0;
99
+ const curDebtUsdc = position ? Number(position.userDebtUsdc) / 1e6 : 0;
100
+ const actualOperatorBorrowed = position ? Number(position.depositedToVault) / 1e6 : 0;
101
+ // Deltas in UI units
102
+ const depositUi = Number(params.depositAmount ?? "0") / divisor;
103
+ const withdrawUi = Number(params.withdrawAmount ?? "0") / divisor;
104
+ const borrowUsdc = Number(params.borrowAmount ?? "0") / 1e6;
105
+ const repayUsdc = Number(params.repayAmount ?? "0") / 1e6;
106
+ const projCollateralUi = Math.max(0, curCollateralUi + depositUi - withdrawUi);
107
+ const projDebtUsdc = Math.max(0, curDebtUsdc + borrowUsdc - repayUsdc);
108
+ const curCollateralUsd = curCollateralUi * price;
109
+ const projCollateralUsd = projCollateralUi * price;
110
+ const curLtvPct = curCollateralUsd > 0 ? (curDebtUsdc / curCollateralUsd) * 100 : 0;
111
+ const projLtvPct = projCollateralUsd > 0 ? (projDebtUsdc / projCollateralUsd) * 100 : 0;
112
+ // Loan APY for a position — ported from ActionModal.computeLoanAPY: the
113
+ // operator borrows up to the per-asset target LTV whenever vault yield beats
114
+ // borrow cost; rates follow the user's actual lender + vault (Dashboard).
115
+ const TARGET_LTV = isSol ? 0.6 : 0.65;
116
+ const borrowMarketNameForRates = !position?.exists
117
+ ? "Kamino Main Market"
118
+ : isJuplendLender
119
+ ? "JupLend"
120
+ : "Kamino Main Market";
121
+ const positionBorrowAPY = params.positionBorrowApyPct ??
122
+ (rates.markets.find((m) => m.name === borrowMarketNameForRates)?.borrowAPY ??
123
+ bestBorrowAPY * 100);
124
+ const perenaVaultAPY = supplyRates.vaults.find((v) => v.name === "Perena USDC")?.supplyAPY ?? 0;
125
+ const positionVaultAPY = params.positionVaultApyPct ?? (perenaVaultAPY > 0 ? perenaVaultAPY : bestSupplyAPY * 100);
126
+ const DUST_DEBT = 0.01;
127
+ const computeLoanApyPct = (userDebt, collateralUsd) => {
128
+ if (userDebt < DUST_DEBT)
129
+ return null;
130
+ let opDebt = actualOperatorBorrowed;
131
+ if (collateralUsd > 0 && positionVaultAPY > positionBorrowAPY) {
132
+ const projected = Math.max(0, collateralUsd * TARGET_LTV - userDebt);
133
+ opDebt = Math.max(actualOperatorBorrowed, projected);
134
+ }
135
+ else if (positionVaultAPY <= positionBorrowAPY) {
136
+ opDebt = 0;
137
+ }
138
+ return ((userDebt + opDebt) * positionBorrowAPY - opDebt * positionVaultAPY) / userDebt;
139
+ };
140
+ const currentLoanApyPct = computeLoanApyPct(curDebtUsdc, curCollateralUsd);
141
+ const projectedLoanApyPct = computeLoanApyPct(projDebtUsdc, projCollateralUsd);
142
+ const projLiqPrice = projCollateralUsd > 0 && projDebtUsdc > 0 && liquidationLtvPct > 0
143
+ ? price * (projLtvPct / liquidationLtvPct)
144
+ : 0;
145
+ const projBuffer = price > 0 && projLiqPrice > 0 ? Math.max(0, ((price - projLiqPrice) / price) * 100) : null;
146
+ const { riskLabel, riskLevel } = assessRisk(price, projLiqPrice);
147
+ // --- Calculator math (ported from CalculatorSection) on projected values ---
148
+ const depositValueUsd = projCollateralUsd;
149
+ const borrowValueUsd = projDebtUsdc; // USDC ≈ $1
150
+ const borrowLimitUsd = depositValueUsd * (MAX_USER_LTV_PCT / 100);
151
+ const earningPerYearUsd = depositValueUsd * TARGET_LTV > borrowValueUsd
152
+ ? (depositValueUsd * TARGET_LTV - borrowValueUsd) * (bestSupplyAPY - bestBorrowAPY)
153
+ : 0;
154
+ const borrowCostPerYearUsd = borrowValueUsd * bestBorrowAPY;
155
+ const calcLoanApy = depositValueUsd > 0 && borrowValueUsd > 0
156
+ ? (borrowCostPerYearUsd - earningPerYearUsd) / borrowValueUsd
157
+ : 0;
158
+ const stakingEarnPerYearUsd = isSol ? depositValueUsd * SOL_STAKING_APY : 0;
159
+ const hasSpreadEarn = depositValueUsd > 0 && borrowValueUsd <= 0 && bestSupplyAPY > bestBorrowAPY;
160
+ const earnMode = depositValueUsd > 0 && borrowValueUsd <= 0 && (hasSpreadEarn || stakingEarnPerYearUsd > 0);
161
+ const totalEarnPerYear = (hasSpreadEarn ? earningPerYearUsd : 0) + stakingEarnPerYearUsd;
162
+ const earnApy = earnMode && depositValueUsd > 0 ? totalEarnPerYear / depositValueUsd : 0;
163
+ return {
164
+ lender,
165
+ collateralPriceUsd: price,
166
+ liquidationLtvPct,
167
+ maxUserLtvPct: MAX_USER_LTV_PCT,
168
+ current: {
169
+ collateralUi: curCollateralUi,
170
+ debtUsdc: curDebtUsdc,
171
+ ltvPct: curLtvPct,
172
+ loanApyPct: currentLoanApyPct,
173
+ },
174
+ projected: {
175
+ collateralUi: projCollateralUi,
176
+ debtUsdc: projDebtUsdc,
177
+ ltvPct: projLtvPct,
178
+ loanApyPct: projectedLoanApyPct,
179
+ liquidationPriceUsd: projLiqPrice > 0 ? projLiqPrice : null,
180
+ dropToLiquidationPct: projBuffer,
181
+ riskLabel,
182
+ riskLevel,
183
+ },
184
+ calculator: {
185
+ depositValueUsd,
186
+ borrowValueUsd,
187
+ borrowLimitUsd,
188
+ loanApyPct: calcLoanApy * 100,
189
+ earnMode,
190
+ earnApyPct: earnApy * 100,
191
+ borrowCostPerYearUsd,
192
+ earningPerYearUsd,
193
+ stakingEarnPerYearUsd,
194
+ selfRepayDate: selfRepayDateFor(calcLoanApy),
195
+ },
196
+ };
197
+ }
198
+ //# sourceMappingURL=quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote.js","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Shared borrow rate computation functions.
3
+ * Extracted from /api/rates/route.ts to be reused by /api/market-data and the rebalancer.
4
+ */
5
+ /** Measure actual slot duration from recent performance samples. */
6
+ export declare function getRecentSlotDurationMs(connection: {
7
+ getRecentPerformanceSamples: (limit: number) => Promise<Array<{
8
+ numSlots: number;
9
+ samplePeriodSecs: number;
10
+ }>>;
11
+ }): Promise<number>;
12
+ export interface CurvePoint {
13
+ utilizationRateBps: number;
14
+ borrowRateBps: number;
15
+ }
16
+ export interface BorrowRateResult {
17
+ availableLiquidity: number;
18
+ totalBorrowed: number;
19
+ utilization: number;
20
+ borrowAPR: number;
21
+ borrowAPY: number;
22
+ }
23
+ export interface CollateralInfo {
24
+ totalDeposited: number;
25
+ depositLimit: number;
26
+ }
27
+ export declare function decodeReserve(data: Buffer): any;
28
+ export declare function computeKaminoBorrowRate(reserve: any, recentSlotDurationMs?: number): BorrowRateResult;
29
+ export declare function computeKaminoSupplyRate(reserve: any, recentSlotDurationMs?: number): {
30
+ supplyAPY: number;
31
+ };
32
+ export interface CollateralLtvInfo {
33
+ loanToValuePct: number;
34
+ liquidationThresholdPct: number;
35
+ }
36
+ export declare function getCollateralLtvInfo(reserve: any): CollateralLtvInfo;
37
+ export declare function getCollateralInfo(reserve: any): CollateralInfo;
38
+ export declare function getJuplendCollateralLtvInfo(vaultConfigData: Buffer): CollateralLtvInfo;
39
+ export declare function getJuplendCollateral(vaultStateData: Buffer): CollateralInfo;
40
+ export declare function computeJuplendBorrowRate(data: Buffer): BorrowRateResult;
41
+ export declare function computeJuplendSupplyRate(data: Buffer): {
42
+ supplyAPY: number;
43
+ };
44
+ //# sourceMappingURL=borrowRates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"borrowRates.d.ts","sourceRoot":"","sources":["../../src/rates/borrowRates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,oEAAoE;AACpE,wBAAsB,uBAAuB,CAAC,UAAU,EAAE;IAAE,2BAA2B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB7L;AAED,MAAM,WAAW,UAAU;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,OAWzC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,oBAAoB,SAA2B,GAAG,gBAAgB,CAyCvH;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,oBAAoB,SAA2B,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAoC5H;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,GAAG,GAAG,iBAAiB,CAKpE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,GAAG,GAAG,cAAc,CAU9D;AAED,wBAAgB,2BAA2B,CAAC,eAAe,EAAE,MAAM,GAAG,iBAAiB,CAYtF;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,cAAc,CAM3E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAuCvE;AAQD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CA8B5E"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Shared borrow rate computation functions.
3
+ * Extracted from /api/rates/route.ts to be reused by /api/market-data and the rebalancer.
4
+ */
5
+ import { createRequire } from "node:module";
6
+ const SF_SCALE = BigInt("1152921504606846976"); // 2^60
7
+ const SLOTS_PER_YEAR = 63072000;
8
+ const SLOTS_PER_SECOND = 2;
9
+ const DEFAULT_SLOT_DURATION_MS = 400;
10
+ const JUPLEND_EXCHANGE_PRECISION = BigInt("1000000000000"); // 1e12
11
+ const JUPLEND_SECONDS_PER_YEAR = 31536000;
12
+ /** Measure actual slot duration from recent performance samples. */
13
+ export async function getRecentSlotDurationMs(connection) {
14
+ try {
15
+ const samples = await connection.getRecentPerformanceSamples(10);
16
+ if (samples.length === 0)
17
+ return DEFAULT_SLOT_DURATION_MS;
18
+ let totalSlots = 0, totalSecs = 0;
19
+ for (const s of samples) {
20
+ totalSlots += s.numSlots;
21
+ totalSecs += s.samplePeriodSecs;
22
+ }
23
+ if (totalSlots === 0)
24
+ return DEFAULT_SLOT_DURATION_MS;
25
+ const measured = (totalSecs * 1000) / totalSlots;
26
+ // Sanity check: local validators report unrealistic durations
27
+ if (measured < 200 || measured > 600)
28
+ return DEFAULT_SLOT_DURATION_MS;
29
+ return measured;
30
+ }
31
+ catch {
32
+ return DEFAULT_SLOT_DURATION_MS;
33
+ }
34
+ }
35
+ export function decodeReserve(data) {
36
+ // Lazy + server-only by design: resolves klend-sdk (an optional peer) from
37
+ // the consumer's node_modules at call time, keeping the heavy SDK out of
38
+ // browser bundles and out of load-time module evaluation. createRequire is
39
+ // invoked inside the function so importing this subpath never throws in
40
+ // environments without the optional peer installed.
41
+ const nodeRequire = createRequire(import.meta.url);
42
+ const { Reserve } = nodeRequire("@kamino-finance/klend-sdk/dist/@codegen/klend/accounts/Reserve");
43
+ return Reserve.decode(data);
44
+ }
45
+ export function computeKaminoBorrowRate(reserve, recentSlotDurationMs = DEFAULT_SLOT_DURATION_MS) {
46
+ const availableAmount = Number(reserve.liquidity.availableAmount);
47
+ const borrowedAmount = Number(BigInt(reserve.liquidity.borrowedAmountSf.toString()) / SF_SCALE);
48
+ const protocolFees = Number(BigInt(reserve.liquidity.accumulatedProtocolFeesSf.toString()) / SF_SCALE);
49
+ const referrerFees = Number(BigInt(reserve.liquidity.accumulatedReferrerFeesSf.toString()) / SF_SCALE);
50
+ const pendingFees = Number(BigInt(reserve.liquidity.pendingReferrerFeesSf.toString()) / SF_SCALE);
51
+ const totalSupply = availableAmount + borrowedAmount - protocolFees - referrerFees - pendingFees;
52
+ const utilization = totalSupply > 0 ? borrowedAmount / totalSupply : 0;
53
+ const curve = reserve.config.borrowRateCurve.points;
54
+ const utilBps = utilization * 10000;
55
+ let borrowRateBps = 0;
56
+ for (let i = 1; i < curve.length; i++) {
57
+ if (curve[i].utilizationRateBps === 0 && curve[i].borrowRateBps === 0 && i > 1)
58
+ break;
59
+ if (utilBps <= curve[i].utilizationRateBps) {
60
+ const x0 = curve[i - 1].utilizationRateBps;
61
+ const x1 = curve[i].utilizationRateBps;
62
+ const y0 = curve[i - 1].borrowRateBps;
63
+ const y1 = curve[i].borrowRateBps;
64
+ borrowRateBps = y0 + ((utilBps - x0) * (y1 - y0)) / (x1 - x0);
65
+ break;
66
+ }
67
+ }
68
+ const slotAdjustment = 1000 / SLOTS_PER_SECOND / recentSlotDurationMs;
69
+ const adjustedRate = (borrowRateBps / 10000) * slotAdjustment;
70
+ const hostFixedRate = (reserve.config.hostFixedInterestRateBps / 10000) * slotAdjustment;
71
+ const borrowAPR = adjustedRate + hostFixedRate;
72
+ const borrowAPY = Math.pow(1 + borrowAPR / SLOTS_PER_YEAR, SLOTS_PER_YEAR) - 1;
73
+ const mintDecimals = Number(reserve.liquidity.mintDecimals);
74
+ const divisor = Math.pow(10, mintDecimals);
75
+ return {
76
+ availableLiquidity: availableAmount / divisor,
77
+ totalBorrowed: borrowedAmount / divisor,
78
+ utilization: utilization * 100,
79
+ borrowAPR: borrowAPR * 100,
80
+ borrowAPY: borrowAPY * 100,
81
+ };
82
+ }
83
+ export function computeKaminoSupplyRate(reserve, recentSlotDurationMs = DEFAULT_SLOT_DURATION_MS) {
84
+ const availableAmount = Number(reserve.liquidity.availableAmount);
85
+ const borrowedAmount = Number(BigInt(reserve.liquidity.borrowedAmountSf.toString()) / SF_SCALE);
86
+ const protocolFees = Number(BigInt(reserve.liquidity.accumulatedProtocolFeesSf.toString()) / SF_SCALE);
87
+ const referrerFees = Number(BigInt(reserve.liquidity.accumulatedReferrerFeesSf.toString()) / SF_SCALE);
88
+ const pendingFees = Number(BigInt(reserve.liquidity.pendingReferrerFeesSf.toString()) / SF_SCALE);
89
+ const totalSupply = availableAmount + borrowedAmount - protocolFees - referrerFees - pendingFees;
90
+ const utilization = totalSupply > 0 ? borrowedAmount / totalSupply : 0;
91
+ const curve = reserve.config.borrowRateCurve.points;
92
+ const utilBps = utilization * 10000;
93
+ let borrowRateBps = 0;
94
+ for (let i = 1; i < curve.length; i++) {
95
+ if (curve[i].utilizationRateBps === 0 && curve[i].borrowRateBps === 0 && i > 1)
96
+ break;
97
+ if (utilBps <= curve[i].utilizationRateBps) {
98
+ const x0 = curve[i - 1].utilizationRateBps;
99
+ const x1 = curve[i].utilizationRateBps;
100
+ const y0 = curve[i - 1].borrowRateBps;
101
+ const y1 = curve[i].borrowRateBps;
102
+ borrowRateBps = y0 + ((utilBps - x0) * (y1 - y0)) / (x1 - x0);
103
+ break;
104
+ }
105
+ }
106
+ const slotAdjustment = 1000 / SLOTS_PER_SECOND / recentSlotDurationMs;
107
+ const adjustedRate = (borrowRateBps / 10000) * slotAdjustment;
108
+ const hostFixedRate = (reserve.config.hostFixedInterestRateBps / 10000) * slotAdjustment;
109
+ const borrowAPR = adjustedRate + hostFixedRate;
110
+ // Protocol take rate: fraction of interest kept by protocol (in bps)
111
+ const protocolTakeRatePct = (reserve.config.protocolTakeRatePct ?? 0) / 100;
112
+ const supplyAPR = borrowAPR * utilization * (1 - protocolTakeRatePct);
113
+ const supplyAPY = Math.pow(1 + supplyAPR / SLOTS_PER_YEAR, SLOTS_PER_YEAR) - 1;
114
+ return { supplyAPY: supplyAPY * 100 };
115
+ }
116
+ export function getCollateralLtvInfo(reserve) {
117
+ return {
118
+ loanToValuePct: reserve.config.loanToValuePct ?? 0,
119
+ liquidationThresholdPct: reserve.config.liquidationThresholdPct ?? 0,
120
+ };
121
+ }
122
+ export function getCollateralInfo(reserve) {
123
+ const availableAmount = Number(reserve.liquidity.availableAmount);
124
+ const borrowedAmount = Number(BigInt(reserve.liquidity.borrowedAmountSf.toString()) / SF_SCALE);
125
+ const mintDecimals = Number(reserve.liquidity.mintDecimals);
126
+ const divisor = Math.pow(10, mintDecimals);
127
+ const totalDeposited = (availableAmount + borrowedAmount) / divisor;
128
+ const depositLimit = Number(BigInt(reserve.config.depositLimit.toString())) / divisor;
129
+ return { totalDeposited, depositLimit };
130
+ }
131
+ export function getJuplendCollateralLtvInfo(vaultConfigData) {
132
+ // VaultConfig layout (packed C):
133
+ // 8 (anchor disc) + 2 vaultId + 2 supplyRateMagnifier (i16) + 2 borrowRateMagnifier (i16)
134
+ // + 2 collateralFactor (u16) + 2 liquidationThreshold (u16)
135
+ // Both factor fields are permille — divide by 10 to get percent. (See JupLend SDK
136
+ // lend.*.mjs liquidationThresholdRatio = ratio * threshold / 1000.)
137
+ const collateralFactor = vaultConfigData.readUInt16LE(8 + 2 + 2 + 2);
138
+ const liquidationThreshold = vaultConfigData.readUInt16LE(8 + 2 + 2 + 2 + 2);
139
+ return {
140
+ loanToValuePct: collateralFactor / 10,
141
+ liquidationThresholdPct: liquidationThreshold / 10,
142
+ };
143
+ }
144
+ export function getJuplendCollateral(vaultStateData) {
145
+ let off = 8; // discriminator
146
+ off += 2 + 1 + 4 + 4 + 4; // vaultId + branchLiquidated + topmostTick + currentBranchId + totalBranchId
147
+ const totalSupplyRaw = Number(vaultStateData.readBigUInt64LE(off));
148
+ const totalDeposited = totalSupplyRaw / 1e8; // cbBTC has 8 decimals
149
+ return { totalDeposited, depositLimit: 0 };
150
+ }
151
+ export function computeJuplendBorrowRate(data) {
152
+ let off = 8; // skip discriminator
153
+ off += 32; // mint
154
+ off += 32; // vault
155
+ const borrowRateBps = data.readUInt16LE(off);
156
+ off += 2;
157
+ off += 2; // feeOnInterest
158
+ off += 2; // lastUtilization
159
+ off += 8; // lastUpdateTimestamp
160
+ const supplyExchangePrice = data.readBigUInt64LE(off);
161
+ off += 8;
162
+ const borrowExchangePrice = data.readBigUInt64LE(off);
163
+ off += 8;
164
+ off += 2; // maxUtilization
165
+ const totalSupplyWithInterest = data.readBigUInt64LE(off);
166
+ off += 8;
167
+ const totalSupplyInterestFree = data.readBigUInt64LE(off);
168
+ off += 8;
169
+ const totalBorrowWithInterest = data.readBigUInt64LE(off);
170
+ off += 8;
171
+ const totalBorrowInterestFree = data.readBigUInt64LE(off);
172
+ off += 8;
173
+ const totalSupply = Number(totalSupplyWithInterest * supplyExchangePrice / JUPLEND_EXCHANGE_PRECISION) +
174
+ Number(totalSupplyInterestFree);
175
+ const totalBorrow = Number(totalBorrowWithInterest * borrowExchangePrice / JUPLEND_EXCHANGE_PRECISION) +
176
+ Number(totalBorrowInterestFree);
177
+ const USDC_DIVISOR = 1e6;
178
+ const availableLiquidity = (totalSupply - totalBorrow) / USDC_DIVISOR;
179
+ const totalBorrowed = totalBorrow / USDC_DIVISOR;
180
+ const utilization = totalSupply > 0 ? (totalBorrow / totalSupply) * 100 : 0;
181
+ const borrowAPR = borrowRateBps / 100; // percent
182
+ const apr = borrowRateBps / 10000; // as fraction
183
+ const borrowAPY = (Math.pow(1 + apr / JUPLEND_SECONDS_PER_YEAR, JUPLEND_SECONDS_PER_YEAR) - 1) * 100;
184
+ return {
185
+ availableLiquidity,
186
+ totalBorrowed,
187
+ utilization,
188
+ borrowAPR,
189
+ borrowAPY,
190
+ };
191
+ }
192
+ // Supply (deposit) APY for a JupLend liquidity reserve — the lender rate earned
193
+ // by collateral supplied into that reserve. Decodes the same tokenReserve struct
194
+ // as computeJuplendBorrowRate and mirrors the SDK's getLiquidityAssetSupplyRate:
195
+ // supplyRate = borrowRate * (1e4 - fee) * borrowWithInterest
196
+ // / (supplyWithInterest * 1e4)
197
+ // (the JupLend analog of Kamino's borrowAPR * utilization * (1 - fee)).
198
+ export function computeJuplendSupplyRate(data) {
199
+ let off = 8; // skip discriminator
200
+ off += 32; // mint
201
+ off += 32; // vault
202
+ const borrowRateBps = data.readUInt16LE(off);
203
+ off += 2;
204
+ const feeOnInterestBps = data.readUInt16LE(off);
205
+ off += 2;
206
+ off += 2; // lastUtilization
207
+ off += 8; // lastUpdateTimestamp
208
+ const supplyExchangePrice = data.readBigUInt64LE(off);
209
+ off += 8;
210
+ const borrowExchangePrice = data.readBigUInt64LE(off);
211
+ off += 8;
212
+ off += 2; // maxUtilization
213
+ const totalSupplyWithInterest = data.readBigUInt64LE(off);
214
+ off += 8;
215
+ off += 8; // totalSupplyInterestFree
216
+ const totalBorrowWithInterest = data.readBigUInt64LE(off);
217
+ off += 8;
218
+ const supplyWithInterest = (totalSupplyWithInterest * supplyExchangePrice) / JUPLEND_EXCHANGE_PRECISION;
219
+ const borrowWithInterest = (totalBorrowWithInterest * borrowExchangePrice) / JUPLEND_EXCHANGE_PRECISION;
220
+ if (supplyWithInterest <= BigInt(0))
221
+ return { supplyAPY: 0 };
222
+ const supplyRateBps = borrowRateBps *
223
+ (1 - feeOnInterestBps / 10000) *
224
+ (Number(borrowWithInterest) / Number(supplyWithInterest));
225
+ const apr = supplyRateBps / 10000; // as fraction
226
+ const supplyAPY = (Math.pow(1 + apr / JUPLEND_SECONDS_PER_YEAR, JUPLEND_SECONDS_PER_YEAR) - 1) * 100;
227
+ return { supplyAPY };
228
+ }
229
+ //# sourceMappingURL=borrowRates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"borrowRates.js","sourceRoot":"","sources":["../../src/rates/borrowRates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { Connection } from "@solana/web3.js";
2
+ export interface CollateralRatesInfo {
3
+ collateralSupplyAPYs: Record<string, number>;
4
+ collateralLtvs: Record<string, {
5
+ loanToValuePct: number;
6
+ liquidationThresholdPct: number;
7
+ }>;
8
+ juplendCollateralSupplyAPYs: Record<string, number>;
9
+ juplendCollateralRewardsAPYs: Record<string, number>;
10
+ juplendCollateralLtvs: Record<string, {
11
+ loanToValuePct: number;
12
+ liquidationThresholdPct: number;
13
+ }>;
14
+ }
15
+ /**
16
+ * Per-collateral supply APYs + LTV thresholds for both lenders. Shared by
17
+ * /api/rates and /api/market-data so widget integrators get liquidation LTVs
18
+ * from the same source the app uses.
19
+ */
20
+ export declare function computeCollateralRatesInfo(connection: Connection, recentSlotDurationMs: number): Promise<CollateralRatesInfo>;
21
+ //# sourceMappingURL=collateralInfo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collateralInfo.d.ts","sourceRoot":"","sources":["../../src/rates/collateralInfo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAuBxD,MAAM,WAAW,mBAAmB;IAClC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,uBAAuB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5F,2BAA2B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpD,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,uBAAuB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpG;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,UAAU,EACtB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAgG9B"}
@@ -0,0 +1,104 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import { decodeReserve, computeKaminoSupplyRate, computeJuplendSupplyRate, getCollateralLtvInfo, getJuplendCollateralLtvInfo, } from "./borrowRates";
3
+ import { deriveJuplendVaultConfigPda, JUPLEND_VAULT_ID, JUPLEND_SOL_VAULT_ID, JUPLEND_LIQUIDITY_PROGRAM, SOL_MINT, CBBTC_MINT, } from "../constants";
4
+ // Collateral reserve addresses for supply APY (Kamino Main Market)
5
+ const COLLATERAL_RESERVES = {
6
+ cbBTC: "37Jk2zkz23vkAYBT66HM2gaqJuNg2nYLsCreQAVt5MWK",
7
+ SOL: "d4A2prbA2whesmvHaL88BH6Ewn5N4bTSU2Ze8P6Bc4Q",
8
+ };
9
+ /**
10
+ * Per-collateral supply APYs + LTV thresholds for both lenders. Shared by
11
+ * /api/rates and /api/market-data so widget integrators get liquidation LTVs
12
+ * from the same source the app uses.
13
+ */
14
+ export async function computeCollateralRatesInfo(connection, recentSlotDurationMs) {
15
+ // Kamino collateral info: supply APY + LTV thresholds per asset
16
+ const collateralSupplyAPYs = {};
17
+ const collateralLtvs = {};
18
+ await Promise.all(Object.entries(COLLATERAL_RESERVES).map(async ([asset, reserveAddr]) => {
19
+ try {
20
+ const info = await connection.getAccountInfo(new PublicKey(reserveAddr));
21
+ if (info) {
22
+ const reserve = decodeReserve(info.data);
23
+ const { supplyAPY } = computeKaminoSupplyRate(reserve, recentSlotDurationMs);
24
+ collateralSupplyAPYs[asset] = supplyAPY;
25
+ collateralLtvs[asset] = getCollateralLtvInfo(reserve);
26
+ }
27
+ }
28
+ catch (e) {
29
+ console.error(`Error computing ${asset} supply APY:`, e.message);
30
+ }
31
+ }));
32
+ // JupLend collateral supply APYs — the lender rate on the SOL/cbBTC liquidity
33
+ // reserve, used when a position is deposited into JupLend rather than Kamino.
34
+ const juplendCollateralSupplyAPYs = {};
35
+ const juplendCollateralMints = [
36
+ ["SOL", SOL_MINT],
37
+ ["cbBTC", CBBTC_MINT],
38
+ ];
39
+ await Promise.all(juplendCollateralMints.map(async ([asset, mint]) => {
40
+ try {
41
+ const reservePda = PublicKey.findProgramAddressSync([Buffer.from("reserve"), mint.toBuffer()], JUPLEND_LIQUIDITY_PROGRAM)[0];
42
+ const info = await connection.getAccountInfo(reservePda);
43
+ if (info) {
44
+ const { supplyAPY } = computeJuplendSupplyRate(info.data);
45
+ juplendCollateralSupplyAPYs[asset] = supplyAPY;
46
+ }
47
+ }
48
+ catch (e) {
49
+ console.error(`Error computing JupLend ${asset} supply APY:`, e.message);
50
+ }
51
+ }));
52
+ // JupLend rewards boost (vault supplyRate minus base supplyRateLiquidity)
53
+ const juplendCollateralRewardsAPYs = {};
54
+ try {
55
+ const vaultsRes = await fetch("https://lite-api.jup.ag/lend/v1/borrow/vaults", {
56
+ headers: { accept: "application/json" },
57
+ signal: AbortSignal.timeout(8000),
58
+ });
59
+ if (vaultsRes.ok) {
60
+ const vaults = await vaultsRes.json();
61
+ const juplendVaultIds = [
62
+ ["SOL", JUPLEND_SOL_VAULT_ID],
63
+ ["cbBTC", JUPLEND_VAULT_ID],
64
+ ];
65
+ for (const [asset, vaultId] of juplendVaultIds) {
66
+ const v = vaults.find((x) => x?.id === vaultId);
67
+ if (!v)
68
+ continue;
69
+ // API rates are 1e2-scaled (e.g. "531" => 5.31%).
70
+ const rewards = Math.max(0, Number(v.supplyRate) - Number(v.supplyRateLiquidity)) / 100;
71
+ if (rewards > 0)
72
+ juplendCollateralRewardsAPYs[asset] = rewards;
73
+ }
74
+ }
75
+ }
76
+ catch (e) {
77
+ console.error("Error fetching JupLend rewards:", e.message);
78
+ }
79
+ // JupLend collateral LTVs (per-vault liquidationThreshold from vault_config)
80
+ const juplendCollateralLtvs = {};
81
+ const juplendVaultConfigs = [
82
+ ["cbBTC", deriveJuplendVaultConfigPda(JUPLEND_VAULT_ID)],
83
+ ["SOL", deriveJuplendVaultConfigPda(JUPLEND_SOL_VAULT_ID)],
84
+ ];
85
+ await Promise.all(juplendVaultConfigs.map(async ([asset, addr]) => {
86
+ try {
87
+ const info = await connection.getAccountInfo(addr);
88
+ if (info) {
89
+ juplendCollateralLtvs[asset] = getJuplendCollateralLtvInfo(info.data);
90
+ }
91
+ }
92
+ catch (e) {
93
+ console.error(`Error fetching JupLend ${asset} vault config:`, e.message);
94
+ }
95
+ }));
96
+ return {
97
+ collateralSupplyAPYs,
98
+ collateralLtvs,
99
+ juplendCollateralSupplyAPYs,
100
+ juplendCollateralRewardsAPYs,
101
+ juplendCollateralLtvs,
102
+ };
103
+ }
104
+ //# sourceMappingURL=collateralInfo.js.map