@drift-labs/sdk 2.96.0-beta.8 → 2.97.0-beta.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.
Files changed (76) hide show
  1. package/README.md +3 -0
  2. package/VERSION +1 -1
  3. package/bun.lockb +0 -0
  4. package/lib/accounts/pollingDriftClientAccountSubscriber.d.ts +5 -3
  5. package/lib/accounts/pollingDriftClientAccountSubscriber.js +24 -1
  6. package/lib/accounts/types.d.ts +5 -0
  7. package/lib/accounts/types.js +7 -1
  8. package/lib/accounts/utils.d.ts +7 -0
  9. package/lib/accounts/utils.js +33 -1
  10. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +5 -4
  11. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +24 -1
  12. package/lib/config.d.ts +6 -1
  13. package/lib/config.js +10 -1
  14. package/lib/constants/perpMarkets.js +33 -1
  15. package/lib/constants/spotMarkets.js +10 -0
  16. package/lib/constants/txConstants.d.ts +1 -0
  17. package/lib/constants/txConstants.js +4 -0
  18. package/lib/driftClient.d.ts +45 -9
  19. package/lib/driftClient.js +191 -49
  20. package/lib/driftClientConfig.d.ts +3 -0
  21. package/lib/events/types.js +1 -5
  22. package/lib/idl/drift.json +170 -2
  23. package/lib/index.d.ts +1 -0
  24. package/lib/index.js +1 -0
  25. package/lib/math/margin.d.ts +16 -1
  26. package/lib/math/margin.js +67 -1
  27. package/lib/orderParams.js +8 -8
  28. package/lib/orderSubscriber/OrderSubscriber.js +1 -6
  29. package/lib/tokenFaucet.js +2 -1
  30. package/lib/tx/baseTxSender.d.ts +0 -1
  31. package/lib/tx/baseTxSender.js +8 -26
  32. package/lib/tx/fastSingleTxSender.js +2 -2
  33. package/lib/tx/forwardOnlyTxSender.js +2 -2
  34. package/lib/tx/reportTransactionError.d.ts +20 -0
  35. package/lib/tx/reportTransactionError.js +103 -0
  36. package/lib/tx/retryTxSender.js +2 -2
  37. package/lib/tx/txHandler.js +10 -7
  38. package/lib/tx/whileValidTxSender.d.ts +4 -5
  39. package/lib/tx/whileValidTxSender.js +16 -17
  40. package/lib/types.d.ts +22 -1
  41. package/lib/types.js +6 -1
  42. package/lib/user.d.ts +4 -1
  43. package/lib/user.js +9 -2
  44. package/lib/util/TransactionConfirmationManager.d.ts +16 -0
  45. package/lib/util/TransactionConfirmationManager.js +174 -0
  46. package/package.json +4 -3
  47. package/src/accounts/pollingDriftClientAccountSubscriber.ts +41 -5
  48. package/src/accounts/types.ts +6 -0
  49. package/src/accounts/utils.ts +42 -0
  50. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +40 -5
  51. package/src/config.ts +17 -1
  52. package/src/constants/perpMarkets.ts +35 -1
  53. package/src/constants/spotMarkets.ts +11 -0
  54. package/src/constants/txConstants.ts +1 -0
  55. package/src/driftClient.ts +426 -64
  56. package/src/driftClientConfig.ts +3 -0
  57. package/src/events/types.ts +1 -5
  58. package/src/idl/drift.json +170 -2
  59. package/src/index.ts +1 -0
  60. package/src/math/margin.ts +137 -1
  61. package/src/orderParams.ts +20 -12
  62. package/src/orderSubscriber/OrderSubscriber.ts +2 -5
  63. package/src/tokenFaucet.ts +2 -2
  64. package/src/tx/baseTxSender.ts +10 -32
  65. package/src/tx/fastSingleTxSender.ts +2 -2
  66. package/src/tx/forwardOnlyTxSender.ts +2 -2
  67. package/src/tx/reportTransactionError.ts +159 -0
  68. package/src/tx/retryTxSender.ts +2 -2
  69. package/src/tx/txHandler.ts +8 -2
  70. package/src/tx/whileValidTxSender.ts +18 -27
  71. package/src/types.ts +31 -1
  72. package/src/user.ts +35 -2
  73. package/src/util/TransactionConfirmationManager.ts +292 -0
  74. package/tests/ci/idl.ts +12 -3
  75. package/tests/ci/verifyConstants.ts +13 -0
  76. package/tests/tx/TransactionConfirmationManager.test.ts +305 -0
