@carrot-protocol/boost-http-client 0.2.15-group-refactor1-dev-b489da8 → 0.2.15-swapper1-dev-cda79a9

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/dist/index.d.ts CHANGED
@@ -22,7 +22,12 @@ export declare class Client {
22
22
  * @returns Index details
23
23
  */
24
24
  index(): Promise<any>;
25
- getUser(user: web3.PublicKey, groups: web3.PublicKey[], getClendAccountSummary: boolean): Promise<GetUserResponse>;
25
+ /**
26
+ * Get user details for a wallet
27
+ * @param user wallet public key
28
+ * @returns User details
29
+ */
30
+ getUser(groups: web3.PublicKey[], user: web3.PublicKey, getClendAccountSummary: boolean): Promise<GetUserResponse>;
26
31
  /**
27
32
  * Get all groups
28
33
  * @param includeBankData Whether to include bank data in the response, if not strictly necessary keep false
@@ -52,16 +57,11 @@ export declare class Client {
52
57
  * @param request Adjust leverage request parameters
53
58
  * @returns Adjust leverage operation result
54
59
  */
55
- adjustLeverage(clendGroup: web3.PublicKey, clendAccount: web3.PublicKey, assetTokenMint: web3.PublicKey, liabilityTokenMint: web3.PublicKey, leverage: number, slippageBps: number): Promise<string>;
60
+ adjustLeverage(clendGroup: web3.PublicKey, clendAccount: web3.PublicKey, assetTokenMint: web3.PublicKey, liabilityTokenMint: web3.PublicKey, leverage: number, slippageBps: number): Promise<any>;
56
61
  /**
57
62
  * Withdraw from or close a leveraged position
58
63
  * @param request Withdraw leverage request parameters
59
64
  * @returns Withdraw leverage operation result
60
65
  */
61
- withdrawLeverage(clendGroup: web3.PublicKey, clendAccount: web3.PublicKey, outputTokenMint: web3.PublicKey, assetTokenMint: web3.PublicKey, liabilityTokenMint: web3.PublicKey, uiAmount: number, slippageBps: number, withdrawAll: boolean): Promise<string>;
62
- /**
63
- * Withdraw emissions from a bank
64
- * @returns Withdraw emissions operation result
65
- */
66
- withdrawEmissions(): Promise<string>;
66
+ withdrawLeverage(clendGroup: web3.PublicKey, clendAccount: web3.PublicKey, outputTokenMint: web3.PublicKey, assetTokenMint: web3.PublicKey, liabilityTokenMint: web3.PublicKey, uiAmount: number, slippageBps: number, withdrawAll: boolean): Promise<any>;
67
67
  }
