@velocity-exchange/sdk 0.9.0 → 0.10.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 (66) hide show
  1. package/lib/browser/adminClient.d.ts +2 -2
  2. package/lib/browser/adminClient.js +3 -11
  3. package/lib/browser/equityFloorManager.d.ts +9 -5
  4. package/lib/browser/equityFloorManager.js +9 -5
  5. package/lib/browser/idl/velocity.d.ts +2 -1
  6. package/lib/browser/idl/velocity.json +2 -1
  7. package/lib/browser/index.d.ts +2 -0
  8. package/lib/browser/index.js +3 -0
  9. package/lib/browser/jupiter/jupiterClient.d.ts +31 -27
  10. package/lib/browser/jupiter/jupiterClient.js +61 -35
  11. package/lib/browser/math/margin.d.ts +12 -10
  12. package/lib/browser/math/margin.js +16 -14
  13. package/lib/browser/math/superStake.d.ts +9 -9
  14. package/lib/browser/math/superStake.js +8 -8
  15. package/lib/browser/swap/UnifiedSwapClient.d.ts +38 -76
  16. package/lib/browser/swap/UnifiedSwapClient.js +46 -117
  17. package/lib/browser/swap/routeInstructions.d.ts +19 -0
  18. package/lib/browser/swap/routeInstructions.js +43 -0
  19. package/lib/browser/swap/types.d.ts +196 -0
  20. package/lib/browser/swap/types.js +88 -0
  21. package/lib/browser/titan/titanClient.d.ts +32 -68
  22. package/lib/browser/titan/titanClient.js +128 -102
  23. package/lib/browser/user.d.ts +16 -18
  24. package/lib/browser/user.js +24 -26
  25. package/lib/browser/velocityClient.d.ts +83 -101
  26. package/lib/browser/velocityClient.js +152 -289
  27. package/lib/node/adminClient.d.ts +2 -2
  28. package/lib/node/adminClient.d.ts.map +1 -1
  29. package/lib/node/adminClient.js +3 -11
  30. package/lib/node/equityFloorManager.d.ts +9 -5
  31. package/lib/node/equityFloorManager.d.ts.map +1 -1
  32. package/lib/node/equityFloorManager.js +9 -5
  33. package/lib/node/idl/velocity.d.ts +2 -1
  34. package/lib/node/idl/velocity.d.ts.map +1 -1
  35. package/lib/node/idl/velocity.json +2 -1
  36. package/lib/node/index.d.ts +2 -0
  37. package/lib/node/index.d.ts.map +1 -1
  38. package/lib/node/index.js +3 -0
  39. package/lib/node/jupiter/jupiterClient.d.ts +31 -27
  40. package/lib/node/jupiter/jupiterClient.d.ts.map +1 -1
  41. package/lib/node/jupiter/jupiterClient.js +61 -35
  42. package/lib/node/math/margin.d.ts +12 -10
  43. package/lib/node/math/margin.d.ts.map +1 -1
  44. package/lib/node/math/margin.js +16 -14
  45. package/lib/node/math/superStake.d.ts +9 -9
  46. package/lib/node/math/superStake.d.ts.map +1 -1
  47. package/lib/node/math/superStake.js +8 -8
  48. package/lib/node/swap/UnifiedSwapClient.d.ts +38 -76
  49. package/lib/node/swap/UnifiedSwapClient.d.ts.map +1 -1
  50. package/lib/node/swap/UnifiedSwapClient.js +46 -117
  51. package/lib/node/swap/routeInstructions.d.ts +20 -0
  52. package/lib/node/swap/routeInstructions.d.ts.map +1 -0
  53. package/lib/node/swap/routeInstructions.js +43 -0
  54. package/lib/node/swap/types.d.ts +197 -0
  55. package/lib/node/swap/types.d.ts.map +1 -0
  56. package/lib/node/swap/types.js +88 -0
  57. package/lib/node/titan/titanClient.d.ts +32 -68
  58. package/lib/node/titan/titanClient.d.ts.map +1 -1
  59. package/lib/node/titan/titanClient.js +128 -102
  60. package/lib/node/user.d.ts +16 -18
  61. package/lib/node/user.d.ts.map +1 -1
  62. package/lib/node/user.js +24 -26
  63. package/lib/node/velocityClient.d.ts +83 -101
  64. package/lib/node/velocityClient.d.ts.map +1 -1
  65. package/lib/node/velocityClient.js +152 -289
  66. package/package.json +1 -1
