@carrot-protocol/boost-http-client 0.1.7-bug-fix-api-integration-dev-4e0eb09 → 0.2.0-data-fixes-dev-f1a2e89
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 +15 -13
- package/dist/index.js +131 -66
- package/dist/types.d.ts +55 -38
- package/package.json +1 -1
- package/src/index.ts +176 -64
- package/src/types.ts +60 -39
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnchorProvider, web3 } from "@coral-xyz/anchor";
|
|
2
|
-
import {
|
|
2
|
+
import { GetBankResponse, GetUserResponse, AdjustLeverageRequest, GetGroupResponse } from "./types";
|
|
3
3
|
export * from "./types";
|
|
4
4
|
/**
|
|
5
5
|
* HTTP Client for Carrot Boost API
|
|
@@ -27,31 +27,33 @@ export declare class Client {
|
|
|
27
27
|
*/
|
|
28
28
|
getUser(user?: web3.PublicKey): Promise<GetUserResponse>;
|
|
29
29
|
/**
|
|
30
|
-
* Get market details
|
|
31
|
-
* @returns
|
|
30
|
+
* Get market details
|
|
31
|
+
* @returns Group Details
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
getGroup(): Promise<GetGroupResponse>;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
* @
|
|
35
|
+
* Get bank details
|
|
36
|
+
* @param addr token mint or bank public key
|
|
37
|
+
* @param addrType "mint" or "bank"
|
|
38
|
+
* @returns Bank details
|
|
37
39
|
*/
|
|
38
|
-
|
|
40
|
+
getBank(addr: web3.PublicKey, addrType: "mint" | "bank"): Promise<GetBankResponse>;
|
|
39
41
|
/**
|
|
40
42
|
* Deposit collateral and create a leveraged position
|
|
41
43
|
* @param request Deposit leverage request parameters
|
|
42
44
|
* @returns Deposit leverage operation result
|
|
43
45
|
*/
|
|
44
|
-
depositLeverage(
|
|
46
|
+
depositLeverage(selectedTokenMint: web3.PublicKey, uiAmount: number, leverage: number, slippageBps: number): Promise<string>;
|
|
45
47
|
/**
|
|
46
|
-
*
|
|
47
|
-
* @param request
|
|
48
|
-
* @returns
|
|
48
|
+
* Adjust the leverage of an existing position
|
|
49
|
+
* @param request Adjust leverage request parameters
|
|
50
|
+
* @returns Adjust leverage operation result
|
|
49
51
|
*/
|
|
50
|
-
|
|
52
|
+
adjustLeverage(params: AdjustLeverageRequest): Promise<any>;
|
|
51
53
|
/**
|
|
52
54
|
* Withdraw from or close a leveraged position
|
|
53
55
|
* @param request Withdraw leverage request parameters
|
|
54
56
|
* @returns Withdraw leverage operation result
|
|
55
57
|
*/
|
|
56
|
-
withdrawLeverage(
|
|
58
|
+
withdrawLeverage(selectedTokenMint: web3.PublicKey, uiAmount: number, slippageBps: number, withdrawAll: boolean): Promise<any>;
|
|
57
59
|
}
|
package/dist/index.js
CHANGED
|
@@ -10,28 +10,6 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
|
11
11
|
o[k2] = m[k];
|
|
12
12
|
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
13
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
15
|
};
|
|
@@ -40,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
40
18
|
};
|
|
41
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
20
|
exports.Client = void 0;
|
|
43
|
-
const axios_1 =
|
|
21
|
+
const axios_1 = __importDefault(require("axios"));
|
|
44
22
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
45
23
|
const bs58_1 = __importDefault(require("bs58"));
|
|
46
24
|
// Re-export types
|
|
@@ -70,7 +48,7 @@ class Client {
|
|
|
70
48
|
return this.provider.wallet.publicKey;
|
|
71
49
|
}
|
|
72
50
|
// sign and send tx to api for sending to network
|
|
73
|
-
async send(unsignedBase64Tx
|
|
51
|
+
async send(unsignedBase64Tx) {
|
|
74
52
|
// deserialize into tx obj
|
|
75
53
|
const txBytes = Buffer.from(unsignedBase64Tx, "base64");
|
|
76
54
|
const tx = anchor_1.web3.VersionedTransaction.deserialize(new Uint8Array(txBytes));
|
|
@@ -81,7 +59,7 @@ class Client {
|
|
|
81
59
|
const encodedAndSignedTx = Buffer.from(signedTx.serialize()).toString("base64");
|
|
82
60
|
// create request obj
|
|
83
61
|
const sendRequest = {
|
|
84
|
-
txns: [encodedAndSignedTx
|
|
62
|
+
txns: [encodedAndSignedTx],
|
|
85
63
|
};
|
|
86
64
|
// send to api
|
|
87
65
|
await handleApiCall(() => this.http.post(`send`, sendRequest));
|
|
@@ -106,48 +84,115 @@ class Client {
|
|
|
106
84
|
user = this.address();
|
|
107
85
|
}
|
|
108
86
|
const body = await handleApiCall(() => this.http.get(`/user?user=${user.toString()}`));
|
|
109
|
-
const
|
|
110
|
-
|
|
87
|
+
const jsonRawResponse = JSON.parse(body);
|
|
88
|
+
// get tokens still in user wallet
|
|
89
|
+
const wallet = {
|
|
90
|
+
usdcBalance: new anchor_1.BN(jsonRawResponse.wallet.usdcBalance, "hex"),
|
|
91
|
+
usdcBalanceUi: Number(jsonRawResponse.wallet.usdcBalanceUi),
|
|
92
|
+
jlpBalance: new anchor_1.BN(jsonRawResponse.wallet.jlpBalance, "hex"),
|
|
93
|
+
jlpBalanceUi: Number(jsonRawResponse.wallet.jlpBalanceUi),
|
|
94
|
+
solBalance: new anchor_1.BN(jsonRawResponse.wallet.solBalance, "hex"),
|
|
95
|
+
solBalanceUi: Number(jsonRawResponse.wallet.solBalanceUi),
|
|
96
|
+
};
|
|
97
|
+
// if no clend account, return undefined for clend
|
|
98
|
+
if (!jsonRawResponse.clendAccount) {
|
|
99
|
+
return {
|
|
100
|
+
wallet,
|
|
101
|
+
clendAccount: undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// parse lending account balances
|
|
105
|
+
const balances = [];
|
|
106
|
+
for (const b of jsonRawResponse.clendAccount.balances) {
|
|
107
|
+
balances.push({
|
|
108
|
+
mint: new anchor_1.web3.PublicKey(b.mint),
|
|
109
|
+
bank: new anchor_1.web3.PublicKey(b.bank),
|
|
110
|
+
assetBalance: new anchor_1.BN(b.assetBalance, "hex"),
|
|
111
|
+
assetBalanceUi: Number(b.assetBalanceUi),
|
|
112
|
+
assetValue: Number(b.assetValue),
|
|
113
|
+
liabilityBalance: new anchor_1.BN(b.liabilityBalance, "hex"),
|
|
114
|
+
liabilityBalanceUi: Number(b.liabilityBalanceUi),
|
|
115
|
+
liabilityValue: Number(b.liabilityValue),
|
|
116
|
+
price: Number(b.price),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// create clend account
|
|
120
|
+
const clendAccount = {
|
|
121
|
+
balances,
|
|
122
|
+
netValue: Number(jsonRawResponse.clendAccount.netValue),
|
|
123
|
+
netApy: Number(jsonRawResponse.clendAccount.netApy),
|
|
124
|
+
pnl: Number(jsonRawResponse.clendAccount.pnl),
|
|
125
|
+
totalAssetValue: Number(jsonRawResponse.clendAccount.totalAssetValue),
|
|
126
|
+
totalLiabilityValue: Number(jsonRawResponse.clendAccount.totalLiabilityValue),
|
|
127
|
+
healthFactorNotional: Number(jsonRawResponse.clendAccount.healthFactorNotional),
|
|
128
|
+
healthFactorRiskAdjusted: Number(jsonRawResponse.clendAccount.healthFactorRiskAdjusted),
|
|
129
|
+
notionalLeverage: Number(jsonRawResponse.clendAccount.notionalLeverage),
|
|
130
|
+
riskAdjustedLeverage: Number(jsonRawResponse.clendAccount.riskAdjustedLeverage),
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
wallet,
|
|
134
|
+
clendAccount,
|
|
135
|
+
};
|
|
111
136
|
}
|
|
112
137
|
/**
|
|
113
|
-
* Get market details
|
|
114
|
-
* @returns
|
|
138
|
+
* Get market details
|
|
139
|
+
* @returns Group Details
|
|
115
140
|
*/
|
|
116
|
-
async
|
|
117
|
-
const body = await handleApiCall(() => this.http.get(`
|
|
118
|
-
const
|
|
141
|
+
async getGroup() {
|
|
142
|
+
const body = await handleApiCall(() => this.http.get(`/group`));
|
|
143
|
+
const marketJson = JSON.parse(body);
|
|
144
|
+
const banks = [];
|
|
145
|
+
for (const bankJson of marketJson.banks) {
|
|
146
|
+
const bank = parseBank(bankJson);
|
|
147
|
+
banks.push(bank);
|
|
148
|
+
}
|
|
149
|
+
const response = {
|
|
150
|
+
banks,
|
|
151
|
+
};
|
|
119
152
|
return response;
|
|
120
153
|
}
|
|
121
154
|
/**
|
|
122
|
-
*
|
|
123
|
-
* @
|
|
155
|
+
* Get bank details
|
|
156
|
+
* @param addr token mint or bank public key
|
|
157
|
+
* @param addrType "mint" or "bank"
|
|
158
|
+
* @returns Bank details
|
|
124
159
|
*/
|
|
125
|
-
async
|
|
126
|
-
const body = await handleApiCall(() => this.http.
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
|
|
160
|
+
async getBank(addr, addrType) {
|
|
161
|
+
const body = await handleApiCall(() => this.http.get(`/bank?${addrType}=${addr.toString()}`));
|
|
162
|
+
const bankJson = JSON.parse(body);
|
|
163
|
+
const bank = parseBank(bankJson.bank);
|
|
164
|
+
const response = {
|
|
165
|
+
bank,
|
|
166
|
+
};
|
|
167
|
+
return response;
|
|
130
168
|
}
|
|
131
169
|
/**
|
|
132
170
|
* Deposit collateral and create a leveraged position
|
|
133
171
|
* @param request Deposit leverage request parameters
|
|
134
172
|
* @returns Deposit leverage operation result
|
|
135
173
|
*/
|
|
136
|
-
async depositLeverage(
|
|
137
|
-
const
|
|
174
|
+
async depositLeverage(selectedTokenMint, uiAmount, leverage, slippageBps) {
|
|
175
|
+
const req = {
|
|
176
|
+
owner: this.address(),
|
|
177
|
+
selectedTokenMint,
|
|
178
|
+
depositAmountUi: uiAmount,
|
|
179
|
+
leverage,
|
|
180
|
+
slippageBps,
|
|
181
|
+
};
|
|
182
|
+
const body = await handleApiCall(() => this.http.post("leverage/deposit", JSON.stringify(req)));
|
|
138
183
|
const depositLeverageResponse = JSON.parse(body);
|
|
139
|
-
const txSig = await this.send(depositLeverageResponse.unsignedBase64Tx
|
|
184
|
+
const txSig = await this.send(depositLeverageResponse.unsignedBase64Tx);
|
|
140
185
|
return txSig;
|
|
141
186
|
}
|
|
142
187
|
/**
|
|
143
|
-
*
|
|
144
|
-
* @param request
|
|
145
|
-
* @returns
|
|
188
|
+
* Adjust the leverage of an existing position
|
|
189
|
+
* @param request Adjust leverage request parameters
|
|
190
|
+
* @returns Adjust leverage operation result
|
|
146
191
|
*/
|
|
147
|
-
async
|
|
148
|
-
const body = await handleApiCall(() => this.http.post("leverage/
|
|
149
|
-
const
|
|
150
|
-
const txSig = await this.send(
|
|
192
|
+
async adjustLeverage(params) {
|
|
193
|
+
const body = await handleApiCall(() => this.http.post("leverage/adjust", JSON.stringify(params)));
|
|
194
|
+
const adjustLeverageResponse = JSON.parse(body);
|
|
195
|
+
const txSig = await this.send(adjustLeverageResponse.unsignedBase64Tx);
|
|
151
196
|
return txSig;
|
|
152
197
|
}
|
|
153
198
|
/**
|
|
@@ -155,10 +200,17 @@ class Client {
|
|
|
155
200
|
* @param request Withdraw leverage request parameters
|
|
156
201
|
* @returns Withdraw leverage operation result
|
|
157
202
|
*/
|
|
158
|
-
async withdrawLeverage(
|
|
159
|
-
const
|
|
203
|
+
async withdrawLeverage(selectedTokenMint, uiAmount, slippageBps, withdrawAll) {
|
|
204
|
+
const req = {
|
|
205
|
+
owner: this.address(),
|
|
206
|
+
selectedTokenMint,
|
|
207
|
+
withdrawAmountUi: uiAmount,
|
|
208
|
+
slippageBps,
|
|
209
|
+
withdrawAll,
|
|
210
|
+
};
|
|
211
|
+
const body = await handleApiCall(() => this.http.post("leverage/withdraw", JSON.stringify(req)));
|
|
160
212
|
const withdrawLeverageResponse = JSON.parse(body);
|
|
161
|
-
const txSig = await this.send(withdrawLeverageResponse.unsignedBase64Tx
|
|
213
|
+
const txSig = await this.send(withdrawLeverageResponse.unsignedBase64Tx);
|
|
162
214
|
return txSig;
|
|
163
215
|
}
|
|
164
216
|
}
|
|
@@ -172,23 +224,21 @@ function handleStatusCode(statusCode) {
|
|
|
172
224
|
}
|
|
173
225
|
}
|
|
174
226
|
// Helper function to handle API calls
|
|
175
|
-
async function handleApiCall(
|
|
227
|
+
async function handleApiCall(call) {
|
|
176
228
|
try {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
return JSON.stringify(response.data);
|
|
229
|
+
const { data } = await call();
|
|
230
|
+
return JSON.stringify(data);
|
|
180
231
|
}
|
|
181
|
-
catch (
|
|
182
|
-
if (
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
throw new Error(JSON.stringify(simplifiedError));
|
|
232
|
+
catch (e) {
|
|
233
|
+
if (axios_1.default.isAxiosError(e)) {
|
|
234
|
+
const res = e.response;
|
|
235
|
+
if (res && typeof res.data === "object") {
|
|
236
|
+
const payload = res.data;
|
|
237
|
+
throw new Error(`${payload.error}${payload.details ? ` ${payload.details}` : ""}`);
|
|
238
|
+
}
|
|
239
|
+
throw new Error(`${e.message}`);
|
|
190
240
|
}
|
|
191
|
-
throw
|
|
241
|
+
throw e;
|
|
192
242
|
}
|
|
193
243
|
}
|
|
194
244
|
function getDummyProvider() {
|
|
@@ -196,3 +246,18 @@ function getDummyProvider() {
|
|
|
196
246
|
skipPreflight: true,
|
|
197
247
|
});
|
|
198
248
|
}
|
|
249
|
+
function parseBank(bankJson) {
|
|
250
|
+
return {
|
|
251
|
+
mint: new anchor_1.web3.PublicKey(bankJson.mint),
|
|
252
|
+
key: new anchor_1.web3.PublicKey(bankJson.key),
|
|
253
|
+
group: new anchor_1.web3.PublicKey(bankJson.group),
|
|
254
|
+
supplyApy: Number(bankJson.supplyApy),
|
|
255
|
+
borrowApy: Number(bankJson.borrowApy),
|
|
256
|
+
utilizationRate: Number(bankJson.utilizationRate),
|
|
257
|
+
assetAmount: new anchor_1.BN(bankJson.assetAmount, "hex"),
|
|
258
|
+
assetAmountUi: Number(bankJson.assetAmountUi),
|
|
259
|
+
liabilityAmount: new anchor_1.BN(bankJson.liabilityAmount, "hex"),
|
|
260
|
+
liabilityAmountUi: Number(bankJson.liabilityAmountUi),
|
|
261
|
+
price: Number(bankJson.price),
|
|
262
|
+
};
|
|
263
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,45 +1,36 @@
|
|
|
1
1
|
import { BN, web3 } from "@coral-xyz/anchor";
|
|
2
|
-
import Decimal from "decimal.js";
|
|
3
2
|
export interface SendRequest {
|
|
4
3
|
txns: string[];
|
|
5
4
|
}
|
|
6
|
-
export interface CreateObligationRequest {
|
|
7
|
-
owner: web3.PublicKey;
|
|
8
|
-
}
|
|
9
|
-
export interface CreateObligationResponse {
|
|
10
|
-
unsignedBase64Tx: string;
|
|
11
|
-
}
|
|
12
5
|
/**
|
|
13
6
|
* Request to deposit collateral and create a leveraged position
|
|
14
7
|
*/
|
|
15
8
|
export interface DepositLeverageRequest {
|
|
16
9
|
owner: web3.PublicKey;
|
|
17
10
|
selectedTokenMint: web3.PublicKey;
|
|
18
|
-
|
|
11
|
+
depositAmountUi: number;
|
|
19
12
|
leverage: number;
|
|
20
|
-
|
|
13
|
+
slippageBps: number;
|
|
21
14
|
}
|
|
22
15
|
/**
|
|
23
16
|
* Response for deposit leverage operation
|
|
24
17
|
*/
|
|
25
18
|
export interface DepositLeverageResponse {
|
|
26
19
|
unsignedBase64Tx: string;
|
|
27
|
-
signedSetBorrowRateBase64Tx: string;
|
|
28
20
|
}
|
|
29
21
|
/**
|
|
30
|
-
* Request to
|
|
22
|
+
* Request to adjust the leverage of an existing position
|
|
31
23
|
*/
|
|
32
|
-
export interface
|
|
24
|
+
export interface AdjustLeverageRequest {
|
|
33
25
|
owner: web3.PublicKey;
|
|
34
26
|
leverage: number;
|
|
35
|
-
|
|
27
|
+
slippageBps: number;
|
|
36
28
|
}
|
|
37
29
|
/**
|
|
38
|
-
* Response for
|
|
30
|
+
* Response for adjust leverage operation
|
|
39
31
|
*/
|
|
40
|
-
export interface
|
|
32
|
+
export interface AdjustLeverageResponse {
|
|
41
33
|
unsignedBase64Tx: string;
|
|
42
|
-
signedSetBorrowRateBase64Tx: string;
|
|
43
34
|
}
|
|
44
35
|
/**
|
|
45
36
|
* Request to withdraw from a leveraged position
|
|
@@ -47,41 +38,67 @@ export interface ModifyLeverageResponse {
|
|
|
47
38
|
export interface WithdrawLeverageRequest {
|
|
48
39
|
owner: web3.PublicKey;
|
|
49
40
|
selectedTokenMint: web3.PublicKey;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
withdrawAmountUi: number;
|
|
42
|
+
slippageBps: number;
|
|
43
|
+
withdrawAll: boolean;
|
|
53
44
|
}
|
|
54
45
|
/**
|
|
55
46
|
* Response for withdraw leverage operation
|
|
56
47
|
*/
|
|
57
48
|
export interface WithdrawLeverageResponse {
|
|
58
49
|
unsignedBase64Tx: string;
|
|
59
|
-
|
|
50
|
+
}
|
|
51
|
+
export interface GetGroupResponse {
|
|
52
|
+
banks: Bank[];
|
|
60
53
|
}
|
|
61
54
|
export interface GetUserResponse {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
totalCollateral: number;
|
|
67
|
-
totalDebt: number;
|
|
68
|
-
ltv: number;
|
|
69
|
-
liquidationLtv: number;
|
|
55
|
+
wallet: UserWallet;
|
|
56
|
+
clendAccount: ClendAccount | undefined;
|
|
57
|
+
}
|
|
58
|
+
export interface UserWallet {
|
|
70
59
|
usdcBalance: BN;
|
|
71
60
|
usdcBalanceUi: number;
|
|
72
61
|
jlpBalance: BN;
|
|
73
62
|
jlpBalanceUi: number;
|
|
74
63
|
solBalance: BN;
|
|
75
64
|
solBalanceUi: number;
|
|
76
|
-
obligationCreated: boolean;
|
|
77
65
|
}
|
|
78
|
-
export interface
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
export interface ClendAccount {
|
|
67
|
+
balances: Balance[];
|
|
68
|
+
netValue: number;
|
|
69
|
+
netApy: number;
|
|
70
|
+
pnl: number;
|
|
71
|
+
totalAssetValue: number;
|
|
72
|
+
totalLiabilityValue: number;
|
|
73
|
+
healthFactorNotional: number;
|
|
74
|
+
healthFactorRiskAdjusted: number;
|
|
75
|
+
notionalLeverage: number;
|
|
76
|
+
riskAdjustedLeverage: number;
|
|
77
|
+
}
|
|
78
|
+
export interface Balance {
|
|
79
|
+
mint: web3.PublicKey;
|
|
80
|
+
bank: web3.PublicKey;
|
|
81
|
+
assetBalance: BN;
|
|
82
|
+
assetBalanceUi: number;
|
|
83
|
+
assetValue: number;
|
|
84
|
+
liabilityBalance: BN;
|
|
85
|
+
liabilityBalanceUi: number;
|
|
86
|
+
liabilityValue: number;
|
|
87
|
+
price: number;
|
|
88
|
+
}
|
|
89
|
+
export interface GetBankResponse {
|
|
90
|
+
bank: Bank;
|
|
91
|
+
}
|
|
92
|
+
export interface Bank {
|
|
93
|
+
group: web3.PublicKey;
|
|
94
|
+
key: web3.PublicKey;
|
|
95
|
+
mint: web3.PublicKey;
|
|
96
|
+
supplyApy: number;
|
|
97
|
+
borrowApy: number;
|
|
98
|
+
utilizationRate: number;
|
|
99
|
+
assetAmount: BN;
|
|
100
|
+
assetAmountUi: number;
|
|
101
|
+
liabilityAmount: BN;
|
|
102
|
+
liabilityAmountUi: number;
|
|
103
|
+
price: number;
|
|
87
104
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import axios, { AxiosInstance, AxiosError, AxiosResponse } from "axios";
|
|
2
|
-
import { AnchorProvider, Wallet, web3 } from "@coral-xyz/anchor";
|
|
2
|
+
import { AnchorProvider, BN, Wallet, web3 } from "@coral-xyz/anchor";
|
|
3
3
|
import {
|
|
4
|
-
CreateObligationResponse,
|
|
5
4
|
DepositLeverageRequest,
|
|
6
5
|
DepositLeverageResponse,
|
|
7
|
-
|
|
6
|
+
GetBankResponse,
|
|
8
7
|
GetUserResponse,
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
AdjustLeverageRequest,
|
|
9
|
+
AdjustLeverageResponse,
|
|
11
10
|
SendRequest,
|
|
12
11
|
WithdrawLeverageRequest,
|
|
13
12
|
WithdrawLeverageResponse,
|
|
13
|
+
UserWallet,
|
|
14
|
+
ClendAccount,
|
|
15
|
+
Balance,
|
|
16
|
+
Bank,
|
|
17
|
+
GetGroupResponse,
|
|
14
18
|
} from "./types";
|
|
15
19
|
import encode from "bs58";
|
|
16
20
|
|
|
@@ -48,10 +52,7 @@ export class Client {
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
// sign and send tx to api for sending to network
|
|
51
|
-
private async send(
|
|
52
|
-
unsignedBase64Tx: string,
|
|
53
|
-
...signedBase64Txns: string[]
|
|
54
|
-
): Promise<string> {
|
|
55
|
+
private async send(unsignedBase64Tx: string): Promise<string> {
|
|
55
56
|
// deserialize into tx obj
|
|
56
57
|
const txBytes = Buffer.from(unsignedBase64Tx, "base64");
|
|
57
58
|
const tx = web3.VersionedTransaction.deserialize(new Uint8Array(txBytes));
|
|
@@ -67,7 +68,7 @@ export class Client {
|
|
|
67
68
|
|
|
68
69
|
// create request obj
|
|
69
70
|
const sendRequest: SendRequest = {
|
|
70
|
-
txns: [encodedAndSignedTx
|
|
71
|
+
txns: [encodedAndSignedTx],
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
// send to api
|
|
@@ -100,40 +101,113 @@ export class Client {
|
|
|
100
101
|
this.http.get(`/user?user=${user.toString()}`),
|
|
101
102
|
);
|
|
102
103
|
|
|
103
|
-
const
|
|
104
|
+
const jsonRawResponse: any = JSON.parse(body);
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
// get tokens still in user wallet
|
|
107
|
+
const wallet: UserWallet = {
|
|
108
|
+
usdcBalance: new BN(jsonRawResponse.wallet.usdcBalance, "hex"),
|
|
109
|
+
usdcBalanceUi: Number(jsonRawResponse.wallet.usdcBalanceUi),
|
|
110
|
+
jlpBalance: new BN(jsonRawResponse.wallet.jlpBalance, "hex"),
|
|
111
|
+
jlpBalanceUi: Number(jsonRawResponse.wallet.jlpBalanceUi),
|
|
112
|
+
solBalance: new BN(jsonRawResponse.wallet.solBalance, "hex"),
|
|
113
|
+
solBalanceUi: Number(jsonRawResponse.wallet.solBalanceUi),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// if no clend account, return undefined for clend
|
|
117
|
+
if (!jsonRawResponse.clendAccount) {
|
|
118
|
+
return {
|
|
119
|
+
wallet,
|
|
120
|
+
clendAccount: undefined,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// parse lending account balances
|
|
125
|
+
const balances: Balance[] = [];
|
|
126
|
+
for (const b of jsonRawResponse.clendAccount.balances) {
|
|
127
|
+
balances.push({
|
|
128
|
+
mint: new web3.PublicKey(b.mint),
|
|
129
|
+
bank: new web3.PublicKey(b.bank),
|
|
130
|
+
assetBalance: new BN(b.assetBalance, "hex"),
|
|
131
|
+
assetBalanceUi: Number(b.assetBalanceUi),
|
|
132
|
+
assetValue: Number(b.assetValue),
|
|
133
|
+
liabilityBalance: new BN(b.liabilityBalance, "hex"),
|
|
134
|
+
liabilityBalanceUi: Number(b.liabilityBalanceUi),
|
|
135
|
+
liabilityValue: Number(b.liabilityValue),
|
|
136
|
+
price: Number(b.price),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// create clend account
|
|
141
|
+
const clendAccount: ClendAccount = {
|
|
142
|
+
balances,
|
|
143
|
+
netValue: Number(jsonRawResponse.clendAccount.netValue),
|
|
144
|
+
netApy: Number(jsonRawResponse.clendAccount.netApy),
|
|
145
|
+
pnl: Number(jsonRawResponse.clendAccount.pnl),
|
|
146
|
+
totalAssetValue: Number(jsonRawResponse.clendAccount.totalAssetValue),
|
|
147
|
+
totalLiabilityValue: Number(
|
|
148
|
+
jsonRawResponse.clendAccount.totalLiabilityValue,
|
|
149
|
+
),
|
|
150
|
+
healthFactorNotional: Number(
|
|
151
|
+
jsonRawResponse.clendAccount.healthFactorNotional,
|
|
152
|
+
),
|
|
153
|
+
healthFactorRiskAdjusted: Number(
|
|
154
|
+
jsonRawResponse.clendAccount.healthFactorRiskAdjusted,
|
|
155
|
+
),
|
|
156
|
+
notionalLeverage: Number(jsonRawResponse.clendAccount.notionalLeverage),
|
|
157
|
+
riskAdjustedLeverage: Number(
|
|
158
|
+
jsonRawResponse.clendAccount.riskAdjustedLeverage,
|
|
159
|
+
),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
wallet,
|
|
164
|
+
clendAccount,
|
|
165
|
+
};
|
|
106
166
|
}
|
|
107
167
|
|
|
108
168
|
/**
|
|
109
|
-
* Get market details
|
|
110
|
-
* @returns
|
|
169
|
+
* Get market details
|
|
170
|
+
* @returns Group Details
|
|
111
171
|
*/
|
|
112
|
-
async
|
|
113
|
-
const body = await handleApiCall(() => this.http.get(`
|
|
172
|
+
async getGroup(): Promise<GetGroupResponse> {
|
|
173
|
+
const body = await handleApiCall(() => this.http.get(`/group`));
|
|
174
|
+
|
|
175
|
+
const marketJson: any = JSON.parse(body);
|
|
176
|
+
const banks: Bank[] = [];
|
|
177
|
+
for (const bankJson of marketJson.banks) {
|
|
178
|
+
const bank = parseBank(bankJson);
|
|
179
|
+
banks.push(bank);
|
|
180
|
+
}
|
|
114
181
|
|
|
115
|
-
const response:
|
|
182
|
+
const response: GetGroupResponse = {
|
|
183
|
+
banks,
|
|
184
|
+
};
|
|
116
185
|
|
|
117
186
|
return response;
|
|
118
187
|
}
|
|
119
188
|
|
|
120
189
|
/**
|
|
121
|
-
*
|
|
122
|
-
* @
|
|
190
|
+
* Get bank details
|
|
191
|
+
* @param addr token mint or bank public key
|
|
192
|
+
* @param addrType "mint" or "bank"
|
|
193
|
+
* @returns Bank details
|
|
123
194
|
*/
|
|
124
|
-
async
|
|
195
|
+
async getBank(
|
|
196
|
+
addr: web3.PublicKey,
|
|
197
|
+
addrType: "mint" | "bank",
|
|
198
|
+
): Promise<GetBankResponse> {
|
|
125
199
|
const body = await handleApiCall(() =>
|
|
126
|
-
this.http.
|
|
127
|
-
"createObligation",
|
|
128
|
-
JSON.stringify({ owner: this.address() }),
|
|
129
|
-
),
|
|
200
|
+
this.http.get(`/bank?${addrType}=${addr.toString()}`),
|
|
130
201
|
);
|
|
131
202
|
|
|
132
|
-
const
|
|
203
|
+
const bankJson: any = JSON.parse(body);
|
|
204
|
+
const bank = parseBank(bankJson.bank);
|
|
133
205
|
|
|
134
|
-
const
|
|
206
|
+
const response: GetBankResponse = {
|
|
207
|
+
bank,
|
|
208
|
+
};
|
|
135
209
|
|
|
136
|
-
return
|
|
210
|
+
return response;
|
|
137
211
|
}
|
|
138
212
|
|
|
139
213
|
/**
|
|
@@ -141,37 +215,43 @@ export class Client {
|
|
|
141
215
|
* @param request Deposit leverage request parameters
|
|
142
216
|
* @returns Deposit leverage operation result
|
|
143
217
|
*/
|
|
144
|
-
async depositLeverage(
|
|
218
|
+
async depositLeverage(
|
|
219
|
+
selectedTokenMint: web3.PublicKey,
|
|
220
|
+
uiAmount: number,
|
|
221
|
+
leverage: number,
|
|
222
|
+
slippageBps: number,
|
|
223
|
+
): Promise<string> {
|
|
224
|
+
const req: DepositLeverageRequest = {
|
|
225
|
+
owner: this.address(),
|
|
226
|
+
selectedTokenMint,
|
|
227
|
+
depositAmountUi: uiAmount,
|
|
228
|
+
leverage,
|
|
229
|
+
slippageBps,
|
|
230
|
+
};
|
|
145
231
|
const body = await handleApiCall(() =>
|
|
146
|
-
this.http.post("leverage/deposit", JSON.stringify(
|
|
232
|
+
this.http.post("leverage/deposit", JSON.stringify(req)),
|
|
147
233
|
);
|
|
148
234
|
|
|
149
235
|
const depositLeverageResponse: DepositLeverageResponse = JSON.parse(body);
|
|
150
236
|
|
|
151
|
-
const txSig = await this.send(
|
|
152
|
-
depositLeverageResponse.unsignedBase64Tx,
|
|
153
|
-
depositLeverageResponse.signedSetBorrowRateBase64Tx,
|
|
154
|
-
);
|
|
237
|
+
const txSig = await this.send(depositLeverageResponse.unsignedBase64Tx);
|
|
155
238
|
|
|
156
239
|
return txSig;
|
|
157
240
|
}
|
|
158
241
|
|
|
159
242
|
/**
|
|
160
|
-
*
|
|
161
|
-
* @param request
|
|
162
|
-
* @returns
|
|
243
|
+
* Adjust the leverage of an existing position
|
|
244
|
+
* @param request Adjust leverage request parameters
|
|
245
|
+
* @returns Adjust leverage operation result
|
|
163
246
|
*/
|
|
164
|
-
async
|
|
247
|
+
async adjustLeverage(params: AdjustLeverageRequest): Promise<any> {
|
|
165
248
|
const body = await handleApiCall(() =>
|
|
166
|
-
this.http.post("leverage/
|
|
249
|
+
this.http.post("leverage/adjust", JSON.stringify(params)),
|
|
167
250
|
);
|
|
168
251
|
|
|
169
|
-
const
|
|
252
|
+
const adjustLeverageResponse: AdjustLeverageResponse = JSON.parse(body);
|
|
170
253
|
|
|
171
|
-
const txSig = await this.send(
|
|
172
|
-
modifyLeverageResponse.unsignedBase64Tx,
|
|
173
|
-
modifyLeverageResponse.signedSetBorrowRateBase64Tx,
|
|
174
|
-
);
|
|
254
|
+
const txSig = await this.send(adjustLeverageResponse.unsignedBase64Tx);
|
|
175
255
|
|
|
176
256
|
return txSig;
|
|
177
257
|
}
|
|
@@ -181,22 +261,38 @@ export class Client {
|
|
|
181
261
|
* @param request Withdraw leverage request parameters
|
|
182
262
|
* @returns Withdraw leverage operation result
|
|
183
263
|
*/
|
|
184
|
-
async withdrawLeverage(
|
|
264
|
+
async withdrawLeverage(
|
|
265
|
+
selectedTokenMint: web3.PublicKey,
|
|
266
|
+
uiAmount: number,
|
|
267
|
+
slippageBps: number,
|
|
268
|
+
withdrawAll: boolean,
|
|
269
|
+
): Promise<any> {
|
|
270
|
+
const req: WithdrawLeverageRequest = {
|
|
271
|
+
owner: this.address(),
|
|
272
|
+
selectedTokenMint,
|
|
273
|
+
withdrawAmountUi: uiAmount,
|
|
274
|
+
slippageBps,
|
|
275
|
+
withdrawAll,
|
|
276
|
+
};
|
|
185
277
|
const body = await handleApiCall(() =>
|
|
186
|
-
this.http.post("leverage/withdraw", JSON.stringify(
|
|
278
|
+
this.http.post("leverage/withdraw", JSON.stringify(req)),
|
|
187
279
|
);
|
|
188
280
|
|
|
189
281
|
const withdrawLeverageResponse: WithdrawLeverageResponse = JSON.parse(body);
|
|
190
282
|
|
|
191
|
-
const txSig = await this.send(
|
|
192
|
-
withdrawLeverageResponse.unsignedBase64Tx,
|
|
193
|
-
withdrawLeverageResponse.signedSetBorrowRateBase64Tx,
|
|
194
|
-
);
|
|
283
|
+
const txSig = await this.send(withdrawLeverageResponse.unsignedBase64Tx);
|
|
195
284
|
|
|
196
285
|
return txSig;
|
|
197
286
|
}
|
|
198
287
|
}
|
|
199
288
|
|
|
289
|
+
type ApiErrorPayload = {
|
|
290
|
+
error: string;
|
|
291
|
+
details?: unknown;
|
|
292
|
+
path: string;
|
|
293
|
+
timestamp: string;
|
|
294
|
+
};
|
|
295
|
+
|
|
200
296
|
function handleStatusCode(statusCode: number): void {
|
|
201
297
|
switch (statusCode) {
|
|
202
298
|
case 200:
|
|
@@ -208,23 +304,23 @@ function handleStatusCode(statusCode: number): void {
|
|
|
208
304
|
|
|
209
305
|
// Helper function to handle API calls
|
|
210
306
|
async function handleApiCall<T>(
|
|
211
|
-
|
|
212
|
-
): Promise<
|
|
307
|
+
call: () => Promise<AxiosResponse<T>>,
|
|
308
|
+
): Promise<string> {
|
|
213
309
|
try {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
throw new Error(
|
|
310
|
+
const { data } = await call();
|
|
311
|
+
return JSON.stringify(data);
|
|
312
|
+
} catch (e) {
|
|
313
|
+
if (axios.isAxiosError(e)) {
|
|
314
|
+
const res = e.response;
|
|
315
|
+
if (res && typeof res.data === "object") {
|
|
316
|
+
const payload = res.data as ApiErrorPayload;
|
|
317
|
+
throw new Error(
|
|
318
|
+
`${payload.error}${payload.details ? ` ${payload.details}` : ""}`,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
throw new Error(`${e.message}`);
|
|
226
322
|
}
|
|
227
|
-
throw
|
|
323
|
+
throw e;
|
|
228
324
|
}
|
|
229
325
|
}
|
|
230
326
|
|
|
@@ -237,3 +333,19 @@ function getDummyProvider(): AnchorProvider {
|
|
|
237
333
|
},
|
|
238
334
|
);
|
|
239
335
|
}
|
|
336
|
+
|
|
337
|
+
function parseBank(bankJson: any): Bank {
|
|
338
|
+
return {
|
|
339
|
+
mint: new web3.PublicKey(bankJson.mint),
|
|
340
|
+
key: new web3.PublicKey(bankJson.key),
|
|
341
|
+
group: new web3.PublicKey(bankJson.group),
|
|
342
|
+
supplyApy: Number(bankJson.supplyApy),
|
|
343
|
+
borrowApy: Number(bankJson.borrowApy),
|
|
344
|
+
utilizationRate: Number(bankJson.utilizationRate),
|
|
345
|
+
assetAmount: new BN(bankJson.assetAmount, "hex"),
|
|
346
|
+
assetAmountUi: Number(bankJson.assetAmountUi),
|
|
347
|
+
liabilityAmount: new BN(bankJson.liabilityAmount, "hex"),
|
|
348
|
+
liabilityAmountUi: Number(bankJson.liabilityAmountUi),
|
|
349
|
+
price: Number(bankJson.price),
|
|
350
|
+
};
|
|
351
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -6,23 +6,15 @@ export interface SendRequest {
|
|
|
6
6
|
txns: string[];
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export interface CreateObligationRequest {
|
|
10
|
-
owner: web3.PublicKey;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface CreateObligationResponse {
|
|
14
|
-
unsignedBase64Tx: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
9
|
/**
|
|
18
10
|
* Request to deposit collateral and create a leveraged position
|
|
19
11
|
*/
|
|
20
12
|
export interface DepositLeverageRequest {
|
|
21
13
|
owner: web3.PublicKey;
|
|
22
14
|
selectedTokenMint: web3.PublicKey;
|
|
23
|
-
|
|
15
|
+
depositAmountUi: number;
|
|
24
16
|
leverage: number;
|
|
25
|
-
|
|
17
|
+
slippageBps: number;
|
|
26
18
|
}
|
|
27
19
|
|
|
28
20
|
/**
|
|
@@ -30,24 +22,22 @@ export interface DepositLeverageRequest {
|
|
|
30
22
|
*/
|
|
31
23
|
export interface DepositLeverageResponse {
|
|
32
24
|
unsignedBase64Tx: string;
|
|
33
|
-
signedSetBorrowRateBase64Tx: string;
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
/**
|
|
37
|
-
* Request to
|
|
28
|
+
* Request to adjust the leverage of an existing position
|
|
38
29
|
*/
|
|
39
|
-
export interface
|
|
30
|
+
export interface AdjustLeverageRequest {
|
|
40
31
|
owner: web3.PublicKey;
|
|
41
32
|
leverage: number;
|
|
42
|
-
|
|
33
|
+
slippageBps: number;
|
|
43
34
|
}
|
|
44
35
|
|
|
45
36
|
/**
|
|
46
|
-
* Response for
|
|
37
|
+
* Response for adjust leverage operation
|
|
47
38
|
*/
|
|
48
|
-
export interface
|
|
39
|
+
export interface AdjustLeverageResponse {
|
|
49
40
|
unsignedBase64Tx: string;
|
|
50
|
-
signedSetBorrowRateBase64Tx: string;
|
|
51
41
|
}
|
|
52
42
|
|
|
53
43
|
/**
|
|
@@ -56,9 +46,9 @@ export interface ModifyLeverageResponse {
|
|
|
56
46
|
export interface WithdrawLeverageRequest {
|
|
57
47
|
owner: web3.PublicKey;
|
|
58
48
|
selectedTokenMint: web3.PublicKey;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
withdrawAmountUi: number;
|
|
50
|
+
slippageBps: number;
|
|
51
|
+
withdrawAll: boolean;
|
|
62
52
|
}
|
|
63
53
|
|
|
64
54
|
/**
|
|
@@ -66,34 +56,65 @@ export interface WithdrawLeverageRequest {
|
|
|
66
56
|
*/
|
|
67
57
|
export interface WithdrawLeverageResponse {
|
|
68
58
|
unsignedBase64Tx: string;
|
|
69
|
-
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface GetGroupResponse {
|
|
62
|
+
banks: Bank[];
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
export interface GetUserResponse {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
totalDebt: number;
|
|
79
|
-
ltv: number;
|
|
80
|
-
liquidationLtv: number;
|
|
66
|
+
wallet: UserWallet;
|
|
67
|
+
clendAccount: ClendAccount | undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface UserWallet {
|
|
81
71
|
usdcBalance: BN;
|
|
82
72
|
usdcBalanceUi: number;
|
|
83
73
|
jlpBalance: BN;
|
|
84
74
|
jlpBalanceUi: number;
|
|
85
75
|
solBalance: BN;
|
|
86
76
|
solBalanceUi: number;
|
|
87
|
-
obligationCreated: boolean;
|
|
88
77
|
}
|
|
89
78
|
|
|
90
|
-
export interface
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
79
|
+
export interface ClendAccount {
|
|
80
|
+
balances: Balance[];
|
|
81
|
+
netValue: number;
|
|
82
|
+
netApy: number;
|
|
83
|
+
pnl: number;
|
|
84
|
+
totalAssetValue: number;
|
|
85
|
+
totalLiabilityValue: number;
|
|
86
|
+
healthFactorNotional: number;
|
|
87
|
+
healthFactorRiskAdjusted: number;
|
|
88
|
+
notionalLeverage: number;
|
|
89
|
+
riskAdjustedLeverage: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface Balance {
|
|
93
|
+
mint: web3.PublicKey;
|
|
94
|
+
bank: web3.PublicKey;
|
|
95
|
+
assetBalance: BN;
|
|
96
|
+
assetBalanceUi: number;
|
|
97
|
+
assetValue: number;
|
|
98
|
+
liabilityBalance: BN;
|
|
99
|
+
liabilityBalanceUi: number;
|
|
100
|
+
liabilityValue: number;
|
|
101
|
+
price: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface GetBankResponse {
|
|
105
|
+
bank: Bank;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface Bank {
|
|
109
|
+
group: web3.PublicKey;
|
|
110
|
+
key: web3.PublicKey;
|
|
111
|
+
mint: web3.PublicKey;
|
|
112
|
+
supplyApy: number;
|
|
113
|
+
borrowApy: number;
|
|
114
|
+
utilizationRate: number;
|
|
115
|
+
assetAmount: BN;
|
|
116
|
+
assetAmountUi: number;
|
|
117
|
+
liabilityAmount: BN;
|
|
118
|
+
liabilityAmountUi: number;
|
|
119
|
+
price: number;
|
|
99
120
|
}
|