@carrot-protocol/boost-http-client 0.3.3 → 0.4.0-stub-position-endpoints-dev-666335f

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.
@@ -0,0 +1,14 @@
1
+ import { AxiosInstance, AxiosResponse } from "axios";
2
+ /**
3
+ * Base API Client
4
+ */
5
+ export declare class ApiClient {
6
+ protected readonly baseUrl: string;
7
+ protected readonly http: AxiosInstance;
8
+ /**
9
+ * Create a new API client
10
+ * @param baseUrl Base URL for the API
11
+ */
12
+ constructor(baseUrl: string);
13
+ protected handleApiCall<T>(call: () => Promise<AxiosResponse<T>>): Promise<string>;
14
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ApiClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ /**
9
+ * Base API Client
10
+ */
11
+ class ApiClient {
12
+ /**
13
+ * Create a new API client
14
+ * @param baseUrl Base URL for the API
15
+ */
16
+ constructor(baseUrl) {
17
+ this.baseUrl = new URL(baseUrl).toString();
18
+ this.http = axios_1.default.create({
19
+ baseURL: this.baseUrl,
20
+ headers: {
21
+ "Content-Type": "application/json",
22
+ },
23
+ });
24
+ }
25
+ // Helper function to handle API calls
26
+ async handleApiCall(call) {
27
+ try {
28
+ const { data } = await call();
29
+ return JSON.stringify(data);
30
+ }
31
+ catch (e) {
32
+ if (axios_1.default.isAxiosError(e)) {
33
+ const res = e.response;
34
+ if (res && typeof res.data === "object") {
35
+ const payload = res.data;
36
+ throw new Error(`${payload.error}${payload.details ? ` ${payload.details}` : ""}`);
37
+ }
38
+ throw new Error(`${e.message}`);
39
+ }
40
+ throw e;
41
+ }
42
+ }
43
+ }
44
+ exports.ApiClient = ApiClient;
@@ -0,0 +1,6 @@
1
+ export type ApiErrorPayload = {
2
+ error: string;
3
+ details?: unknown;
4
+ path: string;
5
+ timestamp: string;
6
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { ApyResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+ export declare class BankChartingExtension extends ApiClient {
5
+ private readonly bank;
6
+ constructor(baseUrl: string, bank: web3.PublicKey);
7
+ getApy(options?: {
8
+ fromTime?: Date;
9
+ toTime?: Date;
10
+ }): Promise<ApyResponse[]>;
11
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BankChartingExtension = void 0;
4
+ const api_1 = require("../../api");
5
+ class BankChartingExtension extends api_1.ApiClient {
6
+ constructor(baseUrl, bank) {
7
+ super(baseUrl);
8
+ this.bank = bank;
9
+ }
10
+ async getApy(options = {}) {
11
+ const body = await this.handleApiCall(() => this.http.get(`/bank/apys`, {
12
+ params: {
13
+ bank: this.bank.toString(),
14
+ fromTime: options.fromTime?.toISOString(),
15
+ toTime: options.toTime?.toISOString(),
16
+ },
17
+ }));
18
+ const response = JSON.parse(body).map((apy) => ({
19
+ time: new Date(apy.time),
20
+ assetApy: Number(apy.supply_apy),
21
+ liabilityApy: Number(apy.borrow_apy),
22
+ }));
23
+ return response;
24
+ }
25
+ }
26
+ exports.BankChartingExtension = BankChartingExtension;
@@ -0,0 +1,5 @@
1
+ export interface ApyResponse {
2
+ time: Date;
3
+ assetApy: number;
4
+ liabilityApy: number;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+ export declare class GroupChartingExtension extends ApiClient {
5
+ private readonly group;
6
+ constructor(baseUrl: string, group: web3.PublicKey);
7
+ getPerformance(options?: {
8
+ fromTime?: Date;
9
+ toTime?: Date;
10
+ }): Promise<PerformanceResponse[]>;
11
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GroupChartingExtension = void 0;
4
+ const api_1 = require("../../api");
5
+ class GroupChartingExtension extends api_1.ApiClient {
6
+ constructor(baseUrl, group) {
7
+ super(baseUrl);
8
+ this.group = group;
9
+ }
10
+ async getPerformance(options = {}) {
11
+ const body = await this.handleApiCall(() => this.http.get(`/group/pnls`, {
12
+ params: {
13
+ group: this.group.toString(),
14
+ fromTime: options.fromTime?.toISOString(),
15
+ toTime: options.toTime?.toISOString(),
16
+ },
17
+ }));
18
+ const response = JSON.parse(body).map((performance) => ({
19
+ time: new Date(performance.time),
20
+ costBasis: Number(performance.cost_basis),
21
+ netValueValue: Number(performance.net_value_value),
22
+ pnlValue: Number(performance.pnl_value),
23
+ }));
24
+ return response;
25
+ }
26
+ }
27
+ exports.GroupChartingExtension = GroupChartingExtension;
@@ -0,0 +1,6 @@
1
+ export interface PerformanceResponse {
2
+ time: Date;
3
+ costBasis: number;
4
+ netValueValue: number;
5
+ pnlValue: number;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { ApyResponse, LoanBalanceResponse, PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+ export declare class PositionChartingExtension extends ApiClient {
5
+ private readonly clendAccount;
6
+ constructor(baseUrl: string, clendAccount: web3.PublicKey);
7
+ getLoanBalance(options?: {
8
+ fromTime?: Date;
9
+ toTime?: Date;
10
+ }): Promise<LoanBalanceResponse[]>;
11
+ getPerformance(options?: {
12
+ fromTime?: Date;
13
+ toTime?: Date;
14
+ }): Promise<PerformanceResponse[]>;
15
+ getApy(options?: {
16
+ fromTime?: Date;
17
+ toTime?: Date;
18
+ }): Promise<ApyResponse[]>;
19
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PositionChartingExtension = void 0;
4
+ const api_1 = require("../../api");
5
+ class PositionChartingExtension extends api_1.ApiClient {
6
+ constructor(baseUrl, clendAccount) {
7
+ super(baseUrl);
8
+ this.clendAccount = clendAccount;
9
+ }
10
+ async getLoanBalance(options = {}) {
11
+ const body = await this.handleApiCall(() => this.http.get(`/account/balances`, {
12
+ params: {
13
+ account: this.clendAccount.toString(),
14
+ fromTime: options.fromTime?.toISOString(),
15
+ toTime: options.toTime?.toISOString(),
16
+ },
17
+ }));
18
+ const response = JSON.parse(body).map((balance) => ({
19
+ time: new Date(balance.time),
20
+ netAssetBalanceValue: Number(balance.net_asset_balance_value),
21
+ netLiabilityBalanceValue: Number(balance.net_liability_balance_value),
22
+ netValueValue: Number(balance.net_value_value),
23
+ notionalLeverage: Number(balance.notional_leverage),
24
+ }));
25
+ return response;
26
+ }
27
+ async getPerformance(options = {}) {
28
+ const body = await this.handleApiCall(() => this.http.get(`/account/performance`, {
29
+ params: {
30
+ account: this.clendAccount.toString(),
31
+ fromTime: options.fromTime?.toISOString(),
32
+ toTime: options.toTime?.toISOString(),
33
+ },
34
+ }));
35
+ const response = JSON.parse(body).map((performance) => ({
36
+ time: new Date(performance.time),
37
+ costBasis: Number(performance.cost_basis),
38
+ netValueValue: Number(performance.net_value_value),
39
+ pnlValue: Number(performance.pnl_value),
40
+ }));
41
+ return response;
42
+ }
43
+ async getApy(options = {}) {
44
+ const body = await this.handleApiCall(() => this.http.get(`/account/apys`, {
45
+ params: {
46
+ account: this.clendAccount.toString(),
47
+ fromTime: options.fromTime?.toISOString(),
48
+ toTime: options.toTime?.toISOString(),
49
+ },
50
+ }));
51
+ const response = JSON.parse(body).map((apy) => ({
52
+ time: new Date(apy.time),
53
+ assetApy: Number(apy.asset_apy),
54
+ liabilityApy: Number(apy.liability_apy),
55
+ netApy: Number(apy.net_apy),
56
+ }));
57
+ return response;
58
+ }
59
+ }
60
+ exports.PositionChartingExtension = PositionChartingExtension;
@@ -0,0 +1,19 @@
1
+ export interface LoanBalanceResponse {
2
+ time: Date;
3
+ netAssetBalanceValue: number;
4
+ netLiabilityBalanceValue: number;
5
+ netValueValue: number;
6
+ notionalLeverage: number;
7
+ }
8
+ export interface PerformanceResponse {
9
+ time: Date;
10
+ costBasis: number;
11
+ netValueValue: number;
12
+ pnlValue: number;
13
+ }
14
+ export interface ApyResponse {
15
+ time: Date;
16
+ assetApy: number;
17
+ liabilityApy: number;
18
+ netApy: number;
19
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+ export declare class WalletChartingExtension extends ApiClient {
5
+ private readonly address;
6
+ constructor(baseUrl: string, address: web3.PublicKey);
7
+ getPerformance(options?: {
8
+ fromTime?: Date;
9
+ toTime?: Date;
10
+ }): Promise<PerformanceResponse[]>;
11
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WalletChartingExtension = void 0;
4
+ const api_1 = require("../../api");
5
+ class WalletChartingExtension extends api_1.ApiClient {
6
+ constructor(baseUrl, address) {
7
+ super(baseUrl);
8
+ this.address = address;
9
+ }
10
+ async getPerformance(options = {}) {
11
+ const body = await this.handleApiCall(() => this.http.get(`/user/pnls`, {
12
+ params: {
13
+ authority: this.address.toString(),
14
+ fromTime: options.fromTime?.toISOString(),
15
+ toTime: options.toTime?.toISOString(),
16
+ },
17
+ }));
18
+ const response = JSON.parse(body).map((performance) => ({
19
+ time: new Date(performance.time),
20
+ costBasis: Number(performance.cost_basis),
21
+ netValueValue: Number(performance.net_value_value),
22
+ pnlValue: Number(performance.pnl_value),
23
+ }));
24
+ return response;
25
+ }
26
+ }
27
+ exports.WalletChartingExtension = WalletChartingExtension;
@@ -0,0 +1,6 @@
1
+ export interface PerformanceResponse {
2
+ time: Date;
3
+ costBasis: number;
4
+ netValueValue: number;
5
+ pnlValue: number;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -1,14 +1,17 @@
1
1
  import { AnchorProvider, web3 } from "@coral-xyz/anchor";
2
- import { GetBankResponse, GetUserResponse, GetGroupResponse, GetGroupsResponse, GetAccountResponse, GetAccountRequest } from "./types";
2
+ import { GetBankResponse, GetUserResponse, GetGroupResponse, GetUserRequest, GetGroupsResponse, GetAccountResponse, GetAccountRequest, ExtensionKey } from "./types";
3
+ import { ApiClient } from "./api";
4
+ import { PositionChartingExtension } from "./charting/position";
5
+ import { BankChartingExtension } from "./charting/bank";
6
+ import { WalletChartingExtension } from "./charting/wallet";
7
+ import { GroupChartingExtension } from "./charting/group";
3
8
  export * from "./types";
4
9
  export * from "./utils";
5
10
  export * as Common from "@carrot-protocol/clend-common";
6
11
  /**
7
12
  * HTTP Client for Carrot Boost API
8
13
  */
9
- export declare class Client {
10
- private readonly baseUrl;
11
- private readonly http;
14
+ export declare class Client extends ApiClient {
12
15
  private readonly provider;
13
16
  private readonly dryRun;
14
17
  /**
@@ -32,7 +35,7 @@ export declare class Client {
32
35
  */
33
36
  private parseClendAccountSummary;
34
37
  private parseClendAccountWithSummary;
35
- getUser(user: web3.PublicKey, groups: web3.PublicKey[], getClendAccountSummary: boolean): Promise<GetUserResponse>;
38
+ getUser(user: GetUserRequest["user"], groups: GetUserRequest["groups"], getClendAccountSummary: GetUserRequest["getClendAccountSummary"]): Promise<GetUserResponse>;
36
39
  /**
37
40
  * Get all groups
38
41
  * @param includeBankData Whether to include bank data in the response, if not strictly necessary keep false
@@ -76,4 +79,5 @@ export declare class Client {
76
79
  * @returns Withdraw emissions operation result
77
80
  */
78
81
  withdrawEmissions(clendAccount: web3.PublicKey): Promise<string>;
82
+ getExtension(extension: ExtensionKey): Promise<((clendAccount: web3.PublicKey) => PositionChartingExtension) | ((group: web3.PublicKey) => GroupChartingExtension) | ((address?: web3.PublicKey) => WalletChartingExtension) | ((bank: web3.PublicKey) => BankChartingExtension)>;
79
83
  }
package/dist/index.js CHANGED
@@ -40,9 +40,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.Client = exports.Common = void 0;
43
- const axios_1 = __importDefault(require("axios"));
44
43
  const anchor_1 = require("@coral-xyz/anchor");
45
44
  const bs58_1 = __importDefault(require("bs58"));
45
+ const api_1 = require("./api");
46
+ const position_1 = require("./charting/position");
47
+ const bank_1 = require("./charting/bank");
48
+ const wallet_1 = require("./charting/wallet");
49
+ const group_1 = require("./charting/group");
46
50
  // Re-export types
47
51
  __exportStar(require("./types"), exports);
48
52
  __exportStar(require("./utils"), exports);
@@ -51,19 +55,13 @@ exports.Common = __importStar(require("@carrot-protocol/clend-common"));
51
55
  /**
52
56
  * HTTP Client for Carrot Boost API
53
57
  */
54
- class Client {
58
+ class Client extends api_1.ApiClient {
55
59
  /**
56
60
  * Create a new Carrot Boost API client
57
61
  * @param baseUrl Base URL for the API
58
62
  */
59
63
  constructor(baseUrl, provider, dryRun) {
60
- this.baseUrl = new URL(baseUrl).toString();
61
- this.http = axios_1.default.create({
62
- baseURL: this.baseUrl,
63
- headers: {
64
- "Content-Type": "application/json",
65
- },
66
- });
64
+ super(baseUrl);
67
65
  if (!provider) {
68
66
  provider = getDummyProvider();
69
67
  }
@@ -95,7 +93,7 @@ class Client {
95
93
  txns: [encodedAndSignedTx],
96
94
  };
97
95
  // send to api
98
- await handleApiCall(() => this.http.post(`send`, sendRequest));
96
+ await this.handleApiCall(() => this.http.post(`send`, sendRequest));
99
97
  // return txsig
100
98
  return bs58_1.default.encode(txSig);
101
99
  }
@@ -104,13 +102,18 @@ class Client {
104
102
  * @returns Index details
105
103
  */
106
104
  async index() {
107
- return handleApiCall(() => this.http.get(""));
105
+ return this.handleApiCall(() => this.http.get(""));
108
106
  }
109
107
  /**
110
108
  * Fetch and parse a single clend account by pubkey
111
109
  */
112
110
  async getAccount(account, getClendAccountSummary) {
113
- const body = await handleApiCall(() => this.http.get(`/account?account=${account.toString()}&getClendAccountSummary=${getClendAccountSummary}`));
111
+ const body = await this.handleApiCall(() => this.http.get(`/account`, {
112
+ params: {
113
+ account: account.toString(),
114
+ getClendAccountSummary,
115
+ },
116
+ }));
114
117
  const jsonRawResponse = JSON.parse(body);
115
118
  return this.parseClendAccountWithSummary(jsonRawResponse, getClendAccountSummary);
116
119
  }
@@ -222,7 +225,13 @@ class Client {
222
225
  }
223
226
  async getUser(user, groups, getClendAccountSummary) {
224
227
  // Make the API call to fetch the raw user data as a string.
225
- const body = await handleApiCall(() => this.http.get(`/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`));
228
+ const body = await this.handleApiCall(() => this.http.get(`/user`, {
229
+ params: {
230
+ user: user.toString(),
231
+ groups: groups.map((g) => g.toString()).join(","),
232
+ getClendAccountSummary,
233
+ },
234
+ }));
226
235
  // Parse the raw string body into a JSON object.
227
236
  const jsonRawResponse = JSON.parse(body);
228
237
  // 1. Parse Wallet Balances
@@ -251,7 +260,11 @@ class Client {
251
260
  * @returns All groups
252
261
  */
253
262
  async getGroups(includeBankData) {
254
- const body = await handleApiCall(() => this.http.get(`/groups?includeBankData=${includeBankData}`));
263
+ const body = await this.handleApiCall(() => this.http.get(`/groups`, {
264
+ params: {
265
+ includeBankData,
266
+ },
267
+ }));
255
268
  const marketJson = JSON.parse(body);
256
269
  const groups = [];
257
270
  for (const groupJson of marketJson.groups) {
@@ -275,7 +288,11 @@ class Client {
275
288
  * @returns Group Details, which is really just all the bank data for that group
276
289
  */
277
290
  async getGroup(groupAddress) {
278
- const body = await handleApiCall(() => this.http.get(`/group?group=${groupAddress.toString()}`));
291
+ const body = await this.handleApiCall(() => this.http.get(`/group`, {
292
+ params: {
293
+ group: groupAddress.toString(),
294
+ },
295
+ }));
279
296
  const marketJson = JSON.parse(body);
280
297
  const group = {
281
298
  group: new anchor_1.web3.PublicKey(marketJson.group.group),
@@ -297,7 +314,11 @@ class Client {
297
314
  * @returns Bank details
298
315
  */
299
316
  async getBank(bankAddress) {
300
- const body = await handleApiCall(() => this.http.get(`/bank?bank=${bankAddress.toString()}`));
317
+ const body = await this.handleApiCall(() => this.http.get(`/bank`, {
318
+ params: {
319
+ bank: bankAddress.toString(),
320
+ },
321
+ }));
301
322
  const bankJson = JSON.parse(body);
302
323
  const bank = parseBank(bankJson.bank);
303
324
  const response = {
@@ -313,7 +334,7 @@ class Client {
313
334
  inputTokenMint,
314
335
  depositAmountUi: uiAmount,
315
336
  };
316
- const body = await handleApiCall(() => this.http.post("deposit", JSON.stringify(req)));
337
+ const body = await this.handleApiCall(() => this.http.post("deposit", JSON.stringify(req)));
317
338
  const depositResponse = JSON.parse(body);
318
339
  const txSig = await this.send(depositResponse.unsignedBase64Tx, depositResponse.userRequestId);
319
340
  return txSig;
@@ -325,7 +346,7 @@ class Client {
325
346
  withdrawAmountUi: uiAmount,
326
347
  withdrawAll,
327
348
  };
328
- const body = await handleApiCall(() => this.http.post("withdraw", JSON.stringify(req)));
349
+ const body = await this.handleApiCall(() => this.http.post("withdraw", JSON.stringify(req)));
329
350
  const withdrawResponse = JSON.parse(body);
330
351
  const txSig = await this.send(withdrawResponse.unsignedBase64Tx, withdrawResponse.userRequestId);
331
352
  return txSig;
@@ -351,7 +372,7 @@ class Client {
351
372
  leverage,
352
373
  slippageBps,
353
374
  };
354
- const body = await handleApiCall(() => this.http.post("leverage/deposit", JSON.stringify(req)));
375
+ const body = await this.handleApiCall(() => this.http.post("leverage/deposit", JSON.stringify(req)));
355
376
  const depositLeverageResponse = JSON.parse(body);
356
377
  const txSig = await this.send(depositLeverageResponse.unsignedBase64Tx, depositLeverageResponse.userRequestId);
357
378
  return txSig;
@@ -369,7 +390,7 @@ class Client {
369
390
  leverage,
370
391
  slippageBps,
371
392
  };
372
- const body = await handleApiCall(() => this.http.post("leverage/adjust", JSON.stringify(req)));
393
+ const body = await this.handleApiCall(() => this.http.post("leverage/adjust", JSON.stringify(req)));
373
394
  const adjustLeverageResponse = JSON.parse(body);
374
395
  const txSig = await this.send(adjustLeverageResponse.unsignedBase64Tx, adjustLeverageResponse.userRequestId);
375
396
  return txSig;
@@ -389,7 +410,7 @@ class Client {
389
410
  slippageBps,
390
411
  withdrawAll,
391
412
  };
392
- const body = await handleApiCall(() => this.http.post("leverage/withdraw", JSON.stringify(req)));
413
+ const body = await this.handleApiCall(() => this.http.post("leverage/withdraw", JSON.stringify(req)));
393
414
  const withdrawLeverageResponse = JSON.parse(body);
394
415
  const txSig = await this.send(withdrawLeverageResponse.unsignedBase64Tx, withdrawLeverageResponse.userRequestId);
395
416
  return txSig;
@@ -402,31 +423,27 @@ class Client {
402
423
  const req = {
403
424
  clendAccount,
404
425
  };
405
- const body = await handleApiCall(() => this.http.post("emissions/withdraw", JSON.stringify(req)));
426
+ const body = await this.handleApiCall(() => this.http.post("emissions/withdraw", JSON.stringify(req)));
406
427
  const withdrawEmissionsResponse = JSON.parse(body);
407
428
  const txSig = await this.send(withdrawEmissionsResponse.unsignedBase64Tx, withdrawEmissionsResponse.userRequestId);
408
429
  return txSig;
409
430
  }
410
- }
411
- exports.Client = Client;
412
- // Helper function to handle API calls
413
- async function handleApiCall(call) {
414
- try {
415
- const { data } = await call();
416
- return JSON.stringify(data);
417
- }
418
- catch (e) {
419
- if (axios_1.default.isAxiosError(e)) {
420
- const res = e.response;
421
- if (res && typeof res.data === "object") {
422
- const payload = res.data;
423
- throw new Error(`${payload.error}${payload.details ? ` ${payload.details}` : ""}`);
424
- }
425
- throw new Error(`${e.message}`);
431
+ async getExtension(extension) {
432
+ switch (extension) {
433
+ case "positionCharting":
434
+ return (clendAccount) => new position_1.PositionChartingExtension(this.baseUrl, clendAccount);
435
+ case "groupCharting":
436
+ return (group) => new group_1.GroupChartingExtension(this.baseUrl, group);
437
+ case "walletCharting":
438
+ return (address) => new wallet_1.WalletChartingExtension(this.baseUrl, address ?? this.address());
439
+ case "bankCharting":
440
+ return (bank) => new bank_1.BankChartingExtension(this.baseUrl, bank);
441
+ default:
442
+ throw new Error(`Unknown extension: ${extension}`);
426
443
  }
427
- throw e;
428
444
  }
429
445
  }
446
+ exports.Client = Client;
430
447
  function getDummyProvider() {
431
448
  return new anchor_1.AnchorProvider(new anchor_1.web3.Connection("http://localhost:8899"), new anchor_1.Wallet(anchor_1.web3.Keypair.generate()), {
432
449
  skipPreflight: true,
package/dist/types.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  import { BN, web3 } from "@coral-xyz/anchor";
2
+ import { PositionChartingExtension } from "./charting/position";
3
+ import { BankChartingExtension } from "./charting/bank";
4
+ import { WalletChartingExtension } from "./charting/wallet";
5
+ import { GroupChartingExtension } from "./charting/group";
2
6
  export interface SendRequest {
3
7
  userRequestId: string;
4
8
  txns: string[];
@@ -247,3 +251,5 @@ export interface UserRequest {
247
251
  openPosition: boolean | null;
248
252
  closePosition: boolean | null;
249
253
  }
254
+ export type ExtensionKey = "positionCharting" | "groupCharting" | "walletCharting" | "bankCharting";
255
+ export type Extension = InstanceType<typeof PositionChartingExtension> | InstanceType<typeof GroupChartingExtension> | InstanceType<typeof WalletChartingExtension> | InstanceType<typeof BankChartingExtension>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrot-protocol/boost-http-client",
3
- "version": "0.3.3",
3
+ "version": "0.4.0-stub-position-endpoints-dev-666335f",
4
4
  "description": "HTTP client for Carrot Boost",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,8 +13,8 @@
13
13
  "version-check": "current_version=$(node -p -e \"require('./package.json').version\") && if npm view @carrot-protocol/boost-http-client@$current_version > /dev/null 2>&1; then echo \"Version $current_version already exists. Please bump it in package.json\"; exit 1; fi"
14
14
  },
15
15
  "dependencies": {
16
+ "@carrot-protocol/clend-common": "^0.1.0",
16
17
  "@coral-xyz/anchor": "^0.29.0",
17
- "@carrot-protocol/clend-common": "0.1.8-group-refactor1-dev-19efede",
18
18
  "axios": "^1.8.3",
19
19
  "bs58": "^6.0.0",
20
20
  "decimal.js": "^10.5.0"
@@ -25,7 +25,7 @@
25
25
  "typescript": "^5.3.3"
26
26
  },
27
27
  "peerDependencies": {
28
- "@coral-xyz/anchor": "^0.29.0",
29
- "@carrot-protocol/clend-common": "^0.1.0"
28
+ "@carrot-protocol/clend-common": "^0.1.0",
29
+ "@coral-xyz/anchor": "^0.29.0"
30
30
  }
31
31
  }
@@ -0,0 +1,46 @@
1
+ import axios, { AxiosInstance, AxiosResponse } from "axios";
2
+ import { ApiErrorPayload } from "./types";
3
+
4
+ /**
5
+ * Base API Client
6
+ */
7
+ export class ApiClient {
8
+ protected readonly baseUrl: string;
9
+ protected readonly http: AxiosInstance;
10
+
11
+ /**
12
+ * Create a new API client
13
+ * @param baseUrl Base URL for the API
14
+ */
15
+ constructor(baseUrl: string) {
16
+ this.baseUrl = new URL(baseUrl).toString();
17
+ this.http = axios.create({
18
+ baseURL: this.baseUrl,
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ },
22
+ });
23
+ }
24
+
25
+ // Helper function to handle API calls
26
+ protected async handleApiCall<T>(
27
+ call: () => Promise<AxiosResponse<T>>,
28
+ ): Promise<string> {
29
+ try {
30
+ const { data } = await call();
31
+ return JSON.stringify(data);
32
+ } catch (e) {
33
+ if (axios.isAxiosError(e)) {
34
+ const res = e.response;
35
+ if (res && typeof res.data === "object") {
36
+ const payload = res.data as ApiErrorPayload;
37
+ throw new Error(
38
+ `${payload.error}${payload.details ? ` ${payload.details}` : ""}`,
39
+ );
40
+ }
41
+ throw new Error(`${e.message}`);
42
+ }
43
+ throw e;
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,6 @@
1
+ export type ApiErrorPayload = {
2
+ error: string;
3
+ details?: unknown;
4
+ path: string;
5
+ timestamp: string;
6
+ };
@@ -0,0 +1,35 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { ApyResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+
5
+ export class BankChartingExtension extends ApiClient {
6
+ private readonly bank: web3.PublicKey;
7
+
8
+ constructor(baseUrl: string, bank: web3.PublicKey) {
9
+ super(baseUrl);
10
+ this.bank = bank;
11
+ }
12
+
13
+ public async getApy(
14
+ options: { fromTime?: Date; toTime?: Date } = {},
15
+ ): Promise<ApyResponse[]> {
16
+ const body = await this.handleApiCall(() =>
17
+ this.http.get(`/bank/apys`, {
18
+ params: {
19
+ bank: this.bank.toString(),
20
+ fromTime: options.fromTime?.toISOString(),
21
+ toTime: options.toTime?.toISOString(),
22
+ },
23
+ }),
24
+ );
25
+
26
+ const response: ApyResponse[] = JSON.parse(body).map(
27
+ (apy: { time: string; supply_apy: string; borrow_apy: string }) => ({
28
+ time: new Date(apy.time),
29
+ assetApy: Number(apy.supply_apy),
30
+ liabilityApy: Number(apy.borrow_apy),
31
+ }),
32
+ );
33
+ return response;
34
+ }
35
+ }
@@ -0,0 +1,5 @@
1
+ export interface ApyResponse {
2
+ time: Date;
3
+ assetApy: number;
4
+ liabilityApy: number;
5
+ }
@@ -0,0 +1,41 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+
5
+ export class GroupChartingExtension extends ApiClient {
6
+ private readonly group: web3.PublicKey;
7
+
8
+ constructor(baseUrl: string, group: web3.PublicKey) {
9
+ super(baseUrl);
10
+ this.group = group;
11
+ }
12
+
13
+ public async getPerformance(
14
+ options: { fromTime?: Date; toTime?: Date } = {},
15
+ ): Promise<PerformanceResponse[]> {
16
+ const body = await this.handleApiCall(() =>
17
+ this.http.get(`/group/pnls`, {
18
+ params: {
19
+ group: this.group.toString(),
20
+ fromTime: options.fromTime?.toISOString(),
21
+ toTime: options.toTime?.toISOString(),
22
+ },
23
+ }),
24
+ );
25
+
26
+ const response: PerformanceResponse[] = JSON.parse(body).map(
27
+ (performance: {
28
+ time: string;
29
+ cost_basis: string;
30
+ net_value_value: string;
31
+ pnl_value: string;
32
+ }) => ({
33
+ time: new Date(performance.time),
34
+ costBasis: Number(performance.cost_basis),
35
+ netValueValue: Number(performance.net_value_value),
36
+ pnlValue: Number(performance.pnl_value),
37
+ }),
38
+ );
39
+ return response;
40
+ }
41
+ }
@@ -0,0 +1,6 @@
1
+ export interface PerformanceResponse {
2
+ time: Date;
3
+ costBasis: number;
4
+ netValueValue: number;
5
+ pnlValue: number;
6
+ }
@@ -0,0 +1,101 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { ApyResponse, LoanBalanceResponse, PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+
5
+ export class PositionChartingExtension extends ApiClient {
6
+ private readonly clendAccount: web3.PublicKey;
7
+
8
+ constructor(baseUrl: string, clendAccount: web3.PublicKey) {
9
+ super(baseUrl);
10
+ this.clendAccount = clendAccount;
11
+ }
12
+
13
+ public async getLoanBalance(
14
+ options: { fromTime?: Date; toTime?: Date } = {},
15
+ ): Promise<LoanBalanceResponse[]> {
16
+ const body = await this.handleApiCall(() =>
17
+ this.http.get(`/account/balances`, {
18
+ params: {
19
+ account: this.clendAccount.toString(),
20
+ fromTime: options.fromTime?.toISOString(),
21
+ toTime: options.toTime?.toISOString(),
22
+ },
23
+ }),
24
+ );
25
+
26
+ const response: LoanBalanceResponse[] = JSON.parse(body).map(
27
+ (balance: {
28
+ time: string;
29
+ net_asset_balance_value: string;
30
+ net_liability_balance_value: string;
31
+ net_value_value: string;
32
+ notional_leverage: string;
33
+ }) => ({
34
+ time: new Date(balance.time),
35
+ netAssetBalanceValue: Number(balance.net_asset_balance_value),
36
+ netLiabilityBalanceValue: Number(balance.net_liability_balance_value),
37
+ netValueValue: Number(balance.net_value_value),
38
+ notionalLeverage: Number(balance.notional_leverage),
39
+ }),
40
+ );
41
+ return response;
42
+ }
43
+
44
+ public async getPerformance(
45
+ options: { fromTime?: Date; toTime?: Date } = {},
46
+ ): Promise<PerformanceResponse[]> {
47
+ const body = await this.handleApiCall(() =>
48
+ this.http.get(`/account/performance`, {
49
+ params: {
50
+ account: this.clendAccount.toString(),
51
+ fromTime: options.fromTime?.toISOString(),
52
+ toTime: options.toTime?.toISOString(),
53
+ },
54
+ }),
55
+ );
56
+
57
+ const response: PerformanceResponse[] = JSON.parse(body).map(
58
+ (performance: {
59
+ time: string;
60
+ cost_basis: string;
61
+ net_value_value: string;
62
+ pnl_value: string;
63
+ }) => ({
64
+ time: new Date(performance.time),
65
+ costBasis: Number(performance.cost_basis),
66
+ netValueValue: Number(performance.net_value_value),
67
+ pnlValue: Number(performance.pnl_value),
68
+ }),
69
+ );
70
+ return response;
71
+ }
72
+
73
+ public async getApy(
74
+ options: { fromTime?: Date; toTime?: Date } = {},
75
+ ): Promise<ApyResponse[]> {
76
+ const body = await this.handleApiCall(() =>
77
+ this.http.get(`/account/apys`, {
78
+ params: {
79
+ account: this.clendAccount.toString(),
80
+ fromTime: options.fromTime?.toISOString(),
81
+ toTime: options.toTime?.toISOString(),
82
+ },
83
+ }),
84
+ );
85
+
86
+ const response: ApyResponse[] = JSON.parse(body).map(
87
+ (apy: {
88
+ time: string;
89
+ asset_apy: string;
90
+ liability_apy: string;
91
+ net_apy: string;
92
+ }) => ({
93
+ time: new Date(apy.time),
94
+ assetApy: Number(apy.asset_apy),
95
+ liabilityApy: Number(apy.liability_apy),
96
+ netApy: Number(apy.net_apy),
97
+ }),
98
+ );
99
+ return response;
100
+ }
101
+ }
@@ -0,0 +1,21 @@
1
+ export interface LoanBalanceResponse {
2
+ time: Date;
3
+ netAssetBalanceValue: number;
4
+ netLiabilityBalanceValue: number;
5
+ netValueValue: number;
6
+ notionalLeverage: number;
7
+ }
8
+
9
+ export interface PerformanceResponse {
10
+ time: Date;
11
+ costBasis: number;
12
+ netValueValue: number;
13
+ pnlValue: number;
14
+ }
15
+
16
+ export interface ApyResponse {
17
+ time: Date;
18
+ assetApy: number;
19
+ liabilityApy: number;
20
+ netApy: number;
21
+ }
@@ -0,0 +1,41 @@
1
+ import { web3 } from "@coral-xyz/anchor";
2
+ import { PerformanceResponse } from "./types";
3
+ import { ApiClient } from "../../api";
4
+
5
+ export class WalletChartingExtension extends ApiClient {
6
+ private readonly address: web3.PublicKey;
7
+
8
+ constructor(baseUrl: string, address: web3.PublicKey) {
9
+ super(baseUrl);
10
+ this.address = address;
11
+ }
12
+
13
+ public async getPerformance(
14
+ options: { fromTime?: Date; toTime?: Date } = {},
15
+ ): Promise<PerformanceResponse[]> {
16
+ const body = await this.handleApiCall(() =>
17
+ this.http.get(`/user/pnls`, {
18
+ params: {
19
+ authority: this.address.toString(),
20
+ fromTime: options.fromTime?.toISOString(),
21
+ toTime: options.toTime?.toISOString(),
22
+ },
23
+ }),
24
+ );
25
+
26
+ const response: PerformanceResponse[] = JSON.parse(body).map(
27
+ (performance: {
28
+ time: string;
29
+ cost_basis: string;
30
+ net_value_value: string;
31
+ pnl_value: string;
32
+ }) => ({
33
+ time: new Date(performance.time),
34
+ costBasis: Number(performance.cost_basis),
35
+ netValueValue: Number(performance.net_value_value),
36
+ pnlValue: Number(performance.pnl_value),
37
+ }),
38
+ );
39
+ return response;
40
+ }
41
+ }
@@ -0,0 +1,6 @@
1
+ export interface PerformanceResponse {
2
+ time: Date;
3
+ costBasis: number;
4
+ netValueValue: number;
5
+ pnlValue: number;
6
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import axios, { AxiosInstance, AxiosError, AxiosResponse } from "axios";
2
1
  import { AnchorProvider, BN, Wallet, web3 } from "@coral-xyz/anchor";
3
2
  import {
4
3
  DepositLeverageRequest,
@@ -33,8 +32,15 @@ import {
33
32
  WithdrawResponse,
34
33
  GetAccountResponse,
35
34
  GetAccountRequest,
35
+ ExtensionKey,
36
+ Extension,
36
37
  } from "./types";
37
38
  import encode from "bs58";
39
+ import { ApiClient } from "./api";
40
+ import { PositionChartingExtension } from "./charting/position";
41
+ import { BankChartingExtension } from "./charting/bank";
42
+ import { WalletChartingExtension } from "./charting/wallet";
43
+ import { GroupChartingExtension } from "./charting/group";
38
44
 
39
45
  // Re-export types
40
46
  export * from "./types";
@@ -46,9 +52,7 @@ export * as Common from "@carrot-protocol/clend-common";
46
52
  /**
47
53
  * HTTP Client for Carrot Boost API
48
54
  */
49
- export class Client {
50
- private readonly baseUrl: string;
51
- private readonly http: AxiosInstance;
55
+ export class Client extends ApiClient {
52
56
  private readonly provider: AnchorProvider;
53
57
  private readonly dryRun: boolean;
54
58
 
@@ -57,13 +61,7 @@ export class Client {
57
61
  * @param baseUrl Base URL for the API
58
62
  */
59
63
  constructor(baseUrl: string, provider?: AnchorProvider, dryRun?: boolean) {
60
- this.baseUrl = new URL(baseUrl).toString();
61
- this.http = axios.create({
62
- baseURL: this.baseUrl,
63
- headers: {
64
- "Content-Type": "application/json",
65
- },
66
- });
64
+ super(baseUrl);
67
65
  if (!provider) {
68
66
  provider = getDummyProvider();
69
67
  }
@@ -107,7 +105,7 @@ export class Client {
107
105
  };
108
106
 
109
107
  // send to api
110
- await handleApiCall(() => this.http.post(`send`, sendRequest));
108
+ await this.handleApiCall(() => this.http.post(`send`, sendRequest));
111
109
 
112
110
  // return txsig
113
111
  return encode.encode(txSig);
@@ -118,7 +116,7 @@ export class Client {
118
116
  * @returns Index details
119
117
  */
120
118
  async index(): Promise<any> {
121
- return handleApiCall(() => this.http.get(""));
119
+ return this.handleApiCall(() => this.http.get(""));
122
120
  }
123
121
 
124
122
  /**
@@ -128,10 +126,13 @@ export class Client {
128
126
  account: GetAccountRequest["account"],
129
127
  getClendAccountSummary: GetAccountRequest["getClendAccountSummary"],
130
128
  ): Promise<GetAccountResponse> {
131
- const body = await handleApiCall(() =>
132
- this.http.get(
133
- `/account?account=${account.toString()}&getClendAccountSummary=${getClendAccountSummary}`,
134
- ),
129
+ const body = await this.handleApiCall(() =>
130
+ this.http.get(`/account`, {
131
+ params: {
132
+ account: account.toString(),
133
+ getClendAccountSummary,
134
+ },
135
+ }),
135
136
  );
136
137
  const jsonRawResponse: any = JSON.parse(body);
137
138
  return this.parseClendAccountWithSummary(
@@ -271,15 +272,19 @@ export class Client {
271
272
  }
272
273
 
273
274
  async getUser(
274
- user: web3.PublicKey,
275
- groups: web3.PublicKey[],
276
- getClendAccountSummary: boolean,
275
+ user: GetUserRequest["user"],
276
+ groups: GetUserRequest["groups"],
277
+ getClendAccountSummary: GetUserRequest["getClendAccountSummary"],
277
278
  ): Promise<GetUserResponse> {
278
279
  // Make the API call to fetch the raw user data as a string.
279
- const body = await handleApiCall(() =>
280
- this.http.get(
281
- `/user?user=${user.toString()}&groups=${groups.map((g) => g.toString()).join(",")}&getClendAccountSummary=${getClendAccountSummary}`,
282
- ),
280
+ const body = await this.handleApiCall(() =>
281
+ this.http.get(`/user`, {
282
+ params: {
283
+ user: user.toString(),
284
+ groups: groups.map((g) => g.toString()).join(","),
285
+ getClendAccountSummary,
286
+ },
287
+ }),
283
288
  );
284
289
 
285
290
  // Parse the raw string body into a JSON object.
@@ -319,8 +324,12 @@ export class Client {
319
324
  * @returns All groups
320
325
  */
321
326
  async getGroups(includeBankData: boolean): Promise<GetGroupsResponse> {
322
- const body = await handleApiCall(() =>
323
- this.http.get(`/groups?includeBankData=${includeBankData}`),
327
+ const body = await this.handleApiCall(() =>
328
+ this.http.get(`/groups`, {
329
+ params: {
330
+ includeBankData,
331
+ },
332
+ }),
324
333
  );
325
334
 
326
335
  const marketJson: any = JSON.parse(body);
@@ -349,8 +358,12 @@ export class Client {
349
358
  * @returns Group Details, which is really just all the bank data for that group
350
359
  */
351
360
  async getGroup(groupAddress: web3.PublicKey): Promise<GetGroupResponse> {
352
- const body = await handleApiCall(() =>
353
- this.http.get(`/group?group=${groupAddress.toString()}`),
361
+ const body = await this.handleApiCall(() =>
362
+ this.http.get(`/group`, {
363
+ params: {
364
+ group: groupAddress.toString(),
365
+ },
366
+ }),
354
367
  );
355
368
 
356
369
  const marketJson: any = JSON.parse(body);
@@ -377,8 +390,12 @@ export class Client {
377
390
  * @returns Bank details
378
391
  */
379
392
  async getBank(bankAddress: web3.PublicKey): Promise<GetBankResponse> {
380
- const body = await handleApiCall(() =>
381
- this.http.get(`/bank?bank=${bankAddress.toString()}`),
393
+ const body = await this.handleApiCall(() =>
394
+ this.http.get(`/bank`, {
395
+ params: {
396
+ bank: bankAddress.toString(),
397
+ },
398
+ }),
382
399
  );
383
400
 
384
401
  const bankJson: any = JSON.parse(body);
@@ -405,7 +422,7 @@ export class Client {
405
422
  depositAmountUi: uiAmount,
406
423
  };
407
424
 
408
- const body = await handleApiCall(() =>
425
+ const body = await this.handleApiCall(() =>
409
426
  this.http.post("deposit", JSON.stringify(req)),
410
427
  );
411
428
 
@@ -432,7 +449,7 @@ export class Client {
432
449
  withdrawAll,
433
450
  };
434
451
 
435
- const body = await handleApiCall(() =>
452
+ const body = await this.handleApiCall(() =>
436
453
  this.http.post("withdraw", JSON.stringify(req)),
437
454
  );
438
455
 
@@ -481,7 +498,7 @@ export class Client {
481
498
  leverage,
482
499
  slippageBps,
483
500
  };
484
- const body = await handleApiCall(() =>
501
+ const body = await this.handleApiCall(() =>
485
502
  this.http.post("leverage/deposit", JSON.stringify(req)),
486
503
  );
487
504
 
@@ -514,7 +531,7 @@ export class Client {
514
531
  leverage,
515
532
  slippageBps,
516
533
  };
517
- const body = await handleApiCall(() =>
534
+ const body = await this.handleApiCall(() =>
518
535
  this.http.post("leverage/adjust", JSON.stringify(req)),
519
536
  );
520
537
 
@@ -551,7 +568,7 @@ export class Client {
551
568
  slippageBps,
552
569
  withdrawAll,
553
570
  };
554
- const body = await handleApiCall(() =>
571
+ const body = await this.handleApiCall(() =>
555
572
  this.http.post("leverage/withdraw", JSON.stringify(req)),
556
573
  );
557
574
 
@@ -574,7 +591,7 @@ export class Client {
574
591
  clendAccount,
575
592
  };
576
593
 
577
- const body = await handleApiCall(() =>
594
+ const body = await this.handleApiCall(() =>
578
595
  this.http.post("emissions/withdraw", JSON.stringify(req)),
579
596
  );
580
597
 
@@ -588,34 +605,24 @@ export class Client {
588
605
 
589
606
  return txSig;
590
607
  }
591
- }
592
608
 
593
- type ApiErrorPayload = {
594
- error: string;
595
- details?: unknown;
596
- path: string;
597
- timestamp: string;
598
- };
599
-
600
- // Helper function to handle API calls
601
- async function handleApiCall<T>(
602
- call: () => Promise<AxiosResponse<T>>,
603
- ): Promise<string> {
604
- try {
605
- const { data } = await call();
606
- return JSON.stringify(data);
607
- } catch (e) {
608
- if (axios.isAxiosError(e)) {
609
- const res = e.response;
610
- if (res && typeof res.data === "object") {
611
- const payload = res.data as ApiErrorPayload;
612
- throw new Error(
613
- `${payload.error}${payload.details ? ` ${payload.details}` : ""}`,
614
- );
615
- }
616
- throw new Error(`${e.message}`);
609
+ public async getExtension(extension: ExtensionKey) {
610
+ switch (extension) {
611
+ case "positionCharting":
612
+ return (clendAccount: web3.PublicKey) =>
613
+ new PositionChartingExtension(this.baseUrl, clendAccount);
614
+ case "groupCharting":
615
+ return (group: web3.PublicKey) =>
616
+ new GroupChartingExtension(this.baseUrl, group);
617
+ case "walletCharting":
618
+ return (address?: web3.PublicKey) =>
619
+ new WalletChartingExtension(this.baseUrl, address ?? this.address());
620
+ case "bankCharting":
621
+ return (bank: web3.PublicKey) =>
622
+ new BankChartingExtension(this.baseUrl, bank);
623
+ default:
624
+ throw new Error(`Unknown extension: ${extension}`);
617
625
  }
618
- throw e;
619
626
  }
620
627
  }
621
628
 
package/src/types.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  import { BN, web3 } from "@coral-xyz/anchor";
2
+ import { PositionChartingExtension } from "./charting/position";
3
+ import { BankChartingExtension } from "./charting/bank";
4
+ import { WalletChartingExtension } from "./charting/wallet";
5
+ import { GroupChartingExtension } from "./charting/group";
2
6
 
3
7
  // Send a tx
4
8
  export interface SendRequest {
@@ -283,3 +287,15 @@ export interface UserRequest {
283
287
  openPosition: boolean | null;
284
288
  closePosition: boolean | null;
285
289
  }
290
+
291
+ export type ExtensionKey =
292
+ | "positionCharting"
293
+ | "groupCharting"
294
+ | "walletCharting"
295
+ | "bankCharting";
296
+
297
+ export type Extension =
298
+ | InstanceType<typeof PositionChartingExtension>
299
+ | InstanceType<typeof GroupChartingExtension>
300
+ | InstanceType<typeof WalletChartingExtension>
301
+ | InstanceType<typeof BankChartingExtension>;