@@ -0,0 +1,159 @@
1
+ import {
2
+ Commitment,
3
+ Connection,
4
+ Finality,
5
+ SendTransactionError,
6
+ VersionedTransactionResponse,
7
+ } from '@solana/web3.js';
8
+ import { DEFAULT_CONFIRMATION_OPTS } from '../config';
9
+
10
+ /**
11
+ * The new getTransaction method expects a Finality type instead of a Commitment type. The only options for Finality are 'confirmed' and 'finalized'.
12
+ * @param commitment
13
+ * @returns
14
+ */
15
+ const commitmentToFinality = (commitment: Commitment): Finality => {
16
+ switch (commitment) {
17
+ case 'confirmed':
18
+ return 'confirmed';
19
+ case 'finalized':
20
+ return 'finalized';
21
+ default:
22
+ throw new Error(
23
+ `Invalid commitment when reporting transaction error. The commitment must be 'confirmed' or 'finalized' but was given '${commitment}'. If you're using this commitment for a specific reason, you may need to roll your own logic here.`
24
+ );
25
+ }
26
+ };
27
+
28
+ const getTransactionResult = async (
29
+ txSig: string,
30
+ connection: Connection,
31
+ commitment?: Commitment
32
+ ): Promise<VersionedTransactionResponse> => {
33
+ const finality = commitmentToFinality(
34
+ commitment || connection.commitment || DEFAULT_CONFIRMATION_OPTS.commitment
35
+ );
36
+ return await connection.getTransaction(txSig, {
37
+ maxSupportedTransactionVersion: 0,
38
+ commitment: finality,
39
+ });
40
+ };
41
+
42
+ const getTransactionResultWithRetry = async (
43
+ txSig: string,
44
+ connection: Connection,
45
+ commitment?: Commitment
46
+ ): Promise<VersionedTransactionResponse> => {
47
+ const start = Date.now();
48
+
49
+ const retryTimeout = 3_000; // Timeout after 3 seconds
50
+ const retryInterval = 800; // Retry with 800ms interval
51
+ const retryCount = 3; // Retry 3 times
52
+
53
+ let currentCount = 0;
54
+ let transactionResult = await getTransactionResult(
55
+ txSig,
56
+ connection,
57
+ commitment
58
+ );
59
+
60
+ // Retry 3 times or until timeout as long as we don't have a result yet
61
+ while (
62
+ !transactionResult &&
63
+ Date.now() - start < retryTimeout &&
64
+ currentCount < retryCount
65
+ ) {
66
+ // Sleep for 1 second :: Do this first so that we don't run the first loop immediately after the initial fetch above
67
+ await new Promise((resolve) => setTimeout(resolve, retryInterval));
68
+
69
+ transactionResult = await getTransactionResult(
70
+ txSig,
71
+ connection,
72
+ commitment
73
+ );
74
+ currentCount++;
75
+ }
76
+
77
+ return transactionResult;
78
+ };
79
+
80
+ /**
81
+ * THROWS if there is an error
82
+ *
83
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
84
+ * @param txSig
85
+ * @param connection
86
+ * @returns
87
+ */
88
+ export const throwTransactionError = async (
89
+ txSig: string,
90
+ connection: Connection,
91
+ commitment?: Commitment
92
+ ): Promise<void> => {
93
+ const err = await getTransactionErrorFromTxSig(txSig, connection, commitment);
94
+
95
+ if (err) {
96
+ throw err;
97
+ }
98
+
99
+ return;
100
+ };
101
+
102
+ /**
103
+ * RETURNS an error if there is one
104
+ *
105
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
106
+ * @param txSig
107
+ * @param connection
108
+ * @returns
109
+ */
110
+ export const getTransactionErrorFromTxSig = async (
111
+ txSig: string,
112
+ connection: Connection,
113
+ commitment?: Commitment
114
+ ): Promise<SendTransactionError> => {
115
+ const transactionResult = await getTransactionResultWithRetry(
116
+ txSig,
117
+ connection,
118
+ commitment
119
+ );
120
+
121
+ if (!transactionResult) {
122
+ // Throw a generic error because we couldn't get the transaction result for the given txSig
123
+ return new SendTransactionError({
124
+ action: 'send',
125
+ signature: txSig,
126
+ transactionMessage: `Transaction Failed`,
127
+ });
128
+ }
129
+
130
+ if (!transactionResult?.meta?.err) {
131
+ // Assume that the transaction was successful and we are here erroneously because we have a result with no error
132
+ return;
133
+ }
134
+
135
+ return getTransactionError(transactionResult);
136
+ };
137
+
138
+ export const getTransactionError = (
139
+ transactionResult: VersionedTransactionResponse
140
+ ): SendTransactionError => {
141
+ if (!transactionResult?.meta?.err) {
142
+ return;
143
+ }
144
+
145
+ const logs = transactionResult?.meta?.logMessages ?? ['No logs'];
146
+
147
+ const lastLog = logs[logs.length - 1];
148
+
149
+ const friendlyMessage = lastLog?.match(/(failed:) (.+)/)?.[2];
150
+
151
+ return new SendTransactionError({
152
+ action: 'send',
153
+ signature: transactionResult?.transaction?.signatures?.[0],
154
+ transactionMessage: `Transaction Failed${
155
+ friendlyMessage ? `: ${friendlyMessage}` : ''
156
+ }`,
157
+ logs,
158
+ });
159
+ };
@@ -1,9 +1,9 @@
1
1
  import { ConfirmationStrategy, TxSigAndSlot } from './types';
