@carrot-protocol/boost-http-client 0.3.1-feat-get-ohlc-endpoint-dev-43df047 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AnchorProvider, web3 } from "@coral-xyz/anchor";
2
- import { GetBankResponse, GetUserResponse, GetGroupResponse, GetGroupsResponse, GetVaultOHLCResponse, GetVaultOHLCRequest } from "./types";
2
+ import { GetBankResponse, GetUserResponse, GetGroupResponse, GetGroupsResponse, GetAccountResponse, GetAccountRequest } from "./types";
3
3
  export * from "./types";
4
4
  export * from "./utils";
5
5
  export * as Common from "@carrot-protocol/clend-common";
@@ -10,11 +10,12 @@ export declare class Client {
10
10
  private readonly baseUrl;
11
11
  private readonly http;
12
12
  private readonly provider;
13
+ private readonly dryRun;
13
14
  /**
14
15
  * Create a new Carrot Boost API client
15
16
  * @param baseUrl Base URL for the API
16
17
  */
17
- constructor(baseUrl: string, provider?: AnchorProvider);
18
+ constructor(baseUrl: string, provider?: AnchorProvider, dryRun?: boolean);
18
19
  address(): web3.PublicKey;
19
20
  private send;
20
21
  /**
@@ -22,6 +23,15 @@ export declare class Client {
22
23
  * @returns Index details
23
24
  */
24
25
  index(): Promise<any>;
26
+ /**
27
+ * Fetch and parse a single clend account by pubkey
28
+ */
29
+ getAccount(account: GetAccountRequest["account"], getClendAccountSummary: GetAccountRequest["getClendAccountSummary"]): Promise<GetAccountResponse>;
30
+ /**
31
+ * Helper to parse a clend account summary array from API response
32
+ */
33
+ private parseClendAccountSummary;
34
+ private parseClendAccountWithSummary;
25
35
  getUser(user: web3.PublicKey, groups: web3.PublicKey[], getClendAccountSummary: boolean): Promise<GetUserResponse>;
26
36
  /**
27
37
  * Get all groups
@@ -41,12 +51,8 @@ export declare class Client {
41
51
  * @returns Bank details
42
52
  */
43
53
  getBank(bankAddress: web3.PublicKey): Promise<GetBankResponse>;
44
- /**
45
- * Get vault OHLC graph data
46
- * @param vaultAddress vault public key
47
- * @returns OHLC graph data
48
- */
49
- getVaultOHLC(vaultAddress: GetVaultOHLCRequest["vault"]): Promise<GetVaultOHLCResponse>;
54
+ deposit(clendGroup: web3.PublicKey, clendAccount: web3.PublicKey | null, inputTokenMint: web3.PublicKey, uiAmount: number): Promise<string>;
55
+ withdraw(clendAccount: web3.PublicKey, outputTokenMint: web3.PublicKey, uiAmount: number, withdrawAll: boolean): Promise<string>;
50
56
  /**
51
57
  * Deposit collateral and create a leveraged position
52
58
  * @param request Deposit leverage request parameters
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ class Client {
56
56
  * Create a new Carrot Boost API client
57
57
  * @param baseUrl Base URL for the API
58
58
  */
59
- constructor(baseUrl, provider) {
59
+ constructor(baseUrl, provider, dryRun) {
60
60
  this.baseUrl = new URL(baseUrl).toString();
61
61
  this.http = axios_1.default.create({
62
62
  baseURL: this.baseUrl,
@@ -67,6 +67,7 @@ class Client {
67
67
  if (!provider) {
68
68
  provider = getDummyProvider();
69
69
  }
70
+ this.dryRun = dryRun ?? false;
70
71
  this.provider = provider;
71
72
  }
72
73
  address() {
@@ -74,6 +75,10 @@ class Client {
74
75
  }
75
76
  // sign and send tx to api for sending to network
76
77
  async send(unsignedBase64Tx, userRequestId) {
78
+ if (this.dryRun) {
79
+ // for debugging purposes only
80
+ console.log("unsigedBase64Tx", unsignedBase64Tx);
81
+ }
77
82
  // deserialize into tx obj
78
83
  const txBytes = Buffer.from(unsignedBase64Tx, "base64");
79
84
  const tx = anchor_1.web3.VersionedTransaction.deserialize(new Uint8Array(txBytes));
@@ -88,7 +93,12 @@ class Client {
88
93
  txns: [encodedAndSignedTx],
89
94
  };
90
95
  // send to api
91
- await handleApiCall(() => this.http.post(`send`, sendRequest));
96
+ if (!this.dryRun) {
97
+ await handleApiCall(() => this.http.post(`send`, sendRequest));
98
+ }
99
+ else {
100
+ console.warn("dry run enabled, did not send tx");
101
+ }
92
102
  // return txsig
93
103
  return bs58_1.default.encode(txSig);
94
104
  }
@@ -99,6 +109,120 @@ class Client {
99
109
  async index() {
100
110
  return handleApiCall(() => this.http.get(""));
101
111
  }
112
+ /**
113
+ * Fetch and parse a single clend account by pubkey
114
+ */
115
+ async getAccount(account, getClendAccountSummary) {
116
+ const body = await handleApiCall(() => this.http.get(`/account?account=${account.toString()}&getClendAccountSummary=${getClendAccountSummary}`));
117
+ const jsonRawResponse = JSON.parse(body);
118
+ return this.parseClendAccountWithSummary(jsonRawResponse, getClendAccountSummary);
119
+ }
120
+ /**
121
+ * Helper to parse a clend account summary array from API response
122
+ */
123
+ parseClendAccountSummary(summaryArr) {
124
+ return summaryArr.map((s) => {
125
+ let input = undefined;
126
+ if (s.input) {
127
+ input = {
128
+ apiPath: s.input.apiPath,
129
+ selectedTokenMint: s.input.selectedTokenMint
130
+ ? new anchor_1.web3.PublicKey(s.input.selectedTokenMint)
131
+ : null,
132
+ amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
133
+ leverage: s.input.leverage ? Number(s.input.leverage) : null,
134
+ slippageBps: s.input.slippageBps ? Number(s.input.slippageBps) : null,
135
+ openPosition: s.input.openPosition != null ? Boolean(s.input.openPosition) : null,
136
+ closePosition: s.input.closePosition != null
137
+ ? Boolean(s.input.closePosition)
138
+ : null,
139
+ };
140
+ }
141
+ const events = (s.events || []).map((event) => {
142
+ let closeBalance = null;
143
+ if (event.closeBalance !== null && event.closeBalance !== undefined) {
144
+ closeBalance = Boolean(event.closeBalance);
145
+ }
146
+ return {
147
+ eventIndex: event.eventIndex,
148
+ eventName: event.eventName,
149
+ bank: event.bank ? new anchor_1.web3.PublicKey(event.bank) : null,
150
+ mint: event.mint ? new anchor_1.web3.PublicKey(event.mint) : null,
151
+ amount: event.amount ? new anchor_1.BN(event.amount, "hex") : null,
152
+ amountUi: event.amountUi ? Number(event.amountUi) : null,
153
+ value: event.value ? Number(event.value) : null,
154
+ price: event.price ? Number(event.price) : null,
155
+ closeBalance,
156
+ };
157
+ });
158
+ const txSummary = {
159
+ txSig: s.txSig,
160
+ time: s.time,
161
+ clendAccount: new anchor_1.web3.PublicKey(s.clendAccount),
162
+ clendAccountAuthority: new anchor_1.web3.PublicKey(s.clendAccountAuthority),
163
+ clendGroup: new anchor_1.web3.PublicKey(s.clendGroup),
164
+ action: s.action,
165
+ input,
166
+ events,
167
+ };
168
+ return txSummary;
169
+ });
170
+ }
171
+ parseClendAccountWithSummary(accountData, getClendAccountSummary) {
172
+ // A. Parse the main ClendAccount object
173
+ const rawClendAccount = accountData.clendAccount;
174
+ const clendAccountBalances = (rawClendAccount.balances || []).map((b) => {
175
+ const liquidation = b.liquidation
176
+ ? {
177
+ price: Number(b.liquidation.price),
178
+ changePercentage: Number(b.liquidation.changePercentage),
179
+ }
180
+ : null;
181
+ const emissionsOutstandingAndUnclaimed = new anchor_1.BN(b.emissionsOutstandingAndUnclaimed, "hex");
182
+ return {
183
+ mint: new anchor_1.web3.PublicKey(b.mint),
184
+ bank: new anchor_1.web3.PublicKey(b.bank),
185
+ tokenYieldApy: Number(b.tokenYieldApy),
186
+ assetBalance: new anchor_1.BN(b.assetBalance, "hex"),
187
+ assetBalanceUi: Number(b.assetBalanceUi),
188
+ assetValue: Number(b.assetValue),
189
+ assetEmissionsApy: Number(b.assetEmissionsApy),
190
+ liabilityBalance: new anchor_1.BN(b.liabilityBalance, "hex"),
191
+ liabilityBalanceUi: Number(b.liabilityBalanceUi),
192
+ liabilityValue: Number(b.liabilityValue),
193
+ liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
194
+ liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
195
+ emissionsOutstandingAndUnclaimed,
196
+ emissionsOutstandingAndUnclaimedUi: Number(b.emissionsOutstandingAndUnclaimedUi),
197
+ price: Number(b.price),
198
+ liquidation,
199
+ };
200
+ });
201
+ const clendAccount = {
202
+ key: new anchor_1.web3.PublicKey(rawClendAccount.key),
203
+ group: new anchor_1.web3.PublicKey(rawClendAccount.group),
204
+ balances: clendAccountBalances,
205
+ netValue: Number(rawClendAccount.netValue),
206
+ netApy: Number(rawClendAccount.netApy),
207
+ pnl: Number(rawClendAccount.pnl),
208
+ totalEmissionsApy: Number(rawClendAccount.totalEmissionsApy),
209
+ totalAssetValue: Number(rawClendAccount.totalAssetValue),
210
+ totalLiabilityValue: Number(rawClendAccount.totalLiabilityValue),
211
+ healthFactorNotional: Number(rawClendAccount.healthFactorNotional),
212
+ healthFactorRiskAdjusted: Number(rawClendAccount.healthFactorRiskAdjusted),
213
+ notionalLeverage: Number(rawClendAccount.notionalLeverage),
214
+ riskAdjustedLeverage: Number(rawClendAccount.riskAdjustedLeverage),
215
+ notionalLtv: Number(rawClendAccount.notionalLtv),
216
+ riskAdjustedLtv: Number(rawClendAccount.riskAdjustedLtv),
217
+ };
218
+ // B. Parse the associated Summary array for the account
219
+ let summary = [];
220
+ if (getClendAccountSummary && accountData.summary) {
221
+ summary = this.parseClendAccountSummary(accountData.summary);
222
+ }
223
+ // C. Combine the parsed account and its summary
224
+ return { clendAccount, summary };
225
+ }
102
226
  async getUser(user, groups, getClendAccountSummary) {
103
227
  // Make the API call to fetch the raw user data as a string.
104
228
  const body = await handleApiCall(() => this.http.get(`/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`));
@@ -117,112 +241,7 @@ class Client {
117
241
  // 2. Parse Clend Accounts and their Summaries
118
242
  // This is the main refactored section. It iterates through the clendAccounts array
119
243
  // 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
- const liquidation = b.liquidation
125
- ? {
126
- price: Number(b.liquidation.price),
127
- changePercentage: Number(b.liquidation.changePercentage),
128
- }
129
- : null;
130
- const emissionsOutstandingAndUnclaimed = new anchor_1.BN(b.emissionsOutstandingAndUnclaimed, "hex");
131
- return {
132
- mint: new anchor_1.web3.PublicKey(b.mint),
133
- bank: new anchor_1.web3.PublicKey(b.bank),
134
- tokenYieldApy: Number(b.tokenYieldApy),
135
- assetBalance: new anchor_1.BN(b.assetBalance, "hex"),
136
- assetBalanceUi: Number(b.assetBalanceUi),
137
- assetValue: Number(b.assetValue),
138
- assetEmissionsApy: Number(b.assetEmissionsApy),
139
- liabilityBalance: new anchor_1.BN(b.liabilityBalance, "hex"),
140
- liabilityBalanceUi: Number(b.liabilityBalanceUi),
141
- liabilityValue: Number(b.liabilityValue),
142
- liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
143
- liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
144
- emissionsOutstandingAndUnclaimed,
145
- emissionsOutstandingAndUnclaimedUi: Number(b.emissionsOutstandingAndUnclaimedUi),
146
- price: Number(b.price),
147
- liquidation,
148
- };
149
- });
150
- const clendAccount = {
151
- key: new anchor_1.web3.PublicKey(rawClendAccount.key),
152
- group: new anchor_1.web3.PublicKey(rawClendAccount.group),
153
- 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),
166
- };
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
- });
244
+ const clendAccounts = (jsonRawResponse.clendAccounts || []).map((accountData) => this.parseClendAccountWithSummary(accountData, getClendAccountSummary));
226
245
  // 3. Return the final, correctly structured response object.
227
246
  return {
228
247
  wallet,
@@ -289,17 +308,30 @@ class Client {
289
308
  };
290
309
  return response;
291
310
  }
292
- /**
293
- * Get vault OHLC graph data
294
- * @param vaultAddress vault public key
295
- * @returns OHLC graph data
296
- */
297
- async getVaultOHLC(vaultAddress) {
298
- const body = await handleApiCall(() => this.http.get(`/vaultOhlc?vault=${vaultAddress.toString()}`));
299
- const response = {
300
- data: JSON.parse(body),
311
+ async deposit(clendGroup, clendAccount, inputTokenMint, uiAmount) {
312
+ const req = {
313
+ owner: this.address(),
314
+ clendGroup,
315
+ clendAccount,
316
+ inputTokenMint,
317
+ depositAmountUi: uiAmount,
301
318
  };
302
- return response;
319
+ const body = await handleApiCall(() => this.http.post("deposit", JSON.stringify(req)));
320
+ const depositResponse = JSON.parse(body);
321
+ const txSig = await this.send(depositResponse.unsignedBase64Tx, depositResponse.userRequestId);
322
+ return txSig;
323
+ }
324
+ async withdraw(clendAccount, outputTokenMint, uiAmount, withdrawAll) {
325
+ const req = {
326
+ clendAccount,
327
+ outputTokenMint,
328
+ withdrawAmountUi: uiAmount,
329
+ withdrawAll,
330
+ };
331
+ const body = await handleApiCall(() => this.http.post("withdraw", JSON.stringify(req)));
332
+ const withdrawResponse = JSON.parse(body);
333
+ const txSig = await this.send(withdrawResponse.unsignedBase64Tx, withdrawResponse.userRequestId);
334
+ return txSig;
303
335
  }
304
336
  /**
305
337
  * Deposit collateral and create a leveraged position
package/dist/types.d.ts CHANGED
@@ -3,6 +3,33 @@ export interface SendRequest {
3
3
  userRequestId: string;
4
4
  txns: string[];
5
5
  }
6
+ /**
7
+ * Request to deposit collateral
8
+ */
9
+ export interface DepositRequest {
10
+ owner: web3.PublicKey;
11
+ clendGroup: web3.PublicKey;
12
+ clendAccount: web3.PublicKey | null;
13
+ inputTokenMint: web3.PublicKey;
14
+ depositAmountUi: number;
15
+ }
16
+ export interface DepositResponse {
17
+ userRequestId: string;
18
+ unsignedBase64Tx: string;
19
+ }
20
+ /**
21
+ * Request to withdraw collateral
22
+ */
23
+ export interface WithdrawRequest {
24
+ clendAccount: web3.PublicKey;
25
+ outputTokenMint: web3.PublicKey;
26
+ withdrawAmountUi: number;
27
+ withdrawAll: boolean;
28
+ }
29
+ export interface WithdrawResponse {
30
+ userRequestId: string;
31
+ unsignedBase64Tx: string;
32
+ }
6
33
  /**
7
34
  * Request to deposit collateral and create a leveraged position
8
35
  */
@@ -84,6 +111,14 @@ export interface GroupAndBanks {
84
111
  groupName: string;
85
112
  banks: Bank[];
86
113
  }
114
+ export interface GetAccountRequest {
115
+ account: web3.PublicKey;
116
+ getClendAccountSummary: boolean;
117
+ }
118
+ export interface GetAccountResponse {
119
+ clendAccount: ClendAccount;
120
+ summary: ClendAccountTxSummary[];
121
+ }
87
122
  export interface GetUserRequest {
88
123
  groups: web3.PublicKey[];
89
124
  user: web3.PublicKey;
@@ -96,19 +131,6 @@ export interface GetUserResponse {
96
131
  summary: ClendAccountTxSummary[];
97
132
  }[];
98
133
  }
99
- export interface GetVaultOHLCRequest {
100
- vault: web3.PublicKey;
101
- }
102
- export interface VaultOHLCDataPoint {
103
- time: number;
104
- open: number;
105
- high: number;
106
- low: number;
107
- close: number;
108
- }
109
- export interface GetVaultOHLCResponse {
110
- data: VaultOHLCDataPoint[];
111
- }
112
134
  export interface UserWallet {
113
135
  balances: UserBalance[];
114
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrot-protocol/boost-http-client",
3
- "version": "0.3.1-feat-get-ohlc-endpoint-dev-43df047",
3
+ "version": "0.3.1",
4
4
  "description": "HTTP client for Carrot Boost",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -27,8 +27,12 @@ import {
27
27
  BankEmissionsMode,
28
28
  WithdrawEmissionsRequest,
29
29
  WithdrawEmissionsResponse,
30
- GetVaultOHLCResponse,
31
- GetVaultOHLCRequest,
30
+ DepositRequest,
31
+ DepositResponse,
32
+ WithdrawRequest,
33
+ WithdrawResponse,
34
+ GetAccountResponse,
35
+ GetAccountRequest,
32
36
  } from "./types";
33
37
  import encode from "bs58";
34
38
 
@@ -46,12 +50,13 @@ export class Client {
46
50
  private readonly baseUrl: string;
47
51
  private readonly http: AxiosInstance;
48
52
  private readonly provider: AnchorProvider;
53
+ private readonly dryRun: boolean;
49
54
 
50
55
  /**
51
56
  * Create a new Carrot Boost API client
52
57
  * @param baseUrl Base URL for the API
53
58
  */
54
- constructor(baseUrl: string, provider?: AnchorProvider) {
59
+ constructor(baseUrl: string, provider?: AnchorProvider, dryRun?: boolean) {
55
60
  this.baseUrl = new URL(baseUrl).toString();
56
61
  this.http = axios.create({
57
62
  baseURL: this.baseUrl,
@@ -62,6 +67,7 @@ export class Client {
62
67
  if (!provider) {
63
68
  provider = getDummyProvider();
64
69
  }
70
+ this.dryRun = dryRun ?? false;
65
71
  this.provider = provider;
66
72
  }
67
73
 
@@ -74,6 +80,11 @@ export class Client {
74
80
  unsignedBase64Tx: string,
75
81
  userRequestId: string,
76
82
  ): Promise<string> {
83
+ if (this.dryRun) {
84
+ // for debugging purposes only
85
+ console.log("unsigedBase64Tx", unsignedBase64Tx);
86
+ }
87
+
77
88
  // deserialize into tx obj
78
89
  const txBytes = Buffer.from(unsignedBase64Tx, "base64");
79
90
  const tx = web3.VersionedTransaction.deserialize(new Uint8Array(txBytes));
@@ -94,7 +105,11 @@ export class Client {
94
105
  };
95
106
 
96
107
  // send to api
97
- await handleApiCall(() => this.http.post(`send`, sendRequest));
108
+ if (!this.dryRun) {
109
+ await handleApiCall(() => this.http.post(`send`, sendRequest));
110
+ } else {
111
+ console.warn("dry run enabled, did not send tx");
112
+ }
98
113
 
99
114
  // return txsig
100
115
  return encode.encode(txSig);
@@ -108,6 +123,155 @@ export class Client {
108
123
  return handleApiCall(() => this.http.get(""));
109
124
  }
110
125
 
126
+ /**
127
+ * Fetch and parse a single clend account by pubkey
128
+ */
129
+ async getAccount(
130
+ account: GetAccountRequest["account"],
131
+ getClendAccountSummary: GetAccountRequest["getClendAccountSummary"],
132
+ ): Promise<GetAccountResponse> {
133
+ const body = await handleApiCall(() =>
134
+ this.http.get(
135
+ `/account?account=${account.toString()}&getClendAccountSummary=${getClendAccountSummary}`,
136
+ ),
137
+ );
138
+ const jsonRawResponse: any = JSON.parse(body);
139
+ return this.parseClendAccountWithSummary(
140
+ jsonRawResponse,
141
+ getClendAccountSummary,
142
+ );
143
+ }
144
+
145
+ /**
146
+ * Helper to parse a clend account summary array from API response
147
+ */
148
+ private parseClendAccountSummary(summaryArr: any[]): ClendAccountTxSummary[] {
149
+ return summaryArr.map((s: any) => {
150
+ let input: UserRequest | undefined = undefined;
151
+ if (s.input) {
152
+ input = {
153
+ apiPath: s.input.apiPath,
154
+ selectedTokenMint: s.input.selectedTokenMint
155
+ ? new web3.PublicKey(s.input.selectedTokenMint)
156
+ : null,
157
+ amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
158
+ leverage: s.input.leverage ? Number(s.input.leverage) : null,
159
+ slippageBps: s.input.slippageBps ? Number(s.input.slippageBps) : null,
160
+ openPosition:
161
+ s.input.openPosition != null ? Boolean(s.input.openPosition) : null,
162
+ closePosition:
163
+ s.input.closePosition != null
164
+ ? Boolean(s.input.closePosition)
165
+ : null,
166
+ };
167
+ }
168
+
169
+ const events: ClendAccountEvent[] = (s.events || []).map((event: any) => {
170
+ let closeBalance: boolean | null = null;
171
+ if (event.closeBalance !== null && event.closeBalance !== undefined) {
172
+ closeBalance = Boolean(event.closeBalance);
173
+ }
174
+
175
+ return {
176
+ eventIndex: event.eventIndex,
177
+ eventName: event.eventName,
178
+ bank: event.bank ? new web3.PublicKey(event.bank) : null,
179
+ mint: event.mint ? new web3.PublicKey(event.mint) : null,
180
+ amount: event.amount ? new BN(event.amount, "hex") : null,
181
+ amountUi: event.amountUi ? Number(event.amountUi) : null,
182
+ value: event.value ? Number(event.value) : null,
183
+ price: event.price ? Number(event.price) : null,
184
+ closeBalance,
185
+ };
186
+ });
187
+
188
+ const txSummary: ClendAccountTxSummary = {
189
+ txSig: s.txSig,
190
+ time: s.time,
191
+ clendAccount: new web3.PublicKey(s.clendAccount),
192
+ clendAccountAuthority: new web3.PublicKey(s.clendAccountAuthority),
193
+ clendGroup: new web3.PublicKey(s.clendGroup),
194
+ action: s.action,
195
+ input,
196
+ events,
197
+ };
198
+ return txSummary;
199
+ });
200
+ }
201
+
202
+ private parseClendAccountWithSummary(
203
+ accountData: any,
204
+ getClendAccountSummary: boolean,
205
+ ): GetAccountResponse {
206
+ // A. Parse the main ClendAccount object
207
+ const rawClendAccount = accountData.clendAccount;
208
+ const clendAccountBalances: ClendAccountBalance[] = (
209
+ rawClendAccount.balances || []
210
+ ).map((b: any) => {
211
+ const liquidation: ClendAccountAssetLiquidation | null = b.liquidation
212
+ ? {
213
+ price: Number(b.liquidation.price),
214
+ changePercentage: Number(b.liquidation.changePercentage),
215
+ }
216
+ : null;
217
+
218
+ const emissionsOutstandingAndUnclaimed = new BN(
219
+ b.emissionsOutstandingAndUnclaimed,
220
+ "hex",
221
+ );
222
+
223
+ return {
224
+ mint: new web3.PublicKey(b.mint),
225
+ bank: new web3.PublicKey(b.bank),
226
+ tokenYieldApy: Number(b.tokenYieldApy),
227
+ assetBalance: new BN(b.assetBalance, "hex"),
228
+ assetBalanceUi: Number(b.assetBalanceUi),
229
+ assetValue: Number(b.assetValue),
230
+ assetEmissionsApy: Number(b.assetEmissionsApy),
231
+ liabilityBalance: new BN(b.liabilityBalance, "hex"),
232
+ liabilityBalanceUi: Number(b.liabilityBalanceUi),
233
+ liabilityValue: Number(b.liabilityValue),
234
+ liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
235
+ liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
236
+ emissionsOutstandingAndUnclaimed,
237
+ emissionsOutstandingAndUnclaimedUi: Number(
238
+ b.emissionsOutstandingAndUnclaimedUi,
239
+ ),
240
+ price: Number(b.price),
241
+ liquidation,
242
+ };
243
+ });
244
+
245
+ const clendAccount: ClendAccount = {
246
+ key: new web3.PublicKey(rawClendAccount.key),
247
+ group: new web3.PublicKey(rawClendAccount.group),
248
+ balances: clendAccountBalances,
249
+ netValue: Number(rawClendAccount.netValue),
250
+ netApy: Number(rawClendAccount.netApy),
251
+ pnl: Number(rawClendAccount.pnl),
252
+ totalEmissionsApy: Number(rawClendAccount.totalEmissionsApy),
253
+ totalAssetValue: Number(rawClendAccount.totalAssetValue),
254
+ totalLiabilityValue: Number(rawClendAccount.totalLiabilityValue),
255
+ healthFactorNotional: Number(rawClendAccount.healthFactorNotional),
256
+ healthFactorRiskAdjusted: Number(
257
+ rawClendAccount.healthFactorRiskAdjusted,
258
+ ),
259
+ notionalLeverage: Number(rawClendAccount.notionalLeverage),
260
+ riskAdjustedLeverage: Number(rawClendAccount.riskAdjustedLeverage),
261
+ notionalLtv: Number(rawClendAccount.notionalLtv),
262
+ riskAdjustedLtv: Number(rawClendAccount.riskAdjustedLtv),
263
+ };
264
+
265
+ // B. Parse the associated Summary array for the account
266
+ let summary: ClendAccountTxSummary[] = [];
267
+ if (getClendAccountSummary && accountData.summary) {
268
+ summary = this.parseClendAccountSummary(accountData.summary);
269
+ }
270
+
271
+ // C. Combine the parsed account and its summary
272
+ return { clendAccount, summary };
273
+ }
274
+
111
275
  async getUser(
112
276
  user: web3.PublicKey,
113
277
  groups: web3.PublicKey[],
@@ -141,137 +305,8 @@ export class Client {
141
305
  // This is the main refactored section. It iterates through the clendAccounts array
142
306
  // from the response, which contains both the account data and its summary.
143
307
  const clendAccounts = (jsonRawResponse.clendAccounts || []).map(
144
- (accountData: any) => {
145
- // A. Parse the main ClendAccount object
146
- const rawClendAccount = accountData.clendAccount;
147
- const clendAccountBalances: ClendAccountBalance[] = (
148
- rawClendAccount.balances || []
149
- ).map((b: any) => {
150
- const liquidation: ClendAccountAssetLiquidation | null = b.liquidation
151
- ? {
152
- price: Number(b.liquidation.price),
153
- changePercentage: Number(b.liquidation.changePercentage),
154
- }
155
- : null;
156
-
157
- const emissionsOutstandingAndUnclaimed = new BN(
158
- b.emissionsOutstandingAndUnclaimed,
159
- "hex",
160
- );
161
-
162
- return {
163
- mint: new web3.PublicKey(b.mint),
164
- bank: new web3.PublicKey(b.bank),
165
- tokenYieldApy: Number(b.tokenYieldApy),
166
- assetBalance: new BN(b.assetBalance, "hex"),
167
- assetBalanceUi: Number(b.assetBalanceUi),
168
- assetValue: Number(b.assetValue),
169
- assetEmissionsApy: Number(b.assetEmissionsApy),
170
- liabilityBalance: new BN(b.liabilityBalance, "hex"),
171
- liabilityBalanceUi: Number(b.liabilityBalanceUi),
172
- liabilityValue: Number(b.liabilityValue),
173
- liabilityBorrowCostApy: Number(b.liabilityBorrowCostApy),
174
- liabilityEmissionsApy: Number(b.liabilityEmissionsApy),
175
- emissionsOutstandingAndUnclaimed,
176
- emissionsOutstandingAndUnclaimedUi: Number(
177
- b.emissionsOutstandingAndUnclaimedUi,
178
- ),
179
- price: Number(b.price),
180
- liquidation,
181
- };
182
- });
183
-
184
- const clendAccount: ClendAccount = {
185
- key: new web3.PublicKey(rawClendAccount.key),
186
- group: new web3.PublicKey(rawClendAccount.group),
187
- balances: clendAccountBalances,
188
- netValue: Number(rawClendAccount.netValue),
189
- netApy: Number(rawClendAccount.netApy),
190
- pnl: Number(rawClendAccount.pnl),
191
- totalEmissionsApy: Number(rawClendAccount.totalEmissionsApy),
192
- totalAssetValue: Number(rawClendAccount.totalAssetValue),
193
- totalLiabilityValue: Number(rawClendAccount.totalLiabilityValue),
194
- healthFactorNotional: Number(rawClendAccount.healthFactorNotional),
195
- healthFactorRiskAdjusted: Number(
196
- rawClendAccount.healthFactorRiskAdjusted,
197
- ),
198
- notionalLeverage: Number(rawClendAccount.notionalLeverage),
199
- riskAdjustedLeverage: Number(rawClendAccount.riskAdjustedLeverage),
200
- notionalLtv: Number(rawClendAccount.notionalLtv),
201
- riskAdjustedLtv: Number(rawClendAccount.riskAdjustedLtv),
202
- };
203
-
204
- // B. Parse the associated Summary array for the account
205
- let summary: ClendAccountTxSummary[] = [];
206
- if (getClendAccountSummary && accountData.summary) {
207
- summary = accountData.summary.map((s: any) => {
208
- let input: UserRequest | undefined = undefined;
209
- if (s.input) {
210
- input = {
211
- apiPath: s.input.apiPath,
212
- selectedTokenMint: s.input.selectedTokenMint
213
- ? new web3.PublicKey(s.input.selectedTokenMint)
214
- : null,
215
- amountUi: s.input.amountUi ? Number(s.input.amountUi) : null,
216
- leverage: s.input.leverage ? Number(s.input.leverage) : null,
217
- slippageBps: s.input.slippageBps
218
- ? Number(s.input.slippageBps)
219
- : null,
220
- openPosition:
221
- s.input.openPosition != null
222
- ? Boolean(s.input.openPosition)
223
- : null,
224
- closePosition:
225
- s.input.closePosition != null
226
- ? Boolean(s.input.closePosition)
227
- : null,
228
- };
229
- }
230
-
231
- const events: ClendAccountEvent[] = (s.events || []).map(
232
- (event: any) => {
233
- let closeBalance: boolean | null = null;
234
- // Only convert to boolean if the value is not null/undefined to preserve the null state.
235
- if (
236
- event.closeBalance !== null &&
237
- event.closeBalance !== undefined
238
- ) {
239
- closeBalance = Boolean(event.closeBalance);
240
- }
241
-
242
- return {
243
- eventIndex: event.eventIndex,
244
- eventName: event.eventName,
245
- bank: event.bank ? new web3.PublicKey(event.bank) : null,
246
- mint: event.mint ? new web3.PublicKey(event.mint) : null,
247
- amount: event.amount ? new BN(event.amount, "hex") : null,
248
- amountUi: event.amountUi ? Number(event.amountUi) : null,
249
- value: event.value ? Number(event.value) : null,
250
- price: event.price ? Number(event.price) : null,
251
- closeBalance,
252
- };
253
- },
254
- );
255
-
256
- const txSummary: ClendAccountTxSummary = {
257
- txSig: s.txSig,
258
- time: s.time,
259
- clendAccount: new web3.PublicKey(s.clendAccount),
260
- clendAccountAuthority: new web3.PublicKey(
261
- s.clendAccountAuthority,
262
- ),
263
- clendGroup: new web3.PublicKey(s.clendGroup),
264
- action: s.action,
265
- input,
266
- events,
267
- };
268
- return txSummary;
269
- });
270
- }
271
-
272
- // C. Combine the parsed account and its summary
273
- return { clendAccount, summary };
274
- },
308
+ (accountData: any) =>
309
+ this.parseClendAccountWithSummary(accountData, getClendAccountSummary),
275
310
  );
276
311
 
277
312
  // 3. Return the final, correctly structured response object.
@@ -358,23 +393,59 @@ export class Client {
358
393
  return response;
359
394
  }
360
395
 
361
- /**
362
- * Get vault OHLC graph data
363
- * @param vaultAddress vault public key
364
- * @returns OHLC graph data
365
- */
366
- async getVaultOHLC(
367
- vaultAddress: GetVaultOHLCRequest["vault"],
368
- ): Promise<GetVaultOHLCResponse> {
396
+ async deposit(
397
+ clendGroup: web3.PublicKey,
398
+ clendAccount: web3.PublicKey | null,
399
+ inputTokenMint: web3.PublicKey,
400
+ uiAmount: number,
401
+ ): Promise<string> {
402
+ const req: DepositRequest = {
403
+ owner: this.address(),
404
+ clendGroup,
405
+ clendAccount,
406
+ inputTokenMint,
407
+ depositAmountUi: uiAmount,
408
+ };
409
+
369
410
  const body = await handleApiCall(() =>
370
- this.http.get(`/vaultOhlc?vault=${vaultAddress.toString()}`),
411
+ this.http.post("deposit", JSON.stringify(req)),
371
412
  );
372
413
 
373
- const response: GetVaultOHLCResponse = {
374
- data: JSON.parse(body),
414
+ const depositResponse: DepositResponse = JSON.parse(body);
415
+
416
+ const txSig = await this.send(
417
+ depositResponse.unsignedBase64Tx,
418
+ depositResponse.userRequestId,
419
+ );
420
+
421
+ return txSig;
422
+ }
423
+
424
+ async withdraw(
425
+ clendAccount: web3.PublicKey,
426
+ outputTokenMint: web3.PublicKey,
427
+ uiAmount: number,
428
+ withdrawAll: boolean,
429
+ ): Promise<string> {
430
+ const req: WithdrawRequest = {
431
+ clendAccount,
432
+ outputTokenMint,
433
+ withdrawAmountUi: uiAmount,
434
+ withdrawAll,
375
435
  };
376
436
 
377
- return response;
437
+ const body = await handleApiCall(() =>
438
+ this.http.post("withdraw", JSON.stringify(req)),
439
+ );
440
+
441
+ const withdrawResponse: WithdrawResponse = JSON.parse(body);
442
+
443
+ const txSig = await this.send(
444
+ withdrawResponse.unsignedBase64Tx,
445
+ withdrawResponse.userRequestId,
446
+ );
447
+
448
+ return txSig;
378
449
  }
379
450
 
380
451
  /**
package/src/types.ts CHANGED
@@ -6,6 +6,37 @@ export interface SendRequest {
6
6
  txns: string[];
7
7
  }
8
8
 
9
+ /**
10
+ * Request to deposit collateral
11
+ */
12
+ export interface DepositRequest {
13
+ owner: web3.PublicKey;
14
+ clendGroup: web3.PublicKey;
15
+ clendAccount: web3.PublicKey | null;
16
+ inputTokenMint: web3.PublicKey;
17
+ depositAmountUi: number;
18
+ }
19
+
20
+ export interface DepositResponse {
21
+ userRequestId: string;
22
+ unsignedBase64Tx: string;
23
+ }
24
+
25
+ /**
26
+ * Request to withdraw collateral
27
+ */
28
+ export interface WithdrawRequest {
29
+ clendAccount: web3.PublicKey;
30
+ outputTokenMint: web3.PublicKey;
31
+ withdrawAmountUi: number;
32
+ withdrawAll: boolean;
33
+ }
34
+
35
+ export interface WithdrawResponse {
36
+ userRequestId: string;
37
+ unsignedBase64Tx: string;
38
+ }
39
+
9
40
  /**
10
41
  * Request to deposit collateral and create a leveraged position
11
42
  */
@@ -98,6 +129,16 @@ export interface GroupAndBanks {
98
129
  banks: Bank[];
99
130
  }
100
131
 
132
+ export interface GetAccountRequest {
133
+ account: web3.PublicKey;
134
+ getClendAccountSummary: boolean;
135
+ }
136
+
137
+ export interface GetAccountResponse {
138
+ clendAccount: ClendAccount;
139
+ summary: ClendAccountTxSummary[];
140
+ }
141
+
101
142
  export interface GetUserRequest {
102
143
  groups: web3.PublicKey[];
103
144
  user: web3.PublicKey;
@@ -112,22 +153,6 @@ export interface GetUserResponse {
112
153
  }[];
113
154
  }
114
155
 
115
- export interface GetVaultOHLCRequest {
116
- vault: web3.PublicKey;
117
- }
118
-
119
- export interface VaultOHLCDataPoint {
120
- time: number;
121
- open: number;
122
- high: number;
123
- low: number;
124
- close: number;
125
- }
126
-
127
- export interface GetVaultOHLCResponse {
128
- data: VaultOHLCDataPoint[];
129
- }
130
-
131
156
  export interface UserWallet {
132
157
  balances: UserBalance[];
133
158
  }