@@ -17,7 +17,7 @@ import { AddressLookupTableAccount, Keypair, PublicKey, TransactionInstruction,
17
17
  import { FeeStructure, OracleGuardRails, OracleSource, ExchangeStatus, SolvencyStatus, MarketStatus, ContractTier, AssetTier, TxParams, AddAmmConstituentMappingDatum, SwapReduceOnly, InitializeConstituentParams, ConstituentStatus, LPPoolAccount, TransferFeeAndPnlPoolDirection, MarketType } from './types';
18
18
  import { BN } from './isomorphic/anchor';
19
19
  import { VelocityClient } from './velocityClient';
20
- import { JupiterClient, QuoteResponse } from './jupiter/jupiterClient';
20
+ import { JupiterClient, JupiterSwapQuote } from './jupiter/jupiterClient';
21
21
  import { SwapMode } from './swap/UnifiedSwapClient';
22
22
  export declare class AdminClient extends VelocityClient {
23
23
  /**
@@ -2283,7 +2283,7 @@ export declare class AdminClient extends VelocityClient {
2283
2283
  slippageBps?: number;
2284
2284
  swapMode?: SwapMode;
2285
2285
  onlyDirectRoutes?: boolean;
2286
- quote?: QuoteResponse;
2286
+ quote?: JupiterSwapQuote;
2287
2287
  lpPoolId: number;
2288
2288
  }): Promise<{
2289
2289
  ixs: TransactionInstruction[];
@@ -4496,21 +4496,13 @@ class AdminClient extends velocityClient_1.VelocityClient {
4496
4496
  if (!quote) {
4497
4497
  throw new Error('Could not fetch swap quote. Please try again.');
4498
4498
  }
4499
+ this.assertQuoteMatchesMarkets(quote, inMarket, outMarket);
4499
4500
  const isExactOut = swapMode === 'ExactOut' || quote.swapMode === 'ExactOut';
4500
4501
  const amountIn = new anchor_1.BN(quote.inAmount);
4501
4502
  const exactOutBufferedAmountIn = amountIn.muln(1001).divn(1000); // Add 10bp buffer
4502
- const transaction = await jupiterClient.getSwap({
4503
+ const { instructions: jupiterInstructions, lookupTables } = await jupiterClient.getRouteInstructions({
4503
4504
  quote,
4504
4505
  userPublicKey: this.provider.wallet.publicKey,
4505
- slippageBps,
4506
- });
4507
- const { transactionMessage, lookupTables } = await jupiterClient.getTransactionMessageAndLookupTables({
4508
- transaction,
4509
- });
4510
- const jupiterInstructions = jupiterClient.getJupiterInstructions({
4511
- transactionMessage,
4512
- inputMint: inMarket.mint,
4513
- outputMint: outMarket.mint,
4514
4506
  });
4515
4507
  const preInstructions = [];
4516
4508
  const tokenProgram = this.getTokenProgramForSpotMarket(outMarket);
@@ -4523,7 +4515,7 @@ class AdminClient extends velocityClient_1.VelocityClient {
4523
4515
  const inAssociatedTokenAccount = await this.getAssociatedTokenAccount(inMarket.marketIndex, false, inTokenProgram);
4524
4516
  const inAccountInfo = await this.connection.getAccountInfo(inAssociatedTokenAccount);
4525
4517
  if (!inAccountInfo) {
4526
- preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(inAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, inMarket.mint, tokenProgram));
4518
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(inAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, inMarket.mint, inTokenProgram));
4527
4519
  }
4528
4520
  const { beginSwapIx, endSwapIx } = await this.getSwapIx({
4529
4521
  lpPoolId,
@@ -18,7 +18,7 @@ import { TxParams } from './types';
18
18
  /** One subaccount's standing relative to its floor. All BN values QUOTE_PRECISION. */
19
19
  export type SubaccountFloorStatus = {
20
20
  subAccountId: number;
21
- /** Cross-margin total collateral, strict (TWAP-bounded) pricing — what the on-chain checks see. */
21
+ /** Net equity (`User.getNetUsdValue`, unweighted live-oracle value), what the onchain checks see. */
22
22
  equity: BN;
23
23
  equityFloor: BN;
24
24
  equityFloorBuffer: BN;
@@ -86,7 +86,7 @@ export type EquityFloorManagerConfig = {
86
86
  subAccountIds?: number[];
87
87
  /**
88
88
  * Client-side equity haircut (QUOTE_PRECISION) applied when sizing floor
89
- * deltas, absorbing the dust by which strict on-chain pricing can differ
89
+ * deltas, absorbing the dust by which onchain oracle pricing can differ
90
90
  * from the client's. Defaults to 1 quote unit ($1).
91
91
  */
92
92
  collateralHaircut?: BN;
@@ -123,8 +123,8 @@ export declare class EquityFloorManager {
123
123
  getMaxQuoteTransferable(fromSubAccountId: number, toSubAccountId: number): BN;
124
124
  /**
125
125
  * Resolves a quote transfer into the exact instruction parameters,
126
- * padding the auto floor delta by the haircut so on-chain strict pricing
127
- * dust cannot fail it. The padded delta never exceeds the amount or the
126
+ * padding the auto floor delta by the haircut so onchain pricing dust
127
+ * cannot fail it. The padded delta never exceeds the amount or the
128
128
  * debited side's floor, so the credited side stays backed whenever it was
129
129
  * before.
130
130
  */
@@ -139,7 +139,11 @@ export declare class EquityFloorManager {
139
139
  * pinned in place and the rest is allocated around them. Throws when the
140
140
  * pool's equity cannot back the total floor plus buffers — at that point
141
141
  * no split works and equity must be deposited (or the admin must lower
142
- * the floor).
142
+ * the floor). Each onchain move also carries a proportional share of the
143
+ * debited side's buffer, so buffers drift toward the same split as the
144
+ * floors; the plan sizes against current buffers and the haircut absorbs
145
+ * the drift dust, but a move can still revert if a credited side cannot
146
+ * back the buffer share it receives.
143
147
  */
144
148
  planFloorRebalance(): FloorMove[];
145
149
  /**
@@ -134,7 +134,7 @@ class EquityFloorManager {
134
134
  }
135
135
  getSubaccountStatus(user) {
136
136
  const userAccount = user.getUserAccountOrThrow();
137
- const equity = user.getTotalCollateral('Initial', true);
137
+ const equity = user.getNetUsdValue();
138
138
  const bufferedFloor = userAccount.equityFloor.add(userAccount.equityFloorBuffer);
139
139
  return {
140
140
  subAccountId: userAccount.subAccountId,
@@ -212,15 +212,15 @@ class EquityFloorManager {
212
212
  }
213
213
  /**
214
214
  * Resolves a quote transfer into the exact instruction parameters,
215
- * padding the auto floor delta by the haircut so on-chain strict pricing
216
- * dust cannot fail it. The padded delta never exceeds the amount or the
215
+ * padding the auto floor delta by the haircut so onchain pricing dust
216
+ * cannot fail it. The padded delta never exceeds the amount or the
217
217
  * debited side's floor, so the credited side stays backed whenever it was
218
218
  * before.
219
219
  */
220
220
  planQuoteTransfer(amount, fromSubAccountId, toSubAccountId) {
221
221
  const fromUser = this.velocityClient.getUser(fromSubAccountId, this.velocityClient.authority);
222
222
  const fromAccount = fromUser.getUserAccountOrThrow();
223
- const equityFloorDelta = (0, margin_1.calculateEquityFloorAutoDelta)(amount, fromUser.getTotalCollateral('Initial', true).sub(this.collateralHaircut), fromAccount.equityFloor, fromAccount.equityFloorBuffer);
223
+ const equityFloorDelta = (0, margin_1.calculateEquityFloorAutoDelta)(amount, fromUser.getNetUsdValue().sub(this.collateralHaircut), fromAccount.equityFloor, fromAccount.equityFloorBuffer);
224
224
  return {
225
225
  amount,
226
226
  marketIndex: numericConstants_2.QUOTE_SPOT_MARKET_INDEX,
@@ -242,7 +242,11 @@ class EquityFloorManager {
242
242
  * pinned in place and the rest is allocated around them. Throws when the
243
243
  * pool's equity cannot back the total floor plus buffers — at that point
244
244
  * no split works and equity must be deposited (or the admin must lower
245
- * the floor).
245
+ * the floor). Each onchain move also carries a proportional share of the
246
+ * debited side's buffer, so buffers drift toward the same split as the
247
+ * floors; the plan sizes against current buffers and the haircut absorbs
248
+ * the drift dust, but a move can still revert if a credited side cannot
249
+ * back the buffer share it receives.
246
250
  */
247
251
  planFloorRebalance() {
248
252
  const subaccounts = this.getManagedUsers().map((user) => this.getSubaccountStatus(user));
@@ -24136,7 +24136,8 @@ export type Velocity = {
24136
24136
  {
24137
24137
  "name": "equityFloor";
24138
24138
  "docs": [
24139
- "Minimum account equity (cross-margin total collateral). Below this the",
24139
+ "Minimum account net equity (unweighted assets plus perp pnl minus",
24140
+ "spot liabilities, see `calculate_user_equity`). Below this the",
24140
24141
  "permissionless breaker can trip. Risk-increasing orders, fills,",
24141
24142
  "withdrawals and deposit transfers must clear `equity_floor +",
24142
24143
  "equity_floor_buffer`. Settable only by the warm/cold admin; 0 disables",
@@ -24130,7 +24130,8 @@
24130
24130
  {
24131
24131
  "name": "equity_floor",
24132
24132
  "docs": [
24133
- "Minimum account equity (cross-margin total collateral). Below this the",
24133
+ "Minimum account net equity (unweighted assets plus perp pnl minus",
24134
+ "spot liabilities, see `calculate_user_equity`). Below this the",
24134
24135
  "permissionless breaker can trip. Risk-increasing orders, fills,",
24135
24136
  "withdrawals and deposit transfers must clear `equity_floor +",
24136
24137
  "equity_floor_buffer`. Settable only by the warm/cold admin; 0 disables",
@@ -65,6 +65,8 @@ export * from './events/parse';
65
65
  export * from './events/pollingLogProvider';
66
66
  export * from './jupiter/jupiterClient';
67
67
  export * from './swap/UnifiedSwapClient';
68
+ export * from './swap/types';
69
+ export * from './swap/routeInstructions';
68
70
  export * from './math/auction';
69
71
  export * from './math/builder';
70
72
  export * from './math/spotMarket';
@@ -96,6 +96,9 @@ __exportStar(require("./events/pollingLogProvider"), exports);
96
96
  __exportStar(require("./jupiter/jupiterClient"), exports);
97
97
  // Primary swap client interface - use this for all swap operations
98
98
  __exportStar(require("./swap/UnifiedSwapClient"), exports);
99
+ // The SwapProvider contract both providers implement, and the shared route filter
100
+ __exportStar(require("./swap/types"), exports);
101
+ __exportStar(require("./swap/routeInstructions"), exports);
99
102
  __exportStar(require("./math/auction"), exports);
100
103
  __exportStar(require("./math/builder"), exports);
101
104
  __exportStar(require("./math/spotMarket"), exports);
@@ -1,6 +1,5 @@
1
1
  import { AddressLookupTableAccount, Connection, PublicKey, TransactionInstruction, TransactionMessage, VersionedTransaction } from '@solana/web3.js';
2
- import { BN } from '../isomorphic/anchor';
3
- import { SwapMode } from '../swap/UnifiedSwapClient';
2
+ import { GetRouteInstructionsParams, SwapMode, SwapProvider, SwapQuote, SwapQuoteParams, SwapRouteInstructions } from '../swap/types';
4
3
  export interface MarketInfo {
5
4
  id: string;
6
5
  inAmount: number;
@@ -207,14 +206,17 @@ export interface QuoteResponse {
207
206
  */
208
207
  errorCode?: string;
209
208
  }
209
+ /** A Jupiter quote plus the payload {@link JupiterClient.getRouteInstructions} needs. */
210
+ export type JupiterSwapQuote = QuoteResponse & SwapQuote;
210
211
  export declare const RECOMMENDED_JUPITER_API_VERSION = "/v1";
211
212
  /** @deprecated Use RECOMMENDED_JUPITER_API instead. lite-api.jup.ag requires migration to api.jup.ag with API key. */
212
213
  export declare const LEGACY_JUPITER_API = "https://lite-api.jup.ag/swap";
213
214
  export declare const RECOMMENDED_JUPITER_API = "https://api.jup.ag/swap";
214
- export declare class JupiterClient {
215
+ export declare class JupiterClient implements SwapProvider {
216
+ readonly providerName: "jupiter";
215
217
  url: string;
216
218
  connection: Connection;
217
- lookupTableCahce: Map<string, AddressLookupTableAccount>;
219
+ lookupTableCache: Map<string, AddressLookupTableAccount>;
218
220
  private apiKey?;
219
221
  /**
220
222
  * Create a Jupiter client
@@ -240,31 +242,34 @@ export declare class JupiterClient {
240
242
  * @param swapMode the swap mode (ExactIn or ExactOut)
241
243
  * @param onlyDirectRoutes whether to only return direct routes
242
244
  */
243
- getQuote({ inputMint, outputMint, amount, maxAccounts, // 50 is an estimated amount with buffer
244
- slippageBps, swapMode, onlyDirectRoutes, excludeDexes, autoSlippage, maxAutoSlippageBps, usdEstimate, }: {
245
- inputMint: PublicKey;
246
- outputMint: PublicKey;
247
- amount: BN;
248
- maxAccounts?: number;
249
- slippageBps?: number;
250
- swapMode?: SwapMode;
251
- onlyDirectRoutes?: boolean;
252
- excludeDexes?: string[];
253
- autoSlippage?: boolean;
254
- maxAutoSlippageBps?: number;
255
- usdEstimate?: number;
256
- }): Promise<QuoteResponse>;
245
+ getQuote({ inputMint, outputMint, amount, maxAccounts, slippageBps, swapMode, onlyDirectRoutes, excludeDexes, autoSlippage, maxAutoSlippageBps, usdEstimate, }: SwapQuoteParams): Promise<JupiterSwapQuote>;
257
246
  /**
258
247
  * Get a swap transaction for quote
259
- * @param quoteResponse quote to perform swap
248
+ * @param quote quote to perform swap, from {@link getQuote}
260
249
  * @param userPublicKey the signer's wallet public key
261
- * @param slippageBps the slippage tolerance in basis points
250
+ *
251
+ * Always builds at the quote's own slippage — the price the caller was
252
+ * shown. Re-quote to change it rather than overriding it here.
262
253
  */
263
- getSwap({ quote, userPublicKey, slippageBps, }: {
264
- quote: QuoteResponse;
254
+ getSwap({ quote, userPublicKey, }: {
255
+ quote: QuoteResponse | JupiterSwapQuote;
265
256
  userPublicKey: PublicKey;
266
- slippageBps?: number;
267
257
  }): Promise<VersionedTransaction>;
258
+ /**
259
+ * The standalone transaction Jupiter's `/swap` endpoint returns, setup and
260
+ * teardown included.
261
+ * @throws If the quote came from a different provider or a different wallet.
262
+ */
263
+ getSwapTransaction({ quote, userPublicKey, }: GetRouteInstructionsParams): Promise<VersionedTransaction>;
264
+ /**
265
+ * Builds the route instructions for a quote returned by {@link getQuote}.
266
+ *
267
+ * The quote carries its own route payload, so this reads no client state
268
+ * and two quotes in flight can never be confused for one another. The swap
269
+ * is built at the slippage the quote was priced at — re-quote to change it.
270
+ * @throws If the quote came from a different provider or a different wallet.
271
+ */
272
+ getRouteInstructions({ quote, userPublicKey, }: GetRouteInstructionsParams): Promise<SwapRouteInstructions>;
268
273
  /**
269
274
  * Get the transaction message and lookup tables for a transaction
270
275
  * @param transaction
@@ -277,10 +282,9 @@ export declare class JupiterClient {
277
282
  }>;
278
283
  getLookupTable(accountKey: PublicKey): Promise<AddressLookupTableAccount | undefined>;
279
284
  /**
280
- * Get the jupiter instructions from transaction by filtering out instructions to compute budget and associated token programs
281
- * @param transactionMessage the transaction message
282
- * @param inputMint the input mint
283
- * @param outputMint the output mint
285
+ * Strips the setup/teardown Jupiter wraps around its route.
286
+ * @deprecated Use {@link getRouteInstructions}, which quotes and filters in
287
+ * one step. Kept for callers holding a decompiled message of their own.
284
288
  */
285
289
  getJupiterInstructions({ transactionMessage, inputMint, outputMint, }: {
286
290
  transactionMessage: TransactionMessage;
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.JupiterClient = exports.RECOMMENDED_JUPITER_API = exports.LEGACY_JUPITER_API = exports.RECOMMENDED_JUPITER_API_VERSION = void 0;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
8
  const node_fetch_1 = __importDefault(require("node-fetch"));
9
+ const routeInstructions_1 = require("../swap/routeInstructions");
10
+ const types_1 = require("../swap/types");
9
11
  exports.RECOMMENDED_JUPITER_API_VERSION = '/v1';
10
12
  /** @deprecated Use RECOMMENDED_JUPITER_API instead. lite-api.jup.ag requires migration to api.jup.ag with API key. */
11
13
  exports.LEGACY_JUPITER_API = 'https://lite-api.jup.ag/swap';
@@ -18,7 +20,8 @@ class JupiterClient {
18
20
  * @param apiKey - API key for Jupiter API. Required for api.jup.ag (free tier available at https://portal.jup.ag)
19
21
  */
20
22
  constructor({ connection, url, apiKey, }) {
21
- this.lookupTableCahce = new Map();
23
+ this.providerName = 'jupiter';
24
+ this.lookupTableCache = new Map();
22
25
  this.connection = connection;
23
26
  this.url = url !== null && url !== void 0 ? url : exports.RECOMMENDED_JUPITER_API;
24
27
  this.apiKey = apiKey;
@@ -45,8 +48,7 @@ class JupiterClient {
45
48
  * @param swapMode the swap mode (ExactIn or ExactOut)
46
49
  * @param onlyDirectRoutes whether to only return direct routes
47
50
  */
48
- async getQuote({ inputMint, outputMint, amount, maxAccounts = 50, // 50 is an estimated amount with buffer
49
- slippageBps = 50, swapMode = 'ExactIn', onlyDirectRoutes = false, excludeDexes, autoSlippage = false, maxAutoSlippageBps, usdEstimate, }) {
51
+ async getQuote({ inputMint, outputMint, amount, maxAccounts = types_1.DEFAULT_SWAP_MAX_ACCOUNTS, slippageBps = 50, swapMode = 'ExactIn', onlyDirectRoutes = false, excludeDexes, autoSlippage = false, maxAutoSlippageBps, usdEstimate, }) {
50
52
  var _a;
51
53
  if (autoSlippage && maxAutoSlippageBps === undefined) {
52
54
  throw new Error('JupiterClient.getQuote: maxAutoSlippageBps is required when autoSlippage is enabled');
@@ -94,19 +96,25 @@ class JupiterClient {
94
96
  if (!quote.inputMint || !quote.outputMint || !quote.outAmount) {
95
97
  throw new Error('Jupiter quote failed: response is missing route fields');
96
98
  }
97
- return quote;
99
+ // Jupiter's /swap endpoint takes the quote body back verbatim, so the
100
+ // quote is its own route payload.
101
+ return (0, types_1.buildSwapQuote)(quote, { provider: 'jupiter', quote });
98
102
  }
99
103
  /**
100
104
  * Get a swap transaction for quote
101
- * @param quoteResponse quote to perform swap
105
+ * @param quote quote to perform swap, from {@link getQuote}
102
106
  * @param userPublicKey the signer's wallet public key
103
- * @param slippageBps the slippage tolerance in basis points
107
+ *
108
+ * Always builds at the quote's own slippage — the price the caller was
109
+ * shown. Re-quote to change it rather than overriding it here.
104
110
  */
105
- async getSwap({ quote, userPublicKey, slippageBps = 50, }) {
111
+ async getSwap({ quote, userPublicKey, }) {
106
112
  var _a;
107
113
  if (!quote) {
108
114
  throw new Error('Jupiter swap quote not provided. Please try again.');
109
115
  }
116
+ // `providerRoute` is our own wrapper, not part of Jupiter's quote body.
117
+ const { providerRoute: _providerRoute, ...quoteResponse } = quote;
110
118
  const apiVersionParam = this.url === exports.RECOMMENDED_JUPITER_API || this.url === exports.LEGACY_JUPITER_API
111
119
  ? exports.RECOMMENDED_JUPITER_API_VERSION
112
120
  : '';
@@ -114,9 +122,9 @@ class JupiterClient {
114
122
  method: 'POST',
115
123
  headers: this.getHeaders('application/json'),
116
124
  body: JSON.stringify({
117
- quoteResponse: quote,
125
+ quoteResponse,
118
126
  userPublicKey,
119
- slippageBps,
127
+ slippageBps: quoteResponse.slippageBps,
120
128
  }),
121
129
  })).json();
122
130
  if (!('swapTransaction' in resp)) {
@@ -131,6 +139,41 @@ class JupiterClient {
131
139
  throw new Error('Something went wrong with creating the Jupiter swap transaction. Please try again.');
132
140
  }
133
141
  }
142
+ /**
143
+ * The standalone transaction Jupiter's `/swap` endpoint returns, setup and
144
+ * teardown included.
145
+ * @throws If the quote came from a different provider or a different wallet.
146
+ */
147
+ async getSwapTransaction({ quote, userPublicKey, }) {
148
+ const jupiterQuote = (0, types_1.expectProviderRoute)(quote, 'jupiter', userPublicKey)
149
+ .quote;
150
+ return this.getSwap({ quote: jupiterQuote, userPublicKey });
151
+ }
152
+ /**
153
+ * Builds the route instructions for a quote returned by {@link getQuote}.
154
+ *
155
+ * The quote carries its own route payload, so this reads no client state
156
+ * and two quotes in flight can never be confused for one another. The swap
157
+ * is built at the slippage the quote was priced at — re-quote to change it.
158
+ * @throws If the quote came from a different provider or a different wallet.
159
+ */
160
+ async getRouteInstructions({ quote, userPublicKey, }) {
161
+ const jupiterQuote = (0, types_1.expectProviderRoute)(quote, 'jupiter', userPublicKey)
162
+ .quote;
163
+ const transaction = await this.getSwap({
164
+ quote: jupiterQuote,
165
+ userPublicKey,
166
+ });
167
+ const { transactionMessage, lookupTables } = await this.getTransactionMessageAndLookupTables({ transaction });
168
+ return {
169
+ instructions: (0, routeInstructions_1.filterRouteInstructions)({
170
+ instructions: transactionMessage.instructions,
171
+ inputMint: new web3_js_1.PublicKey(quote.inputMint),
172
+ outputMint: new web3_js_1.PublicKey(quote.outputMint),
173
+ }),
174
+ lookupTables,
175
+ };
176
+ }
134
177
  /**
135
178
  * Get the transaction message and lookup tables for a transaction
136
179
  * @param transaction
@@ -149,7 +192,7 @@ class JupiterClient {
149
192
  };
150
193
  }
151
194
  async getLookupTable(accountKey) {
152
- const cached = this.lookupTableCahce.get(accountKey.toString());
195
+ const cached = this.lookupTableCache.get(accountKey.toString());
153
196
  if (cached !== undefined) {
154
197
  return cached;
155
198
  }
@@ -159,36 +202,19 @@ class JupiterClient {
159
202
  }
160
203
  // Populate the cache — without this every route re-fetches the same tables,
161
204
  // which is a large share of the RPC calls a swap makes.
162
- this.lookupTableCahce.set(accountKey.toString(), lookupTable);
205
+ this.lookupTableCache.set(accountKey.toString(), lookupTable);
163
206
  return lookupTable;
164
207
  }
165
208
  /**
166
- * Get the jupiter instructions from transaction by filtering out instructions to compute budget and associated token programs
167
- * @param transactionMessage the transaction message
168
- * @param inputMint the input mint
169
- * @param outputMint the output mint
209
+ * Strips the setup/teardown Jupiter wraps around its route.
210
+ * @deprecated Use {@link getRouteInstructions}, which quotes and filters in
211
+ * one step. Kept for callers holding a decompiled message of their own.
170
212
  */
171
213
  getJupiterInstructions({ transactionMessage, inputMint, outputMint, }) {
172
- return transactionMessage.instructions.filter((instruction) => {
173
- if (instruction.programId.toString() ===
174
- 'ComputeBudget111111111111111111111111111111') {
175
- return false;
176
- }
177
- if (instruction.programId.toString() ===
178
- 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA') {
179
- return false;
180
- }
181
- if (instruction.programId.toString() === '11111111111111111111111111111111') {
182
- return false;
183
- }
184
- if (instruction.programId.toString() ===
185
- 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL') {
186
- const mint = instruction.keys[3].pubkey;
187
- if (mint.equals(inputMint) || mint.equals(outputMint)) {
188
- return false;
189
- }
190
- }
191
- return true;
214
+ return (0, routeInstructions_1.filterRouteInstructions)({
215
+ instructions: transactionMessage.instructions,
216
+ inputMint,
217
+ outputMint,
192
218
  });
193
219
  }
194
220
  }
@@ -104,13 +104,14 @@ export declare function calculateCollateralDepositRequiredForTrade(velocityClien
104
104
  * Minimal equity floor to carry along with a quote transfer of `amount` out
105
105
  * of a subaccount so the debited side ends at/above its buffered floor
106
106
  * (`equityFloor + equityFloorBuffer`): the first
107
- * `totalCollateral - (floor + buffer)` of the transfer carries no floor, the
107
+ * `netEquity - (floor + buffer)` of the transfer carries no floor, the
108
108
  * remainder carries floor one-for-one, capped at the floor the subaccount
109
- * actually holds. Returns zero when no floor is set. The result never exceeds
110
- * `amount`, so a credited side that met its own buffered floor before the
111
- * transfer still meets it after. All values QUOTE_PRECISION.
109
+ * actually holds. `netEquity` is `User.getNetUsdValue()`, the metric the
110
+ * onchain floor checks use. Returns zero when no floor is set. The result
111
+ * never exceeds `amount`, so a credited side that met its own buffered floor
112
+ * before the transfer still meets it after. All values QUOTE_PRECISION.
112
113
  */
113
- export declare function calculateEquityFloorAutoDelta(amount: BN, totalCollateral: BN, equityFloor: BN, equityFloorBuffer: BN): BN;
114
+ export declare function calculateEquityFloorAutoDelta(amount: BN, netEquity: BN, equityFloor: BN, equityFloorBuffer: BN): BN;
114
115
  /**
115
116
  * Severity of a subaccount's equity relative to its floor, most to least
116
117
  * severe. `breached`: below the floor, the permissionless breaker can trip.
@@ -120,9 +121,10 @@ export declare function calculateEquityFloorAutoDelta(amount: BN, totalCollatera
120
121
  */
121
122
  export type EquityFloorLevel = 'breached' | 'critical' | 'warning' | 'healthy' | 'disabled';
122
123
  /**
123
- * Classifies `totalCollateral` against the floor thresholds. Used by the
124
- * `EquityFloorManager` and the equity-floor guard bot so both report the same
125
- * levels. `warningBufferMultiple` scales the warning threshold above the
126
- * floor (default 2: warn inside `floor + 2 * buffer`). All QUOTE_PRECISION.
124
+ * Classifies `netEquity` (`User.getNetUsdValue()`) against the floor
125
+ * thresholds. Used by the `EquityFloorManager` and the equity-floor guard bot
126
+ * so both report the same levels. `warningBufferMultiple` scales the warning
127
+ * threshold above the floor (default 2: warn inside `floor + 2 * buffer`).
128
+ * All QUOTE_PRECISION.
127
129
  */
128
- export declare function getEquityFloorLevel(totalCollateral: BN, equityFloor: BN, equityFloorBuffer: BN, warningBufferMultiple?: number): EquityFloorLevel;
130
+ export declare function getEquityFloorLevel(netEquity: BN, equityFloor: BN, equityFloorBuffer: BN, warningBufferMultiple?: number): EquityFloorLevel;
@@ -214,37 +214,39 @@ exports.calculateCollateralDepositRequiredForTrade = calculateCollateralDepositR
214
214
  * Minimal equity floor to carry along with a quote transfer of `amount` out
215
215
  * of a subaccount so the debited side ends at/above its buffered floor
216
216
  * (`equityFloor + equityFloorBuffer`): the first
217
- * `totalCollateral - (floor + buffer)` of the transfer carries no floor, the
217
+ * `netEquity - (floor + buffer)` of the transfer carries no floor, the
218
218
  * remainder carries floor one-for-one, capped at the floor the subaccount
219
- * actually holds. Returns zero when no floor is set. The result never exceeds
220
- * `amount`, so a credited side that met its own buffered floor before the
221
- * transfer still meets it after. All values QUOTE_PRECISION.
219
+ * actually holds. `netEquity` is `User.getNetUsdValue()`, the metric the
220
+ * onchain floor checks use. Returns zero when no floor is set. The result
221
+ * never exceeds `amount`, so a credited side that met its own buffered floor
222
+ * before the transfer still meets it after. All values QUOTE_PRECISION.
222
223
  */
223
- function calculateEquityFloorAutoDelta(amount, totalCollateral, equityFloor, equityFloorBuffer) {
224
+ function calculateEquityFloorAutoDelta(amount, netEquity, equityFloor, equityFloorBuffer) {
224
225
  if (equityFloor.lte(numericConstants_1.ZERO)) {
225
226
  return numericConstants_1.ZERO;
226
227
  }
227
- const excess = anchor_1.BN.max(totalCollateral.sub(equityFloor.add(equityFloorBuffer)), numericConstants_1.ZERO);
228
+ const excess = anchor_1.BN.max(netEquity.sub(equityFloor.add(equityFloorBuffer)), numericConstants_1.ZERO);
228
229
  return anchor_1.BN.min(anchor_1.BN.max(amount.sub(excess), numericConstants_1.ZERO), equityFloor);
229
230
  }
230
231
  exports.calculateEquityFloorAutoDelta = calculateEquityFloorAutoDelta;
231
232
  /**
232
- * Classifies `totalCollateral` against the floor thresholds. Used by the
233
- * `EquityFloorManager` and the equity-floor guard bot so both report the same
234
- * levels. `warningBufferMultiple` scales the warning threshold above the
235
- * floor (default 2: warn inside `floor + 2 * buffer`). All QUOTE_PRECISION.
233
+ * Classifies `netEquity` (`User.getNetUsdValue()`) against the floor
234
+ * thresholds. Used by the `EquityFloorManager` and the equity-floor guard bot
235
+ * so both report the same levels. `warningBufferMultiple` scales the warning
236
+ * threshold above the floor (default 2: warn inside `floor + 2 * buffer`).
237
+ * All QUOTE_PRECISION.
236
238
  */
237
- function getEquityFloorLevel(totalCollateral, equityFloor, equityFloorBuffer, warningBufferMultiple = 2) {
239
+ function getEquityFloorLevel(netEquity, equityFloor, equityFloorBuffer, warningBufferMultiple = 2) {
238
240
  if (equityFloor.lte(numericConstants_1.ZERO)) {
239
241
  return 'disabled';
240
242
  }
241
- if (totalCollateral.lt(equityFloor)) {
243
+ if (netEquity.lt(equityFloor)) {
242
244
  return 'breached';
243
245
  }
244
- if (totalCollateral.lt(equityFloor.add(equityFloorBuffer))) {
246
+ if (netEquity.lt(equityFloor.add(equityFloorBuffer))) {
245
247
  return 'critical';
246
248
  }
247
- if (totalCollateral.lt(equityFloor.add(equityFloorBuffer.muln(warningBufferMultiple)))) {
249
+ if (netEquity.lt(equityFloor.add(equityFloorBuffer.muln(warningBufferMultiple)))) {
248
250
  return 'warning';
249
251
  }
250
252
  return 'healthy';
@@ -1,5 +1,5 @@
1
1
  import { AddressLookupTableAccount, PublicKey, TransactionInstruction } from '@solana/web3.js';
2
- import { JupiterClient, QuoteResponse } from '../jupiter/jupiterClient';
2
+ import { JupiterClient, JupiterSwapQuote } from '../jupiter/jupiterClient';
3
3
  import { VelocityClient } from '../velocityClient';
4
4
  import { BN } from '../isomorphic/anchor';
5
5
  import { User } from '../user';
@@ -61,7 +61,7 @@ export declare function fetchBSolVelocityEmissions(): Promise<fetch.Response>;
61
61
  * @param {boolean} [params.forceMarinade] - Force the direct Marinade stake path over a Jupiter
62
62
  * swap even if Jupiter would be cheaper (market index 2 only)
63
63
  * @param {boolean} [params.onlyDirectRoutes] - Restrict Jupiter routing to direct swaps only
64
- * @param {QuoteResponse} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse instead of
64
+ * @param {JupiterSwapQuote} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse instead of
65
65
  * fetching a fresh one
66
66
  * @return {Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[];
67
67
  * method: 'jupiter' | 'marinade'; price?: number }>} The instructions to submit, any address
@@ -78,7 +78,7 @@ export declare function findBestSuperStakeIxs({ marketIndex, amount, jupiterClie
78
78
  userAccountPublicKey?: PublicKey;
79
79
  forceMarinade?: boolean;
80
80
  onlyDirectRoutes?: boolean;
81
- jupiterQuote?: QuoteResponse;
81
+ jupiterQuote?: JupiterSwapQuote;
82
82
  }): Promise<{
83
83
  ixs: TransactionInstruction[];
84
84
  lookupTables: AddressLookupTableAccount[];
@@ -100,7 +100,7 @@ export declare function findBestSuperStakeIxs({ marketIndex, amount, jupiterClie
100
100
  * @param {PublicKey} [params.userAccountPublicKey] - The target sub-account
101
101
  * @param {boolean} [params.forceMarinade] - Force the Marinade path regardless of Jupiter pricing
102
102
  * @param {boolean} [params.onlyDirectRoutes] - Restrict Jupiter routing to direct swaps only
103
- * @param {QuoteResponse} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
103
+ * @param {JupiterSwapQuote} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
104
104
  * @return {Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[];
105
105
  * method: 'jupiter' | 'marinade'; price: number }>} The chosen route's instructions, required
106
106
  * lookup tables, the method used, and the mSOL/SOL price used for the decision
@@ -113,7 +113,7 @@ export declare function findBestMSolSuperStakeIxs({ amount, jupiterClient, veloc
113
113
  userAccountPublicKey?: PublicKey;
114
114
  forceMarinade?: boolean;
115
115
  onlyDirectRoutes?: boolean;
116
- jupiterQuote?: QuoteResponse;
116
+ jupiterQuote?: JupiterSwapQuote;
117
117
  }): Promise<{
118
118
  ixs: TransactionInstruction[];
119
119
  lookupTables: AddressLookupTableAccount[];
@@ -130,7 +130,7 @@ export declare function findBestMSolSuperStakeIxs({ amount, jupiterClient, veloc
130
130
  * @param {VelocityClient} params.velocityClient - Velocity client
131
131
  * @param {PublicKey} [params.userAccountPublicKey] - The target sub-account
132
132
  * @param {boolean} [params.onlyDirectRoutes] - Restrict Jupiter routing to direct swaps only
133
- * @param {QuoteResponse} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
133
+ * @param {JupiterSwapQuote} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
134
134
  * @return {Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[];
135
135
  * method: 'jupiter' | 'marinade'; price?: number }>} Always resolves with `method: 'jupiter'`
136
136
  */
@@ -140,7 +140,7 @@ export declare function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, ve
140
140
  velocityClient: VelocityClient;
141
141
  userAccountPublicKey?: PublicKey;
142
142
  onlyDirectRoutes?: boolean;
143
- jupiterQuote?: QuoteResponse;
143
+ jupiterQuote?: JupiterSwapQuote;
144
144
  }): Promise<{
145
145
  ixs: TransactionInstruction[];
146
146
  lookupTables: AddressLookupTableAccount[];
@@ -161,7 +161,7 @@ export declare function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, ve
161
161
  * @param {VelocityClient} params.velocityClient - Velocity client
162
162
  * @param {PublicKey} [params.userAccountPublicKey] - The target sub-account
163
163
  * @param {boolean} [params.onlyDirectRoutes] - Restrict Jupiter routing to direct swaps only
164
- * @param {QuoteResponse} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
164
+ * @param {JupiterSwapQuote} [params.jupiterQuote] - A pre-fetched Jupiter quote to reuse
165
165
  * @return {Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[];
166
166
  * method: 'jupiter' | 'marinade' }>} Always resolves with `method: 'jupiter'`
167
167
  */
@@ -173,7 +173,7 @@ export declare function findBestLstSuperStakeIxs({ amount, jupiterClient, veloci
173
173
  velocityClient: VelocityClient;
174
174
  userAccountPublicKey?: PublicKey;
175
175
  onlyDirectRoutes?: boolean;
176
- jupiterQuote?: QuoteResponse;
176
+ jupiterQuote?: JupiterSwapQuote;
177
177
  }): Promise<{
178
178
  ixs: TransactionInstruction[];
179
179
  lookupTables: AddressLookupTableAccount[];