@carrot-protocol/boost-http-client 0.2.15 → 0.2.16-group-refactor1-dev-50c976e

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrot-protocol/boost-http-client",
3
- "version": "0.2.15",
3
+ "version": "0.2.16-group-refactor1-dev-50c976e",
4
4
  "description": "HTTP client for Carrot Boost",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@coral-xyz/anchor": "^0.29.0",
17
- "@carrot-protocol/clend-common": "0.1.8-group-refactor1-dev-19efede",
17
+ "@carrot-protocol/clend-common": "0.1.7",
18
18
  "axios": "^1.8.3",
19
19
  "bs58": "^6.0.0",
20
20
  "decimal.js": "^10.5.0"
package/src/index.ts CHANGED
@@ -12,21 +12,13 @@ import {
12
12
  WithdrawLeverageResponse,
13
13
  UserWallet,
14
14
  ClendAccount,
15
- ClendAccountBalance,
15
+ Balance,
16
16
  Bank,
17
17
  GetGroupResponse,
18
18
  ClendAccountEvent,
19
19
  GetUserRequest,
20
20
  ClendAccountTxSummary,
21
21
  UserRequest,
22
- UserBalance,
23
- ClendAccountAssetLiquidation,
24
- GetGroupsResponse,
25
- GroupAndBanks,
26
- BankEmissions,
27
- BankEmissionsMode,
28
- WithdrawEmissionsRequest,
29
- WithdrawEmissionsResponse,
30
22
  } from "./types";
31
23
  import encode from "bs58";
32
24
 
@@ -106,207 +98,153 @@ export class Client {
106
98
  return handleApiCall(() => this.http.get(""));
107
99
  }
108
100
 
