@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.
- package/lib/browser/adminClient.d.ts +2 -2
- package/lib/browser/adminClient.js +3 -11
- package/lib/browser/equityFloorManager.d.ts +9 -5
- package/lib/browser/equityFloorManager.js +9 -5
- package/lib/browser/idl/velocity.d.ts +2 -1
- package/lib/browser/idl/velocity.json +2 -1
- package/lib/browser/index.d.ts +2 -0
- package/lib/browser/index.js +3 -0
- package/lib/browser/jupiter/jupiterClient.d.ts +31 -27
- package/lib/browser/jupiter/jupiterClient.js +61 -35
- package/lib/browser/math/margin.d.ts +12 -10
- package/lib/browser/math/margin.js +16 -14
- package/lib/browser/math/superStake.d.ts +9 -9
- package/lib/browser/math/superStake.js +8 -8
- package/lib/browser/swap/UnifiedSwapClient.d.ts +38 -76
- package/lib/browser/swap/UnifiedSwapClient.js +46 -117
- package/lib/browser/swap/routeInstructions.d.ts +19 -0
- package/lib/browser/swap/routeInstructions.js +43 -0
- package/lib/browser/swap/types.d.ts +196 -0
- package/lib/browser/swap/types.js +88 -0
- package/lib/browser/titan/titanClient.d.ts +32 -68
- package/lib/browser/titan/titanClient.js +128 -102
- package/lib/browser/user.d.ts +16 -18
- package/lib/browser/user.js +24 -26
- package/lib/browser/velocityClient.d.ts +83 -101
- package/lib/browser/velocityClient.js +152 -289
- package/lib/node/adminClient.d.ts +2 -2
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +3 -11
- package/lib/node/equityFloorManager.d.ts +9 -5
- package/lib/node/equityFloorManager.d.ts.map +1 -1
- package/lib/node/equityFloorManager.js +9 -5
- package/lib/node/idl/velocity.d.ts +2 -1
- package/lib/node/idl/velocity.d.ts.map +1 -1
- package/lib/node/idl/velocity.json +2 -1
- package/lib/node/index.d.ts +2 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +3 -0
- package/lib/node/jupiter/jupiterClient.d.ts +31 -27
- package/lib/node/jupiter/jupiterClient.d.ts.map +1 -1
- package/lib/node/jupiter/jupiterClient.js +61 -35
- package/lib/node/math/margin.d.ts +12 -10
- package/lib/node/math/margin.d.ts.map +1 -1
- package/lib/node/math/margin.js +16 -14
- package/lib/node/math/superStake.d.ts +9 -9
- package/lib/node/math/superStake.d.ts.map +1 -1
- package/lib/node/math/superStake.js +8 -8
- package/lib/node/swap/UnifiedSwapClient.d.ts +38 -76
- package/lib/node/swap/UnifiedSwapClient.d.ts.map +1 -1
- package/lib/node/swap/UnifiedSwapClient.js +46 -117
- package/lib/node/swap/routeInstructions.d.ts +20 -0
- package/lib/node/swap/routeInstructions.d.ts.map +1 -0
- package/lib/node/swap/routeInstructions.js +43 -0
- package/lib/node/swap/types.d.ts +197 -0
- package/lib/node/swap/types.d.ts.map +1 -0
- package/lib/node/swap/types.js +88 -0
- package/lib/node/titan/titanClient.d.ts +32 -68
- package/lib/node/titan/titanClient.d.ts.map +1 -1
- package/lib/node/titan/titanClient.js +128 -102
- package/lib/node/user.d.ts +16 -18
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +24 -26
- package/lib/node/velocityClient.d.ts +83 -101
- package/lib/node/velocityClient.d.ts.map +1 -1
- package/lib/node/velocityClient.js +152 -289
- 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,
|
|
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?:
|
|
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
|
|
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,
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
127
|
-
*
|
|
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.
|
|
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
|
|
216
|
-
*
|
|
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.
|
|
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 (
|
|
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 (
|
|
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",
|
package/lib/browser/index.d.ts
CHANGED
|
@@ -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';
|
package/lib/browser/index.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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,
|
|
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
|
|
248
|
+
* @param quote quote to perform swap, from {@link getQuote}
|
|
260
249
|
* @param userPublicKey the signer's wallet public key
|
|
261
|
-
*
|
|
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,
|
|
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
|
-
*
|
|
281
|
-
* @
|
|
282
|
-
*
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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
|
|
105
|
+
* @param quote quote to perform swap, from {@link getQuote}
|
|
102
106
|
* @param userPublicKey the signer's wallet public key
|
|
103
|
-
*
|
|
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,
|
|
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
|
|
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.
|
|
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.
|
|
205
|
+
this.lookupTableCache.set(accountKey.toString(), lookupTable);
|
|
163
206
|
return lookupTable;
|
|
164
207
|
}
|
|
165
208
|
/**
|
|
166
|
-
*
|
|
167
|
-
* @
|
|
168
|
-
*
|
|
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
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
* `
|
|
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.
|
|
110
|
-
*
|
|
111
|
-
*
|
|
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,
|
|
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 `
|
|
124
|
-
* `EquityFloorManager` and the equity-floor guard bot
|
|
125
|
-
* levels. `warningBufferMultiple` scales the warning
|
|
126
|
-
* floor (default 2: warn inside `floor + 2 * buffer`).
|
|
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(
|
|
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
|
-
* `
|
|
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.
|
|
220
|
-
*
|
|
221
|
-
*
|
|
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,
|
|
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(
|
|
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 `
|
|
233
|
-
* `EquityFloorManager` and the equity-floor guard bot
|
|
234
|
-
* levels. `warningBufferMultiple` scales the warning
|
|
235
|
-
* floor (default 2: warn inside `floor + 2 * buffer`).
|
|
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(
|
|
239
|
+
function getEquityFloorLevel(netEquity, equityFloor, equityFloorBuffer, warningBufferMultiple = 2) {
|
|
238
240
|
if (equityFloor.lte(numericConstants_1.ZERO)) {
|
|
239
241
|
return 'disabled';
|
|
240
242
|
}
|
|
241
|
-
if (
|
|
243
|
+
if (netEquity.lt(equityFloor)) {
|
|
242
244
|
return 'breached';
|
|
243
245
|
}
|
|
244
|
-
if (
|
|
246
|
+
if (netEquity.lt(equityFloor.add(equityFloorBuffer))) {
|
|
245
247
|
return 'critical';
|
|
246
248
|
}
|
|
247
|
-
if (
|
|
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,
|
|
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 {
|
|
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?:
|
|
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 {
|
|
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?:
|
|
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 {
|
|
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?:
|
|
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 {
|
|
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?:
|
|
176
|
+
jupiterQuote?: JupiterSwapQuote;
|
|
177
177
|
}): Promise<{
|
|
178
178
|
ixs: TransactionInstruction[];
|
|
179
179
|
lookupTables: AddressLookupTableAccount[];
|