@cetusprotocol/dlmm-zap-sdk 0.0.1 → 1.0.0
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/README.md +243 -72
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @cetusprotocol/zap-sdk
|
|
2
2
|
|
|
3
|
-
The SDK provides a Zap module for specialized liquidity operations with different modes to suit various trading strategies. This module enables users to perform complex liquidity operations with flexibility in how they want to manage their positions.
|
|
3
|
+
The SDK provides a Zap module for specialized liquidity operations with different modes to suit various trading strategies. This module enables users to perform complex liquidity operations with flexibility in how they want to manage their positions in DLMM (Dynamic Liquidity Market Maker) pools.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ npm install @cetusprotocol/zap-sdk
|
|
|
21
21
|
Import the SDK into the TypeScript file where you intend to use it:
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
|
-
import {
|
|
24
|
+
import { CetusDlmmZapSDK } from '@cetusprotocol/zap-sdk'
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
### Initializing the SDK
|
|
@@ -31,7 +31,7 @@ Initialize the SDK with the required configuration parameters. This typically in
|
|
|
31
31
|
If you would like to use the mainnet network and the official Sui rpc url, you can do so as follows:
|
|
32
32
|
|
|
33
33
|
```typescript
|
|
34
|
-
const sdk =
|
|
34
|
+
const sdk = CetusDlmmZapSDK.createSDK({ env: 'mainnet' })
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
If you wish to set your own full node URL or network (You have the option to select either 'mainnet' or 'testnet' for the network), you can do so as follows:
|
|
@@ -39,17 +39,14 @@ If you wish to set your own full node URL or network (You have the option to sel
|
|
|
39
39
|
```typescript
|
|
40
40
|
const env = 'mainnet'
|
|
41
41
|
const full_rpc_url = 'YOUR_FULL_NODE_URL'
|
|
42
|
-
const wallet = 'YOUR_WALLET_ADDRESS'
|
|
43
42
|
|
|
44
|
-
const sdk =
|
|
43
|
+
const sdk = CetusDlmmZapSDK.createSDK({ env, full_rpc_url })
|
|
45
44
|
```
|
|
46
45
|
|
|
47
|
-
If you wish to set your own
|
|
46
|
+
If you wish to set your own SuiClient, you can do so as follows:
|
|
48
47
|
|
|
49
48
|
```typescript
|
|
50
|
-
const sdk =
|
|
51
|
-
// or
|
|
52
|
-
const sdk = CetusZapSDK.createSDK({ env, full_rpc_url })
|
|
49
|
+
const sdk = CetusDlmmZapSDK.createSDK({ env, sui_client })
|
|
53
50
|
```
|
|
54
51
|
|
|
55
52
|
## Usage
|
|
@@ -73,74 +70,146 @@ sdk.updateFullRpcUrl(new_rpc_url)
|
|
|
73
70
|
### Common Parameters
|
|
74
71
|
|
|
75
72
|
- `pool_id`: The ID of the liquidity pool
|
|
76
|
-
- `
|
|
77
|
-
- `
|
|
73
|
+
- `lower_bin_id` & `upper_bin_id`: Bin ID range boundaries for the position
|
|
74
|
+
- `active_id`: Current active bin ID of the pool
|
|
75
|
+
- `bin_step`: The bin step size of the pool
|
|
76
|
+
- `strategy_type`: Strategy type for the position (e.g., `StrategyType.Spot`)
|
|
78
77
|
- `slippage`: Maximum acceptable price slippage (e.g., 0.01 for 1%)
|
|
79
78
|
- `coin_type_a` & `coin_type_b`: Coin type identifiers for the trading pair
|
|
80
|
-
- `
|
|
79
|
+
- `active_bin_of_pool`: Information about the active bin if it's within the position range
|
|
81
80
|
|
|
82
81
|
### 1. Deposit Operations
|
|
83
82
|
|
|
84
83
|
#### Deposit Mode-Specific Parameters
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- `fixed_amount`: Fixed amount to deposit
|
|
89
|
-
- `fixed_coin_a`: Boolean indicating whether to fix coin A (true) or coin B (false)
|
|
90
|
-
|
|
91
|
-
2. **FlexibleBoth** (This feature will be supported in a future release, currently a placeholder)
|
|
85
|
+
**OnlyCoinA/OnlyCoinB Mode**
|
|
92
86
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
3. **OnlyCoinA/OnlyCoinB**
|
|
97
|
-
- `coin_amount`: Amount of single coin to deposit
|
|
87
|
+
- `fix_amount_a`: Boolean indicating whether to fix coin A (true) or coin B (false)
|
|
88
|
+
- `coin_amount`: Amount of single coin to deposit
|
|
98
89
|
|
|
99
90
|
#### Deposit Usage Example
|
|
100
91
|
|
|
92
|
+
**Create New Position**
|
|
93
|
+
|
|
101
94
|
```typescript
|
|
95
|
+
import { CetusDlmmZapSDK } from '@cetusprotocol/zap-sdk'
|
|
96
|
+
import { StrategyType, toDecimalsAmount } from '@cetusprotocol/common-sdk'
|
|
97
|
+
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'
|
|
98
|
+
|
|
102
99
|
// Initialize SDK and get pool information
|
|
103
|
-
const sdk =
|
|
100
|
+
const sdk = CetusDlmmZapSDK.createSDK({ env: 'mainnet' })
|
|
101
|
+
const wallet = 'YOUR_WALLET_ADDRESS'
|
|
102
|
+
sdk.setSenderAddress(wallet)
|
|
104
103
|
|
|
105
104
|
const pool_id = 'YOUR_POOL_ID'
|
|
106
|
-
const pool = await sdk.
|
|
105
|
+
const pool = await sdk.DlmmSDK.Pool.getPool(pool_id)
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
if (!pool) {
|
|
108
|
+
throw new Error('Pool not found')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const { active_id, bin_step, bin_manager } = pool
|
|
112
|
+
|
|
113
|
+
// Define your position range
|
|
114
|
+
const lower_bin_id = active_id
|
|
115
|
+
const upper_bin_id = active_id + 2
|
|
116
|
+
|
|
117
|
+
// Get active bin information if it's within range
|
|
118
|
+
const amounts_in_active_bin = await sdk.DlmmSDK.Position.getActiveBinIfInRange(
|
|
119
|
+
bin_manager.bin_manager_handle,
|
|
120
|
+
lower_bin_id,
|
|
121
|
+
upper_bin_id,
|
|
122
|
+
active_id,
|
|
123
|
+
bin_step
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
// Pre-calculate deposit amounts (OnlyCoinB mode)
|
|
109
127
|
const result = await sdk.Zap.preCalculateDepositAmount(
|
|
110
128
|
{
|
|
111
129
|
pool_id,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
strategy_type: StrategyType.Spot,
|
|
131
|
+
active_bin_of_pool: amounts_in_active_bin,
|
|
132
|
+
lower_bin_id,
|
|
133
|
+
upper_bin_id,
|
|
134
|
+
active_id: pool.active_id,
|
|
135
|
+
bin_step: pool.bin_step,
|
|
116
136
|
},
|
|
117
137
|
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
fixed_coin_a: false,
|
|
138
|
+
fix_amount_a: false, // false means fix coin B
|
|
139
|
+
coin_amount: toDecimalsAmount(0.1, 9).toString(), // Amount of coin B
|
|
121
140
|
}
|
|
122
141
|
)
|
|
123
142
|
|
|
143
|
+
// Build transaction
|
|
144
|
+
const tx = await sdk.Zap.buildDepositPayload({
|
|
145
|
+
deposit_obj: result,
|
|
146
|
+
pool_id,
|
|
147
|
+
strategy_type: StrategyType.Spot,
|
|
148
|
+
lower_bin_id,
|
|
149
|
+
upper_bin_id,
|
|
150
|
+
active_id: pool.active_id,
|
|
151
|
+
bin_step: pool.bin_step,
|
|
152
|
+
slippage: 0.01,
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// Execute the transaction
|
|
156
|
+
// Note: send_key_pair should be your wallet's keypair or signer
|
|
157
|
+
// For example: const send_key_pair = new Ed25519Keypair(...)
|
|
158
|
+
const res = await sdk.FullClient.executeTx(send_key_pair, tx, false)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Add Liquidity to Existing Position**
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
124
164
|
const pos_id = 'YOUR_POSITION_ID'
|
|
125
|
-
|
|
165
|
+
const position = await sdk.DlmmSDK.Position.getPosition(pos_id)
|
|
166
|
+
const { lower_bin_id, upper_bin_id } = position
|
|
167
|
+
|
|
168
|
+
// Get active bin information if it's within range
|
|
169
|
+
const amounts_in_active_bin = await sdk.DlmmSDK.Position.getActiveBinIfInRange(
|
|
170
|
+
bin_manager.bin_manager_handle,
|
|
171
|
+
lower_bin_id,
|
|
172
|
+
upper_bin_id,
|
|
173
|
+
active_id,
|
|
174
|
+
bin_step
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
const result = await sdk.Zap.preCalculateDepositAmount(
|
|
178
|
+
{
|
|
179
|
+
pool_id,
|
|
180
|
+
strategy_type: StrategyType.Spot,
|
|
181
|
+
active_bin_of_pool: amounts_in_active_bin,
|
|
182
|
+
lower_bin_id,
|
|
183
|
+
upper_bin_id,
|
|
184
|
+
active_id: pool.active_id,
|
|
185
|
+
bin_step: pool.bin_step,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
fix_amount_a: true, // true means fix coin A
|
|
189
|
+
coin_amount: toDecimalsAmount(0.5, 6).toString(), // Amount of coin A
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// Build transaction with position object
|
|
126
194
|
const tx = await sdk.Zap.buildDepositPayload({
|
|
127
195
|
deposit_obj: result,
|
|
128
196
|
pool_id,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
197
|
+
strategy_type: StrategyType.Spot,
|
|
198
|
+
lower_bin_id,
|
|
199
|
+
upper_bin_id,
|
|
200
|
+
active_id: pool.active_id,
|
|
201
|
+
bin_step: pool.bin_step,
|
|
133
202
|
slippage: 0.01,
|
|
134
203
|
pos_obj: {
|
|
135
|
-
// Optional: Add to existing position
|
|
136
204
|
pos_id,
|
|
137
205
|
collect_fee: false,
|
|
138
206
|
collect_rewarder_types: [],
|
|
139
207
|
},
|
|
140
208
|
})
|
|
141
209
|
|
|
142
|
-
//
|
|
143
|
-
|
|
210
|
+
// Execute the transaction
|
|
211
|
+
// Note: send_key_pair should be your wallet's keypair or signer
|
|
212
|
+
const res = await sdk.FullClient.executeTx(send_key_pair, tx, false)
|
|
144
213
|
```
|
|
145
214
|
|
|
146
215
|
### 2. Withdraw Operations
|
|
@@ -149,58 +218,160 @@ Withdrawals require an existing position in the pool.
|
|
|
149
218
|
|
|
150
219
|
#### Withdraw Mode-Specific Parameters
|
|
151
220
|
|
|
152
|
-
1. **
|
|
221
|
+
1. **OnlyCoinA/OnlyCoinB**
|
|
153
222
|
|
|
154
|
-
- `
|
|
155
|
-
- `
|
|
223
|
+
- `expected_receive_amount`: Expected amount to receive
|
|
224
|
+
- `is_receive_coin_a`: Boolean indicating whether to receive coin A (true) or coin B (false)
|
|
225
|
+
- `mode`: Withdrawal mode - `'OnlyCoinA'`, `'OnlyCoinB'`, or `'Both'`
|
|
156
226
|
|
|
157
|
-
2. **
|
|
158
|
-
- `
|
|
159
|
-
- `
|
|
227
|
+
2. **Both**
|
|
228
|
+
- `expected_receive_amount`: Expected amount to receive (will be split between both coins)
|
|
229
|
+
- `is_receive_coin_a`: Boolean indicating which coin the expected amount refers to
|
|
230
|
+
- `mode`: Set to `'Both'`
|
|
160
231
|
|
|
161
232
|
#### Withdraw Usage Example
|
|
162
233
|
|
|
234
|
+
**Calculate Available Withdraw Amount**
|
|
235
|
+
|
|
163
236
|
```typescript
|
|
237
|
+
import { parseLiquidityShares } from '@cetusprotocol/dlmm-sdk'
|
|
238
|
+
|
|
239
|
+
const pool_id = 'YOUR_POOL_ID'
|
|
240
|
+
const pos_id = 'YOUR_POSITION_ID'
|
|
241
|
+
|
|
164
242
|
// Get pool and position information
|
|
165
|
-
const pool = await sdk.
|
|
166
|
-
const position = await sdk.
|
|
243
|
+
const pool = await sdk.DlmmSDK.Pool.getPool(pool_id)
|
|
244
|
+
const position = await sdk.DlmmSDK.Position.getPosition(pos_id)
|
|
167
245
|
|
|
168
246
|
if (!pool || !position) {
|
|
169
247
|
throw new Error('Pool or Position not found')
|
|
170
248
|
}
|
|
171
249
|
|
|
172
|
-
|
|
250
|
+
const { bin_step, bin_manager, active_id } = pool
|
|
251
|
+
const { lower_bin_id, liquidity_shares } = position
|
|
252
|
+
|
|
253
|
+
// Get active bin information
|
|
254
|
+
const active_bin = await sdk.DlmmSDK.Pool.getBinInfo(
|
|
255
|
+
bin_manager.bin_manager_handle,
|
|
256
|
+
active_id,
|
|
257
|
+
bin_step
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
// Parse liquidity shares to get bin range
|
|
261
|
+
const liquidity_shares_data = parseLiquidityShares(
|
|
262
|
+
liquidity_shares,
|
|
263
|
+
bin_step,
|
|
264
|
+
lower_bin_id,
|
|
265
|
+
active_bin
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
// Calculate available withdraw amount
|
|
269
|
+
const available_obj = sdk.Zap.calculateZapOutAvailableAmount({
|
|
270
|
+
remove_bin_range: liquidity_shares_data.bins,
|
|
271
|
+
active_id,
|
|
272
|
+
bin_step,
|
|
273
|
+
is_receive_coin_a: false, // Receive coin B
|
|
274
|
+
mode: 'OnlyCoinB',
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
console.log('Available withdraw amount:', available_obj)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Withdraw in OnlyCoinB Mode**
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { toDecimalsAmount } from '@cetusprotocol/common-sdk'
|
|
284
|
+
|
|
285
|
+
const { coin_type_a, coin_type_b, bin_step, bin_manager, active_id, reward_manager } = pool
|
|
286
|
+
const slippage = 0.01
|
|
287
|
+
const is_receive_coin_a = false
|
|
288
|
+
const expected_receive_amount = toDecimalsAmount(0.05, 9).toString() // Amount of coin B
|
|
289
|
+
const mode = 'OnlyCoinB'
|
|
290
|
+
|
|
291
|
+
// Get active bin and parse liquidity shares
|
|
292
|
+
const active_bin = await sdk.DlmmSDK.Pool.getBinInfo(
|
|
293
|
+
bin_manager.bin_manager_handle,
|
|
294
|
+
active_id,
|
|
295
|
+
bin_step
|
|
296
|
+
)
|
|
297
|
+
const liquidity_shares_data = parseLiquidityShares(
|
|
298
|
+
liquidity_shares,
|
|
299
|
+
bin_step,
|
|
300
|
+
lower_bin_id,
|
|
301
|
+
active_bin
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
// Pre-calculate withdrawal
|
|
173
305
|
const result = await sdk.Zap.preCalculateWithdrawAmount({
|
|
174
|
-
|
|
306
|
+
remove_bin_range: liquidity_shares_data.bins,
|
|
307
|
+
active_id,
|
|
308
|
+
bin_step,
|
|
309
|
+
expected_receive_amount,
|
|
310
|
+
is_receive_coin_a,
|
|
311
|
+
mode,
|
|
312
|
+
coin_type_a,
|
|
313
|
+
coin_type_b,
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
// Build transaction
|
|
317
|
+
const tx = await sdk.Zap.buildWithdrawPayload({
|
|
318
|
+
withdraw_obj: result,
|
|
319
|
+
swap_slippage: 0.01,
|
|
175
320
|
pool_id,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
321
|
+
position_id: pos_id,
|
|
322
|
+
active_id,
|
|
323
|
+
bin_step,
|
|
324
|
+
slippage,
|
|
325
|
+
reward_coins: reward_manager.rewards.map((reward) => reward.reward_coin),
|
|
326
|
+
collect_fee: true,
|
|
327
|
+
remove_percent: Number(result.remove_percent),
|
|
328
|
+
coin_type_a,
|
|
329
|
+
coin_type_b,
|
|
330
|
+
is_close_position: false, // Set to true to close the position
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
// Execute the transaction
|
|
334
|
+
// Note: send_key_pair should be your wallet's keypair or signer
|
|
335
|
+
const res = await sdk.FullClient.executeTx(send_key_pair, tx, false)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Withdraw in Both Mode**
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const mode = 'Both'
|
|
342
|
+
const expected_receive_amount = toDecimalsAmount(0.05, 9).toString()
|
|
343
|
+
const is_receive_coin_a = false
|
|
344
|
+
|
|
345
|
+
const result = await sdk.Zap.preCalculateWithdrawAmount({
|
|
346
|
+
remove_bin_range: liquidity_shares_data.bins,
|
|
347
|
+
active_id,
|
|
348
|
+
bin_step,
|
|
349
|
+
expected_receive_amount,
|
|
350
|
+
is_receive_coin_a,
|
|
351
|
+
mode,
|
|
352
|
+
coin_type_a,
|
|
353
|
+
coin_type_b,
|
|
185
354
|
})
|
|
186
355
|
|
|
187
|
-
// Build and send transaction
|
|
188
356
|
const tx = await sdk.Zap.buildWithdrawPayload({
|
|
189
357
|
withdraw_obj: result,
|
|
358
|
+
swap_slippage: 0.01,
|
|
190
359
|
pool_id,
|
|
191
|
-
pos_id,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
360
|
+
position_id: pos_id,
|
|
361
|
+
active_id,
|
|
362
|
+
bin_step,
|
|
363
|
+
slippage,
|
|
364
|
+
reward_coins: reward_manager.rewards.map((reward) => reward.reward_coin),
|
|
365
|
+
collect_fee: true,
|
|
366
|
+
remove_percent: Number(result.remove_percent),
|
|
367
|
+
coin_type_a,
|
|
368
|
+
coin_type_b,
|
|
369
|
+
is_close_position: true, // Close the position
|
|
200
370
|
})
|
|
201
371
|
|
|
202
|
-
//
|
|
203
|
-
|
|
372
|
+
// Execute the transaction
|
|
373
|
+
// Note: send_key_pair should be your wallet's keypair or signer
|
|
374
|
+
const res = await sdk.FullClient.executeTx(send_key_pair, tx, false)
|
|
204
375
|
```
|
|
205
376
|
|
|
206
377
|
## More About Cetus
|
package/dist/index.d.mts
CHANGED
|
@@ -81,6 +81,12 @@ type CalculationWithdrawOptions = {
|
|
|
81
81
|
expected_receive_amount: string;
|
|
82
82
|
is_receive_coin_a: boolean;
|
|
83
83
|
mode: WithdrawMode;
|
|
84
|
+
coin_decimal_a: number;
|
|
85
|
+
coin_decimal_b: number;
|
|
86
|
+
prices?: {
|
|
87
|
+
coin_a_price: string;
|
|
88
|
+
coin_b_price: string;
|
|
89
|
+
};
|
|
84
90
|
} & CoinPairType;
|
|
85
91
|
type CalculationWithdrawAvailableAmountOptions = {
|
|
86
92
|
remove_bin_range: BinAmount[];
|
|
@@ -88,6 +94,12 @@ type CalculationWithdrawAvailableAmountOptions = {
|
|
|
88
94
|
bin_step: number;
|
|
89
95
|
is_receive_coin_a: boolean;
|
|
90
96
|
mode: WithdrawMode;
|
|
97
|
+
coin_decimal_a: number;
|
|
98
|
+
coin_decimal_b: number;
|
|
99
|
+
prices?: {
|
|
100
|
+
coin_a_price: string;
|
|
101
|
+
coin_b_price: string;
|
|
102
|
+
};
|
|
91
103
|
};
|
|
92
104
|
/**
|
|
93
105
|
* Result of a withdrawal calculation
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,12 @@ type CalculationWithdrawOptions = {
|
|
|
81
81
|
expected_receive_amount: string;
|
|
82
82
|
is_receive_coin_a: boolean;
|
|
83
83
|
mode: WithdrawMode;
|
|
84
|
+
coin_decimal_a: number;
|
|
85
|
+
coin_decimal_b: number;
|
|
86
|
+
prices?: {
|
|
87
|
+
coin_a_price: string;
|
|
88
|
+
coin_b_price: string;
|
|
89
|
+
};
|
|
84
90
|
} & CoinPairType;
|
|
85
91
|
type CalculationWithdrawAvailableAmountOptions = {
|
|
86
92
|
remove_bin_range: BinAmount[];
|
|
@@ -88,6 +94,12 @@ type CalculationWithdrawAvailableAmountOptions = {
|
|
|
88
94
|
bin_step: number;
|
|
89
95
|
is_receive_coin_a: boolean;
|
|
90
96
|
mode: WithdrawMode;
|
|
97
|
+
coin_decimal_a: number;
|
|
98
|
+
coin_decimal_b: number;
|
|
99
|
+
prices?: {
|
|
100
|
+
coin_a_price: string;
|
|
101
|
+
coin_b_price: string;
|
|
102
|
+
};
|
|
91
103
|
};
|
|
92
104
|
/**
|
|
93
105
|
* Result of a withdrawal calculation
|