package/dist/index.js CHANGED
@@ -99,131 +99,143 @@ class Client {
99
99
  async index() {
100
100
  return handleApiCall(() => this.http.get(""));
101
101
  }
102
- async getUser(user, groups, getClendAccountSummary) {
103
- // Make the API call to fetch the raw user data as a string.
102
+ /**
103
+ * Get user details for a wallet
104
+ * @param user wallet public key
105
+ * @returns User details
106
+ */
107
+ async getUser(groups, user, getClendAccountSummary) {
104
108
  const body = await handleApiCall(() => this.http.get(`/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`));
105
- // Parse the raw string body into a JSON object.
106
109
  const jsonRawResponse = JSON.parse(body);
107
- // 1. Parse Wallet Balances
108
- // This section correctly iterates through the wallet balances and creates typed objects.
109
- const walletBalances = (jsonRawResponse.wallet.balances || []).map((b) => ({
110
- mint: new anchor_1.web3.PublicKey(b.mint),
111
- balance: new anchor_1.BN(b.balance, "hex"),
112
- balanceUi: Number(b.balanceUi),
113
- }));
110
+ console.log(JSON.stringify(jsonRawResponse, null, 2));
111
+ // parse balances
112
+ const walletBalances = [];
113
+ for (const b of jsonRawResponse.wallet.balances) {
114
+ walletBalances.push({
115
+ mint: new anchor_1.web3.PublicKey(b.mint),
116
+ balance: new anchor_1.BN(b.balance, "hex"),
117
+ balanceUi: Number(b.balanceUi),
118
+ });
119
+ }
120
+ // get tokens still in user wallet
114
121
  const wallet = {
115
122
  balances: walletBalances,
116
123
  };
117
- // 2. Parse Clend Accounts and their Summaries
118
- // This is the main refactored section. It iterates through the clendAccounts array
119
- // from the response, which contains both the account data and its summary.
120
- const clendAccounts = (jsonRawResponse.clendAccounts || []).map((accountData) => {
121
- // A. Parse the main ClendAccount object
122
- const rawClendAccount = accountData.clendAccount;
123
- const clendAccountBalances = (rawClendAccount.balances || []).map((b) => {
124
+ // get tx summary for each account and group them
125
+ const summaryByAccount = new Map();
126
+ if (getClendAccountSummary && jsonRawResponse.summary) {
127
+ for (const s of jsonRawResponse.summary) {
128
+ const accountAddress = new anchor_1.web3.PublicKey(s.clendAccount).toBase58();
129
+ if (!summaryByAccount.has(accountAddress)) {
130
+ summaryByAccount.set(accountAddress, []);
131
+ }
132
+ const txSummary = {
133
+ txSig: s.txSig,
134
+ time: s.time,
135
+ clendAccount: new anchor_1.web3.PublicKey(s.clendAccount),
136
+ clendAccountAuthority: new anchor_1.web3.PublicKey(s.clendAccountAuthority),
137
+ clendGroup: new anchor_1.web3.PublicKey(s.clendGroup),
138
+ action: s.action,
139
+ input: undefined,
140
+ events: [],
141
+ };
142
+ // parse inputs if they exist
143
+ if (s.input) {
144
+ const input = {
145
+ apiPath: s.input.apiPath,
146
+ selectedTokenMint: s.input.selectedTokenMint
147
+ ? new anchor_1.web3.PublicKey(s.input.selectedTokenMint)
148
+ : null,
149
+ amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
150
+ leverage: s.input.leverage ? Number(s.input.leverage) : null,
151
+ slippageBps: s.input.slippageBps
152
+ ? Number(s.input.slippageBps)
153
+ : null,
154
+ openPosition: s.input.openPosition
155
+ ? Boolean(s.input.openPosition)
156
+ : null,
157
+ closePosition: s.input.closePosition
158
+ ? Boolean(s.input.closePosition)
159
+ : null,
160
+ };
161
+ txSummary.input = input;
162
+ }
163
+ // get events for each summary
164
+ for (const event of s.events) {
165
+ let closeBalance = null;
166
+ if (event.closeBalance !== null) {
167
+ closeBalance = Boolean(event.closeBalance);
168
+ }
169
+ // parse amount
170
+ const clendAccountEvent = {
171
+ eventIndex: event.eventIndex,
172
+ eventName: event.eventName,
173
+ bank: event.bank ? new anchor_1.web3.PublicKey(event.bank) : null,
174
+ mint: event.mint ? new anchor_1.web3.PublicKey(event.mint) : null,
175
+ amount: event.amount ? new anchor_1.BN(event.amount, "hex") : null,
176
+ amountUi: event.amountUi ? Number(event.amountUi) : null,
177
+ value: event.value ? Number(event.value) : null,
178
+ price: event.price ? Number(event.price) : null,
179
+ closeBalance,
180
+ };
181
+ txSummary.events.push(clendAccountEvent);
182
+ }
183
+ summaryByAccount.get(accountAddress).push(txSummary);
184
+ }
185
+ }
186
+ // if no clend accounts, return empty array
187
+ const clendAccounts = [];
188
+ for (const accountAndSumary of jsonRawResponse.clendAccounts) {
189
+ const clendAccountBalances = [];
190
+ const ca = accountAndSumary.clendAccount;
191
+ for (const b of ca.balances) {
192
+ // parse liquidation data if exists
124
193
  const liquidation = b.liquidation
125
194
  ? {
126
195
  price: Number(b.liquidation.price),
127
196
  changePercentage: Number(b.liquidation.changePercentage),
128
197
  }
129
198
  : null;
130
- const emissionsOutstandingAndUnclaimed = new anchor_1.BN(b.emissionsOutstandingAndUnclaimed, "hex");
131
- return {
199
+ // create clend account balance
200
+ clendAccountBalances.push({
132
201
  mint: new anchor_1.web3.PublicKey(b.mint),
133
202
  bank: new anchor_1.web3.PublicKey(b.bank),
134
- tokenYieldApy: Number(b.tokenYieldApy),
135
203
  assetBalance: new anchor_1.BN(b.assetBalance, "hex"),
136
204
  assetBalanceUi: Number(b.assetBalanceUi),
137
205
  assetValue: Number(b.assetValue),
138
- assetEmissionsApy: Number(b.assetEmissionsApy),
206
+ assetYieldBps: Number(b.assetYieldBps),
207
+ assetYieldApy: Number(b.assetYieldApy),
139
208
  liabilityBalance: new anchor_1.BN(b.liabilityBalance, "hex"),
140
209
  liabilityBalanceUi: Number(b.liabilityBalanceUi),
141
210
  liabilityValue: Number(b.liabilityValue),
211
+ liabilityBorrowCostBps: Number(b.liabilityBorrowCostBps),
142
212
  liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
143
- liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
144
- emissionsOutstandingAndUnclaimed,
145
- emissionsOutstandingAndUnclaimedUi: Number(b.emissionsOutstandingAndUnclaimedUi),
146
213
  price: Number(b.price),
147
214
  liquidation,
148
- };
149
- });
215
+ });
216
+ }
217
+ // create clend account
218
+ const clendAccountAddress = new anchor_1.web3.PublicKey(accountAndSumary.clendAccount.key);
150
219
  const clendAccount = {
151
- key: new anchor_1.web3.PublicKey(rawClendAccount.key),
152
- group: new anchor_1.web3.PublicKey(rawClendAccount.group),
220
+ key: clendAccountAddress,
221
+ group: new anchor_1.web3.PublicKey(ca.group),
153
222
  balances: clendAccountBalances,
154
- netValue: Number(rawClendAccount.netValue),
155
- netApy: Number(rawClendAccount.netApy),
156
- pnl: Number(rawClendAccount.pnl),
157
- totalEmissionsApy: Number(rawClendAccount.totalEmissionsApy),
158
- totalAssetValue: Number(rawClendAccount.totalAssetValue),
159
- totalLiabilityValue: Number(rawClendAccount.totalLiabilityValue),
160
- healthFactorNotional: Number(rawClendAccount.healthFactorNotional),
161
- healthFactorRiskAdjusted: Number(rawClendAccount.healthFactorRiskAdjusted),
162
- notionalLeverage: Number(rawClendAccount.notionalLeverage),
163
- riskAdjustedLeverage: Number(rawClendAccount.riskAdjustedLeverage),
164
- notionalLtv: Number(rawClendAccount.notionalLtv),
165
- riskAdjustedLtv: Number(rawClendAccount.riskAdjustedLtv),
223
+ netValue: Number(ca.netValue),
224
+ netApy: Number(ca.netApy),
225
+ pnl: Number(ca.pnl),
226
+ totalAssetValue: Number(ca.totalAssetValue),
227
+ totalLiabilityValue: Number(ca.totalLiabilityValue),
228
+ healthFactorNotional: Number(ca.healthFactorNotional),
229
+ healthFactorRiskAdjusted: Number(ca.healthFactorRiskAdjusted),
230
+ notionalLeverage: Number(ca.notionalLeverage),
231
+ riskAdjustedLeverage: Number(ca.riskAdjustedLeverage),
232
+ notionalLtv: Number(ca.notionalLtv),
233
+ riskAdjustedLtv: Number(ca.riskAdjustedLtv),
166
234
  };
167
- // B. Parse the associated Summary array for the account
168
- let summary = [];
169
- if (getClendAccountSummary && accountData.summary) {
170
- summary = accountData.summary.map((s) => {
171
- let input = undefined;
172
- if (s.input) {
173
- input = {
174
- apiPath: s.input.apiPath,
175
- selectedTokenMint: s.input.selectedTokenMint
176
- ? new anchor_1.web3.PublicKey(s.input.selectedTokenMint)
177
- : null,
178
- amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
179
- leverage: s.input.leverage ? Number(s.input.leverage) : null,
180
- slippageBps: s.input.slippageBps
181
- ? Number(s.input.slippageBps)
182
- : null,
183
- openPosition: s.input.openPosition != null
184
- ? Boolean(s.input.openPosition)
185
- : null,
186
- closePosition: s.input.closePosition != null
187
- ? Boolean(s.input.closePosition)
188
- : null,
189
- };
190
- }
191
- const events = (s.events || []).map((event) => {
192
- let closeBalance = null;
193
- // Only convert to boolean if the value is not null/undefined to preserve the null state.
194
- if (event.closeBalance !== null &&
195
- event.closeBalance !== undefined) {
196
- closeBalance = Boolean(event.closeBalance);
197
- }
198
- return {
199
- eventIndex: event.eventIndex,
200
- eventName: event.eventName,
201
- bank: event.bank ? new anchor_1.web3.PublicKey(event.bank) : null,
202
- mint: event.mint ? new anchor_1.web3.PublicKey(event.mint) : null,
203
- amount: event.amount ? new anchor_1.BN(event.amount, "hex") : null,
204
- amountUi: event.amountUi ? Number(event.amountUi) : null,
205
- value: event.value ? Number(event.value) : null,
206
- price: event.price ? Number(event.price) : null,
207
- closeBalance,
208
- };
209
- });
210
- const txSummary = {
211
- txSig: s.txSig,
212
- time: s.time,
213
- clendAccount: new anchor_1.web3.PublicKey(s.clendAccount),
214
- clendAccountAuthority: new anchor_1.web3.PublicKey(s.clendAccountAuthority),
215
- clendGroup: new anchor_1.web3.PublicKey(s.clendGroup),
216
- action: s.action,
217
- input,
218
- events,
219
- };
220
- return txSummary;
221
- });
222
- }
223
- // C. Combine the parsed account and its summary
224
- return { clendAccount, summary };
225
- });
226
- // 3. Return the final, correctly structured response object.
235
+ // find corresponding tx summary for account
236
+ const summary = summaryByAccount.get(clendAccountAddress.toString()) || [];
237
+ clendAccounts.push({ clendAccount, summary });
238
+ }
227
239
  return {
228
240
  wallet,
229
241
  clendAccounts,
@@ -322,6 +334,8 @@ class Client {
322
334
  */
323
335
  async adjustLeverage(clendGroup, clendAccount, assetTokenMint, liabilityTokenMint, leverage, slippageBps) {
324
336
  const req = {
337
+ owner: this.address(),
338
+ clendGroup,
325
339
  clendAccount,
326
340
  assetTokenMint,
327
341
  liabilityTokenMint,
@@ -340,6 +354,8 @@ class Client {
340
354
  */
341
355
  async withdrawLeverage(clendGroup, clendAccount, outputTokenMint, assetTokenMint, liabilityTokenMint, uiAmount, slippageBps, withdrawAll) {
342
356
  const req = {
357
+ owner: this.address(),
358
+ clendGroup,
343
359
  clendAccount,
344
360
  outputTokenMint,
345
361
  assetTokenMint,
@@ -353,21 +369,16 @@ class Client {
353
369
  const txSig = await this.send(withdrawLeverageResponse.unsignedBase64Tx, withdrawLeverageResponse.userRequestId);
354
370
  return txSig;
355
371
  }
356
- /**
357
- * Withdraw emissions from a bank
358
- * @returns Withdraw emissions operation result
359
- */
360
- async withdrawEmissions() {
361
- const req = {
362
- owner: this.address(),
363
- };
364
- const body = await handleApiCall(() => this.http.post("emissions/withdraw", JSON.stringify(req)));
365
- const withdrawEmissionsResponse = JSON.parse(body);
366
- const txSig = await this.send(withdrawEmissionsResponse.unsignedBase64Tx, withdrawEmissionsResponse.userRequestId);
367
- return txSig;
368
- }
369
372
  }
370
373
  exports.Client = Client;
374
+ function handleStatusCode(statusCode) {
375
+ switch (statusCode) {
376
+ case 200:
377
+ break;
378
+ default:
379
+ throw new Error(`unexpected status code: ${statusCode}`);
380
+ }
381
+ }
371
382
  // Helper function to handle API calls
372
383
  async function handleApiCall(call) {
373
384
  try {
@@ -392,17 +403,6 @@ function getDummyProvider() {
392
403
  });
393
404
  }
394
405
  function parseBank(bankJson) {
395
- let bankEmissions = null;
396
- if (bankJson.emissions) {
397
- bankEmissions = {
398
- emissionsMode: bankJson.emissions.emissionsMode,
399
- emissionsApy: Number(bankJson.emissions.emissionsApy),
400
- emissionsMint: new anchor_1.web3.PublicKey(bankJson.emissions.emissionsMint),
401
- emissionsTokenPrice: Number(bankJson.emissions.emissionsTokenPrice),
402
- emissionsRate: new anchor_1.BN(bankJson.emissions.emissionsRate, "hex"),
403
- emissionsRemainingUi: Number(bankJson.emissions.emissionsRemainingUi),
404
- };
405
- }
406
406
  return {
407
407
  mint: new anchor_1.web3.PublicKey(bankJson.mint),
408
408
  key: new anchor_1.web3.PublicKey(bankJson.key),
@@ -416,7 +416,6 @@ function parseBank(bankJson) {
416
416
  assetMaintWeight: Number(bankJson.assetMaintWeight),
417
417
  totalAssetShares: Number(bankJson.totalAssetShares),
418
418
  assetShareValue: Number(bankJson.assetShareValue),
419
- tokenYieldApy: Number(bankJson.tokenYieldApy),
420
419
  liabilityAmount: new anchor_1.BN(bankJson.liabilityAmount, "hex"),
421
420
  liabilityAmountUi: Number(bankJson.liabilityAmountUi),
422
421
  liabilityInitWeight: Number(bankJson.liabilityInitWeight),
@@ -428,6 +427,5 @@ function parseBank(bankJson) {
428
427
  depositLimitUi: Number(bankJson.depositLimitUi),
429
428
  borrowLimit: new anchor_1.BN(bankJson.borrowLimit, "hex"),
430
429
  borrowLimitUi: Number(bankJson.borrowLimitUi),
431
- emissions: bankEmissions,
432
430
  };
433
431
  }
package/dist/types.d.ts CHANGED
@@ -28,6 +28,8 @@ export interface DepositLeverageResponse {
28
28
  * Request to adjust the leverage of an existing position
29
29
  */
30
30
  export interface AdjustLeverageRequest {
31
+ owner: web3.PublicKey;
32
+ clendGroup: web3.PublicKey;
31
33
  clendAccount: web3.PublicKey;
32
34
  assetTokenMint: web3.PublicKey;
33
35
  liabilityTokenMint: web3.PublicKey;
@@ -45,6 +47,8 @@ export interface AdjustLeverageResponse {
45
47
  * Request to withdraw from a leveraged position
46
48
  */
47
49
  export interface WithdrawLeverageRequest {
50
+ owner: web3.PublicKey;
51
+ clendGroup: web3.PublicKey;
48
52
  clendAccount: web3.PublicKey;
49
53
  outputTokenMint: web3.PublicKey;
50
54
  assetTokenMint: web3.PublicKey;
@@ -60,19 +64,6 @@ export interface WithdrawLeverageResponse {
60
64
  userRequestId: string;
61
65
  unsignedBase64Tx: string;
62
66
  }
63
- /**
64
- * Request to withdraw emissions from a bank
65
- */
66
- export interface WithdrawEmissionsRequest {
67
- owner: web3.PublicKey;
68
- }
69
- /**
70
- * Response for withdraw emissions operation
71
- */
72
- export interface WithdrawEmissionsResponse {
73
- userRequestId: string;
74
- unsignedBase64Tx: string;
75
- }
76
67
  export interface GetGroupsResponse {
77
68
  groups: GroupAndBanks[];
78
69
  }
@@ -111,7 +102,6 @@ export interface ClendAccount {
111
102
  netValue: number;
112
103
  netApy: number;
113
104
  pnl: number;
114
- totalEmissionsApy: number;
115
105
  totalAssetValue: number;
116
106
  totalLiabilityValue: number;
117
107
  healthFactorNotional: number;
@@ -124,18 +114,16 @@ export interface ClendAccount {
124
114
  export interface ClendAccountBalance {
125
115
  mint: web3.PublicKey;
126
116
  bank: web3.PublicKey;
127
- tokenYieldApy: number;
128
117
  assetBalance: BN;
129
118
  assetBalanceUi: number;
130
119
  assetValue: number;
131
- assetEmissionsApy: number;
120
+ assetYieldBps: number;
121
+ assetYieldApy: number;
132
122
  liabilityBalance: BN;
133
123
  liabilityBalanceUi: number;
134
124
  liabilityValue: number;
125
+ liabilityBorrowCostBps: number;
135
126
  liabilityBorrowCostApy: number;
136
- liabilityEmissionsApy: number;
137
- emissionsOutstandingAndUnclaimed: BN;
138
- emissionsOutstandingAndUnclaimedUi: number;
139
127
  price: number;
140
128
  liquidation: ClendAccountAssetLiquidation | null;
141
129
  }
@@ -150,7 +138,6 @@ export interface Bank {
150
138
  group: web3.PublicKey;
151
139
  key: web3.PublicKey;
152
140
  mint: web3.PublicKey;
153
- tokenYieldApy: number;
154
141
  supplyApy: number;
155
142
  borrowApy: number;
156
143
  utilizationRate: number;
@@ -171,17 +158,7 @@ export interface Bank {
171
158
  depositLimitUi: number;
172
159
  borrowLimit: BN;
173
160
  borrowLimitUi: number;
174
- emissions: BankEmissions | null;
175
- }
176
- export interface BankEmissions {
177
- emissionsMode: BankEmissionsMode;
178
- emissionsApy: number;
179
- emissionsMint: web3.PublicKey;
180
- emissionsTokenPrice: number;
181
- emissionsRate: BN;
182
- emissionsRemainingUi: number;
183
161
  }
184
- export type BankEmissionsMode = "LENDING_ONLY" | "BORROW_ONLY" | "LENDING_AND_BORROWING";
185
162
  export interface ClendAccountTxSummary {
186
163
  txSig: string;
187
164
  time: Date;
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import { web3 } from "@coral-xyz/anchor";
2
2
  import { ClendAccount } from "./types";
3
3
  export declare function netValueInToken(clendAccount: ClendAccount, tokenMint: web3.PublicKey): number;
4
+ export declare function getProductionGroups(): web3.PublicKey[];
5
+ export declare function getStagingGroups(): web3.PublicKey[];
package/dist/utils.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.netValueInToken = netValueInToken;
4
+ exports.getProductionGroups = getProductionGroups;
5
+ exports.getStagingGroups = getStagingGroups;
6
+ const anchor_1 = require("@coral-xyz/anchor");
4
7
  // returns the net value of the clend account in a given tokens price
5
8
  function netValueInToken(clendAccount, tokenMint) {
6
9
  const clendAccountTokenBalance = clendAccount.balances.find((balance) => balance.mint.equals(tokenMint));
@@ -9,3 +12,9 @@ function netValueInToken(clendAccount, tokenMint) {
9
12
  }
10
13
  return clendAccount.netValue / clendAccountTokenBalance.price;
11
14
  }
15
+ function getProductionGroups() {
16
+ return [new anchor_1.web3.PublicKey("9bCWxAXFdWQ9GcZTSU3G636T6EyGXYMgaWR74yc7QZz8")];
17
+ }
18
+ function getStagingGroups() {
19
+ return [new anchor_1.web3.PublicKey("HKMDWLBK7yUmorSx9argg2rYcro6KoWf41N57FccKRP5")];
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrot-protocol/boost-http-client",
3
- "version": "0.2.15-group-refactor1-dev-b489da8",
3
+ "version": "0.2.15-swapper1-dev-cda79a9",
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.8-group-refactor1-dev-cb4b228",
18
18
  "axios": "^1.8.3",
19
19
  "bs58": "^6.0.0",
20
20
  "decimal.js": "^10.5.0"
package/src/index.ts CHANGED
@@ -23,10 +23,6 @@ import {
23
23
  ClendAccountAssetLiquidation,
24
24
  GetGroupsResponse,
25
25
  GroupAndBanks,
26
- BankEmissions,
27
- BankEmissionsMode,
28
- WithdrawEmissionsRequest,
29
- WithdrawEmissionsResponse,
30
26
  } from "./types";
31
27
  import encode from "bs58";
32
28
 
@@ -106,178 +102,177 @@ export class Client {
106
102
  return handleApiCall(() => this.http.get(""));
107
103
  }
108
104
 
105
+ /**
106
+ * Get user details for a wallet
107
+ * @param user wallet public key
108
+ * @returns User details
109
+ */
109
110
  async getUser(
110
- user: web3.PublicKey,
111
111
  groups: web3.PublicKey[],
112
+ user: web3.PublicKey,
112
113
  getClendAccountSummary: boolean,
113
114
  ): Promise<GetUserResponse> {
114
- // Make the API call to fetch the raw user data as a string.
115
115
  const body = await handleApiCall(() =>
116
116
  this.http.get(
117
117
  `/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`,
118
118
  ),
119
119
  );
120
120
 
121
- // Parse the raw string body into a JSON object.
122
121
  const jsonRawResponse: any = JSON.parse(body);
122
+ console.log(JSON.stringify(jsonRawResponse, null, 2));
123
+
124
+ // parse balances
125
+ const walletBalances: UserBalance[] = [];
126
+ for (const b of jsonRawResponse.wallet.balances) {
127
+ walletBalances.push({
128
+ mint: new web3.PublicKey(b.mint),
129
+ balance: new BN(b.balance, "hex"),
130
+ balanceUi: Number(b.balanceUi),
131
+ });
132
+ }
123
133
 
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
-
134
+ // get tokens still in user wallet
134
135
  const wallet: UserWallet = {
135
136
  balances: walletBalances,
136
137
  };
137
138
 
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
- });
139
+ // get tx summary for each account and group them
140
+ const summaryByAccount = new Map<string, ClendAccountTxSummary[]>();
141
+ if (getClendAccountSummary && jsonRawResponse.summary) {
142
+ for (const s of jsonRawResponse.summary) {
143
+ const accountAddress = new web3.PublicKey(s.clendAccount).toBase58();
144
+ if (!summaryByAccount.has(accountAddress)) {
145
+ summaryByAccount.set(accountAddress, []);
146
+ }
181
147
 
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),
148
+ const txSummary: ClendAccountTxSummary = {
149
+ txSig: s.txSig,
150
+ time: s.time,
151
+ clendAccount: new web3.PublicKey(s.clendAccount),
152
+ clendAccountAuthority: new web3.PublicKey(s.clendAccountAuthority),
153
+ clendGroup: new web3.PublicKey(s.clendGroup),
154
+ action: s.action,
155
+ input: undefined,
156
+ events: [],
200
157
  };
201
158
 
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
- }
159
+ // parse inputs if they exist
160
+ if (s.input) {
161
+ const input: UserRequest = {
162
+ apiPath: s.input.apiPath,
163
+ selectedTokenMint: s.input.selectedTokenMint
164
+ ? new web3.PublicKey(s.input.selectedTokenMint)
165
+ : null,
166
+ amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
167
+ leverage: s.input.leverage ? Number(s.input.leverage) : null,
168
+ slippageBps: s.input.slippageBps
169
+ ? Number(s.input.slippageBps)
170
+ : null,
171
+ openPosition: s.input.openPosition
172
+ ? Boolean(s.input.openPosition)
173
+ : null,
174
+ closePosition: s.input.closePosition
175
+ ? Boolean(s.input.closePosition)
176
+ : null,
177
+ };
178
+ txSummary.input = input;
179
+ }
228
180
 
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
- });
181
+ // get events for each summary
182
+ for (const event of s.events) {
183
+ let closeBalance: boolean | null = null;
184
+ if (event.closeBalance !== null) {
185
+ closeBalance = Boolean(event.closeBalance);
186
+ }
187
+
188
+ // parse amount
189
+ const clendAccountEvent: ClendAccountEvent = {
190
+ eventIndex: event.eventIndex,
191
+ eventName: event.eventName,
192
+ bank: event.bank ? new web3.PublicKey(event.bank) : null,
193
+ mint: event.mint ? new web3.PublicKey(event.mint) : null,
194
+ amount: event.amount ? new BN(event.amount, "hex") : null,
195
+ amountUi: event.amountUi ? Number(event.amountUi) : null,
196
+ value: event.value ? Number(event.value) : null,
197
+ price: event.price ? Number(event.price) : null,
198
+ closeBalance,
199
+ };
200
+ txSummary.events.push(clendAccountEvent);
268
201
  }
269
202
 
270
- // C. Combine the parsed account and its summary
271
- return { clendAccount, summary };
272
- },
273
- );
203
+ summaryByAccount.get(accountAddress)!.push(txSummary);
204
+ }
205
+ }
206
+
207
+ // if no clend accounts, return empty array
208
+ const clendAccounts: {
209
+ clendAccount: ClendAccount;
210
+ summary: ClendAccountTxSummary[];
211
+ }[] = [];
212
+ for (const accountAndSumary of jsonRawResponse.clendAccounts) {
213
+ const clendAccountBalances: ClendAccountBalance[] = [];
214
+ const ca = accountAndSumary.clendAccount;
215
+ for (const b of ca.balances) {
216
+ // parse liquidation data if exists
217
+ const liquidation: ClendAccountAssetLiquidation | null = b.liquidation
218
+ ? {
219
+ price: Number(b.liquidation.price),
220
+ changePercentage: Number(b.liquidation.changePercentage),
221
+ }
222
+ : null;
223
+
224
+ // create clend account balance
225
+ clendAccountBalances.push({
226
+ mint: new web3.PublicKey(b.mint),
227
+ bank: new web3.PublicKey(b.bank),
228
+ assetBalance: new BN(b.assetBalance, "hex"),
229
+ assetBalanceUi: Number(b.assetBalanceUi),
230
+ assetValue: Number(b.assetValue),
231
+ assetYieldBps: Number(b.assetYieldBps),
232
+ assetYieldApy: Number(b.assetYieldApy),
233
+ liabilityBalance: new BN(b.liabilityBalance, "hex"),
234
+ liabilityBalanceUi: Number(b.liabilityBalanceUi),
235
+ liabilityValue: Number(b.liabilityValue),
236
+ liabilityBorrowCostBps: Number(b.liabilityBorrowCostBps),
237
+ liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
238
+ price: Number(b.price),
239
+ liquidation,
240
+ });
241
+ }
242
+
243
+ // create clend account
244
+ const clendAccountAddress = new web3.PublicKey(
245
+ accountAndSumary.clendAccount.key,
246
+ );
247
+ const clendAccount: ClendAccount = {
248
+ key: clendAccountAddress,
249
+ group: new web3.PublicKey(ca.group),
250
+ balances: clendAccountBalances,
251
+ netValue: Number(ca.netValue),
252
+ netApy: Number(ca.netApy),
253
+ pnl: Number(ca.pnl),
254
+ totalAssetValue: Number(ca.totalAssetValue),
255
+ totalLiabilityValue: Number(ca.totalLiabilityValue),
256
+ healthFactorNotional: Number(ca.healthFactorNotional),
257
+ healthFactorRiskAdjusted: Number(ca.healthFactorRiskAdjusted),
258
+ notionalLeverage: Number(ca.notionalLeverage),
259
+ riskAdjustedLeverage: Number(ca.riskAdjustedLeverage),
260
+ notionalLtv: Number(ca.notionalLtv),
261
+ riskAdjustedLtv: Number(ca.riskAdjustedLtv),
262
+ };
263
+
264
+ // find corresponding tx summary for account
265
+ const summary =
266
+ summaryByAccount.get(clendAccountAddress.toString()) || [];
267
+ clendAccounts.push({ clendAccount, summary });
268
+ }
274
269
 
275
- // 3. Return the final, correctly structured response object.
276
270
  return {
277
271
  wallet,
278
272
  clendAccounts,
279
273
  };
280
274
  }
275
+
281
276
  /**
282
277
  * Get all groups
283
278
  * @param includeBankData Whether to include bank data in the response, if not strictly necessary keep false
@@ -417,8 +412,10 @@ export class Client {
417
412
  liabilityTokenMint: web3.PublicKey,
418
413
  leverage: number,
419
414
  slippageBps: number,
420
- ): Promise<string> {
415
+ ): Promise<any> {
421
416
  const req: AdjustLeverageRequest = {
417
+ owner: this.address(),
418
+ clendGroup,
422
419
  clendAccount,
423
420
  assetTokenMint,
424
421
  liabilityTokenMint,
@@ -453,8 +450,10 @@ export class Client {
453
450
  uiAmount: number,
454
451
  slippageBps: number,
455
452
  withdrawAll: boolean,
456
- ): Promise<string> {
453
+ ): Promise<any> {
457
454
  const req: WithdrawLeverageRequest = {
455
+ owner: this.address(),
456
+ clendGroup,
458
457
  clendAccount,
459
458
  outputTokenMint,
460
459
  assetTokenMint,
@@ -476,30 +475,6 @@ export class Client {
476
475
 
477
476
  return txSig;
478
477
  }
479
-
480
- /**
481
- * Withdraw emissions from a bank
482
- * @returns Withdraw emissions operation result
483
- */
484
- async withdrawEmissions(): Promise<string> {
485
- const req: WithdrawEmissionsRequest = {
486
- owner: this.address(),
487
- };
488
-
489
- const body = await handleApiCall(() =>
490
- this.http.post("emissions/withdraw", JSON.stringify(req)),
491
- );
492
-
493
- const withdrawEmissionsResponse: WithdrawEmissionsResponse =
494
- JSON.parse(body);
495
-
496
- const txSig = await this.send(
497
- withdrawEmissionsResponse.unsignedBase64Tx,
498
- withdrawEmissionsResponse.userRequestId,
499
- );
500
-
501
- return txSig;
502
- }
503
478
  }
504
479
 
505
480
  type ApiErrorPayload = {
@@ -509,6 +484,15 @@ type ApiErrorPayload = {
509
484
  timestamp: string;
510
485
  };
511
486
 
487
+ function handleStatusCode(statusCode: number): void {
488
+ switch (statusCode) {
489
+ case 200:
490
+ break;
491
+ default:
492
+ throw new Error(`unexpected status code: ${statusCode}`);
493
+ }
494
+ }
495
+
512
496
  // Helper function to handle API calls
513
497
  async function handleApiCall<T>(
514
498
  call: () => Promise<AxiosResponse<T>>,
@@ -542,18 +526,6 @@ function getDummyProvider(): AnchorProvider {
542
526
  }
543
527
 
544
528
  function parseBank(bankJson: any): Bank {
545
- let bankEmissions: BankEmissions | null = null;
546
- if (bankJson.emissions) {
547
- bankEmissions = {
548
- emissionsMode: bankJson.emissions.emissionsMode as BankEmissionsMode,
549
- emissionsApy: Number(bankJson.emissions.emissionsApy),
550
- emissionsMint: new web3.PublicKey(bankJson.emissions.emissionsMint),
551
- emissionsTokenPrice: Number(bankJson.emissions.emissionsTokenPrice),
552
- emissionsRate: new BN(bankJson.emissions.emissionsRate, "hex"),
553
- emissionsRemainingUi: Number(bankJson.emissions.emissionsRemainingUi),
554
- };
555
- }
556
-
557
529
  return {
558
530
  mint: new web3.PublicKey(bankJson.mint),
559
531
  key: new web3.PublicKey(bankJson.key),
@@ -567,7 +539,6 @@ function parseBank(bankJson: any): Bank {
567
539
  assetMaintWeight: Number(bankJson.assetMaintWeight),
568
540
  totalAssetShares: Number(bankJson.totalAssetShares),
569
541
  assetShareValue: Number(bankJson.assetShareValue),
570
- tokenYieldApy: Number(bankJson.tokenYieldApy),
571
542
  liabilityAmount: new BN(bankJson.liabilityAmount, "hex"),
572
543
  liabilityAmountUi: Number(bankJson.liabilityAmountUi),
573
544
  liabilityInitWeight: Number(bankJson.liabilityInitWeight),
@@ -579,6 +550,5 @@ function parseBank(bankJson: any): Bank {
579
550
  depositLimitUi: Number(bankJson.depositLimitUi),
580
551
  borrowLimit: new BN(bankJson.borrowLimit, "hex"),
581
552
  borrowLimitUi: Number(bankJson.borrowLimitUi),
582
- emissions: bankEmissions,
583
553
  };
584
554
  }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BN, web3 } from "@coral-xyz/anchor";
2
2
 
3
- // Send a tx
3
+ // Represents a request to send a transaction
4
4
  export interface SendRequest {
5
5
  userRequestId: string;
6
6
  txns: string[];
@@ -33,6 +33,8 @@ export interface DepositLeverageResponse {
33
33
  * Request to adjust the leverage of an existing position
34
34
  */
35
35
  export interface AdjustLeverageRequest {
36
+ owner: web3.PublicKey;
37
+ clendGroup: web3.PublicKey;
36
38
  clendAccount: web3.PublicKey;
37
39
  assetTokenMint: web3.PublicKey;
38
40
  liabilityTokenMint: web3.PublicKey;
@@ -52,6 +54,8 @@ export interface AdjustLeverageResponse {
52
54
  * Request to withdraw from a leveraged position
53
55
  */
54
56
  export interface WithdrawLeverageRequest {
57
+ owner: web3.PublicKey;
58
+ clendGroup: web3.PublicKey;
55
59
  clendAccount: web3.PublicKey;
56
60
  outputTokenMint: web3.PublicKey;
57
61
  assetTokenMint: web3.PublicKey;
@@ -69,21 +73,6 @@ export interface WithdrawLeverageResponse {
69
73
  unsignedBase64Tx: string;
70
74
  }
71
75
 
72
- /**
73
- * Request to withdraw emissions from a bank
74
- */
75
- export interface WithdrawEmissionsRequest {
76
- owner: web3.PublicKey;
77
- }
78
-
79
- /**
80
- * Response for withdraw emissions operation
81
- */
82
- export interface WithdrawEmissionsResponse {
83
- userRequestId: string;
84
- unsignedBase64Tx: string;
85
- }
86
-
87
76
  export interface GetGroupsResponse {
88
77
  groups: GroupAndBanks[];
89
78
  }
@@ -129,7 +118,6 @@ export interface ClendAccount {
129
118
  netValue: number;
130
119
  netApy: number;
131
120
  pnl: number;
132
- totalEmissionsApy: number;
133
121
  totalAssetValue: number;
134
122
  totalLiabilityValue: number;
135
123
  healthFactorNotional: number;
@@ -143,18 +131,16 @@ export interface ClendAccount {
143
131
  export interface ClendAccountBalance {
144
132
  mint: web3.PublicKey;
145
133
  bank: web3.PublicKey;
146
- tokenYieldApy: number;
147
134
  assetBalance: BN;
148
135
  assetBalanceUi: number;
149
136
  assetValue: number;
150
- assetEmissionsApy: number;
137
+ assetYieldBps: number;
138
+ assetYieldApy: number;
151
139
  liabilityBalance: BN;
152
140
  liabilityBalanceUi: number;
153
141
  liabilityValue: number;
142
+ liabilityBorrowCostBps: number;
154
143
  liabilityBorrowCostApy: number;
155
- liabilityEmissionsApy: number;
156
- emissionsOutstandingAndUnclaimed: BN;
157
- emissionsOutstandingAndUnclaimedUi: number;
158
144
  price: number;
159
145
  liquidation: ClendAccountAssetLiquidation | null;
160
146
  }
@@ -172,7 +158,6 @@ export interface Bank {
172
158
  group: web3.PublicKey;
173
159
  key: web3.PublicKey;
174
160
  mint: web3.PublicKey;
175
- tokenYieldApy: number;
176
161
  supplyApy: number;
177
162
  borrowApy: number;
178
163
  utilizationRate: number;
@@ -193,23 +178,8 @@ export interface Bank {
193
178
  depositLimitUi: number;
194
179
  borrowLimit: BN;
195
180
  borrowLimitUi: number;
196
- emissions: BankEmissions | null;
197
- }
198
-
199
- export interface BankEmissions {
200
- emissionsMode: BankEmissionsMode;
201
- emissionsApy: number;
202
- emissionsMint: web3.PublicKey;
203
- emissionsTokenPrice: number;
204
- emissionsRate: BN;
205
- emissionsRemainingUi: number;
206
181
  }
207
182
 
208
- export type BankEmissionsMode =
209
- | "LENDING_ONLY"
210
- | "BORROW_ONLY"
211
- | "LENDING_AND_BORROWING";
212
-
213
183
  export interface ClendAccountTxSummary {
214
184
  txSig: string;
215
185
  time: Date;
package/src/utils.ts CHANGED
@@ -15,3 +15,11 @@ export function netValueInToken(
15
15
 
16
16
  return clendAccount.netValue / clendAccountTokenBalance.price;
17
17
  }
18
+
19
+ export function getProductionGroups(): web3.PublicKey[] {
20
+ return [new web3.PublicKey("9bCWxAXFdWQ9GcZTSU3G636T6EyGXYMgaWR74yc7QZz8")];
21
+ }
22
+
23
+ export function getStagingGroups(): web3.PublicKey[] {
24
+ return [new web3.PublicKey("HKMDWLBK7yUmorSx9argg2rYcro6KoWf41N57FccKRP5")];
25
+ }