109
- async getUser(
110
- user: web3.PublicKey,
111
- groups: web3.PublicKey[],
112
- getClendAccountSummary: boolean,
113
- ): Promise<GetUserResponse> {
114
- // Make the API call to fetch the raw user data as a string.
101
+ /**
102
+ * Get user details for a wallet
103
+ * @param user wallet public key
104
+ * @returns User details
105
+ */
106
+ async getUser(request: GetUserRequest): Promise<GetUserResponse> {
107
+ // use loaded wallet if not provided
108
+ let user = request.user;
109
+ if (!user) {
110
+ user = this.address();
111
+ }
112
+
115
113
  const body = await handleApiCall(() =>
116
114
  this.http.get(
117
- `/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`,
115
+ `/user?user=${user.toString()}&getClendAccountSummary=${request.getClendAccountSummary}`,
118
116
  ),
119
117
  );
120
118
 
121
- // Parse the raw string body into a JSON object.
122
119
  const jsonRawResponse: any = JSON.parse(body);
123
120
 
124
- // 1. Parse Wallet Balances
125
- // This section correctly iterates through the wallet balances and creates typed objects.
126
- const walletBalances: UserBalance[] = (
127
- jsonRawResponse.wallet.balances || []
128
- ).map((b: any) => ({
129
- mint: new web3.PublicKey(b.mint),
130
- balance: new BN(b.balance, "hex"),
131
- balanceUi: Number(b.balanceUi),
132
- }));
133
-
121
+ // get tokens still in user wallet
134
122
  const wallet: UserWallet = {
135
- balances: walletBalances,
123
+ usdcBalance: new BN(jsonRawResponse.wallet.usdcBalance, "hex"),
124
+ usdcBalanceUi: Number(jsonRawResponse.wallet.usdcBalanceUi),
125
+ jlpBalance: new BN(jsonRawResponse.wallet.jlpBalance, "hex"),
126
+ jlpBalanceUi: Number(jsonRawResponse.wallet.jlpBalanceUi),
127
+ solBalance: new BN(jsonRawResponse.wallet.solBalance, "hex"),
128
+ solBalanceUi: Number(jsonRawResponse.wallet.solBalanceUi),
136
129
  };
137
130
 
138
- // 2. Parse Clend Accounts and their Summaries
139
- // This is the main refactored section. It iterates through the clendAccounts array
140
- // from the response, which contains both the account data and its summary.
141
- const clendAccounts = (jsonRawResponse.clendAccounts || []).map(
142
- (accountData: any) => {
143
- // A. Parse the main ClendAccount object
144
- const rawClendAccount = accountData.clendAccount;
145
- const clendAccountBalances: ClendAccountBalance[] = (
146
- rawClendAccount.balances || []
147
- ).map((b: any) => {
148
- const liquidation: ClendAccountAssetLiquidation | null = b.liquidation
149
- ? {
150
- price: Number(b.liquidation.price),
151
- changePercentage: Number(b.liquidation.changePercentage),
152
- }
153
- : null;
154
-
155
- const emissionsOutstandingAndUnclaimed = new BN(
156
- b.emissionsOutstandingAndUnclaimed,
157
- "hex",
158
- );
159
-
160
- return {
161
- mint: new web3.PublicKey(b.mint),
162
- bank: new web3.PublicKey(b.bank),
163
- tokenYieldApy: Number(b.tokenYieldApy),
164
- assetBalance: new BN(b.assetBalance, "hex"),
165
- assetBalanceUi: Number(b.assetBalanceUi),
166
- assetValue: Number(b.assetValue),
167
- assetEmissionsApy: Number(b.assetEmissionsApy),
168
- liabilityBalance: new BN(b.liabilityBalance, "hex"),
169
- liabilityBalanceUi: Number(b.liabilityBalanceUi),
170
- liabilityValue: Number(b.liabilityValue),
171
- liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
172
- liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
173
- emissionsOutstandingAndUnclaimed,
174
- emissionsOutstandingAndUnclaimedUi: Number(
175
- b.emissionsOutstandingAndUnclaimedUi,
176
- ),
177
- price: Number(b.price),
178
- liquidation,
179
- };
180
- });
181
-
182
- const clendAccount: ClendAccount = {
183
- key: new web3.PublicKey(rawClendAccount.key),
184
- group: new web3.PublicKey(rawClendAccount.group),
185
- balances: clendAccountBalances,
186
- netValue: Number(rawClendAccount.netValue),
187
- netApy: Number(rawClendAccount.netApy),
188
- pnl: Number(rawClendAccount.pnl),
189
- totalEmissionsApy: Number(rawClendAccount.totalEmissionsApy),
190
- totalAssetValue: Number(rawClendAccount.totalAssetValue),
191
- totalLiabilityValue: Number(rawClendAccount.totalLiabilityValue),
192
- healthFactorNotional: Number(rawClendAccount.healthFactorNotional),
193
- healthFactorRiskAdjusted: Number(
194
- rawClendAccount.healthFactorRiskAdjusted,
195
- ),
196
- notionalLeverage: Number(rawClendAccount.notionalLeverage),
197
- riskAdjustedLeverage: Number(rawClendAccount.riskAdjustedLeverage),
198
- notionalLtv: Number(rawClendAccount.notionalLtv),
199
- riskAdjustedLtv: Number(rawClendAccount.riskAdjustedLtv),
131
+ // if no clend account, return undefined for clend
132
+ if (!jsonRawResponse.clendAccount) {
133
+ return {
134
+ wallet,
135
+ clendAccount: undefined,
136
+ summary: [],
137
+ };
138
+ }
139
+
140
+ // parse lending account balances
141
+ const balances: Balance[] = [];
142
+ for (const b of jsonRawResponse.clendAccount.balances) {
143
+ balances.push({
144
+ mint: new web3.PublicKey(b.mint),
145
+ bank: new web3.PublicKey(b.bank),
146
+ assetBalance: new BN(b.assetBalance, "hex"),
147
+ assetBalanceUi: Number(b.assetBalanceUi),
148
+ assetValue: Number(b.assetValue),
149
+ liabilityBalance: new BN(b.liabilityBalance, "hex"),
150
+ liabilityBalanceUi: Number(b.liabilityBalanceUi),
151
+ liabilityValue: Number(b.liabilityValue),
152
+ price: Number(b.price),
153
+ });
154
+ }
155
+
156
+ // create clend account
157
+ const clendAccount: ClendAccount = {
158
+ balances,
159
+ netValue: Number(jsonRawResponse.clendAccount.netValue),
160
+ netApy: Number(jsonRawResponse.clendAccount.netApy),
161
+ pnl: Number(jsonRawResponse.clendAccount.pnl),
162
+ totalAssetValue: Number(jsonRawResponse.clendAccount.totalAssetValue),
163
+ totalLiabilityValue: Number(
164
+ jsonRawResponse.clendAccount.totalLiabilityValue,
165
+ ),
166
+ healthFactorNotional: Number(
167
+ jsonRawResponse.clendAccount.healthFactorNotional,
168
+ ),
169
+ healthFactorRiskAdjusted: Number(
170
+ jsonRawResponse.clendAccount.healthFactorRiskAdjusted,
171
+ ),
172
+ notionalLeverage: Number(jsonRawResponse.clendAccount.notionalLeverage),
173
+ riskAdjustedLeverage: Number(
174
+ jsonRawResponse.clendAccount.riskAdjustedLeverage,
175
+ ),
176
+ liquidationPrice: Number(jsonRawResponse.clendAccount.liquidationPrice),
177
+ liquidationPriceChangePercentage: Number(
178
+ jsonRawResponse.clendAccount.liquidationPriceChangePercentage,
179
+ ),
180
+ notionalLtv: Number(jsonRawResponse.clendAccount.notionalLtv),
181
+ riskAdjustedLtv: Number(jsonRawResponse.clendAccount.riskAdjustedLtv),
182
+ };
183
+
184
+ // get tx summary for each account
185
+ const summary: ClendAccountTxSummary[] = [];
186
+ for (const s of jsonRawResponse.summary) {
187
+ const txSummary: ClendAccountTxSummary = {
188
+ txSig: s.txSig,
189
+ time: s.time,
190
+ clendAccount: new web3.PublicKey(s.clendAccount),
191
+ clendAccountAuthority: new web3.PublicKey(s.clendAccountAuthority),
192
+ clendGroup: new web3.PublicKey(s.clendGroup),
193
+ action: s.action,
194
+ input: undefined,
195
+ events: [],
196
+ };
197
+
198
+ // parse inputs if they exist
199
+ if (s.input) {
200
+ const input: UserRequest = {
201
+ apiPath: s.input.apiPath,
202
+ selectedTokenMint: s.input.selectedTokenMint
203
+ ? new web3.PublicKey(s.input.selectedTokenMint)
204
+ : null,
205
+ amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
206
+ leverage: s.input.leverage ? Number(s.input.leverage) : null,
207
+ slippageBps: s.input.slippageBps ? Number(s.input.slippageBps) : null,
208
+ openPosition: s.input.openPosition
209
+ ? Boolean(s.input.openPosition)
210
+ : null,
211
+ closePosition: s.input.closePosition
212
+ ? Boolean(s.input.closePosition)
213
+ : null,
200
214
  };
215
+ txSummary.input = input;
216
+ }
201
217
 
202
- // B. Parse the associated Summary array for the account
203
- let summary: ClendAccountTxSummary[] = [];
204
- if (getClendAccountSummary && accountData.summary) {
205
- summary = accountData.summary.map((s: any) => {
206
- let input: UserRequest | undefined = undefined;
207
- if (s.input) {
208
- input = {
209
- apiPath: s.input.apiPath,
210
- selectedTokenMint: s.input.selectedTokenMint
211
- ? new web3.PublicKey(s.input.selectedTokenMint)
212
- : null,
213
- amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
214
- leverage: s.input.leverage ? Number(s.input.leverage) : null,
215
- slippageBps: s.input.slippageBps
216
- ? Number(s.input.slippageBps)
217
- : null,
218
- openPosition:
219
- s.input.openPosition != null
220
- ? Boolean(s.input.openPosition)
221
- : null,
222
- closePosition:
223
- s.input.closePosition != null
224
- ? Boolean(s.input.closePosition)
225
- : null,
226
- };
227
- }
228
-
229
- const events: ClendAccountEvent[] = (s.events || []).map(
230
- (event: any) => {
231
- let closeBalance: boolean | null = null;
232
- // Only convert to boolean if the value is not null/undefined to preserve the null state.
233
- if (
234
- event.closeBalance !== null &&
235
- event.closeBalance !== undefined
236
- ) {
237
- closeBalance = Boolean(event.closeBalance);
238
- }
239
-
240
- return {
241
- eventIndex: event.eventIndex,
242
- eventName: event.eventName,
243
- bank: event.bank ? new web3.PublicKey(event.bank) : null,
244
- mint: event.mint ? new web3.PublicKey(event.mint) : null,
245
- amount: event.amount ? new BN(event.amount, "hex") : null,
246
- amountUi: event.amountUi ? Number(event.amountUi) : null,
247
- value: event.value ? Number(event.value) : null,
248
- price: event.price ? Number(event.price) : null,
249
- closeBalance,
250
- };
251
- },
252
- );
253
-
254
- const txSummary: ClendAccountTxSummary = {
255
- txSig: s.txSig,
256
- time: s.time,
257
- clendAccount: new web3.PublicKey(s.clendAccount),
258
- clendAccountAuthority: new web3.PublicKey(
259
- s.clendAccountAuthority,
260
- ),
261
- clendGroup: new web3.PublicKey(s.clendGroup),
262
- action: s.action,
263
- input,
264
- events,
265
- };
266
- return txSummary;
267
- });
218
+ // get events for each summary
219
+ for (const event of s.events) {
220
+ let closeBalance: boolean | null = null;
221
+ if (event.closeBalance !== null) {
222
+ closeBalance = Boolean(event.closeBalance);
268
223
  }
269
224
 
270
- // C. Combine the parsed account and its summary
271
- return { clendAccount, summary };
272
- },
273
- );
225
+ // parse amount
226
+ const clendAccountEvent: ClendAccountEvent = {
227
+ eventIndex: event.eventIndex,
228
+ eventName: event.eventName,
229
+ bank: event.bank ? new web3.PublicKey(event.bank) : null,
230
+ mint: event.mint ? new web3.PublicKey(event.mint) : null,
231
+ amount: event.amount ? new BN(event.amount, "hex") : null,
232
+ amountUi: event.amountUi ? Number(event.amountUi) : null,
233
+ value: event.value ? Number(event.value) : null,
234
+ price: event.price ? Number(event.price) : null,
235
+ closeBalance,
236
+ };
237
+ txSummary.events.push(clendAccountEvent);
238
+ }
239
+ summary.push(txSummary);
240
+ }
274
241
 
275
- // 3. Return the final, correctly structured response object.
276
242
  return {
277
243
  wallet,
278
- clendAccounts,
244
+ clendAccount,
245
+ summary,
279
246
  };
280
247
  }
281
- /**
282
- * Get all groups
283
- * @param includeBankData Whether to include bank data in the response, if not strictly necessary keep false
284
- * @returns All groups
285
- */
286
- async getGroups(includeBankData: boolean): Promise<GetGroupsResponse> {
287
- const body = await handleApiCall(() =>
288
- this.http.get(`/groups?includeBankData=${includeBankData}`),
289
- );
290
-
291
- const marketJson: any = JSON.parse(body);
292
- const groups: GroupAndBanks[] = [];
293
- for (const groupJson of marketJson.groups) {
294
- const group: web3.PublicKey = new web3.PublicKey(groupJson.group);
295
- const groupName = groupJson.groupName;
296
- const banks: Bank[] = [];
297
- for (const bankJson of groupJson.banks) {
298
- const bank = parseBank(bankJson);
299
- banks.push(bank);
300
- }
301
- groups.push({ group, groupName, banks });
302
- }
303
-
304
- const response: GetGroupsResponse = {
305
- groups,
306
- };
307
-
308
- return response;
309
- }
310
248
 
311
249
  /**
312
250
  * Get market details
@@ -319,18 +257,14 @@ export class Client {
319
257
  );
320
258
 
321
259
  const marketJson: any = JSON.parse(body);
322
- const group: GroupAndBanks = {
323
- group: new web3.PublicKey(marketJson.group.group),
324
- groupName: marketJson.group.groupName,
325
- banks: [],
326
- };
327
- for (const bankJson of marketJson.group.banks) {
260
+ const banks: Bank[] = [];
261
+ for (const bankJson of marketJson.banks) {
328
262
  const bank = parseBank(bankJson);
329
- group.banks.push(bank);
263
+ banks.push(bank);
330
264
  }
331
265
 
332
266
  const response: GetGroupResponse = {
333
- group,
267
+ banks,
334
268
  };
335
269
 
336
270
  return response;
@@ -362,19 +296,14 @@ export class Client {
362
296
  * @returns Deposit leverage operation result
363
297
  */
364
298
  async depositLeverage(
365
- clendGroup: web3.PublicKey,
366
- clendAccount: web3.PublicKey | null,
367
- inputTokenMint: web3.PublicKey,
368
- assetTokenMint: web3.PublicKey,
369
- liabilityTokenMint: web3.PublicKey,
299
+ inputMint: web3.PublicKey,
300
+ assetMint: web3.PublicKey,
301
+ liabilityMint: web3.PublicKey,
370
302
  uiAmount: number,
371
303
  leverage: number,
372
304
  slippageBps: number,
373
305
  ): Promise<string> {
374
- if (
375
- !inputTokenMint.equals(assetTokenMint) &&
376
- !inputTokenMint.equals(liabilityTokenMint)
377
- ) {
306
+ if (!inputMint.equals(assetMint) || !inputMint.equals(liabilityMint)) {
378
307
  throw new Error(
379
308
  "Input mint must be the same as the asset or liability mint",
380
309
  );
@@ -382,11 +311,9 @@ export class Client {
382
311
 
383
312
  const req: DepositLeverageRequest = {
384
313
  owner: this.address(),
385
- clendGroup,
386
- clendAccount,
387
- inputTokenMint,
388
- assetTokenMint,
389
- liabilityTokenMint,
314
+ inputMint,
315
+ assetMint,
316
+ liabilityMint,
390
317
  depositAmountUi: uiAmount,
391
318
  leverage,
392
319
  slippageBps,
@@ -410,17 +337,9 @@ export class Client {
410
337
  * @param request Adjust leverage request parameters
411
338
  * @returns Adjust leverage operation result
412
339
  */
413
- async adjustLeverage(
414
- clendAccount: web3.PublicKey,
415
- assetTokenMint: web3.PublicKey,
416
- liabilityTokenMint: web3.PublicKey,
417
- leverage: number,
418
- slippageBps: number,
419
- ): Promise<string> {
340
+ async adjustLeverage(leverage: number, slippageBps: number): Promise<any> {
420
341
  const req: AdjustLeverageRequest = {
421
- clendAccount,
422
- assetTokenMint,
423
- liabilityTokenMint,
342
+ owner: this.address(),
424
343
  leverage,
425
344
  slippageBps,
426
345
  };
@@ -444,19 +363,14 @@ export class Client {
444
363
  * @returns Withdraw leverage operation result
445
364
  */
446
365
  async withdrawLeverage(
447
- clendAccount: web3.PublicKey,
448
- outputTokenMint: web3.PublicKey,
449
- assetTokenMint: web3.PublicKey,
450
- liabilityTokenMint: web3.PublicKey,
366
+ selectedTokenMint: web3.PublicKey,
451
367
  uiAmount: number,
452
368
  slippageBps: number,
453
369
  withdrawAll: boolean,
454
- ): Promise<string> {
370
+ ): Promise<any> {
455
371
  const req: WithdrawLeverageRequest = {
456
- clendAccount,
457
- outputTokenMint,
458
- assetTokenMint,
459
- liabilityTokenMint,
372
+ owner: this.address(),
373
+ selectedTokenMint,
460
374
  withdrawAmountUi: uiAmount,
461
375
  slippageBps,
462
376
  withdrawAll,
@@ -474,30 +388,6 @@ export class Client {
474
388
 
475
389
  return txSig;
476
390
  }
477
-
478
- /**
479
- * Withdraw emissions from a bank
480
- * @returns Withdraw emissions operation result
481
- */
482
- async withdrawEmissions(): Promise<string> {
483
- const req: WithdrawEmissionsRequest = {
484
- owner: this.address(),
485
- };
486
-
487
- const body = await handleApiCall(() =>
488
- this.http.post("emissions/withdraw", JSON.stringify(req)),
489
- );
490
-
491
- const withdrawEmissionsResponse: WithdrawEmissionsResponse =
492
- JSON.parse(body);
493
-
494
- const txSig = await this.send(
495
- withdrawEmissionsResponse.unsignedBase64Tx,
496
- withdrawEmissionsResponse.userRequestId,
497
- );
498
-
499
- return txSig;
500
- }
501
391
  }
502
392
 
503
393
  type ApiErrorPayload = {
@@ -507,6 +397,15 @@ type ApiErrorPayload = {
507
397
  timestamp: string;
508
398
  };
509
399
 
400
+ function handleStatusCode(statusCode: number): void {
401
+ switch (statusCode) {
402
+ case 200:
403
+ break;
404
+ default:
405
+ throw new Error(`unexpected status code: ${statusCode}`);
406
+ }
407
+ }
408
+
510
409
  // Helper function to handle API calls
511
410
  async function handleApiCall<T>(
512
411
  call: () => Promise<AxiosResponse<T>>,
@@ -540,18 +439,6 @@ function getDummyProvider(): AnchorProvider {
540
439
  }
541
440
 
542
441
  function parseBank(bankJson: any): Bank {
543
- let bankEmissions: BankEmissions | null = null;
544
- if (bankJson.emissions) {
545
- bankEmissions = {
546
- emissionsMode: bankJson.emissions.emissionsMode as BankEmissionsMode,
547
- emissionsApy: Number(bankJson.emissions.emissionsApy),
548
- emissionsMint: new web3.PublicKey(bankJson.emissions.emissionsMint),
549
- emissionsTokenPrice: Number(bankJson.emissions.emissionsTokenPrice),
550
- emissionsRate: new BN(bankJson.emissions.emissionsRate, "hex"),
551
- emissionsRemainingUi: Number(bankJson.emissions.emissionsRemainingUi),
552
- };
553
- }
554
-
555
442
  return {
556
443
  mint: new web3.PublicKey(bankJson.mint),
557
444
  key: new web3.PublicKey(bankJson.key),
@@ -565,7 +452,6 @@ function parseBank(bankJson: any): Bank {
565
452
  assetMaintWeight: Number(bankJson.assetMaintWeight),
566
453
  totalAssetShares: Number(bankJson.totalAssetShares),
567
454
  assetShareValue: Number(bankJson.assetShareValue),
568
- tokenYieldApy: Number(bankJson.tokenYieldApy),
569
455
  liabilityAmount: new BN(bankJson.liabilityAmount, "hex"),
570
456
  liabilityAmountUi: Number(bankJson.liabilityAmountUi),
571
457
  liabilityInitWeight: Number(bankJson.liabilityInitWeight),
@@ -577,6 +463,5 @@ function parseBank(bankJson: any): Bank {
577
463
  depositLimitUi: Number(bankJson.depositLimitUi),
578
464
  borrowLimit: new BN(bankJson.borrowLimit, "hex"),
579
465
  borrowLimitUi: Number(bankJson.borrowLimitUi),
580
- emissions: bankEmissions,
581
466
  };
582
467
  }