2
2
  import { ConfirmOptions, Connection } from '@solana/web3.js';
3
- import { AnchorProvider } from '@coral-xyz/anchor';
4
3
  import { BaseTxSender } from './baseTxSender';
5
4
  import { TxHandler } from './txHandler';
6
5
  import { IWallet } from '../types';
6
+ import { DEFAULT_CONFIRMATION_OPTS } from '../config';
7
7
 
8
8
  const DEFAULT_TIMEOUT = 35000;
9
9
  const DEFAULT_RETRY = 2000;
@@ -24,7 +24,7 @@ export class RetryTxSender extends BaseTxSender {
24
24
  public constructor({
25
25
  connection,
26
26
  wallet,
27
- opts = { ...AnchorProvider.defaultOptions(), maxRetries: 0 },
27
+ opts = { ...DEFAULT_CONFIRMATION_OPTS, maxRetries: 0 },
28
28
  timeout = DEFAULT_TIMEOUT,
29
29
  retrySleep = DEFAULT_RETRY,
30
30
  additionalConnections = new Array<Connection>(),
@@ -29,6 +29,7 @@ import { CachedBlockhashFetcher } from './blockhashFetcher/cachedBlockhashFetche
29
29
  import { BaseBlockhashFetcher } from './blockhashFetcher/baseBlockhashFetcher';
30
30
  import { BlockhashFetcher } from './blockhashFetcher/types';
31
31
  import { isVersionedTransaction } from './utils';
32
+ import { DEFAULT_CONFIRMATION_OPTS } from '../config';
32
33
 
33
34
  /**
34
35
  * Explanation for SIGNATURE_BLOCK_AND_EXPIRY:
@@ -81,7 +82,8 @@ export class TxHandler {
81
82
  private preSignedCb?: () => void;
82
83
  private onSignedCb?: (txSigs: DriftClientMetricsEvents['txSigned']) => void;
83
84
 
84
- private blockhashCommitment: Commitment = 'finalized';
85
+ private blockhashCommitment: Commitment =
86
+ DEFAULT_CONFIRMATION_OPTS.commitment;
85
87
  private blockHashFetcher: BlockhashFetcher;
86
88
 
87
89
  constructor(props: {
@@ -98,6 +100,11 @@ export class TxHandler {
98
100
  this.connection = props.connection;
99
101
  this.wallet = props.wallet;
100
102
  this.confirmationOptions = props.confirmationOptions;
103
+ this.blockhashCommitment =
104
+ props.confirmationOptions?.preflightCommitment ??
105
+ props?.connection?.commitment ??
106
+ this.blockhashCommitment ??
107
+ 'confirmed';
101
108
 
102
109
  this.blockHashFetcher = props?.config?.blockhashCachingEnabled
103
110
  ? new CachedBlockhashFetcher(
@@ -536,7 +543,6 @@ export class TxHandler {
536
543
  }
537
544
  } else {
538
545
  const marketLookupTable = await fetchMarketLookupTableAccount();
539
-
540
546
  lookupTables = lookupTables
541
547
  ? [...lookupTables, marketLookupTable]
542
548
  : [marketLookupTable];
@@ -1,22 +1,20 @@
1
- import { TxSigAndSlot } from './types';
1
+ import { ConfirmationStrategy, TxSigAndSlot } from './types';
2
2
  import {
3
- Commitment,
4
3
  ConfirmOptions,
5
4
  Connection,
5
+ SendTransactionError,
6
6
  Signer,
7
7
  Transaction,
8
8
  VersionedTransaction,
9
9
  } from '@solana/web3.js';
10
- import { AnchorProvider } from '@coral-xyz/anchor';
11
10
  import { BaseTxSender } from './baseTxSender';
12
11
  import bs58 from 'bs58';
13
12
  import { TxHandler } from './txHandler';
14
13
  import { IWallet } from '../types';
14
+ import { DEFAULT_CONFIRMATION_OPTS } from '../config';
15
15
 
16
16
  const DEFAULT_RETRY = 2000;
17
17
 
18
- const VALID_BLOCK_HEIGHT_OFFSET = -150; // This is a bit of weirdness but the lastValidBlockHeight value returned from connection.getLatestBlockhash is always 300 blocks ahead of the current block, even though the transaction actually expires after 150 blocks. This accounts for that so that we can at least accuractely estimate the transaction expiry.
19
-
20
18
  type ResolveReference = {
21
19
  resolve?: () => void;
22
20
  };
@@ -33,7 +31,6 @@ export class WhileValidTxSender extends BaseTxSender {
33
31
  string,
34
32
  { blockhash: string; lastValidBlockHeight: number }
35
33
  >();
36
- blockhashCommitment: Commitment;
37
34
 
38
35
  useBlockHeightOffset = true;
39
36
 
@@ -62,11 +59,11 @@ export class WhileValidTxSender extends BaseTxSender {
62
59
  public constructor({
63
60
  connection,
64
61
  wallet,
65
- opts = { ...AnchorProvider.defaultOptions(), maxRetries: 0 },
62
+ opts = { ...DEFAULT_CONFIRMATION_OPTS, maxRetries: 0 },
66
63
  retrySleep = DEFAULT_RETRY,
67
64
  additionalConnections = new Array<Connection>(),
65
+ confirmationStrategy = ConfirmationStrategy.Combo,
68
66
  additionalTxSenderCallbacks = [],
69
- blockhashCommitment = 'finalized',
70
67
  txHandler,
71
68
  trackTxLandRate,
72
69
  txLandRateLookbackWindowMinutes,
@@ -78,7 +75,7 @@ export class WhileValidTxSender extends BaseTxSender {
78
75
  retrySleep?: number;
79
76
  additionalConnections?;
80
77
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
81
- blockhashCommitment?: Commitment;
78
+ confirmationStrategy?: ConfirmationStrategy;
82
79
  txHandler?: TxHandler;
83
80
  trackTxLandRate?: boolean;
84
81
  txLandRateLookbackWindowMinutes?: number;
@@ -93,10 +90,10 @@ export class WhileValidTxSender extends BaseTxSender {
93
90
  txHandler,
94
91
  trackTxLandRate,
95
92
  txLandRateLookbackWindowMinutes,
93
+ confirmationStrategy,
96
94
  landRateToFeeFunc,
97
95
  });
98
96
  this.retrySleep = retrySleep;
99
- this.blockhashCommitment = blockhashCommitment;
100
97
 
101
98
  this.checkAndSetUseBlockHeightOffset();
102
99
  }
@@ -139,7 +136,7 @@ export class WhileValidTxSender extends BaseTxSender {
139
136
 
140
137
  // handle subclass-specific side effects
141
138
  const txSig = bs58.encode(
142
- signedTx.signatures[0]?.signature || signedTx.signatures[0]
139
+ signedTx?.signature || signedTx.signatures[0]?.signature
143
140
  );
144
141
  this.untilValid.set(txSig, latestBlockhash);
145
142
 
@@ -234,27 +231,21 @@ export class WhileValidTxSender extends BaseTxSender {
234
231
 
235
232
  let slot: number;
236
233
  try {
237
- const { blockhash, lastValidBlockHeight } = this.untilValid.get(txid);
238
-
239
- const result = await this.connection.confirmTransaction(
240
- {
241
- signature: txid,
242
- blockhash,
243
- lastValidBlockHeight: this.useBlockHeightOffset
244
- ? lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET
245
- : lastValidBlockHeight,
246
- },
247
- opts?.commitment
248
- );
249
-
250
- if (!result) {
251
- throw new Error(`Couldn't get signature status for txid: ${txid}`);
252
- }
234
+ const result = await this.confirmTransaction(txid, opts.commitment);
253
235
 
254
236
  this.txSigCache?.set(txid, true);
255
237
 
256
238
  await this.checkConfirmationResultForError(txid, result.value);
257
239
 
240
+ if (result?.value?.err) {
241
+ // Fallback error handling if there's a problem reporting the error in checkConfirmationResultForError
242
+ throw new SendTransactionError({
243
+ action: 'send',
244
+ signature: txid,
245
+ transactionMessage: `Transaction Failed`,
246
+ });
247
+ }
248
+
258
249
  slot = result.context.slot;
259
250
  // eslint-disable-next-line no-useless-catch
260
251
  } catch (e) {
package/src/types.ts CHANGED
@@ -1,4 +1,9 @@
1
- import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
1
+ import {
2
+ Keypair,
3
+ PublicKey,
4
+ Transaction,
5
+ VersionedTransaction,
6
+ } from '@solana/web3.js';
2
7
  import { BN, ZERO } from '.';
3
8
 
4
9
  // Utility type which lets you denote record with values of type A mapped to a record with the same keys but values of type B
@@ -1051,6 +1056,24 @@ export const DefaultOrderParams: OrderParams = {
1051
1056
  auctionEndPrice: null,
1052
1057
  };
1053
1058
 
1059
+ export type SwiftServerMessage = {
1060
+ slot: BN;
1061
+ swiftOrderSignature: Uint8Array;
1062
+ };
1063
+
1064
+ export type SwiftOrderParamsMessage = {
1065
+ swiftOrderParams: OptionalOrderParams;
1066
+ expectedOrderId: number;
1067
+ subAccountId: number;
1068
+ takeProfitOrderParams: SwiftTriggerOrderParams | null;
1069
+ stopLossOrderParams: SwiftTriggerOrderParams | null;
1070
+ };
1071
+
1072
+ export type SwiftTriggerOrderParams = {
1073
+ triggerPrice: BN;
1074
+ baseAssetAmount: BN;
1075
+ };
1076
+
1054
1077
  export type MakerInfo = {
1055
1078
  maker: PublicKey;
1056
1079
  makerStats: PublicKey;
@@ -1070,6 +1093,11 @@ export type ReferrerInfo = {
1070
1093
  referrerStats: PublicKey;
1071
1094
  };
1072
1095
 
1096
+ export enum PlaceAndTakeOrderSuccessCondition {
1097
+ PartialFill = 1,
1098
+ FullFill = 2,
1099
+ }
1100
+
1073
1101
  type ExactType<T> = Pick<T, keyof T>;
1074
1102
 
1075
1103
  export type BaseTxParams = ExactType<{
@@ -1097,6 +1125,7 @@ export interface IWallet {
1097
1125
  signTransaction(tx: Transaction): Promise<Transaction>;
1098
1126
  signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
1099
1127
  publicKey: PublicKey;
1128
+ payer?: Keypair;
1100
1129
  }
1101
1130
  export interface IVersionedWallet {
1102
1131
  signVersionedTransaction(
@@ -1106,6 +1135,7 @@ export interface IVersionedWallet {
1106
1135
  txs: VersionedTransaction[]
1107
1136
  ): Promise<VersionedTransaction[]>;
1108
1137
  publicKey: PublicKey;
1138
+ payer?: Keypair;
1109
1139
  }
1110
1140
 
1111
1141
  export type FeeStructure = {
package/src/user.ts CHANGED
@@ -78,6 +78,8 @@ import {
78
78
  import { calculateMarketOpenBidAsk } from './math/amm';
79
79
  import {
80
80
  calculateBaseAssetValueWithOracle,
81
+ calculateCollateralDepositRequiredForTrade,
82
+ calculateMarginUSDCRequiredForTrade,
81
83
  calculateWorstCaseBaseAssetAmount,
82
84
  } from './math/margin';
83
85
  import { OraclePriceData } from './oracles/types';
@@ -2274,6 +2276,7 @@ export class User {
2274
2276
  * @param estimatedEntryPrice
2275
2277
  * @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
2276
2278
  * @param includeOpenOrders
2279
+ * @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
2277
2280
  * @returns Precision : PRICE_PRECISION
2278
2281
  */
2279
2282
  public liquidationPrice(
@@ -2281,7 +2284,8 @@ export class User {
2281
2284
  positionBaseSizeChange: BN = ZERO,
2282
2285
  estimatedEntryPrice: BN = ZERO,
2283
2286
  marginCategory: MarginCategory = 'Maintenance',
2284
- includeOpenOrders = false
2287
+ includeOpenOrders = false,
2288
+ offsetCollateral = ZERO
2285
2289
  ): BN {
2286
2290
  const totalCollateral = this.getTotalCollateral(marginCategory);
2287
2291
  const marginRequirement = this.getMarginRequirement(
@@ -2290,7 +2294,10 @@ export class User {
2290
2294
  false,
2291
2295
  includeOpenOrders
2292
2296
  );
2293
- let freeCollateral = BN.max(ZERO, totalCollateral.sub(marginRequirement));
2297
+ let freeCollateral = BN.max(
2298
+ ZERO,
2299
+ totalCollateral.sub(marginRequirement)
2300
+ ).add(offsetCollateral);
2294
2301
 
2295
2302
  const oracle =
2296
2303
  this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
@@ -2593,6 +2600,32 @@ export class User {
2593
2600
  );
2594
2601
  }
2595
2602
 
2603
+ public getMarginUSDCRequiredForTrade(
2604
+ targetMarketIndex: number,
2605
+ baseSize: BN
2606
+ ): BN {
2607
+ return calculateMarginUSDCRequiredForTrade(
2608
+ this.driftClient,
2609
+ targetMarketIndex,
2610
+ baseSize,
2611
+ this.getUserAccount().maxMarginRatio
2612
+ );
2613
+ }
2614
+
2615
+ public getCollateralDepositRequiredForTrade(
2616
+ targetMarketIndex: number,
2617
+ baseSize: BN,
2618
+ collateralIndex: number
2619
+ ): BN {
2620
+ return calculateCollateralDepositRequiredForTrade(
2621
+ this.driftClient,
2622
+ targetMarketIndex,
2623
+ baseSize,
2624
+ collateralIndex,
2625
+ this.getUserAccount().maxMarginRatio
2626
+ );
2627
+ }
2628
+
2596
2629
  /**
2597
2630
  * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
2598
2631
  *