@velocity-exchange/sdk 0.8.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 +13 -10
- package/lib/browser/adminClient.js +16 -21
- package/lib/browser/decode/user.js +3 -1
- package/lib/browser/equityFloorManager.d.ts +154 -0
- package/lib/browser/equityFloorManager.js +283 -0
- package/lib/browser/idl/velocity.d.ts +85 -10
- package/lib/browser/idl/velocity.json +85 -10
- package/lib/browser/index.d.ts +4 -0
- package/lib/browser/index.js +5 -0
- package/lib/browser/jupiter/jupiterClient.d.ts +31 -27
- package/lib/browser/jupiter/jupiterClient.js +84 -37
- package/lib/browser/math/margin.d.ts +28 -0
- package/lib/browser/math/margin.js +43 -1
- 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 +53 -110
- 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 +37 -67
- package/lib/browser/titan/titanClient.js +160 -103
- package/lib/browser/types.d.ts +6 -2
- package/lib/browser/types.js +2 -0
- package/lib/browser/user.d.ts +43 -18
- package/lib/browser/user.js +94 -45
- package/lib/browser/velocityClient.d.ts +86 -103
- package/lib/browser/velocityClient.js +157 -298
- package/lib/node/adminClient.d.ts +13 -10
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +16 -21
- package/lib/node/decode/user.d.ts.map +1 -1
- package/lib/node/decode/user.js +3 -1
- package/lib/node/equityFloorManager.d.ts +155 -0
- package/lib/node/equityFloorManager.d.ts.map +1 -0
- package/lib/node/equityFloorManager.js +283 -0
- package/lib/node/idl/velocity.d.ts +85 -10
- package/lib/node/idl/velocity.d.ts.map +1 -1
- package/lib/node/idl/velocity.json +85 -10
- package/lib/node/index.d.ts +4 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +5 -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 +84 -37
- package/lib/node/math/margin.d.ts +28 -0
- package/lib/node/math/margin.d.ts.map +1 -1
- package/lib/node/math/margin.js +43 -1
- 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 +53 -110
- 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 +37 -67
- package/lib/node/titan/titanClient.d.ts.map +1 -1
- package/lib/node/titan/titanClient.js +160 -103
- package/lib/node/types.d.ts +6 -2
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/types.js +2 -0
- package/lib/node/user.d.ts +43 -18
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +94 -45
- package/lib/node/velocityClient.d.ts +86 -103
- package/lib/node/velocityClient.d.ts.map +1 -1
- package/lib/node/velocityClient.js +157 -298
- package/package.json +1 -1
|
@@ -3,14 +3,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TitanClient = exports.SwapMode = void 0;
|
|
4
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
5
5
|
const msgpack_1 = require("@msgpack/msgpack");
|
|
6
|
+
const routeInstructions_1 = require("../swap/routeInstructions");
|
|
7
|
+
const types_1 = require("../swap/types");
|
|
6
8
|
var SwapMode;
|
|
7
9
|
(function (SwapMode) {
|
|
8
10
|
SwapMode["ExactIn"] = "ExactIn";
|
|
9
11
|
SwapMode["ExactOut"] = "ExactOut";
|
|
10
12
|
})(SwapMode || (exports.SwapMode = SwapMode = {}));
|
|
11
13
|
const TITAN_API_URL = 'https://api.titan.exchange';
|
|
14
|
+
/** Retries for a route's lookup tables, which must all resolve for the tx to fit. */
|
|
15
|
+
const LOOKUP_TABLE_FETCH_RETRIES = 2;
|
|
16
|
+
const LOOKUP_TABLE_RETRY_BASE_DELAY_MS = 150;
|
|
17
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
/** Titan sends pubkeys as raw bytes. Absent fields decode to `undefined`. */
|
|
19
|
+
const decodePubkey = (bytes) => bytes ? new web3_js_1.PublicKey(bytes).toString() : undefined;
|
|
20
|
+
/**
|
|
21
|
+
* For the normalized quote's small metadata fields, which are typed `number`.
|
|
22
|
+
* Only safe because slots, durations and bps are far below 2^53 — never use it
|
|
23
|
+
* on a token amount.
|
|
24
|
+
*/
|
|
25
|
+
const toNumber = (value) => value === undefined ? undefined : Number(value);
|
|
12
26
|
class TitanClient {
|
|
13
27
|
constructor({ connection, authToken, url, proxyUrl, }) {
|
|
28
|
+
this.providerName = 'titan';
|
|
29
|
+
this.lookupTableCache = new Map();
|
|
14
30
|
this.connection = connection;
|
|
15
31
|
this.authToken = authToken;
|
|
16
32
|
this.url = url !== null && url !== void 0 ? url : TITAN_API_URL;
|
|
@@ -26,25 +42,41 @@ class TitanClient {
|
|
|
26
42
|
outputMint: outputMint.toString(),
|
|
27
43
|
amount: amount.toString(),
|
|
28
44
|
userPublicKey: userPublicKey.toString(),
|
|
29
|
-
...(slippageBps && { slippageBps: slippageBps.toString() }),
|
|
30
|
-
...(swapMode && { swapMode: normalizedSwapMode.toString() }),
|
|
31
|
-
...(maxAccounts && {
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
...(slippageBps != null && { slippageBps: slippageBps.toString() }),
|
|
46
|
+
...(swapMode != null && { swapMode: normalizedSwapMode.toString() }),
|
|
47
|
+
...(maxAccounts != null && {
|
|
48
|
+
accountsLimitTotal: maxAccounts.toString(),
|
|
49
|
+
}),
|
|
50
|
+
...(excludeDexes != null && { excludeDexes: excludeDexes.join(',') }),
|
|
51
|
+
// Only sent when explicitly true — Titan treats the field's presence,
|
|
52
|
+
// not its value, as the toggle.
|
|
53
|
+
...(onlyDirectRoutes === true && {
|
|
34
54
|
onlyDirectRoutes: onlyDirectRoutes.toString(),
|
|
35
55
|
}),
|
|
36
|
-
...(sizeConstraint && {
|
|
37
|
-
|
|
56
|
+
...(sizeConstraint != null && {
|
|
57
|
+
sizeConstraint: sizeConstraint.toString(),
|
|
58
|
+
}),
|
|
59
|
+
...(accountsLimitWritable != null && {
|
|
38
60
|
accountsLimitWritable: accountsLimitWritable.toString(),
|
|
39
61
|
}),
|
|
40
62
|
});
|
|
41
63
|
}
|
|
42
64
|
/**
|
|
43
|
-
* Get
|
|
65
|
+
* Get the best available route for a swap.
|
|
66
|
+
*
|
|
67
|
+
* The route is returned on the quote's `providerRoute`, so
|
|
68
|
+
* {@link getRouteInstructions} builds exactly what was quoted here, at the
|
|
69
|
+
* slippage quoted here.
|
|
70
|
+
* @throws If `userPublicKey` is missing — Titan bakes the user's token
|
|
71
|
+
* accounts into the route, so a route quoted for one wallet cannot be
|
|
72
|
+
* executed by another. The wallet is recorded on the route and enforced
|
|
73
|
+
* when the route is built.
|
|
44
74
|
*/
|
|
45
|
-
async getQuote({ inputMint, outputMint, amount, userPublicKey, maxAccounts =
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
async getQuote({ inputMint, outputMint, amount, userPublicKey, maxAccounts = types_1.DEFAULT_SWAP_MAX_ACCOUNTS, slippageBps, swapMode, onlyDirectRoutes, excludeDexes, sizeConstraint, accountsLimitWritable, }) {
|
|
76
|
+
var _a, _b, _c, _d, _e;
|
|
77
|
+
if (!userPublicKey) {
|
|
78
|
+
throw new Error('Titan quotes require a userPublicKey.');
|
|
79
|
+
}
|
|
48
80
|
const params = this.buildParams({
|
|
49
81
|
inputMint,
|
|
50
82
|
outputMint,
|
|
@@ -83,29 +115,43 @@ class TitanClient {
|
|
|
83
115
|
throw new Error(`Titan API error: ${response.status} ${response.statusText}`);
|
|
84
116
|
}
|
|
85
117
|
const buffer = await response.arrayBuffer();
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
this.lastQuoteParams = params.toString();
|
|
118
|
+
// `useBigInt64` or every u64 above 2^53 is silently rounded on the way in,
|
|
119
|
+
// including the `inAmount` callers size `beginSwap` off.
|
|
120
|
+
const data = (0, msgpack_1.decode)(buffer, { useBigInt64: true });
|
|
90
121
|
// We are only querying for the best avaiable route so use that
|
|
91
122
|
const route = data.quotes[Object.keys(data.quotes)[0]];
|
|
92
123
|
if (!route) {
|
|
93
124
|
throw new Error('No routes available');
|
|
94
125
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
126
|
+
if (!((_a = route.instructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
127
|
+
throw new Error('Titan route has no instructions');
|
|
128
|
+
}
|
|
129
|
+
// Titan echoes the pair it routed. Take the pair from the response rather
|
|
130
|
+
// than assuming the request was honoured — a route for another pair pays
|
|
131
|
+
// out into a token account `endSwap` isn't watching, and only fails
|
|
132
|
+
// on-chain once the funds have already moved.
|
|
133
|
+
const routedInputMint = (_b = decodePubkey(data.inputMint)) !== null && _b !== void 0 ? _b : inputMint.toString();
|
|
134
|
+
const routedOutputMint = (_c = decodePubkey(data.outputMint)) !== null && _c !== void 0 ? _c : outputMint.toString();
|
|
135
|
+
if (routedInputMint !== inputMint.toString() ||
|
|
136
|
+
routedOutputMint !== outputMint.toString()) {
|
|
137
|
+
throw new Error(`Titan quoted ${routedInputMint} -> ${routedOutputMint} but the swap asked for ${inputMint.toString()} -> ${outputMint.toString()}.`);
|
|
138
|
+
}
|
|
139
|
+
return (0, types_1.buildSwapQuote)({
|
|
140
|
+
inputMint: routedInputMint,
|
|
141
|
+
outputMint: routedOutputMint,
|
|
142
|
+
// The route's own input, not the requested amount — under ExactOut the
|
|
143
|
+
// request is the output, and callers size `beginSwap` off `inAmount`.
|
|
144
|
+
inAmount: ((_d = route.inAmount) !== null && _d !== void 0 ? _d : amount).toString(),
|
|
99
145
|
outAmount: route.outAmount.toString(),
|
|
100
146
|
swapMode: data.swapMode,
|
|
101
|
-
slippageBps: route.slippageBps,
|
|
147
|
+
slippageBps: Number(route.slippageBps),
|
|
102
148
|
platformFee: route.platformFee
|
|
103
149
|
? {
|
|
104
150
|
amount: route.platformFee.amount.toString(),
|
|
105
|
-
feeBps: route.platformFee.fee_bps,
|
|
151
|
+
feeBps: Number(route.platformFee.fee_bps),
|
|
106
152
|
}
|
|
107
153
|
: undefined,
|
|
108
|
-
routePlan: ((
|
|
154
|
+
routePlan: ((_e = route.steps) === null || _e === void 0 ? void 0 : _e.map((step) => {
|
|
109
155
|
var _a;
|
|
110
156
|
return ({
|
|
111
157
|
swapInfo: {
|
|
@@ -116,81 +162,108 @@ class TitanClient {
|
|
|
116
162
|
inAmount: step.inAmount.toString(),
|
|
117
163
|
outAmount: step.outAmount.toString(),
|
|
118
164
|
feeAmount: ((_a = step.feeAmount) === null || _a === void 0 ? void 0 : _a.toString()) || '0',
|
|
119
|
-
feeMint: step.feeMint
|
|
165
|
+
feeMint: step.feeMint
|
|
166
|
+
? new web3_js_1.PublicKey(step.feeMint).toString()
|
|
167
|
+
: '',
|
|
120
168
|
},
|
|
121
169
|
percent: 100,
|
|
122
170
|
});
|
|
123
171
|
})) || [],
|
|
124
|
-
contextSlot: route.contextSlot,
|
|
125
|
-
timeTaken: route.timeTaken,
|
|
126
|
-
};
|
|
172
|
+
contextSlot: toNumber(route.contextSlot),
|
|
173
|
+
timeTaken: toNumber(route.timeTaken),
|
|
174
|
+
}, { provider: 'titan', route, quotedFor: userPublicKey.toString() });
|
|
127
175
|
}
|
|
128
176
|
/**
|
|
129
|
-
*
|
|
177
|
+
* The route as Titan built it, compiled into a signable transaction. Titan
|
|
178
|
+
* returns instructions rather than a transaction, so unlike Jupiter there is
|
|
179
|
+
* nothing to strip — the route already includes its own setup and teardown.
|
|
180
|
+
* @throws If the quote came from a different provider or a different wallet,
|
|
181
|
+
* or if a lookup table the route depends on can't be loaded.
|
|
130
182
|
*/
|
|
131
|
-
async
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const data = this.lastQuoteData;
|
|
138
|
-
// We are only querying for the best avaiable route so use that
|
|
139
|
-
const route = data.quotes[Object.keys(data.quotes)[0]];
|
|
140
|
-
if (!route) {
|
|
141
|
-
throw new Error('No routes available');
|
|
183
|
+
async getSwapTransaction({ quote, userPublicKey, }) {
|
|
184
|
+
var _a;
|
|
185
|
+
const route = (0, types_1.expectProviderRoute)(quote, 'titan', userPublicKey)
|
|
186
|
+
.route;
|
|
187
|
+
if (!((_a = route.instructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
188
|
+
throw new Error('No instructions provided in the route');
|
|
142
189
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
190
|
+
const [{ instructions, lookupTables }, { blockhash }] = await Promise.all([
|
|
191
|
+
this.getInstructionsAndLookupTables(route),
|
|
192
|
+
this.connection.getLatestBlockhash(),
|
|
193
|
+
]);
|
|
194
|
+
return new web3_js_1.VersionedTransaction(new web3_js_1.TransactionMessage({
|
|
195
|
+
payerKey: userPublicKey,
|
|
196
|
+
recentBlockhash: blockhash,
|
|
197
|
+
instructions,
|
|
198
|
+
}).compileToV0Message(lookupTables));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Builds the route instructions for a quote returned by {@link getQuote}.
|
|
202
|
+
*
|
|
203
|
+
* The route travels on the quote, so this reads no client state and two
|
|
204
|
+
* quotes in flight can never be confused for one another. Slippage was
|
|
205
|
+
* fixed when Titan built the route, so there is nothing to apply here.
|
|
206
|
+
* @throws If the quote came from a different provider or a different wallet,
|
|
207
|
+
* or if a lookup table the route depends on can't be loaded.
|
|
208
|
+
*/
|
|
209
|
+
async getRouteInstructions({ quote, userPublicKey, }) {
|
|
210
|
+
var _a;
|
|
211
|
+
const route = (0, types_1.expectProviderRoute)(quote, 'titan', userPublicKey)
|
|
212
|
+
.route;
|
|
213
|
+
if (!((_a = route.instructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
214
|
+
throw new Error('No instructions provided in the route');
|
|
156
215
|
}
|
|
157
|
-
|
|
216
|
+
// Errors propagate as-is. Replacing them with generic copy here loses
|
|
217
|
+
// the reason the swap can't be built — an unresolvable lookup table,
|
|
218
|
+
// say — which the caller needs to decide whether re-quoting will help.
|
|
219
|
+
const { instructions, lookupTables } = await this.getInstructionsAndLookupTables(route);
|
|
220
|
+
return {
|
|
221
|
+
instructions: (0, routeInstructions_1.filterRouteInstructions)({
|
|
222
|
+
instructions,
|
|
223
|
+
inputMint: new web3_js_1.PublicKey(quote.inputMint),
|
|
224
|
+
outputMint: new web3_js_1.PublicKey(quote.outputMint),
|
|
225
|
+
}),
|
|
226
|
+
lookupTables,
|
|
227
|
+
};
|
|
158
228
|
}
|
|
159
229
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* @
|
|
230
|
+
* Fetches a lookup table required by a route, retrying transient RPC
|
|
231
|
+
* failures (rate limiting in particular) before giving up. Checks the
|
|
232
|
+
* instance cache first and populates it on a fresh fetch.
|
|
233
|
+
* @throws If the table still can't be loaded, or doesn't exist on-chain.
|
|
164
234
|
*/
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
235
|
+
async fetchLookupTable(altPubkey) {
|
|
236
|
+
const cached = this.lookupTableCache.get(altPubkey.toString());
|
|
237
|
+
if (cached !== undefined) {
|
|
238
|
+
return cached;
|
|
239
|
+
}
|
|
240
|
+
let lastError;
|
|
241
|
+
for (let attempt = 0; attempt <= LOOKUP_TABLE_FETCH_RETRIES; attempt++) {
|
|
242
|
+
if (attempt > 0) {
|
|
243
|
+
await sleep(LOOKUP_TABLE_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
172
244
|
}
|
|
173
|
-
|
|
174
|
-
|
|
245
|
+
let altAccount;
|
|
246
|
+
try {
|
|
247
|
+
altAccount = await this.connection.getAddressLookupTable(altPubkey);
|
|
175
248
|
}
|
|
176
|
-
|
|
177
|
-
|
|
249
|
+
catch (err) {
|
|
250
|
+
// Transient — rate limiting, connection reset. Worth another go.
|
|
251
|
+
lastError = err;
|
|
252
|
+
continue;
|
|
178
253
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const mint = instruction.keys[3].pubkey;
|
|
183
|
-
if (mint.equals(inputMint) || mint.equals(outputMint)) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
254
|
+
if (altAccount.value) {
|
|
255
|
+
this.lookupTableCache.set(altPubkey.toString(), altAccount.value);
|
|
256
|
+
return altAccount.value;
|
|
187
257
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
258
|
+
// A successful response with no value means the route references a
|
|
259
|
+
// table that isn't on-chain. Retrying won't conjure it up.
|
|
260
|
+
throw new Error(`Address lookup table ${altPubkey.toString()} does not exist`);
|
|
261
|
+
}
|
|
262
|
+
throw new Error(`Failed to fetch address lookup table ${altPubkey.toString()}: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
191
263
|
}
|
|
192
|
-
async
|
|
193
|
-
|
|
264
|
+
async getInstructionsAndLookupTables(route) {
|
|
265
|
+
var _a;
|
|
266
|
+
const instructions = route.instructions.map((instruction) => ({
|
|
194
267
|
programId: new web3_js_1.PublicKey(instruction.p),
|
|
195
268
|
keys: instruction.a.map((meta) => ({
|
|
196
269
|
pubkey: new web3_js_1.PublicKey(meta.p),
|
|
@@ -199,29 +272,13 @@ class TitanClient {
|
|
|
199
272
|
})),
|
|
200
273
|
data: Buffer.from(instruction.d),
|
|
201
274
|
}));
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const altAccount = await this.connection.getAddressLookupTable(new web3_js_1.PublicKey(altPubkey));
|
|
210
|
-
if (altAccount.value) {
|
|
211
|
-
addressLookupTables.push(altAccount.value);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
catch (err) {
|
|
215
|
-
console.warn(`Failed to fetch address lookup table:`, err);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
const transactionMessage = new web3_js_1.TransactionMessage({
|
|
220
|
-
payerKey: userPublicKey,
|
|
221
|
-
recentBlockhash: blockhash,
|
|
222
|
-
instructions: solanaInstructions,
|
|
223
|
-
});
|
|
224
|
-
return { transactionMessage, lookupTables: addressLookupTables };
|
|
275
|
+
// These all have to resolve. A table that fails to load isn't a slightly
|
|
276
|
+
// worse route — every account it would have compressed to a 1-byte index
|
|
277
|
+
// gets inlined as a 32-byte pubkey instead, which pushes the transaction
|
|
278
|
+
// past the size limit and only surfaces later as an opaque
|
|
279
|
+
// "encoding overruns Uint8Array". Failing here lets the caller re-quote.
|
|
280
|
+
const lookupTables = await Promise.all(((_a = route.addressLookupTables) !== null && _a !== void 0 ? _a : []).map((altPubkey) => this.fetchLookupTable(new web3_js_1.PublicKey(altPubkey))));
|
|
281
|
+
return { instructions, lookupTables };
|
|
225
282
|
}
|
|
226
283
|
}
|
|
227
284
|
exports.TitanClient = TitanClient;
|
package/lib/browser/types.d.ts
CHANGED
|
@@ -116,7 +116,9 @@ export declare enum UserStatus {
|
|
|
116
116
|
BEING_LIQUIDATED = 1,
|
|
117
117
|
BANKRUPT = 2,
|
|
118
118
|
REDUCE_ONLY = 4,
|
|
119
|
-
ADVANCED_LP = 8
|
|
119
|
+
ADVANCED_LP = 8,
|
|
120
|
+
/** Owned by a Strategy Vault (authority is a vault PDA; equity prices vault shares). Revenue-share sweeps skip such Users so a builder/referral reward can't enter vault NAV. */
|
|
121
|
+
VAULT_OWNED = 32
|
|
120
122
|
}
|
|
121
123
|
/** Bitmask mirror of `UserAccount.specialUserStatus`. `VAMM_HEDGER` marks the account used by the protocol's own vAMM-hedging bot. */
|
|
122
124
|
export declare enum SpecialUserStatus {
|
|
@@ -1697,8 +1699,10 @@ export type UserAccount = {
|
|
|
1697
1699
|
poolId: number;
|
|
1698
1700
|
/** bitmask, see `SpecialUserStatus` */
|
|
1699
1701
|
specialUserStatus: number;
|
|
1700
|
-
/** QUOTE_PRECISION (1e6); admin-set minimum cross-margin total collateral
|
|
1702
|
+
/** QUOTE_PRECISION (1e6); admin-set minimum cross-margin total collateral; below it the permissionless breaker can trip; 0 = disabled */
|
|
1701
1703
|
equityFloor: BN;
|
|
1704
|
+
/** QUOTE_PRECISION (1e6); extra headroom above `equityFloor` required by risk-increasing orders, fills, withdrawals and transfers; no effect while `equityFloor` is 0 */
|
|
1705
|
+
equityFloorBuffer: BN;
|
|
1702
1706
|
};
|
|
1703
1707
|
/** A user's balance in one spot market. Decoded mirror of the on-chain `SpotPosition`. */
|
|
1704
1708
|
export type SpotPosition = {
|
package/lib/browser/types.js
CHANGED
|
@@ -103,6 +103,8 @@ var UserStatus;
|
|
|
103
103
|
UserStatus[UserStatus["REDUCE_ONLY"] = 4] = "REDUCE_ONLY";
|
|
104
104
|
UserStatus[UserStatus["ADVANCED_LP"] = 8] = "ADVANCED_LP";
|
|
105
105
|
// 16 reserved (was PROTECTED_MAKER)
|
|
106
|
+
/** Owned by a Strategy Vault (authority is a vault PDA; equity prices vault shares). Revenue-share sweeps skip such Users so a builder/referral reward can't enter vault NAV. */
|
|
107
|
+
UserStatus[UserStatus["VAULT_OWNED"] = 32] = "VAULT_OWNED";
|
|
106
108
|
})(UserStatus || (exports.UserStatus = UserStatus = {}));
|
|
107
109
|
/** Bitmask mirror of `UserAccount.specialUserStatus`. `VAMM_HEDGER` marks the account used by the protocol's own vAMM-hedging bot. */
|
|
108
110
|
var SpecialUserStatus;
|
package/lib/browser/user.d.ts
CHANGED
|
@@ -362,24 +362,23 @@ export declare class User {
|
|
|
362
362
|
* @param marginCategory `'Initial'` or `'Maintenance'` asset/liability weights; omit for unweighted (100%) values.
|
|
363
363
|
* @param liquidationBuffer Optional buffer (MARGIN_PRECISION, 1e4) added to the liability weight side.
|
|
364
364
|
* @param includeOpenOrders If false, ignores open bids/asks and only counts the current balance (faster, less conservative).
|
|
365
|
-
* @param strict Use the worse of live oracle price vs 5-minute TWAP. Defaults to false.
|
|
366
|
-
* @param now Unix timestamp (seconds) used for TWAP staleness when `strict` is set; defaults to current time.
|
|
365
|
+
* @param strict Use the worse of live oracle price vs the market's stored 5-minute TWAP. Defaults to false.
|
|
367
366
|
* @returns `{ totalAssetValue, totalLiabilityValue }`, both QUOTE_PRECISION (1e6) and non-negative.
|
|
368
367
|
*/
|
|
369
|
-
getSpotMarketAssetAndLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean
|
|
368
|
+
getSpotMarketAssetAndLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): {
|
|
370
369
|
totalAssetValue: BN;
|
|
371
370
|
totalLiabilityValue: BN;
|
|
372
371
|
};
|
|
373
372
|
/** Convenience wrapper around `getSpotMarketAssetAndLiabilityValue` returning only `totalLiabilityValue`. See that method for parameter semantics. Returns QUOTE_PRECISION (1e6). */
|
|
374
|
-
getSpotMarketLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean
|
|
373
|
+
getSpotMarketLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): BN;
|
|
375
374
|
/** Thin wrapper around the `math/spotBalance` `getSpotLiabilityValue` helper that supplies the user's `maxMarginRatio`. Returns QUOTE_PRECISION (1e6), negative. */
|
|
376
375
|
getSpotLiabilityValue(tokenAmount: BN, strictOraclePrice: StrictOraclePrice, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory, liquidationBuffer?: BN): BN;
|
|
377
376
|
/** Convenience wrapper around `getSpotMarketAssetAndLiabilityValue` returning only `totalAssetValue`. See that method for parameter semantics. Returns QUOTE_PRECISION (1e6), non-negative. */
|
|
378
|
-
getSpotMarketAssetValue(marketIndex?: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean
|
|
377
|
+
getSpotMarketAssetValue(marketIndex?: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean): BN;
|
|
379
378
|
/** Thin wrapper around the `math/spotBalance` `getSpotAssetValue` helper that supplies the user's `maxMarginRatio`. Returns QUOTE_PRECISION (1e6), non-negative. */
|
|
380
379
|
getSpotAssetValue(tokenAmount: BN, strictOraclePrice: StrictOraclePrice, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory): BN;
|
|
381
380
|
/** Net spot value (`totalAssetValue - totalLiabilityValue`) for a single spot market. See `getSpotMarketAssetAndLiabilityValue` for parameter semantics. Returns QUOTE_PRECISION (1e6), can be negative. */
|
|
382
|
-
getSpotPositionValue(marketIndex: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean
|
|
381
|
+
getSpotPositionValue(marketIndex: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean): BN;
|
|
383
382
|
/**
|
|
384
383
|
* Net spot value (`totalAssetValue - totalLiabilityValue`) across all spot
|
|
385
384
|
* markets combined.
|
|
@@ -411,20 +410,45 @@ export declare class User {
|
|
|
411
410
|
*/
|
|
412
411
|
getTotalCollateral(marginCategory?: MarginCategory, strict?: boolean, includeOpenOrders?: boolean, liquidationBuffer?: BN, perpMarketIndex?: number): BN;
|
|
413
412
|
/**
|
|
414
|
-
* True when the account has an admin-set `equityFloor` and its
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
* of the
|
|
418
|
-
*
|
|
419
|
-
*
|
|
413
|
+
* True when the account has an admin-set `equityFloor` and its net equity
|
|
414
|
+
* (`getNetUsdValue`: unweighted assets and perp PnL minus unweighted spot
|
|
415
|
+
* liabilities, at live oracle prices) is below it. This is the trip
|
|
416
|
+
* threshold of the permissionless `tripEquityFloorBreaker`; action gating
|
|
417
|
+
* happens at `equityFloor + equityFloorBuffer` (see
|
|
418
|
+
* `isBelowBufferedEquityFloor`). Mirrors `User::is_below_equity_floor`
|
|
419
|
+
* onchain.
|
|
420
420
|
*/
|
|
421
|
-
isBelowEquityFloor(
|
|
421
|
+
isBelowEquityFloor(): boolean;
|
|
422
422
|
/**
|
|
423
|
-
*
|
|
423
|
+
* The equity required by risk-increasing actions:
|
|
424
|
+
* `equityFloor + equityFloorBuffer` (QUOTE_PRECISION). Mirrors
|
|
425
|
+
* `User::buffered_equity_floor` on-chain. Meaningless while
|
|
426
|
+
* `equityFloor` is 0 (the checks are disabled).
|
|
427
|
+
*/
|
|
428
|
+
getBufferedEquityFloor(): BN;
|
|
429
|
+
/**
|
|
430
|
+
* True when the account has an admin-set `equityFloor` and its net equity
|
|
431
|
+
* (`getNetUsdValue`) is below `equityFloor + equityFloorBuffer`. While
|
|
432
|
+
* below, the program rejects risk-increasing order placement and fills,
|
|
433
|
+
* withdrawals, and transfers out of the account (`EquityBelowFloor`);
|
|
434
|
+
* reduce-only activity stays allowed. Mirrors
|
|
435
|
+
* `User::is_below_buffered_equity_floor` on-chain.
|
|
436
|
+
*/
|
|
437
|
+
isBelowBufferedEquityFloor(): boolean;
|
|
438
|
+
/**
|
|
439
|
+
* Net equity (`getNetUsdValue`) in excess of the admin-set `equityFloor`,
|
|
424
440
|
* floored at zero (QUOTE_PRECISION). Unbounded (`null`) when no floor is set.
|
|
425
|
-
*
|
|
441
|
+
* This is headroom above the trip threshold; headroom above the level
|
|
442
|
+
* risk-increasing actions must clear is `getEquityAboveBufferedFloor`.
|
|
443
|
+
*/
|
|
444
|
+
getEquityAboveFloor(): BN | null;
|
|
445
|
+
/**
|
|
446
|
+
* Net equity (`getNetUsdValue`) in excess of `equityFloor +
|
|
447
|
+
* equityFloorBuffer`, floored at zero (QUOTE_PRECISION). Unbounded
|
|
448
|
+
* (`null`) when no floor is set. When this reaches zero, risk-increasing
|
|
449
|
+
* actions start rejecting.
|
|
426
450
|
*/
|
|
427
|
-
|
|
451
|
+
getEquityAboveBufferedFloor(): BN | null;
|
|
428
452
|
/**
|
|
429
453
|
* Builds the liquidation-buffer map to pass into margin calculations while
|
|
430
454
|
* a liquidation is in progress: `'cross'` is set to the state account's
|
|
@@ -768,7 +792,7 @@ export declare class User {
|
|
|
768
792
|
* @param outMarketIndex
|
|
769
793
|
* @param calculateSwap Optional function to simulate the in-to-out conversion (e.g. to model swap fees/slippage); defaults to a 1:1 oracle-price conversion.
|
|
770
794
|
* @param iterationLimit How many binary-search iterations to run before erroring out. Defaults to 1000.
|
|
771
|
-
* @returns `inAmount`/`outAmount` in each market's own token decimals, and the resulting `leverage` (TEN_THOUSAND, 1e4 precision) after the swap.
|
|
795
|
+
* @returns `inAmount`/`outAmount` in each market's own token decimals, and the resulting `leverage` (TEN_THOUSAND, 1e4 precision) after the swap. Sizing is TWAP-bounded to match the program's margin check; `leverage` is marked at the live oracle price so it stays comparable to `getLeverage()`.
|
|
772
796
|
*/
|
|
773
797
|
getMaxSwapAmount({ inMarketIndex, outMarketIndex, calculateSwap, iterationLimit, }: {
|
|
774
798
|
inMarketIndex: number;
|
|
@@ -796,7 +820,8 @@ export declare class User {
|
|
|
796
820
|
totalLiabilityValue: BN;
|
|
797
821
|
};
|
|
798
822
|
/**
|
|
799
|
-
* Estimates what the user leverage will be after swap
|
|
823
|
+
* Estimates what the user leverage will be after swap, marked at the live
|
|
824
|
+
* oracle price so it stays comparable to `getLeverage()`.
|
|
800
825
|
* @param inMarketIndex Market being sold/paid from.
|
|
801
826
|
* @param outMarketIndex Market being bought/received.
|
|
802
827
|
* @param inAmount Amount removed from `inMarketIndex`, that market's own token decimals.
|