@percolatorct/sdk 0.3.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/LICENSE +201 -0
- package/README.md +492 -0
- package/dist/abi/accounts.d.ts +257 -0
- package/dist/abi/encode.d.ts +46 -0
- package/dist/abi/errors.d.ts +34 -0
- package/dist/abi/index.d.ts +4 -0
- package/dist/abi/instructions.d.ts +990 -0
- package/dist/config/program-ids.d.ts +50 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4604 -0
- package/dist/index.js.map +1 -0
- package/dist/math/index.d.ts +2 -0
- package/dist/math/trading.d.ts +107 -0
- package/dist/math/warmup.d.ts +55 -0
- package/dist/oracle/price-router.d.ts +38 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/tx.d.ts +31 -0
- package/dist/solana/adl.d.ts +305 -0
- package/dist/solana/ata.d.ts +18 -0
- package/dist/solana/dex-oracle.d.ts +49 -0
- package/dist/solana/discovery.d.ts +263 -0
- package/dist/solana/index.d.ts +9 -0
- package/dist/solana/oracle.d.ts +44 -0
- package/dist/solana/pda.d.ts +54 -0
- package/dist/solana/slab.d.ts +316 -0
- package/dist/solana/stake.d.ts +216 -0
- package/dist/solana/token-program.d.ts +19 -0
- package/dist/validation.d.ts +45 -0
- package/package.json +45 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4604 @@
|
|
|
1
|
+
// src/abi/encode.ts
|
|
2
|
+
import { PublicKey } from "@solana/web3.js";
|
|
3
|
+
function encU8(val) {
|
|
4
|
+
if (!Number.isInteger(val) || val < 0 || val > 255) {
|
|
5
|
+
throw new Error(`encU8: value out of range (0..255), got ${val}`);
|
|
6
|
+
}
|
|
7
|
+
return new Uint8Array([val]);
|
|
8
|
+
}
|
|
9
|
+
function encU16(val) {
|
|
10
|
+
if (!Number.isInteger(val) || val < 0 || val > 65535) {
|
|
11
|
+
throw new Error(`encU16: value out of range (0..65535), got ${val}`);
|
|
12
|
+
}
|
|
13
|
+
const buf = new Uint8Array(2);
|
|
14
|
+
new DataView(buf.buffer).setUint16(0, val, true);
|
|
15
|
+
return buf;
|
|
16
|
+
}
|
|
17
|
+
function encU32(val) {
|
|
18
|
+
if (!Number.isInteger(val) || val < 0 || val > 4294967295) {
|
|
19
|
+
throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);
|
|
20
|
+
}
|
|
21
|
+
const buf = new Uint8Array(4);
|
|
22
|
+
new DataView(buf.buffer).setUint32(0, val, true);
|
|
23
|
+
return buf;
|
|
24
|
+
}
|
|
25
|
+
function encU64(val) {
|
|
26
|
+
const n = typeof val === "string" ? BigInt(val) : val;
|
|
27
|
+
if (n < 0n) throw new Error("encU64: value must be non-negative");
|
|
28
|
+
if (n > 0xffffffffffffffffn) throw new Error("encU64: value exceeds u64 max");
|
|
29
|
+
const buf = new Uint8Array(8);
|
|
30
|
+
new DataView(buf.buffer).setBigUint64(0, n, true);
|
|
31
|
+
return buf;
|
|
32
|
+
}
|
|
33
|
+
function encI64(val) {
|
|
34
|
+
const n = typeof val === "string" ? BigInt(val) : val;
|
|
35
|
+
const min = -(1n << 63n);
|
|
36
|
+
const max = (1n << 63n) - 1n;
|
|
37
|
+
if (n < min || n > max) throw new Error("encI64: value out of range");
|
|
38
|
+
const buf = new Uint8Array(8);
|
|
39
|
+
new DataView(buf.buffer).setBigInt64(0, n, true);
|
|
40
|
+
return buf;
|
|
41
|
+
}
|
|
42
|
+
function encU128(val) {
|
|
43
|
+
const n = typeof val === "string" ? BigInt(val) : val;
|
|
44
|
+
if (n < 0n) throw new Error("encU128: value must be non-negative");
|
|
45
|
+
const max = (1n << 128n) - 1n;
|
|
46
|
+
if (n > max) throw new Error("encU128: value exceeds u128 max");
|
|
47
|
+
const buf = new Uint8Array(16);
|
|
48
|
+
const view = new DataView(buf.buffer);
|
|
49
|
+
const lo = n & 0xffffffffffffffffn;
|
|
50
|
+
const hi = n >> 64n;
|
|
51
|
+
view.setBigUint64(0, lo, true);
|
|
52
|
+
view.setBigUint64(8, hi, true);
|
|
53
|
+
return buf;
|
|
54
|
+
}
|
|
55
|
+
function encI128(val) {
|
|
56
|
+
const n = typeof val === "string" ? BigInt(val) : val;
|
|
57
|
+
const min = -(1n << 127n);
|
|
58
|
+
const max = (1n << 127n) - 1n;
|
|
59
|
+
if (n < min || n > max) throw new Error("encI128: value out of range");
|
|
60
|
+
let unsigned = n;
|
|
61
|
+
if (n < 0n) {
|
|
62
|
+
unsigned = (1n << 128n) + n;
|
|
63
|
+
}
|
|
64
|
+
const buf = new Uint8Array(16);
|
|
65
|
+
const view = new DataView(buf.buffer);
|
|
66
|
+
const lo = unsigned & 0xffffffffffffffffn;
|
|
67
|
+
const hi = unsigned >> 64n;
|
|
68
|
+
view.setBigUint64(0, lo, true);
|
|
69
|
+
view.setBigUint64(8, hi, true);
|
|
70
|
+
return buf;
|
|
71
|
+
}
|
|
72
|
+
function encPubkey(val) {
|
|
73
|
+
try {
|
|
74
|
+
const pk = typeof val === "string" ? new PublicKey(val) : val;
|
|
75
|
+
return pk.toBytes();
|
|
76
|
+
} catch (e) {
|
|
77
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
78
|
+
throw new Error(`encPubkey: invalid public key "${String(val)}" \u2014 ${msg}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function encBool(val) {
|
|
82
|
+
return encU8(val ? 1 : 0);
|
|
83
|
+
}
|
|
84
|
+
function concatBytes(...arrays) {
|
|
85
|
+
const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);
|
|
86
|
+
const result = new Uint8Array(totalLen);
|
|
87
|
+
let offset = 0;
|
|
88
|
+
for (const arr of arrays) {
|
|
89
|
+
result.set(arr, offset);
|
|
90
|
+
offset += arr.length;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/abi/instructions.ts
|
|
96
|
+
var IX_TAG = {
|
|
97
|
+
InitMarket: 0,
|
|
98
|
+
InitUser: 1,
|
|
99
|
+
InitLP: 2,
|
|
100
|
+
DepositCollateral: 3,
|
|
101
|
+
WithdrawCollateral: 4,
|
|
102
|
+
KeeperCrank: 5,
|
|
103
|
+
TradeNoCpi: 6,
|
|
104
|
+
LiquidateAtOracle: 7,
|
|
105
|
+
CloseAccount: 8,
|
|
106
|
+
TopUpInsurance: 9,
|
|
107
|
+
TradeCpi: 10,
|
|
108
|
+
SetRiskThreshold: 11,
|
|
109
|
+
UpdateAdmin: 12,
|
|
110
|
+
CloseSlab: 13,
|
|
111
|
+
UpdateConfig: 14,
|
|
112
|
+
SetMaintenanceFee: 15,
|
|
113
|
+
SetOracleAuthority: 16,
|
|
114
|
+
PushOraclePrice: 17,
|
|
115
|
+
SetOraclePriceCap: 18,
|
|
116
|
+
ResolveMarket: 19,
|
|
117
|
+
WithdrawInsurance: 20,
|
|
118
|
+
AdminForceClose: 21,
|
|
119
|
+
UpdateRiskParams: 22,
|
|
120
|
+
RenounceAdmin: 23,
|
|
121
|
+
CreateInsuranceMint: 24,
|
|
122
|
+
DepositInsuranceLP: 25,
|
|
123
|
+
WithdrawInsuranceLP: 26,
|
|
124
|
+
PauseMarket: 27,
|
|
125
|
+
UnpauseMarket: 28,
|
|
126
|
+
AcceptAdmin: 29,
|
|
127
|
+
SetInsuranceWithdrawPolicy: 30,
|
|
128
|
+
WithdrawInsuranceLimited: 31,
|
|
129
|
+
SetPythOracle: 32,
|
|
130
|
+
UpdateMarkPrice: 33,
|
|
131
|
+
UpdateHyperpMark: 34,
|
|
132
|
+
TradeCpiV2: 35,
|
|
133
|
+
UnresolveMarket: 36,
|
|
134
|
+
CreateLpVault: 37,
|
|
135
|
+
LpVaultDeposit: 38,
|
|
136
|
+
LpVaultWithdraw: 39,
|
|
137
|
+
LpVaultCrankFees: 40,
|
|
138
|
+
/** PERC-306: Fund per-market isolated insurance balance */
|
|
139
|
+
FundMarketInsurance: 41,
|
|
140
|
+
/** PERC-306: Set insurance isolation BPS for a market */
|
|
141
|
+
SetInsuranceIsolation: 42,
|
|
142
|
+
// Tag 43 is ChallengeSettlement on-chain (PERC-314).
|
|
143
|
+
// PERC-305 (ExecuteAdl) is NOT implemented on-chain — do NOT assign tag 43 here.
|
|
144
|
+
// When PERC-305 is implemented, assign a new unused tag (≥47).
|
|
145
|
+
/** PERC-314: Challenge settlement price during dispute window */
|
|
146
|
+
ChallengeSettlement: 43,
|
|
147
|
+
/** PERC-314: Resolve dispute (admin adjudication) */
|
|
148
|
+
ResolveDispute: 44,
|
|
149
|
+
/** PERC-315: Deposit LP vault tokens as perp collateral */
|
|
150
|
+
DepositLpCollateral: 45,
|
|
151
|
+
/** PERC-315: Withdraw LP collateral (position must be closed) */
|
|
152
|
+
WithdrawLpCollateral: 46,
|
|
153
|
+
/** PERC-309: Queue a large LP withdrawal (user; creates withdraw_queue PDA). */
|
|
154
|
+
QueueWithdrawal: 47,
|
|
155
|
+
/** PERC-309: Claim one epoch tranche from a queued LP withdrawal (user). */
|
|
156
|
+
ClaimQueuedWithdrawal: 48,
|
|
157
|
+
/** PERC-309: Cancel a queued withdrawal, refund remaining LP tokens (user). */
|
|
158
|
+
CancelQueuedWithdrawal: 49,
|
|
159
|
+
/** PERC-305: Auto-deleverage — surgically close profitable positions when PnL cap is exceeded (permissionless). */
|
|
160
|
+
ExecuteAdl: 50,
|
|
161
|
+
/** Close a stale slab of an invalid/old layout and recover rent SOL (admin only). */
|
|
162
|
+
CloseStaleSlabs: 51,
|
|
163
|
+
/** Reclaim rent from an uninitialised slab whose market creation failed mid-flow. Slab must sign. */
|
|
164
|
+
ReclaimSlabRent: 52,
|
|
165
|
+
/** Permissionless on-chain audit crank: verifies conservation invariants and pauses market on violation. */
|
|
166
|
+
AuditCrank: 53,
|
|
167
|
+
/** Cross-Market Portfolio Margining: SetOffsetPair */
|
|
168
|
+
SetOffsetPair: 54,
|
|
169
|
+
/** Cross-Market Portfolio Margining: AttestCrossMargin */
|
|
170
|
+
AttestCrossMargin: 55,
|
|
171
|
+
/** PERC-622: Advance oracle phase (permissionless crank) */
|
|
172
|
+
AdvanceOraclePhase: 56,
|
|
173
|
+
/** PERC-623: Top up a market's keeper fund (permissionless) */
|
|
174
|
+
TopUpKeeperFund: 57,
|
|
175
|
+
/** PERC-629: Slash a market creator's deposit (permissionless) */
|
|
176
|
+
SlashCreationDeposit: 58,
|
|
177
|
+
/** PERC-628: Initialize the global shared vault (admin) */
|
|
178
|
+
InitSharedVault: 59,
|
|
179
|
+
/** PERC-628: Allocate virtual liquidity to a market (admin) */
|
|
180
|
+
AllocateMarket: 60,
|
|
181
|
+
/** PERC-628: Queue a withdrawal for the current epoch */
|
|
182
|
+
QueueWithdrawalSV: 61,
|
|
183
|
+
/** PERC-628: Claim a queued withdrawal after epoch elapses */
|
|
184
|
+
ClaimEpochWithdrawal: 62,
|
|
185
|
+
/** PERC-628: Advance the shared vault epoch (permissionless crank) */
|
|
186
|
+
AdvanceEpoch: 63,
|
|
187
|
+
/** PERC-608: Mint a Position NFT for a user's open position. */
|
|
188
|
+
MintPositionNft: 64,
|
|
189
|
+
/** PERC-608: Transfer position ownership via the NFT (keeper-gated). */
|
|
190
|
+
TransferPositionOwnership: 65,
|
|
191
|
+
/** PERC-608: Burn the Position NFT when a position is closed. */
|
|
192
|
+
BurnPositionNft: 66,
|
|
193
|
+
/** PERC-608: Keeper sets pending_settlement flag before a funding transfer. */
|
|
194
|
+
SetPendingSettlement: 67,
|
|
195
|
+
/** PERC-608: Keeper clears pending_settlement flag after KeeperCrank. */
|
|
196
|
+
ClearPendingSettlement: 68,
|
|
197
|
+
/** PERC-608: Internal CPI call from percolator-nft TransferHook to update on-chain owner. */
|
|
198
|
+
TransferOwnershipCpi: 69,
|
|
199
|
+
/** PERC-8111: Set per-wallet position cap (admin only, cap_e6=0 disables). */
|
|
200
|
+
SetWalletCap: 70,
|
|
201
|
+
/** PERC-8110: Set OI imbalance hard-block threshold (admin only). */
|
|
202
|
+
SetOiImbalanceHardBlock: 71
|
|
203
|
+
};
|
|
204
|
+
var HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
205
|
+
function encodeFeedId(feedId) {
|
|
206
|
+
const hex = feedId.startsWith("0x") ? feedId.slice(2) : feedId;
|
|
207
|
+
if (!HEX_RE.test(hex)) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Invalid feed ID: expected 64 hex chars, got "${hex.length === 64 ? "non-hex characters" : hex.length + " chars"}"`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const bytes = new Uint8Array(32);
|
|
213
|
+
for (let i = 0; i < 64; i += 2) {
|
|
214
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
215
|
+
}
|
|
216
|
+
return bytes;
|
|
217
|
+
}
|
|
218
|
+
var INIT_MARKET_DATA_LEN = 264;
|
|
219
|
+
function encodeInitMarket(args) {
|
|
220
|
+
const data = concatBytes(
|
|
221
|
+
encU8(IX_TAG.InitMarket),
|
|
222
|
+
encPubkey(args.admin),
|
|
223
|
+
encPubkey(args.collateralMint),
|
|
224
|
+
encodeFeedId(args.indexFeedId),
|
|
225
|
+
encU64(args.maxStalenessSecs),
|
|
226
|
+
encU16(args.confFilterBps),
|
|
227
|
+
encU8(args.invert),
|
|
228
|
+
encU32(args.unitScale),
|
|
229
|
+
encU64(args.initialMarkPriceE6),
|
|
230
|
+
encU64(args.warmupPeriodSlots),
|
|
231
|
+
encU64(args.maintenanceMarginBps),
|
|
232
|
+
encU64(args.initialMarginBps),
|
|
233
|
+
encU64(args.tradingFeeBps),
|
|
234
|
+
encU64(args.maxAccounts),
|
|
235
|
+
encU128(args.newAccountFee),
|
|
236
|
+
encU128(args.riskReductionThreshold),
|
|
237
|
+
encU128(args.maintenanceFeePerSlot),
|
|
238
|
+
encU64(args.maxCrankStalenessSlots),
|
|
239
|
+
encU64(args.liquidationFeeBps),
|
|
240
|
+
encU128(args.liquidationFeeCap),
|
|
241
|
+
encU64(args.liquidationBufferBps),
|
|
242
|
+
encU128(args.minLiquidationAbs)
|
|
243
|
+
);
|
|
244
|
+
if (data.length !== INIT_MARKET_DATA_LEN) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`encodeInitMarket: expected ${INIT_MARKET_DATA_LEN} bytes, got ${data.length}`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
return data;
|
|
250
|
+
}
|
|
251
|
+
function encodeInitUser(args) {
|
|
252
|
+
return concatBytes(encU8(IX_TAG.InitUser), encU64(args.feePayment));
|
|
253
|
+
}
|
|
254
|
+
function encodeInitLP(args) {
|
|
255
|
+
return concatBytes(
|
|
256
|
+
encU8(IX_TAG.InitLP),
|
|
257
|
+
encPubkey(args.matcherProgram),
|
|
258
|
+
encPubkey(args.matcherContext),
|
|
259
|
+
encU64(args.feePayment)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function encodeDepositCollateral(args) {
|
|
263
|
+
return concatBytes(
|
|
264
|
+
encU8(IX_TAG.DepositCollateral),
|
|
265
|
+
encU16(args.userIdx),
|
|
266
|
+
encU64(args.amount)
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
function encodeWithdrawCollateral(args) {
|
|
270
|
+
return concatBytes(
|
|
271
|
+
encU8(IX_TAG.WithdrawCollateral),
|
|
272
|
+
encU16(args.userIdx),
|
|
273
|
+
encU64(args.amount)
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
function encodeKeeperCrank(args) {
|
|
277
|
+
return concatBytes(
|
|
278
|
+
encU8(IX_TAG.KeeperCrank),
|
|
279
|
+
encU16(args.callerIdx),
|
|
280
|
+
encU8(args.allowPanic ? 1 : 0)
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
function encodeTradeNoCpi(args) {
|
|
284
|
+
return concatBytes(
|
|
285
|
+
encU8(IX_TAG.TradeNoCpi),
|
|
286
|
+
encU16(args.lpIdx),
|
|
287
|
+
encU16(args.userIdx),
|
|
288
|
+
encI128(args.size)
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
function encodeLiquidateAtOracle(args) {
|
|
292
|
+
return concatBytes(
|
|
293
|
+
encU8(IX_TAG.LiquidateAtOracle),
|
|
294
|
+
encU16(args.targetIdx)
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function encodeCloseAccount(args) {
|
|
298
|
+
return concatBytes(encU8(IX_TAG.CloseAccount), encU16(args.userIdx));
|
|
299
|
+
}
|
|
300
|
+
function encodeTopUpInsurance(args) {
|
|
301
|
+
return concatBytes(encU8(IX_TAG.TopUpInsurance), encU64(args.amount));
|
|
302
|
+
}
|
|
303
|
+
function encodeTradeCpi(args) {
|
|
304
|
+
return concatBytes(
|
|
305
|
+
encU8(IX_TAG.TradeCpi),
|
|
306
|
+
encU16(args.lpIdx),
|
|
307
|
+
encU16(args.userIdx),
|
|
308
|
+
encI128(args.size)
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
function encodeTradeCpiV2(args) {
|
|
312
|
+
return concatBytes(
|
|
313
|
+
encU8(IX_TAG.TradeCpiV2),
|
|
314
|
+
encU16(args.lpIdx),
|
|
315
|
+
encU16(args.userIdx),
|
|
316
|
+
encI128(args.size),
|
|
317
|
+
encU8(args.bump)
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
function encodeSetRiskThreshold(args) {
|
|
321
|
+
return concatBytes(
|
|
322
|
+
encU8(IX_TAG.SetRiskThreshold),
|
|
323
|
+
encU128(args.newThreshold)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
function encodeUpdateAdmin(args) {
|
|
327
|
+
return concatBytes(encU8(IX_TAG.UpdateAdmin), encPubkey(args.newAdmin));
|
|
328
|
+
}
|
|
329
|
+
function encodeCloseSlab() {
|
|
330
|
+
return encU8(IX_TAG.CloseSlab);
|
|
331
|
+
}
|
|
332
|
+
function encodeUpdateConfig(args) {
|
|
333
|
+
return concatBytes(
|
|
334
|
+
encU8(IX_TAG.UpdateConfig),
|
|
335
|
+
encU64(args.fundingHorizonSlots),
|
|
336
|
+
encU64(args.fundingKBps),
|
|
337
|
+
encU128(args.fundingInvScaleNotionalE6),
|
|
338
|
+
encI64(args.fundingMaxPremiumBps),
|
|
339
|
+
// Rust: i64 (can be negative)
|
|
340
|
+
encI64(args.fundingMaxBpsPerSlot),
|
|
341
|
+
// Rust: i64 (can be negative)
|
|
342
|
+
encU128(args.threshFloor),
|
|
343
|
+
encU64(args.threshRiskBps),
|
|
344
|
+
encU64(args.threshUpdateIntervalSlots),
|
|
345
|
+
encU64(args.threshStepBps),
|
|
346
|
+
encU64(args.threshAlphaBps),
|
|
347
|
+
encU128(args.threshMin),
|
|
348
|
+
encU128(args.threshMax),
|
|
349
|
+
encU128(args.threshMinStep)
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
function encodeSetMaintenanceFee(args) {
|
|
353
|
+
return concatBytes(
|
|
354
|
+
encU8(IX_TAG.SetMaintenanceFee),
|
|
355
|
+
encU128(args.newFee)
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
function encodeSetOracleAuthority(args) {
|
|
359
|
+
return concatBytes(
|
|
360
|
+
encU8(IX_TAG.SetOracleAuthority),
|
|
361
|
+
encPubkey(args.newAuthority)
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
function encodePushOraclePrice(args) {
|
|
365
|
+
return concatBytes(
|
|
366
|
+
encU8(IX_TAG.PushOraclePrice),
|
|
367
|
+
encU64(args.priceE6),
|
|
368
|
+
encI64(args.timestamp)
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
function encodeSetOraclePriceCap(args) {
|
|
372
|
+
return concatBytes(
|
|
373
|
+
encU8(IX_TAG.SetOraclePriceCap),
|
|
374
|
+
encU64(args.maxChangeE2bps)
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
function encodeResolveMarket() {
|
|
378
|
+
return encU8(IX_TAG.ResolveMarket);
|
|
379
|
+
}
|
|
380
|
+
function encodeWithdrawInsurance() {
|
|
381
|
+
return encU8(IX_TAG.WithdrawInsurance);
|
|
382
|
+
}
|
|
383
|
+
function encodeAdminForceClose(args) {
|
|
384
|
+
return concatBytes(
|
|
385
|
+
encU8(IX_TAG.AdminForceClose),
|
|
386
|
+
encU16(args.targetIdx)
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
function encodeUpdateRiskParams(args) {
|
|
390
|
+
const parts = [
|
|
391
|
+
encU8(IX_TAG.UpdateRiskParams),
|
|
392
|
+
encU64(args.initialMarginBps),
|
|
393
|
+
encU64(args.maintenanceMarginBps)
|
|
394
|
+
];
|
|
395
|
+
if (args.tradingFeeBps !== void 0) {
|
|
396
|
+
parts.push(encU64(args.tradingFeeBps));
|
|
397
|
+
}
|
|
398
|
+
return concatBytes(...parts);
|
|
399
|
+
}
|
|
400
|
+
var RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;
|
|
401
|
+
var UNRESOLVE_CONFIRMATION = 0xDEADBEEFCAFE1234n;
|
|
402
|
+
function encodeRenounceAdmin() {
|
|
403
|
+
return concatBytes(
|
|
404
|
+
encU8(IX_TAG.RenounceAdmin),
|
|
405
|
+
encU64(RENOUNCE_ADMIN_CONFIRMATION)
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
function encodeCreateInsuranceMint() {
|
|
409
|
+
return encU8(IX_TAG.CreateInsuranceMint);
|
|
410
|
+
}
|
|
411
|
+
function encodeDepositInsuranceLP(args) {
|
|
412
|
+
return concatBytes(encU8(IX_TAG.DepositInsuranceLP), encU64(args.amount));
|
|
413
|
+
}
|
|
414
|
+
function encodeWithdrawInsuranceLP(args) {
|
|
415
|
+
return concatBytes(encU8(IX_TAG.WithdrawInsuranceLP), encU64(args.lpAmount));
|
|
416
|
+
}
|
|
417
|
+
function encodeLpVaultWithdraw(args) {
|
|
418
|
+
return concatBytes(encU8(IX_TAG.LpVaultWithdraw), encU64(args.lpAmount));
|
|
419
|
+
}
|
|
420
|
+
function encodePauseMarket() {
|
|
421
|
+
return encU8(IX_TAG.PauseMarket);
|
|
422
|
+
}
|
|
423
|
+
function encodeUnpauseMarket() {
|
|
424
|
+
return encU8(IX_TAG.UnpauseMarket);
|
|
425
|
+
}
|
|
426
|
+
function encodeSetPythOracle(args) {
|
|
427
|
+
if (args.feedId.length !== 32) throw new Error("feedId must be 32 bytes");
|
|
428
|
+
if (args.maxStalenessSecs <= 0n) throw new Error("maxStalenessSecs must be > 0");
|
|
429
|
+
const buf = new Uint8Array(43);
|
|
430
|
+
const dv3 = new DataView(buf.buffer);
|
|
431
|
+
buf[0] = 32;
|
|
432
|
+
buf.set(args.feedId, 1);
|
|
433
|
+
dv3.setBigUint64(
|
|
434
|
+
33,
|
|
435
|
+
args.maxStalenessSecs,
|
|
436
|
+
/* little-endian */
|
|
437
|
+
true
|
|
438
|
+
);
|
|
439
|
+
dv3.setUint16(41, args.confFilterBps, true);
|
|
440
|
+
return buf;
|
|
441
|
+
}
|
|
442
|
+
var PYTH_RECEIVER_PROGRAM_ID = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ";
|
|
443
|
+
async function derivePythPriceUpdateAccount(feedId, shardId = 0) {
|
|
444
|
+
const { PublicKey: PublicKey12 } = await import("@solana/web3.js");
|
|
445
|
+
const shardBuf = new Uint8Array(2);
|
|
446
|
+
new DataView(shardBuf.buffer).setUint16(0, shardId, true);
|
|
447
|
+
const [pda] = PublicKey12.findProgramAddressSync(
|
|
448
|
+
[shardBuf, feedId],
|
|
449
|
+
new PublicKey12(PYTH_RECEIVER_PROGRAM_ID)
|
|
450
|
+
);
|
|
451
|
+
return pda.toBase58();
|
|
452
|
+
}
|
|
453
|
+
IX_TAG["SetPythOracle"] = 32;
|
|
454
|
+
IX_TAG["UpdateMarkPrice"] = 33;
|
|
455
|
+
function encodeUpdateMarkPrice() {
|
|
456
|
+
return new Uint8Array([33]);
|
|
457
|
+
}
|
|
458
|
+
var MARK_PRICE_EMA_WINDOW_SLOTS = 72000n;
|
|
459
|
+
var MARK_PRICE_EMA_ALPHA_E6 = 2000000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);
|
|
460
|
+
function computeEmaMarkPrice(markPrevE6, oracleE6, dtSlots, alphaE6 = MARK_PRICE_EMA_ALPHA_E6, capE2bps = 0n) {
|
|
461
|
+
if (oracleE6 === 0n) return markPrevE6;
|
|
462
|
+
if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;
|
|
463
|
+
let oracleClamped = oracleE6;
|
|
464
|
+
if (capE2bps > 0n) {
|
|
465
|
+
const maxDelta = markPrevE6 * capE2bps * dtSlots / 1000000n;
|
|
466
|
+
const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;
|
|
467
|
+
const hi = markPrevE6 + maxDelta;
|
|
468
|
+
if (oracleClamped < lo) oracleClamped = lo;
|
|
469
|
+
if (oracleClamped > hi) oracleClamped = hi;
|
|
470
|
+
}
|
|
471
|
+
const effectiveAlpha = alphaE6 * dtSlots > 1000000n ? 1000000n : alphaE6 * dtSlots;
|
|
472
|
+
const oneMinusAlpha = 1000000n - effectiveAlpha;
|
|
473
|
+
return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1000000n;
|
|
474
|
+
}
|
|
475
|
+
IX_TAG["UpdateHyperpMark"] = 34;
|
|
476
|
+
function encodeUpdateHyperpMark() {
|
|
477
|
+
return new Uint8Array([34]);
|
|
478
|
+
}
|
|
479
|
+
function encodeFundMarketInsurance(args) {
|
|
480
|
+
return concatBytes(encU8(IX_TAG.FundMarketInsurance), encU64(args.amount));
|
|
481
|
+
}
|
|
482
|
+
function encodeSetInsuranceIsolation(args) {
|
|
483
|
+
return concatBytes(encU8(IX_TAG.SetInsuranceIsolation), encU16(args.bps));
|
|
484
|
+
}
|
|
485
|
+
function encodeQueueWithdrawal(args) {
|
|
486
|
+
return concatBytes(encU8(IX_TAG.QueueWithdrawal), encU64(args.lpAmount));
|
|
487
|
+
}
|
|
488
|
+
function encodeClaimQueuedWithdrawal() {
|
|
489
|
+
return encU8(IX_TAG.ClaimQueuedWithdrawal);
|
|
490
|
+
}
|
|
491
|
+
function encodeCancelQueuedWithdrawal() {
|
|
492
|
+
return encU8(IX_TAG.CancelQueuedWithdrawal);
|
|
493
|
+
}
|
|
494
|
+
function encodeExecuteAdl(args) {
|
|
495
|
+
return concatBytes(encU8(IX_TAG.ExecuteAdl), encU16(args.targetIdx));
|
|
496
|
+
}
|
|
497
|
+
function encodeCloseStaleSlabs() {
|
|
498
|
+
return encU8(IX_TAG.CloseStaleSlabs);
|
|
499
|
+
}
|
|
500
|
+
function encodeReclaimSlabRent() {
|
|
501
|
+
return encU8(IX_TAG.ReclaimSlabRent);
|
|
502
|
+
}
|
|
503
|
+
function encodeAuditCrank() {
|
|
504
|
+
return encU8(IX_TAG.AuditCrank);
|
|
505
|
+
}
|
|
506
|
+
var VAMM_MAGIC = 0x504552434d415443n;
|
|
507
|
+
var CTX_VAMM_OFFSET = 64;
|
|
508
|
+
var BPS_DENOM = 10000n;
|
|
509
|
+
function computeVammQuote(params, oraclePriceE6, tradeSize, isLong) {
|
|
510
|
+
const absSize = tradeSize < 0n ? -tradeSize : tradeSize;
|
|
511
|
+
const absNotionalE6 = absSize * oraclePriceE6 / 1000000n;
|
|
512
|
+
let impactBps = 0n;
|
|
513
|
+
if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {
|
|
514
|
+
impactBps = absNotionalE6 * BigInt(params.impactKBps) / params.liquidityNotionalE6;
|
|
515
|
+
}
|
|
516
|
+
const maxTotal = BigInt(params.maxTotalBps);
|
|
517
|
+
const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);
|
|
518
|
+
const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;
|
|
519
|
+
const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;
|
|
520
|
+
let totalBps = baseFee + clampedImpact;
|
|
521
|
+
if (totalBps > maxTotal) totalBps = maxTotal;
|
|
522
|
+
if (isLong) {
|
|
523
|
+
return oraclePriceE6 * (BPS_DENOM + totalBps) / BPS_DENOM;
|
|
524
|
+
} else {
|
|
525
|
+
if (totalBps >= BPS_DENOM) return 1n;
|
|
526
|
+
return oraclePriceE6 * (BPS_DENOM - totalBps) / BPS_DENOM;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function encodeAdvanceOraclePhase() {
|
|
530
|
+
return encU8(IX_TAG.AdvanceOraclePhase);
|
|
531
|
+
}
|
|
532
|
+
var ORACLE_PHASE_NASCENT = 0;
|
|
533
|
+
var ORACLE_PHASE_GROWING = 1;
|
|
534
|
+
var ORACLE_PHASE_MATURE = 2;
|
|
535
|
+
var PHASE1_MIN_SLOTS = 648000n;
|
|
536
|
+
var PHASE1_VOLUME_MIN_SLOTS = 36000n;
|
|
537
|
+
var PHASE2_VOLUME_THRESHOLD = 100000000000n;
|
|
538
|
+
var PHASE2_MATURITY_SLOTS = 3024000n;
|
|
539
|
+
function checkPhaseTransition(currentSlot, marketCreatedSlot, oraclePhase, cumulativeVolumeE6, phase2DeltaSlots, hasMatureOracle) {
|
|
540
|
+
switch (oraclePhase) {
|
|
541
|
+
case 0: {
|
|
542
|
+
const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);
|
|
543
|
+
const timeReady = elapsed >= PHASE1_MIN_SLOTS;
|
|
544
|
+
const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;
|
|
545
|
+
if (timeReady || volumeReady) {
|
|
546
|
+
return [ORACLE_PHASE_GROWING, true];
|
|
547
|
+
}
|
|
548
|
+
return [ORACLE_PHASE_NASCENT, false];
|
|
549
|
+
}
|
|
550
|
+
case 1: {
|
|
551
|
+
if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];
|
|
552
|
+
const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);
|
|
553
|
+
const elapsedSincePhase2 = currentSlot - phase2Start;
|
|
554
|
+
if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {
|
|
555
|
+
return [ORACLE_PHASE_MATURE, true];
|
|
556
|
+
}
|
|
557
|
+
return [ORACLE_PHASE_GROWING, false];
|
|
558
|
+
}
|
|
559
|
+
default:
|
|
560
|
+
return [ORACLE_PHASE_MATURE, false];
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function encodeTopUpKeeperFund(args) {
|
|
564
|
+
return concatBytes(encU8(IX_TAG.TopUpKeeperFund), encU64(args.amount));
|
|
565
|
+
}
|
|
566
|
+
function encodeSlashCreationDeposit() {
|
|
567
|
+
return encU8(IX_TAG.SlashCreationDeposit);
|
|
568
|
+
}
|
|
569
|
+
function encodeInitSharedVault(args) {
|
|
570
|
+
return concatBytes(
|
|
571
|
+
encU8(IX_TAG.InitSharedVault),
|
|
572
|
+
encU64(args.epochDurationSlots),
|
|
573
|
+
encU16(args.maxMarketExposureBps)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
function encodeAllocateMarket(args) {
|
|
577
|
+
return concatBytes(encU8(IX_TAG.AllocateMarket), encU128(args.amount));
|
|
578
|
+
}
|
|
579
|
+
function encodeQueueWithdrawalSV(args) {
|
|
580
|
+
return concatBytes(encU8(IX_TAG.QueueWithdrawalSV), encU64(args.lpAmount));
|
|
581
|
+
}
|
|
582
|
+
function encodeClaimEpochWithdrawal() {
|
|
583
|
+
return encU8(IX_TAG.ClaimEpochWithdrawal);
|
|
584
|
+
}
|
|
585
|
+
function encodeAdvanceEpoch() {
|
|
586
|
+
return encU8(IX_TAG.AdvanceEpoch);
|
|
587
|
+
}
|
|
588
|
+
function encodeSetOiImbalanceHardBlock(args) {
|
|
589
|
+
if (args.thresholdBps < 0 || args.thresholdBps > 1e4) {
|
|
590
|
+
throw new Error(`encodeSetOiImbalanceHardBlock: thresholdBps must be 0\u201310_000, got ${args.thresholdBps}`);
|
|
591
|
+
}
|
|
592
|
+
return concatBytes(encU8(IX_TAG.SetOiImbalanceHardBlock), encU16(args.thresholdBps));
|
|
593
|
+
}
|
|
594
|
+
function encodeMintPositionNft(args) {
|
|
595
|
+
return concatBytes(encU8(IX_TAG.MintPositionNft), encU16(args.userIdx));
|
|
596
|
+
}
|
|
597
|
+
function encodeTransferPositionOwnership(args) {
|
|
598
|
+
return concatBytes(encU8(IX_TAG.TransferPositionOwnership), encU16(args.userIdx));
|
|
599
|
+
}
|
|
600
|
+
function encodeBurnPositionNft(args) {
|
|
601
|
+
return concatBytes(encU8(IX_TAG.BurnPositionNft), encU16(args.userIdx));
|
|
602
|
+
}
|
|
603
|
+
function encodeSetPendingSettlement(args) {
|
|
604
|
+
return concatBytes(encU8(IX_TAG.SetPendingSettlement), encU16(args.userIdx));
|
|
605
|
+
}
|
|
606
|
+
function encodeClearPendingSettlement(args) {
|
|
607
|
+
return concatBytes(encU8(IX_TAG.ClearPendingSettlement), encU16(args.userIdx));
|
|
608
|
+
}
|
|
609
|
+
function encodeTransferOwnershipCpi(args) {
|
|
610
|
+
return concatBytes(
|
|
611
|
+
encU8(IX_TAG.TransferOwnershipCpi),
|
|
612
|
+
encU16(args.userIdx),
|
|
613
|
+
encPubkey(args.newOwner)
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
function encodeSetWalletCap(args) {
|
|
617
|
+
return concatBytes(encU8(IX_TAG.SetWalletCap), encU64(args.capE6));
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/abi/accounts.ts
|
|
621
|
+
import {
|
|
622
|
+
SYSVAR_CLOCK_PUBKEY,
|
|
623
|
+
SYSVAR_RENT_PUBKEY,
|
|
624
|
+
SystemProgram
|
|
625
|
+
} from "@solana/web3.js";
|
|
626
|
+
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
|
627
|
+
var ACCOUNTS_INIT_MARKET = [
|
|
628
|
+
{ name: "admin", signer: true, writable: true },
|
|
629
|
+
{ name: "slab", signer: false, writable: true },
|
|
630
|
+
{ name: "mint", signer: false, writable: false },
|
|
631
|
+
{ name: "vault", signer: false, writable: false },
|
|
632
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
633
|
+
{ name: "clock", signer: false, writable: false },
|
|
634
|
+
{ name: "rent", signer: false, writable: false },
|
|
635
|
+
{ name: "dummyAta", signer: false, writable: false },
|
|
636
|
+
{ name: "systemProgram", signer: false, writable: false }
|
|
637
|
+
];
|
|
638
|
+
var ACCOUNTS_INIT_USER = [
|
|
639
|
+
{ name: "user", signer: true, writable: true },
|
|
640
|
+
{ name: "slab", signer: false, writable: true },
|
|
641
|
+
{ name: "userAta", signer: false, writable: true },
|
|
642
|
+
{ name: "vault", signer: false, writable: true },
|
|
643
|
+
{ name: "tokenProgram", signer: false, writable: false }
|
|
644
|
+
];
|
|
645
|
+
var ACCOUNTS_INIT_LP = [
|
|
646
|
+
{ name: "user", signer: true, writable: true },
|
|
647
|
+
{ name: "slab", signer: false, writable: true },
|
|
648
|
+
{ name: "userAta", signer: false, writable: true },
|
|
649
|
+
{ name: "vault", signer: false, writable: true },
|
|
650
|
+
{ name: "tokenProgram", signer: false, writable: false }
|
|
651
|
+
];
|
|
652
|
+
var ACCOUNTS_DEPOSIT_COLLATERAL = [
|
|
653
|
+
{ name: "user", signer: true, writable: true },
|
|
654
|
+
{ name: "slab", signer: false, writable: true },
|
|
655
|
+
{ name: "userAta", signer: false, writable: true },
|
|
656
|
+
{ name: "vault", signer: false, writable: true },
|
|
657
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
658
|
+
{ name: "clock", signer: false, writable: false }
|
|
659
|
+
];
|
|
660
|
+
var ACCOUNTS_WITHDRAW_COLLATERAL = [
|
|
661
|
+
{ name: "user", signer: true, writable: true },
|
|
662
|
+
{ name: "slab", signer: false, writable: true },
|
|
663
|
+
{ name: "vault", signer: false, writable: true },
|
|
664
|
+
{ name: "userAta", signer: false, writable: true },
|
|
665
|
+
{ name: "vaultPda", signer: false, writable: false },
|
|
666
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
667
|
+
{ name: "clock", signer: false, writable: false },
|
|
668
|
+
{ name: "oracleIdx", signer: false, writable: false }
|
|
669
|
+
];
|
|
670
|
+
var ACCOUNTS_KEEPER_CRANK = [
|
|
671
|
+
{ name: "caller", signer: true, writable: true },
|
|
672
|
+
{ name: "slab", signer: false, writable: true },
|
|
673
|
+
{ name: "clock", signer: false, writable: false },
|
|
674
|
+
{ name: "oracle", signer: false, writable: false }
|
|
675
|
+
];
|
|
676
|
+
var ACCOUNTS_TRADE_NOCPI = [
|
|
677
|
+
{ name: "user", signer: true, writable: true },
|
|
678
|
+
{ name: "lp", signer: true, writable: true },
|
|
679
|
+
{ name: "slab", signer: false, writable: true },
|
|
680
|
+
{ name: "oracle", signer: false, writable: false }
|
|
681
|
+
];
|
|
682
|
+
var ACCOUNTS_LIQUIDATE_AT_ORACLE = [
|
|
683
|
+
{ name: "unused", signer: false, writable: false },
|
|
684
|
+
{ name: "slab", signer: false, writable: true },
|
|
685
|
+
{ name: "clock", signer: false, writable: false },
|
|
686
|
+
{ name: "oracle", signer: false, writable: false }
|
|
687
|
+
];
|
|
688
|
+
var ACCOUNTS_CLOSE_ACCOUNT = [
|
|
689
|
+
{ name: "user", signer: true, writable: true },
|
|
690
|
+
{ name: "slab", signer: false, writable: true },
|
|
691
|
+
{ name: "vault", signer: false, writable: true },
|
|
692
|
+
{ name: "userAta", signer: false, writable: true },
|
|
693
|
+
{ name: "vaultPda", signer: false, writable: false },
|
|
694
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
695
|
+
{ name: "clock", signer: false, writable: false },
|
|
696
|
+
{ name: "oracle", signer: false, writable: false }
|
|
697
|
+
];
|
|
698
|
+
var ACCOUNTS_TOPUP_INSURANCE = [
|
|
699
|
+
{ name: "user", signer: true, writable: true },
|
|
700
|
+
{ name: "slab", signer: false, writable: true },
|
|
701
|
+
{ name: "userAta", signer: false, writable: true },
|
|
702
|
+
{ name: "vault", signer: false, writable: true },
|
|
703
|
+
{ name: "tokenProgram", signer: false, writable: false }
|
|
704
|
+
];
|
|
705
|
+
var ACCOUNTS_TRADE_CPI = [
|
|
706
|
+
{ name: "user", signer: true, writable: true },
|
|
707
|
+
{ name: "lpOwner", signer: false, writable: false },
|
|
708
|
+
// LP delegated to matcher - no signature needed
|
|
709
|
+
{ name: "slab", signer: false, writable: true },
|
|
710
|
+
{ name: "oracle", signer: false, writable: false },
|
|
711
|
+
{ name: "matcherProg", signer: false, writable: false },
|
|
712
|
+
{ name: "matcherCtx", signer: false, writable: true },
|
|
713
|
+
{ name: "lpPda", signer: false, writable: false }
|
|
714
|
+
];
|
|
715
|
+
var ACCOUNTS_SET_RISK_THRESHOLD = [
|
|
716
|
+
{ name: "admin", signer: true, writable: true },
|
|
717
|
+
{ name: "slab", signer: false, writable: true }
|
|
718
|
+
];
|
|
719
|
+
var ACCOUNTS_UPDATE_ADMIN = [
|
|
720
|
+
{ name: "admin", signer: true, writable: true },
|
|
721
|
+
{ name: "slab", signer: false, writable: true }
|
|
722
|
+
];
|
|
723
|
+
var ACCOUNTS_CLOSE_SLAB = [
|
|
724
|
+
{ name: "admin", signer: true, writable: true },
|
|
725
|
+
{ name: "slab", signer: false, writable: true }
|
|
726
|
+
];
|
|
727
|
+
var ACCOUNTS_UPDATE_CONFIG = [
|
|
728
|
+
{ name: "admin", signer: true, writable: true },
|
|
729
|
+
{ name: "slab", signer: false, writable: true }
|
|
730
|
+
];
|
|
731
|
+
var ACCOUNTS_SET_MAINTENANCE_FEE = [
|
|
732
|
+
{ name: "admin", signer: true, writable: true },
|
|
733
|
+
{ name: "slab", signer: false, writable: true }
|
|
734
|
+
];
|
|
735
|
+
var ACCOUNTS_SET_ORACLE_AUTHORITY = [
|
|
736
|
+
{ name: "admin", signer: true, writable: true },
|
|
737
|
+
{ name: "slab", signer: false, writable: true }
|
|
738
|
+
];
|
|
739
|
+
var ACCOUNTS_SET_ORACLE_PRICE_CAP = [
|
|
740
|
+
{ name: "admin", signer: true, writable: true },
|
|
741
|
+
{ name: "slab", signer: false, writable: true }
|
|
742
|
+
];
|
|
743
|
+
var ACCOUNTS_PUSH_ORACLE_PRICE = [
|
|
744
|
+
{ name: "authority", signer: true, writable: true },
|
|
745
|
+
{ name: "slab", signer: false, writable: true }
|
|
746
|
+
];
|
|
747
|
+
var ACCOUNTS_RESOLVE_MARKET = [
|
|
748
|
+
{ name: "admin", signer: true, writable: true },
|
|
749
|
+
{ name: "slab", signer: false, writable: true }
|
|
750
|
+
];
|
|
751
|
+
var ACCOUNTS_WITHDRAW_INSURANCE = [
|
|
752
|
+
{ name: "admin", signer: true, writable: true },
|
|
753
|
+
{ name: "slab", signer: false, writable: true },
|
|
754
|
+
{ name: "adminAta", signer: false, writable: true },
|
|
755
|
+
{ name: "vault", signer: false, writable: true },
|
|
756
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
757
|
+
{ name: "vaultPda", signer: false, writable: false }
|
|
758
|
+
];
|
|
759
|
+
var ACCOUNTS_PAUSE_MARKET = [
|
|
760
|
+
{ name: "admin", signer: true, writable: true },
|
|
761
|
+
{ name: "slab", signer: false, writable: true }
|
|
762
|
+
];
|
|
763
|
+
var ACCOUNTS_UNPAUSE_MARKET = [
|
|
764
|
+
{ name: "admin", signer: true, writable: true },
|
|
765
|
+
{ name: "slab", signer: false, writable: true }
|
|
766
|
+
];
|
|
767
|
+
function buildAccountMetas(spec, keys) {
|
|
768
|
+
let keysArray;
|
|
769
|
+
if (Array.isArray(keys)) {
|
|
770
|
+
keysArray = keys;
|
|
771
|
+
} else {
|
|
772
|
+
keysArray = spec.map((s) => {
|
|
773
|
+
const key = keys[s.name];
|
|
774
|
+
if (!key) {
|
|
775
|
+
throw new Error(
|
|
776
|
+
`buildAccountMetas: missing key for account "${s.name}". Provided keys: [${Object.keys(keys).join(", ")}]`
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
return key;
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
if (keysArray.length !== spec.length) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Account count mismatch: expected ${spec.length}, got ${keysArray.length}`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
return spec.map((s, i) => ({
|
|
788
|
+
pubkey: keysArray[i],
|
|
789
|
+
isSigner: s.signer,
|
|
790
|
+
isWritable: s.writable
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
793
|
+
var ACCOUNTS_CREATE_INSURANCE_MINT = [
|
|
794
|
+
{ name: "admin", signer: true, writable: false },
|
|
795
|
+
{ name: "slab", signer: false, writable: false },
|
|
796
|
+
{ name: "insLpMint", signer: false, writable: true },
|
|
797
|
+
{ name: "vaultAuthority", signer: false, writable: false },
|
|
798
|
+
{ name: "collateralMint", signer: false, writable: false },
|
|
799
|
+
{ name: "systemProgram", signer: false, writable: false },
|
|
800
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
801
|
+
{ name: "rent", signer: false, writable: false },
|
|
802
|
+
{ name: "payer", signer: true, writable: true }
|
|
803
|
+
];
|
|
804
|
+
var ACCOUNTS_DEPOSIT_INSURANCE_LP = [
|
|
805
|
+
{ name: "depositor", signer: true, writable: false },
|
|
806
|
+
{ name: "slab", signer: false, writable: true },
|
|
807
|
+
{ name: "depositorAta", signer: false, writable: true },
|
|
808
|
+
{ name: "vault", signer: false, writable: true },
|
|
809
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
810
|
+
{ name: "insLpMint", signer: false, writable: true },
|
|
811
|
+
{ name: "depositorLpAta", signer: false, writable: true },
|
|
812
|
+
{ name: "vaultAuthority", signer: false, writable: false }
|
|
813
|
+
];
|
|
814
|
+
var ACCOUNTS_WITHDRAW_INSURANCE_LP = [
|
|
815
|
+
{ name: "withdrawer", signer: true, writable: false },
|
|
816
|
+
{ name: "slab", signer: false, writable: true },
|
|
817
|
+
{ name: "withdrawerAta", signer: false, writable: true },
|
|
818
|
+
{ name: "vault", signer: false, writable: true },
|
|
819
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
820
|
+
{ name: "insLpMint", signer: false, writable: true },
|
|
821
|
+
{ name: "withdrawerLpAta", signer: false, writable: true },
|
|
822
|
+
{ name: "vaultAuthority", signer: false, writable: false }
|
|
823
|
+
];
|
|
824
|
+
var ACCOUNTS_LP_VAULT_WITHDRAW = [
|
|
825
|
+
{ name: "withdrawer", signer: true, writable: false },
|
|
826
|
+
{ name: "slab", signer: false, writable: true },
|
|
827
|
+
{ name: "withdrawerAta", signer: false, writable: true },
|
|
828
|
+
{ name: "vault", signer: false, writable: true },
|
|
829
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
830
|
+
{ name: "lpVaultMint", signer: false, writable: true },
|
|
831
|
+
{ name: "withdrawerLpAta", signer: false, writable: true },
|
|
832
|
+
{ name: "vaultAuthority", signer: false, writable: false },
|
|
833
|
+
{ name: "lpVaultState", signer: false, writable: true },
|
|
834
|
+
{ name: "creatorLockPda", signer: false, writable: true }
|
|
835
|
+
];
|
|
836
|
+
var ACCOUNTS_FUND_MARKET_INSURANCE = [
|
|
837
|
+
{ name: "admin", signer: true, writable: true },
|
|
838
|
+
{ name: "slab", signer: false, writable: true },
|
|
839
|
+
{ name: "adminAta", signer: false, writable: true },
|
|
840
|
+
{ name: "vault", signer: false, writable: true },
|
|
841
|
+
{ name: "tokenProgram", signer: false, writable: false }
|
|
842
|
+
];
|
|
843
|
+
var ACCOUNTS_SET_INSURANCE_ISOLATION = [
|
|
844
|
+
{ name: "admin", signer: true, writable: false },
|
|
845
|
+
{ name: "slab", signer: false, writable: true }
|
|
846
|
+
];
|
|
847
|
+
var ACCOUNTS_QUEUE_WITHDRAWAL = [
|
|
848
|
+
{ name: "user", signer: true, writable: true },
|
|
849
|
+
{ name: "slab", signer: false, writable: true },
|
|
850
|
+
{ name: "lpVaultState", signer: false, writable: false },
|
|
851
|
+
{ name: "withdrawQueue", signer: false, writable: true },
|
|
852
|
+
{ name: "systemProgram", signer: false, writable: false }
|
|
853
|
+
];
|
|
854
|
+
var ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL = [
|
|
855
|
+
{ name: "user", signer: true, writable: true },
|
|
856
|
+
{ name: "slab", signer: false, writable: true },
|
|
857
|
+
{ name: "withdrawQueue", signer: false, writable: true },
|
|
858
|
+
{ name: "lpVaultMint", signer: false, writable: true },
|
|
859
|
+
{ name: "userLpAta", signer: false, writable: true },
|
|
860
|
+
{ name: "vault", signer: false, writable: true },
|
|
861
|
+
{ name: "userAta", signer: false, writable: true },
|
|
862
|
+
{ name: "vaultAuthority", signer: false, writable: false },
|
|
863
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
864
|
+
{ name: "lpVaultState", signer: false, writable: true }
|
|
865
|
+
];
|
|
866
|
+
var ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL = [
|
|
867
|
+
{ name: "user", signer: true, writable: true },
|
|
868
|
+
{ name: "slab", signer: false, writable: false },
|
|
869
|
+
{ name: "withdrawQueue", signer: false, writable: true }
|
|
870
|
+
];
|
|
871
|
+
var ACCOUNTS_EXECUTE_ADL = [
|
|
872
|
+
{ name: "caller", signer: true, writable: false },
|
|
873
|
+
{ name: "slab", signer: false, writable: true },
|
|
874
|
+
{ name: "clock", signer: false, writable: false },
|
|
875
|
+
{ name: "oracle", signer: false, writable: false }
|
|
876
|
+
];
|
|
877
|
+
var ACCOUNTS_CLOSE_STALE_SLABS = [
|
|
878
|
+
{ name: "dest", signer: true, writable: true },
|
|
879
|
+
{ name: "slab", signer: false, writable: true }
|
|
880
|
+
];
|
|
881
|
+
var ACCOUNTS_RECLAIM_SLAB_RENT = [
|
|
882
|
+
{ name: "dest", signer: true, writable: true },
|
|
883
|
+
{ name: "slab", signer: true, writable: true }
|
|
884
|
+
];
|
|
885
|
+
var ACCOUNTS_AUDIT_CRANK = [
|
|
886
|
+
{ name: "slab", signer: false, writable: true }
|
|
887
|
+
];
|
|
888
|
+
var ACCOUNTS_ADVANCE_ORACLE_PHASE = [
|
|
889
|
+
{ name: "slab", signer: false, writable: true }
|
|
890
|
+
];
|
|
891
|
+
var ACCOUNTS_TOPUP_KEEPER_FUND = [
|
|
892
|
+
{ name: "funder", signer: true, writable: true },
|
|
893
|
+
{ name: "slab", signer: false, writable: true },
|
|
894
|
+
{ name: "keeperFund", signer: false, writable: true }
|
|
895
|
+
];
|
|
896
|
+
var ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK = [
|
|
897
|
+
{ name: "admin", signer: true, writable: false },
|
|
898
|
+
{ name: "slab", signer: false, writable: true }
|
|
899
|
+
];
|
|
900
|
+
var ACCOUNTS_MINT_POSITION_NFT = [
|
|
901
|
+
{ name: "payer", signer: true, writable: true },
|
|
902
|
+
{ name: "slab", signer: false, writable: true },
|
|
903
|
+
{ name: "positionNftPda", signer: false, writable: true },
|
|
904
|
+
{ name: "nftMint", signer: false, writable: true },
|
|
905
|
+
{ name: "ownerAta", signer: false, writable: true },
|
|
906
|
+
{ name: "owner", signer: true, writable: false },
|
|
907
|
+
{ name: "vaultAuthority", signer: false, writable: false },
|
|
908
|
+
{ name: "token2022Program", signer: false, writable: false },
|
|
909
|
+
{ name: "systemProgram", signer: false, writable: false },
|
|
910
|
+
{ name: "rent", signer: false, writable: false }
|
|
911
|
+
];
|
|
912
|
+
var ACCOUNTS_TRANSFER_POSITION_OWNERSHIP = [
|
|
913
|
+
{ name: "currentOwner", signer: true, writable: true },
|
|
914
|
+
{ name: "slab", signer: false, writable: true },
|
|
915
|
+
{ name: "positionNftPda", signer: false, writable: true },
|
|
916
|
+
{ name: "nftMint", signer: false, writable: true },
|
|
917
|
+
{ name: "currentOwnerAta", signer: false, writable: true },
|
|
918
|
+
{ name: "newOwnerAta", signer: false, writable: true },
|
|
919
|
+
{ name: "newOwner", signer: false, writable: false },
|
|
920
|
+
{ name: "token2022Program", signer: false, writable: false }
|
|
921
|
+
];
|
|
922
|
+
var ACCOUNTS_BURN_POSITION_NFT = [
|
|
923
|
+
{ name: "owner", signer: true, writable: true },
|
|
924
|
+
{ name: "slab", signer: false, writable: true },
|
|
925
|
+
{ name: "positionNftPda", signer: false, writable: true },
|
|
926
|
+
{ name: "nftMint", signer: false, writable: true },
|
|
927
|
+
{ name: "ownerAta", signer: false, writable: true },
|
|
928
|
+
{ name: "vaultAuthority", signer: false, writable: false },
|
|
929
|
+
{ name: "token2022Program", signer: false, writable: false }
|
|
930
|
+
];
|
|
931
|
+
var ACCOUNTS_SET_PENDING_SETTLEMENT = [
|
|
932
|
+
{ name: "keeper", signer: true, writable: false },
|
|
933
|
+
{ name: "slab", signer: false, writable: false },
|
|
934
|
+
{ name: "positionNftPda", signer: false, writable: true }
|
|
935
|
+
];
|
|
936
|
+
var ACCOUNTS_CLEAR_PENDING_SETTLEMENT = [
|
|
937
|
+
{ name: "keeper", signer: true, writable: false },
|
|
938
|
+
{ name: "slab", signer: false, writable: false },
|
|
939
|
+
{ name: "positionNftPda", signer: false, writable: true }
|
|
940
|
+
];
|
|
941
|
+
var ACCOUNTS_SET_WALLET_CAP = [
|
|
942
|
+
{ name: "admin", signer: true, writable: false },
|
|
943
|
+
{ name: "slab", signer: false, writable: true }
|
|
944
|
+
];
|
|
945
|
+
var WELL_KNOWN = {
|
|
946
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
947
|
+
clock: SYSVAR_CLOCK_PUBKEY,
|
|
948
|
+
rent: SYSVAR_RENT_PUBKEY,
|
|
949
|
+
systemProgram: SystemProgram.programId
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
// src/abi/errors.ts
|
|
953
|
+
var PERCOLATOR_ERRORS = {
|
|
954
|
+
0: {
|
|
955
|
+
name: "InvalidMagic",
|
|
956
|
+
hint: "The slab account has invalid data. Ensure you're using the correct slab address."
|
|
957
|
+
},
|
|
958
|
+
1: {
|
|
959
|
+
name: "InvalidVersion",
|
|
960
|
+
hint: "Slab version mismatch. The program may have been upgraded. Check for CLI updates."
|
|
961
|
+
},
|
|
962
|
+
2: {
|
|
963
|
+
name: "AlreadyInitialized",
|
|
964
|
+
hint: "This account is already initialized. Use a different account or skip initialization."
|
|
965
|
+
},
|
|
966
|
+
3: {
|
|
967
|
+
name: "NotInitialized",
|
|
968
|
+
hint: "The slab is not initialized. Run 'init-market' first."
|
|
969
|
+
},
|
|
970
|
+
4: {
|
|
971
|
+
name: "InvalidSlabLen",
|
|
972
|
+
hint: "Slab account has wrong size. Create a new slab account with correct size."
|
|
973
|
+
},
|
|
974
|
+
5: {
|
|
975
|
+
name: "InvalidOracleKey",
|
|
976
|
+
hint: "Oracle account doesn't match config. Check the --oracle parameter matches the market's oracle."
|
|
977
|
+
},
|
|
978
|
+
6: {
|
|
979
|
+
name: "OracleStale",
|
|
980
|
+
hint: "Oracle price is too old. Wait for oracle to update or check if oracle is paused."
|
|
981
|
+
},
|
|
982
|
+
7: {
|
|
983
|
+
name: "OracleConfTooWide",
|
|
984
|
+
hint: "Oracle confidence interval is too wide. Wait for more stable market conditions."
|
|
985
|
+
},
|
|
986
|
+
8: {
|
|
987
|
+
name: "InvalidVaultAta",
|
|
988
|
+
hint: "Vault token account is invalid. Check the vault account is correctly configured."
|
|
989
|
+
},
|
|
990
|
+
9: {
|
|
991
|
+
name: "InvalidMint",
|
|
992
|
+
hint: "Token mint doesn't match. Ensure you're using the correct collateral token."
|
|
993
|
+
},
|
|
994
|
+
10: {
|
|
995
|
+
name: "ExpectedSigner",
|
|
996
|
+
hint: "Missing required signature. Ensure the correct wallet is specified with --wallet."
|
|
997
|
+
},
|
|
998
|
+
11: {
|
|
999
|
+
name: "ExpectedWritable",
|
|
1000
|
+
hint: "Account must be writable. This is likely a CLI bug - please report it."
|
|
1001
|
+
},
|
|
1002
|
+
12: {
|
|
1003
|
+
name: "OracleInvalid",
|
|
1004
|
+
hint: "Oracle data is invalid. Check the oracle account is a valid Pyth price feed."
|
|
1005
|
+
},
|
|
1006
|
+
13: {
|
|
1007
|
+
name: "EngineInsufficientBalance",
|
|
1008
|
+
hint: "Not enough collateral. Deposit more with 'deposit' before this operation."
|
|
1009
|
+
},
|
|
1010
|
+
14: {
|
|
1011
|
+
name: "EngineUndercollateralized",
|
|
1012
|
+
hint: "Account is undercollateralized. Deposit more collateral or reduce position size."
|
|
1013
|
+
},
|
|
1014
|
+
15: {
|
|
1015
|
+
name: "EngineUnauthorized",
|
|
1016
|
+
hint: "Not authorized. You must be the account owner or admin for this operation."
|
|
1017
|
+
},
|
|
1018
|
+
16: {
|
|
1019
|
+
name: "EngineInvalidMatchingEngine",
|
|
1020
|
+
hint: "Matcher program/context doesn't match LP config. Check --matcher-program and --matcher-context."
|
|
1021
|
+
},
|
|
1022
|
+
17: {
|
|
1023
|
+
name: "EnginePnlNotWarmedUp",
|
|
1024
|
+
hint: "PnL not warmed up yet. Wait for the warmup period to complete before trading."
|
|
1025
|
+
},
|
|
1026
|
+
18: {
|
|
1027
|
+
name: "EngineOverflow",
|
|
1028
|
+
hint: "Numeric overflow in calculation. Try a smaller amount or position size."
|
|
1029
|
+
},
|
|
1030
|
+
19: {
|
|
1031
|
+
name: "EngineAccountNotFound",
|
|
1032
|
+
hint: "Account not found at this index. Run 'init-user' or 'init-lp' first, or check the index."
|
|
1033
|
+
},
|
|
1034
|
+
20: {
|
|
1035
|
+
name: "EngineNotAnLPAccount",
|
|
1036
|
+
hint: "Expected an LP account but got a user account. Check the --lp-idx parameter."
|
|
1037
|
+
},
|
|
1038
|
+
21: {
|
|
1039
|
+
name: "EnginePositionSizeMismatch",
|
|
1040
|
+
hint: "Position size mismatch between user and LP. This shouldn't happen - please report it."
|
|
1041
|
+
},
|
|
1042
|
+
22: {
|
|
1043
|
+
name: "EngineRiskReductionOnlyMode",
|
|
1044
|
+
hint: "Market is in risk-reduction mode. Only position-reducing trades are allowed."
|
|
1045
|
+
},
|
|
1046
|
+
23: {
|
|
1047
|
+
name: "EngineAccountKindMismatch",
|
|
1048
|
+
hint: "Wrong account type. User operations require user accounts, LP operations require LP accounts."
|
|
1049
|
+
},
|
|
1050
|
+
24: {
|
|
1051
|
+
name: "InvalidTokenAccount",
|
|
1052
|
+
hint: "Token account is invalid. Ensure you have an ATA for the collateral mint."
|
|
1053
|
+
},
|
|
1054
|
+
25: {
|
|
1055
|
+
name: "InvalidTokenProgram",
|
|
1056
|
+
hint: "Invalid token program. Ensure SPL Token program is accessible."
|
|
1057
|
+
},
|
|
1058
|
+
26: {
|
|
1059
|
+
name: "InvalidConfigParam",
|
|
1060
|
+
hint: "Invalid configuration parameter. Check that leverage, fees, and risk thresholds are within allowed ranges."
|
|
1061
|
+
},
|
|
1062
|
+
27: {
|
|
1063
|
+
name: "HyperpTradeNoCpiDisabled",
|
|
1064
|
+
hint: "TradeNoCpi is disabled for this market. Use TradeCpi with LP matching instead."
|
|
1065
|
+
},
|
|
1066
|
+
28: {
|
|
1067
|
+
name: "InsuranceMintAlreadyExists",
|
|
1068
|
+
hint: "Insurance LP mint already exists for this market. Cannot recreate."
|
|
1069
|
+
},
|
|
1070
|
+
29: {
|
|
1071
|
+
name: "InsuranceMintNotCreated",
|
|
1072
|
+
hint: "Insurance LP mint has not been created yet. Run CreateInsuranceMint first."
|
|
1073
|
+
},
|
|
1074
|
+
30: {
|
|
1075
|
+
name: "InsuranceBelowThreshold",
|
|
1076
|
+
hint: "Insurance fund balance is below the required threshold. Deposit more to insurance fund."
|
|
1077
|
+
},
|
|
1078
|
+
31: {
|
|
1079
|
+
name: "InsuranceZeroAmount",
|
|
1080
|
+
hint: "Insurance deposit/withdrawal amount must be greater than zero."
|
|
1081
|
+
},
|
|
1082
|
+
32: {
|
|
1083
|
+
name: "InsuranceSupplyMismatch",
|
|
1084
|
+
hint: "Insurance LP token supply doesn't match vault balance. This is an internal error - please report it."
|
|
1085
|
+
},
|
|
1086
|
+
33: {
|
|
1087
|
+
name: "MarketPaused",
|
|
1088
|
+
hint: "This market is currently paused by the admin. Trading, deposits, and withdrawals are disabled."
|
|
1089
|
+
},
|
|
1090
|
+
34: {
|
|
1091
|
+
name: "AdminRenounceNotAllowed",
|
|
1092
|
+
hint: "Cannot renounce admin \u2014 the market must be RESOLVED first before renouncing admin control."
|
|
1093
|
+
},
|
|
1094
|
+
35: {
|
|
1095
|
+
name: "InvalidConfirmation",
|
|
1096
|
+
hint: "Invalid confirmation code for RenounceAdmin. This is a safety check \u2014 please verify the code."
|
|
1097
|
+
},
|
|
1098
|
+
36: {
|
|
1099
|
+
name: "InsufficientSeed",
|
|
1100
|
+
hint: "Vault seed balance is below the required minimum (500,000,000 raw tokens). Deposit more tokens to the vault before InitMarket."
|
|
1101
|
+
},
|
|
1102
|
+
37: {
|
|
1103
|
+
name: "InsufficientDexLiquidity",
|
|
1104
|
+
hint: "DEX pool has insufficient liquidity for safe Hyperp oracle bootstrapping. The quote-side reserves must meet the minimum threshold."
|
|
1105
|
+
},
|
|
1106
|
+
38: {
|
|
1107
|
+
name: "LpVaultAlreadyExists",
|
|
1108
|
+
hint: "LP vault already created for this market. Each market can only have one LP vault."
|
|
1109
|
+
},
|
|
1110
|
+
39: {
|
|
1111
|
+
name: "LpVaultNotCreated",
|
|
1112
|
+
hint: "LP vault not yet created. Call CreateLpVault first before depositing or withdrawing."
|
|
1113
|
+
},
|
|
1114
|
+
40: {
|
|
1115
|
+
name: "LpVaultZeroAmount",
|
|
1116
|
+
hint: "LP vault deposit or withdrawal amount must be greater than zero."
|
|
1117
|
+
},
|
|
1118
|
+
41: {
|
|
1119
|
+
name: "LpVaultSupplyMismatch",
|
|
1120
|
+
hint: "LP vault supply/capital mismatch \u2014 LP share supply > 0 but vault capital is 0. This is an internal error \u2014 please report it."
|
|
1121
|
+
},
|
|
1122
|
+
42: {
|
|
1123
|
+
name: "LpVaultWithdrawExceedsAvailable",
|
|
1124
|
+
hint: "LP vault withdrawal exceeds available capital. Some capital is reserved for open interest coverage."
|
|
1125
|
+
},
|
|
1126
|
+
43: {
|
|
1127
|
+
name: "LpVaultInvalidFeeShare",
|
|
1128
|
+
hint: "LP vault fee share basis points out of range. Must be 0\u201310,000 (0%\u2013100%)."
|
|
1129
|
+
},
|
|
1130
|
+
44: {
|
|
1131
|
+
name: "LpVaultNoNewFees",
|
|
1132
|
+
hint: "No new fees to distribute to LP vault. Wait for more trading activity to accrue fees."
|
|
1133
|
+
},
|
|
1134
|
+
// ── PERC-312 / PERC-314 / PERC-315 / PERC-309 / PERC-8111 / PERC-8110 (codes 45–60) ─────────
|
|
1135
|
+
45: {
|
|
1136
|
+
name: "SafetyValveDominantSideBlocked",
|
|
1137
|
+
hint: "New position on the dominant side is blocked while the market is rebalancing (safety valve)."
|
|
1138
|
+
},
|
|
1139
|
+
46: {
|
|
1140
|
+
name: "DisputeWindowClosed",
|
|
1141
|
+
hint: "The dispute window for this resolved market has closed."
|
|
1142
|
+
},
|
|
1143
|
+
47: {
|
|
1144
|
+
name: "DisputeAlreadyExists",
|
|
1145
|
+
hint: "A dispute already exists for this market \u2014 cannot open another."
|
|
1146
|
+
},
|
|
1147
|
+
48: {
|
|
1148
|
+
name: "MarketNotResolved",
|
|
1149
|
+
hint: "Market is not resolved \u2014 cannot dispute an active market."
|
|
1150
|
+
},
|
|
1151
|
+
49: {
|
|
1152
|
+
name: "NoActiveDispute",
|
|
1153
|
+
hint: "No active dispute found for this market."
|
|
1154
|
+
},
|
|
1155
|
+
50: {
|
|
1156
|
+
name: "LpCollateralDisabled",
|
|
1157
|
+
hint: "LP collateral is not enabled for this market."
|
|
1158
|
+
},
|
|
1159
|
+
51: {
|
|
1160
|
+
name: "LpCollateralPositionOpen",
|
|
1161
|
+
hint: "Cannot withdraw LP collateral while a position is still open."
|
|
1162
|
+
},
|
|
1163
|
+
52: {
|
|
1164
|
+
name: "WithdrawQueueAlreadyExists",
|
|
1165
|
+
hint: "A withdrawal queue entry already exists for this user/market."
|
|
1166
|
+
},
|
|
1167
|
+
53: {
|
|
1168
|
+
name: "WithdrawQueueNotFound",
|
|
1169
|
+
hint: "No queued withdrawal found for this user/market."
|
|
1170
|
+
},
|
|
1171
|
+
54: {
|
|
1172
|
+
name: "WithdrawQueueNothingClaimable",
|
|
1173
|
+
hint: "Nothing is claimable from the withdrawal queue this epoch \u2014 wait for the next epoch."
|
|
1174
|
+
},
|
|
1175
|
+
55: {
|
|
1176
|
+
name: "AuditViolation",
|
|
1177
|
+
hint: "Audit crank detected a conservation invariant violation \u2014 this is a critical internal error, please report it."
|
|
1178
|
+
},
|
|
1179
|
+
56: {
|
|
1180
|
+
name: "CrossMarginPairNotFound",
|
|
1181
|
+
hint: "Cross-margin offset pair is not configured for these two slabs."
|
|
1182
|
+
},
|
|
1183
|
+
57: {
|
|
1184
|
+
name: "CrossMarginAttestationStale",
|
|
1185
|
+
hint: "Cross-margin attestation is stale \u2014 too many slots have elapsed since the last attestation."
|
|
1186
|
+
},
|
|
1187
|
+
58: {
|
|
1188
|
+
name: "WalletPositionCapExceeded",
|
|
1189
|
+
hint: "Trade rejected: the resulting position would exceed the per-wallet position cap (max_wallet_pos_e6) for this market."
|
|
1190
|
+
},
|
|
1191
|
+
59: {
|
|
1192
|
+
name: "OiImbalanceHardBlock",
|
|
1193
|
+
hint: "Trade rejected: it would increase the OI imbalance (|long_oi \u2212 short_oi| / total_oi) beyond the configured hard-block threshold (oi_imbalance_hard_block_bps). Try the opposite side."
|
|
1194
|
+
},
|
|
1195
|
+
60: {
|
|
1196
|
+
name: "EngineInvalidEntryPrice",
|
|
1197
|
+
hint: "Entry price must be positive when opening a position."
|
|
1198
|
+
},
|
|
1199
|
+
61: {
|
|
1200
|
+
name: "EngineSideBlocked",
|
|
1201
|
+
hint: "New position blocked \u2014 this side is in DrainOnly or ResetPending mode. Wait for the market to stabilise."
|
|
1202
|
+
},
|
|
1203
|
+
62: {
|
|
1204
|
+
name: "EngineCorruptState",
|
|
1205
|
+
hint: "Engine detected a corrupt state invariant violation \u2014 this is a critical internal error, please report it."
|
|
1206
|
+
},
|
|
1207
|
+
63: {
|
|
1208
|
+
name: "InsuranceFundNotDepleted",
|
|
1209
|
+
hint: "ADL rejected \u2014 insurance fund is not fully depleted (balance > 0). ADL is only permitted once insurance is exhausted."
|
|
1210
|
+
},
|
|
1211
|
+
64: {
|
|
1212
|
+
name: "NoAdlCandidates",
|
|
1213
|
+
hint: "ADL rejected \u2014 no eligible candidate positions found for deleveraging."
|
|
1214
|
+
},
|
|
1215
|
+
65: {
|
|
1216
|
+
name: "BankruptPositionAlreadyClosed",
|
|
1217
|
+
hint: "ADL rejected \u2014 the target position is already closed (size == 0). Re-rank and pick a different target."
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
function decodeError(code) {
|
|
1221
|
+
return PERCOLATOR_ERRORS[code];
|
|
1222
|
+
}
|
|
1223
|
+
function getErrorName(code) {
|
|
1224
|
+
return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;
|
|
1225
|
+
}
|
|
1226
|
+
function getErrorHint(code) {
|
|
1227
|
+
return PERCOLATOR_ERRORS[code]?.hint;
|
|
1228
|
+
}
|
|
1229
|
+
var CUSTOM_ERROR_HEX_MAX_LEN = 8;
|
|
1230
|
+
function parseErrorFromLogs(logs) {
|
|
1231
|
+
if (!Array.isArray(logs)) {
|
|
1232
|
+
return null;
|
|
1233
|
+
}
|
|
1234
|
+
const re = new RegExp(
|
|
1235
|
+
`custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,
|
|
1236
|
+
"i"
|
|
1237
|
+
);
|
|
1238
|
+
for (const log of logs) {
|
|
1239
|
+
if (typeof log !== "string") {
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
const match = log.match(re);
|
|
1243
|
+
if (match) {
|
|
1244
|
+
const code = parseInt(match[1], 16);
|
|
1245
|
+
if (!Number.isFinite(code) || code < 0 || code > 4294967295) {
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
const info = decodeError(code);
|
|
1249
|
+
return {
|
|
1250
|
+
code,
|
|
1251
|
+
name: info?.name ?? `Unknown(${code})`,
|
|
1252
|
+
hint: info?.hint
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return null;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// src/solana/slab.ts
|
|
1260
|
+
import { PublicKey as PublicKey3 } from "@solana/web3.js";
|
|
1261
|
+
function dv(data) {
|
|
1262
|
+
return new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1263
|
+
}
|
|
1264
|
+
function readU8(data, off) {
|
|
1265
|
+
return data[off];
|
|
1266
|
+
}
|
|
1267
|
+
function readU16LE(data, off) {
|
|
1268
|
+
return dv(data).getUint16(off, true);
|
|
1269
|
+
}
|
|
1270
|
+
function readU32LE(data, off) {
|
|
1271
|
+
return dv(data).getUint32(off, true);
|
|
1272
|
+
}
|
|
1273
|
+
function readU64LE(data, off) {
|
|
1274
|
+
return dv(data).getBigUint64(off, true);
|
|
1275
|
+
}
|
|
1276
|
+
function readI64LE(data, off) {
|
|
1277
|
+
return dv(data).getBigInt64(off, true);
|
|
1278
|
+
}
|
|
1279
|
+
function readI128LE(buf, offset) {
|
|
1280
|
+
const lo = readU64LE(buf, offset);
|
|
1281
|
+
const hi = readU64LE(buf, offset + 8);
|
|
1282
|
+
const unsigned = hi << 64n | lo;
|
|
1283
|
+
const SIGN_BIT = 1n << 127n;
|
|
1284
|
+
if (unsigned >= SIGN_BIT) {
|
|
1285
|
+
return unsigned - (1n << 128n);
|
|
1286
|
+
}
|
|
1287
|
+
return unsigned;
|
|
1288
|
+
}
|
|
1289
|
+
function readU128LE(buf, offset) {
|
|
1290
|
+
const lo = readU64LE(buf, offset);
|
|
1291
|
+
const hi = readU64LE(buf, offset + 8);
|
|
1292
|
+
return hi << 64n | lo;
|
|
1293
|
+
}
|
|
1294
|
+
var MAGIC = 0x504552434f4c4154n;
|
|
1295
|
+
var FLAG_RESOLVED = 1 << 0;
|
|
1296
|
+
var V0_HEADER_LEN = 72;
|
|
1297
|
+
var V0_CONFIG_LEN = 408;
|
|
1298
|
+
var V0_ENGINE_OFF = 480;
|
|
1299
|
+
var V0_ACCOUNT_SIZE = 240;
|
|
1300
|
+
var V0_RESERVED_OFF = 48;
|
|
1301
|
+
var V0_ENGINE_PARAMS_OFF = 48;
|
|
1302
|
+
var V0_PARAMS_SIZE = 56;
|
|
1303
|
+
var V0_ENGINE_CURRENT_SLOT_OFF = 104;
|
|
1304
|
+
var V0_ENGINE_FUNDING_INDEX_OFF = 112;
|
|
1305
|
+
var V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;
|
|
1306
|
+
var V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;
|
|
1307
|
+
var V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;
|
|
1308
|
+
var V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;
|
|
1309
|
+
var V0_ENGINE_TOTAL_OI_OFF = 160;
|
|
1310
|
+
var V0_ENGINE_C_TOT_OFF = 176;
|
|
1311
|
+
var V0_ENGINE_PNL_POS_TOT_OFF = 192;
|
|
1312
|
+
var V0_ENGINE_LIQ_CURSOR_OFF = 208;
|
|
1313
|
+
var V0_ENGINE_GC_CURSOR_OFF = 210;
|
|
1314
|
+
var V0_ENGINE_LAST_SWEEP_START_OFF = 216;
|
|
1315
|
+
var V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;
|
|
1316
|
+
var V0_ENGINE_CRANK_CURSOR_OFF = 232;
|
|
1317
|
+
var V0_ENGINE_SWEEP_START_IDX_OFF = 234;
|
|
1318
|
+
var V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;
|
|
1319
|
+
var V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;
|
|
1320
|
+
var V0_ENGINE_NET_LP_POS_OFF = 256;
|
|
1321
|
+
var V0_ENGINE_LP_SUM_ABS_OFF = 272;
|
|
1322
|
+
var V0_ENGINE_LP_MAX_ABS_OFF = 288;
|
|
1323
|
+
var V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;
|
|
1324
|
+
var V0_ENGINE_BITMAP_OFF = 320;
|
|
1325
|
+
var V1_HEADER_LEN = 104;
|
|
1326
|
+
var V1_CONFIG_LEN = 496;
|
|
1327
|
+
var V1_ENGINE_OFF = 600;
|
|
1328
|
+
var V1_ENGINE_OFF_LEGACY = 640;
|
|
1329
|
+
var V1_ACCOUNT_SIZE = 248;
|
|
1330
|
+
var V1_RESERVED_OFF = 80;
|
|
1331
|
+
var V1_ENGINE_PARAMS_OFF = 72;
|
|
1332
|
+
var V1_PARAMS_SIZE = 288;
|
|
1333
|
+
var V1_ENGINE_CURRENT_SLOT_OFF = 360;
|
|
1334
|
+
var V1_ENGINE_FUNDING_INDEX_OFF = 368;
|
|
1335
|
+
var V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;
|
|
1336
|
+
var V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;
|
|
1337
|
+
var V1_ENGINE_MARK_PRICE_OFF = 400;
|
|
1338
|
+
var V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;
|
|
1339
|
+
var V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;
|
|
1340
|
+
var V1_ENGINE_TOTAL_OI_OFF = 440;
|
|
1341
|
+
var V1_ENGINE_LONG_OI_OFF = 456;
|
|
1342
|
+
var V1_ENGINE_SHORT_OI_OFF = 472;
|
|
1343
|
+
var V1_ENGINE_C_TOT_OFF = 488;
|
|
1344
|
+
var V1_ENGINE_PNL_POS_TOT_OFF = 504;
|
|
1345
|
+
var V1_ENGINE_LIQ_CURSOR_OFF = 520;
|
|
1346
|
+
var V1_ENGINE_GC_CURSOR_OFF = 522;
|
|
1347
|
+
var V1_ENGINE_LAST_SWEEP_START_OFF = 528;
|
|
1348
|
+
var V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;
|
|
1349
|
+
var V1_ENGINE_CRANK_CURSOR_OFF = 544;
|
|
1350
|
+
var V1_ENGINE_SWEEP_START_IDX_OFF = 546;
|
|
1351
|
+
var V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;
|
|
1352
|
+
var V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;
|
|
1353
|
+
var V1_ENGINE_NET_LP_POS_OFF = 568;
|
|
1354
|
+
var V1_ENGINE_LP_SUM_ABS_OFF = 584;
|
|
1355
|
+
var V1_ENGINE_LP_MAX_ABS_OFF = 600;
|
|
1356
|
+
var V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;
|
|
1357
|
+
var V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;
|
|
1358
|
+
var V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;
|
|
1359
|
+
var V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;
|
|
1360
|
+
var V1_ENGINE_BITMAP_OFF = 656;
|
|
1361
|
+
var V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672;
|
|
1362
|
+
var V1D_CONFIG_LEN = 320;
|
|
1363
|
+
var V1D_ENGINE_OFF = 424;
|
|
1364
|
+
var V1D_ACCOUNT_SIZE = 248;
|
|
1365
|
+
var V1D_ENGINE_INSURANCE_OFF = 16;
|
|
1366
|
+
var V1D_ENGINE_PARAMS_OFF = 96;
|
|
1367
|
+
var V1D_PARAMS_SIZE = 288;
|
|
1368
|
+
var V1D_ENGINE_CURRENT_SLOT_OFF = 384;
|
|
1369
|
+
var V1D_ENGINE_FUNDING_INDEX_OFF = 392;
|
|
1370
|
+
var V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;
|
|
1371
|
+
var V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;
|
|
1372
|
+
var V1D_ENGINE_MARK_PRICE_OFF = 424;
|
|
1373
|
+
var V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;
|
|
1374
|
+
var V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;
|
|
1375
|
+
var V1D_ENGINE_TOTAL_OI_OFF = 464;
|
|
1376
|
+
var V1D_ENGINE_LONG_OI_OFF = 480;
|
|
1377
|
+
var V1D_ENGINE_SHORT_OI_OFF = 496;
|
|
1378
|
+
var V1D_ENGINE_C_TOT_OFF = 512;
|
|
1379
|
+
var V1D_ENGINE_PNL_POS_TOT_OFF = 528;
|
|
1380
|
+
var V1D_ENGINE_LIQ_CURSOR_OFF = 544;
|
|
1381
|
+
var V1D_ENGINE_GC_CURSOR_OFF = 546;
|
|
1382
|
+
var V1D_ENGINE_LAST_SWEEP_START_OFF = 552;
|
|
1383
|
+
var V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;
|
|
1384
|
+
var V1D_ENGINE_CRANK_CURSOR_OFF = 568;
|
|
1385
|
+
var V1D_ENGINE_SWEEP_START_IDX_OFF = 570;
|
|
1386
|
+
var V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;
|
|
1387
|
+
var V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;
|
|
1388
|
+
var V1D_ENGINE_NET_LP_POS_OFF = 592;
|
|
1389
|
+
var V1D_ENGINE_LP_SUM_ABS_OFF = 608;
|
|
1390
|
+
var V1D_ENGINE_BITMAP_OFF = 624;
|
|
1391
|
+
var V2_HEADER_LEN = 104;
|
|
1392
|
+
var V2_CONFIG_LEN = 496;
|
|
1393
|
+
var V2_ENGINE_OFF = 600;
|
|
1394
|
+
var V2_ACCOUNT_SIZE = 248;
|
|
1395
|
+
var V2_ENGINE_BITMAP_OFF = 432;
|
|
1396
|
+
var V2_ENGINE_CURRENT_SLOT_OFF = 352;
|
|
1397
|
+
var V2_ENGINE_FUNDING_INDEX_OFF = 360;
|
|
1398
|
+
var V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;
|
|
1399
|
+
var V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;
|
|
1400
|
+
var V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;
|
|
1401
|
+
var V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;
|
|
1402
|
+
var V2_ENGINE_TOTAL_OI_OFF = 408;
|
|
1403
|
+
var V2_ENGINE_C_TOT_OFF = 424;
|
|
1404
|
+
var V2_ENGINE_PNL_POS_TOT_OFF = 440;
|
|
1405
|
+
var V2_ENGINE_LIQ_CURSOR_OFF = 456;
|
|
1406
|
+
var V2_ENGINE_GC_CURSOR_OFF = 458;
|
|
1407
|
+
var V2_ENGINE_LAST_SWEEP_START_OFF = 464;
|
|
1408
|
+
var V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;
|
|
1409
|
+
var V2_ENGINE_CRANK_CURSOR_OFF = 480;
|
|
1410
|
+
var V2_ENGINE_SWEEP_START_IDX_OFF = 482;
|
|
1411
|
+
var V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;
|
|
1412
|
+
var V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;
|
|
1413
|
+
var V2_ENGINE_NET_LP_POS_OFF = 504;
|
|
1414
|
+
var V2_ENGINE_LP_SUM_ABS_OFF = 520;
|
|
1415
|
+
var V2_ENGINE_LP_MAX_ABS_OFF = 536;
|
|
1416
|
+
var V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;
|
|
1417
|
+
var V_ADL_ENGINE_OFF = 624;
|
|
1418
|
+
var V_ADL_CONFIG_LEN = 520;
|
|
1419
|
+
var V_ADL_ACCOUNT_SIZE = 312;
|
|
1420
|
+
var V_ADL_ENGINE_PARAMS_OFF = 96;
|
|
1421
|
+
var V_ADL_PARAMS_SIZE = 336;
|
|
1422
|
+
var V_ADL_ENGINE_CURRENT_SLOT_OFF = 432;
|
|
1423
|
+
var V_ADL_ENGINE_FUNDING_INDEX_OFF = 440;
|
|
1424
|
+
var V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456;
|
|
1425
|
+
var V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464;
|
|
1426
|
+
var V_ADL_ENGINE_MARK_PRICE_OFF = 504;
|
|
1427
|
+
var V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528;
|
|
1428
|
+
var V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;
|
|
1429
|
+
var V_ADL_ENGINE_TOTAL_OI_OFF = 544;
|
|
1430
|
+
var V_ADL_ENGINE_LONG_OI_OFF = 560;
|
|
1431
|
+
var V_ADL_ENGINE_SHORT_OI_OFF = 576;
|
|
1432
|
+
var V_ADL_ENGINE_C_TOT_OFF = 592;
|
|
1433
|
+
var V_ADL_ENGINE_PNL_POS_TOT_OFF = 608;
|
|
1434
|
+
var V_ADL_ENGINE_LIQ_CURSOR_OFF = 640;
|
|
1435
|
+
var V_ADL_ENGINE_GC_CURSOR_OFF = 642;
|
|
1436
|
+
var V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;
|
|
1437
|
+
var V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;
|
|
1438
|
+
var V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;
|
|
1439
|
+
var V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;
|
|
1440
|
+
var V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;
|
|
1441
|
+
var V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;
|
|
1442
|
+
var V_ADL_ENGINE_NET_LP_POS_OFF = 904;
|
|
1443
|
+
var V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;
|
|
1444
|
+
var V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;
|
|
1445
|
+
var V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;
|
|
1446
|
+
var V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;
|
|
1447
|
+
var V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;
|
|
1448
|
+
var V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;
|
|
1449
|
+
var V_ADL_ENGINE_BITMAP_OFF = 1006;
|
|
1450
|
+
var V_ADL_ACCT_WARMUP_STARTED_OFF = 64;
|
|
1451
|
+
var V_ADL_ACCT_WARMUP_SLOPE_OFF = 72;
|
|
1452
|
+
var V_ADL_ACCT_POSITION_SIZE_OFF = 88;
|
|
1453
|
+
var V_ADL_ACCT_ENTRY_PRICE_OFF = 104;
|
|
1454
|
+
var V_ADL_ACCT_FUNDING_INDEX_OFF = 112;
|
|
1455
|
+
var V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128;
|
|
1456
|
+
var V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160;
|
|
1457
|
+
var V_ADL_ACCT_OWNER_OFF = 192;
|
|
1458
|
+
var V_ADL_ACCT_FEE_CREDITS_OFF = 224;
|
|
1459
|
+
var V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240;
|
|
1460
|
+
var V1M_ENGINE_OFF = 640;
|
|
1461
|
+
var V1M_CONFIG_LEN = 536;
|
|
1462
|
+
var V1M_ACCOUNT_SIZE = 248;
|
|
1463
|
+
var V1M_ENGINE_PARAMS_OFF = 72;
|
|
1464
|
+
var V1M_PARAMS_SIZE = 336;
|
|
1465
|
+
var V1M_ENGINE_CURRENT_SLOT_OFF = 408;
|
|
1466
|
+
var V1M_ENGINE_FUNDING_INDEX_OFF = 416;
|
|
1467
|
+
var V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;
|
|
1468
|
+
var V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;
|
|
1469
|
+
var V1M_ENGINE_MARK_PRICE_OFF = 448;
|
|
1470
|
+
var V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;
|
|
1471
|
+
var V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;
|
|
1472
|
+
var V1M_ENGINE_TOTAL_OI_OFF = 488;
|
|
1473
|
+
var V1M_ENGINE_LONG_OI_OFF = 504;
|
|
1474
|
+
var V1M_ENGINE_SHORT_OI_OFF = 520;
|
|
1475
|
+
var V1M_ENGINE_C_TOT_OFF = 536;
|
|
1476
|
+
var V1M_ENGINE_PNL_POS_TOT_OFF = 552;
|
|
1477
|
+
var V1M_ENGINE_LIQ_CURSOR_OFF = 568;
|
|
1478
|
+
var V1M_ENGINE_GC_CURSOR_OFF = 570;
|
|
1479
|
+
var V1M_ENGINE_LAST_SWEEP_START_OFF = 576;
|
|
1480
|
+
var V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;
|
|
1481
|
+
var V1M_ENGINE_CRANK_CURSOR_OFF = 592;
|
|
1482
|
+
var V1M_ENGINE_SWEEP_START_IDX_OFF = 594;
|
|
1483
|
+
var V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;
|
|
1484
|
+
var V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;
|
|
1485
|
+
var V1M_ENGINE_NET_LP_POS_OFF = 616;
|
|
1486
|
+
var V1M_ENGINE_LP_SUM_ABS_OFF = 632;
|
|
1487
|
+
var V1M_ENGINE_LP_MAX_ABS_OFF = 648;
|
|
1488
|
+
var V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;
|
|
1489
|
+
var V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;
|
|
1490
|
+
var V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;
|
|
1491
|
+
var V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;
|
|
1492
|
+
var V1M_ENGINE_BITMAP_OFF = 720;
|
|
1493
|
+
var ENGINE_OFF = V1_ENGINE_OFF;
|
|
1494
|
+
var ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;
|
|
1495
|
+
function computeSlabSize(engineOff, bitmapOff, accountSize, maxAccounts, postBitmap = 18) {
|
|
1496
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1497
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1498
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1499
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1500
|
+
const accountsOff = Math.ceil(preAccountsLen / 8) * 8;
|
|
1501
|
+
return engineOff + accountsOff + maxAccounts * accountSize;
|
|
1502
|
+
}
|
|
1503
|
+
var TIERS = [64, 256, 1024, 4096];
|
|
1504
|
+
var V0_SIZES = /* @__PURE__ */ new Map();
|
|
1505
|
+
var V1_SIZES = /* @__PURE__ */ new Map();
|
|
1506
|
+
var V1_SIZES_LEGACY = /* @__PURE__ */ new Map();
|
|
1507
|
+
var V1D_SIZES = /* @__PURE__ */ new Map();
|
|
1508
|
+
var V2_SIZES = /* @__PURE__ */ new Map();
|
|
1509
|
+
var V1M_SIZES = /* @__PURE__ */ new Map();
|
|
1510
|
+
var V_ADL_SIZES = /* @__PURE__ */ new Map();
|
|
1511
|
+
var V1D_SIZES_LEGACY = /* @__PURE__ */ new Map();
|
|
1512
|
+
for (const n of TIERS) {
|
|
1513
|
+
V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);
|
|
1514
|
+
V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);
|
|
1515
|
+
V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);
|
|
1516
|
+
V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);
|
|
1517
|
+
V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);
|
|
1518
|
+
V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);
|
|
1519
|
+
V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);
|
|
1520
|
+
V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);
|
|
1521
|
+
}
|
|
1522
|
+
var SLAB_TIERS_V2 = {
|
|
1523
|
+
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
|
|
1524
|
+
large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V2 BPF intermediate)" }
|
|
1525
|
+
};
|
|
1526
|
+
var SLAB_TIERS_V1M = {};
|
|
1527
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
1528
|
+
const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);
|
|
1529
|
+
SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };
|
|
1530
|
+
}
|
|
1531
|
+
var SLAB_TIERS_V_ADL = {};
|
|
1532
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
1533
|
+
const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);
|
|
1534
|
+
SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };
|
|
1535
|
+
}
|
|
1536
|
+
function buildLayout(version, maxAccounts, engineOffOverride) {
|
|
1537
|
+
const isV0 = version === 0;
|
|
1538
|
+
const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);
|
|
1539
|
+
const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;
|
|
1540
|
+
const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;
|
|
1541
|
+
const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL : isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;
|
|
1542
|
+
const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;
|
|
1543
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1544
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1545
|
+
const postBitmap = 18;
|
|
1546
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1547
|
+
const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1548
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
1549
|
+
return {
|
|
1550
|
+
version,
|
|
1551
|
+
headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,
|
|
1552
|
+
configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,
|
|
1553
|
+
configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,
|
|
1554
|
+
reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,
|
|
1555
|
+
engineOff,
|
|
1556
|
+
accountSize,
|
|
1557
|
+
maxAccounts,
|
|
1558
|
+
bitmapWords,
|
|
1559
|
+
accountsOff: engineOff + accountsOffRel,
|
|
1560
|
+
engineInsuranceOff: 16,
|
|
1561
|
+
engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,
|
|
1562
|
+
paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,
|
|
1563
|
+
engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,
|
|
1564
|
+
engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,
|
|
1565
|
+
engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1566
|
+
engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1567
|
+
engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,
|
|
1568
|
+
engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
1569
|
+
engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
1570
|
+
engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,
|
|
1571
|
+
engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,
|
|
1572
|
+
engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,
|
|
1573
|
+
engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,
|
|
1574
|
+
enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,
|
|
1575
|
+
engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,
|
|
1576
|
+
engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,
|
|
1577
|
+
engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,
|
|
1578
|
+
engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
1579
|
+
engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,
|
|
1580
|
+
engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,
|
|
1581
|
+
engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
1582
|
+
engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
1583
|
+
engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,
|
|
1584
|
+
engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,
|
|
1585
|
+
engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,
|
|
1586
|
+
engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
1587
|
+
engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
1588
|
+
engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
1589
|
+
engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
1590
|
+
engineBitmapOff: actualBitmapOff,
|
|
1591
|
+
postBitmap: 18,
|
|
1592
|
+
acctOwnerOff: ACCT_OWNER_OFF,
|
|
1593
|
+
hasInsuranceIsolation: !isV0,
|
|
1594
|
+
engineInsuranceIsolatedOff: isV0 ? -1 : 48,
|
|
1595
|
+
engineInsuranceIsolationBpsOff: isV0 ? -1 : 64
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
function buildLayoutV1D(maxAccounts, postBitmap = 2) {
|
|
1599
|
+
const engineOff = V1D_ENGINE_OFF;
|
|
1600
|
+
const bitmapOff = V1D_ENGINE_BITMAP_OFF;
|
|
1601
|
+
const accountSize = V1D_ACCOUNT_SIZE;
|
|
1602
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1603
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1604
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1605
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1606
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
1607
|
+
return {
|
|
1608
|
+
version: 1,
|
|
1609
|
+
headerLen: V1_HEADER_LEN,
|
|
1610
|
+
configOffset: V1_HEADER_LEN,
|
|
1611
|
+
configLen: V1D_CONFIG_LEN,
|
|
1612
|
+
reservedOff: V1_RESERVED_OFF,
|
|
1613
|
+
engineOff,
|
|
1614
|
+
accountSize,
|
|
1615
|
+
maxAccounts,
|
|
1616
|
+
bitmapWords,
|
|
1617
|
+
accountsOff: engineOff + accountsOffRel,
|
|
1618
|
+
engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,
|
|
1619
|
+
engineParamsOff: V1D_ENGINE_PARAMS_OFF,
|
|
1620
|
+
paramsSize: V1D_PARAMS_SIZE,
|
|
1621
|
+
engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,
|
|
1622
|
+
engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,
|
|
1623
|
+
engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1624
|
+
engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1625
|
+
engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,
|
|
1626
|
+
engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
1627
|
+
engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
1628
|
+
engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,
|
|
1629
|
+
engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,
|
|
1630
|
+
engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,
|
|
1631
|
+
engineCTotOff: V1D_ENGINE_C_TOT_OFF,
|
|
1632
|
+
enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,
|
|
1633
|
+
engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,
|
|
1634
|
+
engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,
|
|
1635
|
+
engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,
|
|
1636
|
+
engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
1637
|
+
engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,
|
|
1638
|
+
engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,
|
|
1639
|
+
engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
1640
|
+
engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
1641
|
+
engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,
|
|
1642
|
+
engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,
|
|
1643
|
+
engineLpMaxAbsOff: -1,
|
|
1644
|
+
// not present in deployed V1
|
|
1645
|
+
engineLpMaxAbsSweepOff: -1,
|
|
1646
|
+
// not present in deployed V1
|
|
1647
|
+
engineEmergencyOiModeOff: -1,
|
|
1648
|
+
// not present in deployed V1
|
|
1649
|
+
engineEmergencyStartSlotOff: -1,
|
|
1650
|
+
// not present in deployed V1
|
|
1651
|
+
engineLastBreakerSlotOff: -1,
|
|
1652
|
+
// not present in deployed V1
|
|
1653
|
+
engineBitmapOff: V1D_ENGINE_BITMAP_OFF,
|
|
1654
|
+
postBitmap,
|
|
1655
|
+
acctOwnerOff: ACCT_OWNER_OFF,
|
|
1656
|
+
hasInsuranceIsolation: true,
|
|
1657
|
+
engineInsuranceIsolatedOff: 48,
|
|
1658
|
+
// same within InsuranceFund
|
|
1659
|
+
engineInsuranceIsolationBpsOff: 64
|
|
1660
|
+
// same within InsuranceFund
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
function buildLayoutV2(maxAccounts) {
|
|
1664
|
+
const engineOff = V2_ENGINE_OFF;
|
|
1665
|
+
const bitmapOff = V2_ENGINE_BITMAP_OFF;
|
|
1666
|
+
const accountSize = V2_ACCOUNT_SIZE;
|
|
1667
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1668
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1669
|
+
const postBitmap = 18;
|
|
1670
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1671
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1672
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
1673
|
+
return {
|
|
1674
|
+
version: 2,
|
|
1675
|
+
headerLen: V2_HEADER_LEN,
|
|
1676
|
+
configOffset: V2_HEADER_LEN,
|
|
1677
|
+
configLen: V2_CONFIG_LEN,
|
|
1678
|
+
reservedOff: V1_RESERVED_OFF,
|
|
1679
|
+
// V2 shares V1's header layout (reserved at 80)
|
|
1680
|
+
engineOff,
|
|
1681
|
+
accountSize,
|
|
1682
|
+
maxAccounts,
|
|
1683
|
+
bitmapWords,
|
|
1684
|
+
accountsOff: engineOff + accountsOffRel,
|
|
1685
|
+
engineInsuranceOff: 16,
|
|
1686
|
+
engineParamsOff: V1_ENGINE_PARAMS_OFF,
|
|
1687
|
+
// same as V1: 72
|
|
1688
|
+
paramsSize: V1_PARAMS_SIZE,
|
|
1689
|
+
// same as V1: 288
|
|
1690
|
+
engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,
|
|
1691
|
+
engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,
|
|
1692
|
+
engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1693
|
+
engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1694
|
+
engineMarkPriceOff: -1,
|
|
1695
|
+
// V2 has no mark_price
|
|
1696
|
+
engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
1697
|
+
engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
1698
|
+
engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,
|
|
1699
|
+
engineLongOiOff: -1,
|
|
1700
|
+
// V2 has no long_oi
|
|
1701
|
+
engineShortOiOff: -1,
|
|
1702
|
+
// V2 has no short_oi
|
|
1703
|
+
engineCTotOff: V2_ENGINE_C_TOT_OFF,
|
|
1704
|
+
enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,
|
|
1705
|
+
engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,
|
|
1706
|
+
engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,
|
|
1707
|
+
engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,
|
|
1708
|
+
engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
1709
|
+
engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,
|
|
1710
|
+
engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,
|
|
1711
|
+
engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
1712
|
+
engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
1713
|
+
engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,
|
|
1714
|
+
engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,
|
|
1715
|
+
engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,
|
|
1716
|
+
engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
1717
|
+
engineEmergencyOiModeOff: -1,
|
|
1718
|
+
// V2 has no emergency OI fields
|
|
1719
|
+
engineEmergencyStartSlotOff: -1,
|
|
1720
|
+
engineLastBreakerSlotOff: -1,
|
|
1721
|
+
engineBitmapOff: V2_ENGINE_BITMAP_OFF,
|
|
1722
|
+
postBitmap: 18,
|
|
1723
|
+
acctOwnerOff: ACCT_OWNER_OFF,
|
|
1724
|
+
hasInsuranceIsolation: true,
|
|
1725
|
+
engineInsuranceIsolatedOff: 48,
|
|
1726
|
+
engineInsuranceIsolationBpsOff: 64
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function buildLayoutV1M(maxAccounts) {
|
|
1730
|
+
const engineOff = V1M_ENGINE_OFF;
|
|
1731
|
+
const bitmapOff = V1M_ENGINE_BITMAP_OFF;
|
|
1732
|
+
const accountSize = V1M_ACCOUNT_SIZE;
|
|
1733
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1734
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1735
|
+
const postBitmap = 18;
|
|
1736
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1737
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1738
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
1739
|
+
return {
|
|
1740
|
+
version: 1,
|
|
1741
|
+
headerLen: V1_HEADER_LEN,
|
|
1742
|
+
configOffset: V1_HEADER_LEN,
|
|
1743
|
+
configLen: V1M_CONFIG_LEN,
|
|
1744
|
+
reservedOff: V1_RESERVED_OFF,
|
|
1745
|
+
engineOff,
|
|
1746
|
+
accountSize,
|
|
1747
|
+
maxAccounts,
|
|
1748
|
+
bitmapWords,
|
|
1749
|
+
accountsOff: engineOff + accountsOffRel,
|
|
1750
|
+
engineInsuranceOff: 16,
|
|
1751
|
+
engineParamsOff: V1M_ENGINE_PARAMS_OFF,
|
|
1752
|
+
paramsSize: V1M_PARAMS_SIZE,
|
|
1753
|
+
engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,
|
|
1754
|
+
engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,
|
|
1755
|
+
engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1756
|
+
engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1757
|
+
engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,
|
|
1758
|
+
engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
1759
|
+
engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
1760
|
+
engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,
|
|
1761
|
+
engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,
|
|
1762
|
+
engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,
|
|
1763
|
+
engineCTotOff: V1M_ENGINE_C_TOT_OFF,
|
|
1764
|
+
enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,
|
|
1765
|
+
engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,
|
|
1766
|
+
engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,
|
|
1767
|
+
engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,
|
|
1768
|
+
engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
1769
|
+
engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,
|
|
1770
|
+
engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,
|
|
1771
|
+
engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
1772
|
+
engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
1773
|
+
engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,
|
|
1774
|
+
engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,
|
|
1775
|
+
engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,
|
|
1776
|
+
engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
1777
|
+
engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
1778
|
+
engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
1779
|
+
engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
1780
|
+
engineBitmapOff: V1M_ENGINE_BITMAP_OFF,
|
|
1781
|
+
postBitmap: 18,
|
|
1782
|
+
acctOwnerOff: ACCT_OWNER_OFF,
|
|
1783
|
+
hasInsuranceIsolation: true,
|
|
1784
|
+
engineInsuranceIsolatedOff: 48,
|
|
1785
|
+
engineInsuranceIsolationBpsOff: 64
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
function buildLayoutVADL(maxAccounts) {
|
|
1789
|
+
const engineOff = V_ADL_ENGINE_OFF;
|
|
1790
|
+
const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;
|
|
1791
|
+
const accountSize = V_ADL_ACCOUNT_SIZE;
|
|
1792
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
1793
|
+
const bitmapBytes = bitmapWords * 8;
|
|
1794
|
+
const postBitmap = 18;
|
|
1795
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
1796
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
1797
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
1798
|
+
return {
|
|
1799
|
+
version: 1,
|
|
1800
|
+
headerLen: V1_HEADER_LEN,
|
|
1801
|
+
// 104 (unchanged)
|
|
1802
|
+
configOffset: V1_HEADER_LEN,
|
|
1803
|
+
configLen: V_ADL_CONFIG_LEN,
|
|
1804
|
+
// 520
|
|
1805
|
+
reservedOff: V1_RESERVED_OFF,
|
|
1806
|
+
// 80
|
|
1807
|
+
engineOff,
|
|
1808
|
+
accountSize,
|
|
1809
|
+
maxAccounts,
|
|
1810
|
+
bitmapWords,
|
|
1811
|
+
accountsOff: engineOff + accountsOffRel,
|
|
1812
|
+
engineInsuranceOff: 16,
|
|
1813
|
+
engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,
|
|
1814
|
+
// 96 (vault=16 + InsuranceFund=80)
|
|
1815
|
+
paramsSize: V_ADL_PARAMS_SIZE,
|
|
1816
|
+
// 336
|
|
1817
|
+
engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,
|
|
1818
|
+
// 432
|
|
1819
|
+
engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,
|
|
1820
|
+
// 440
|
|
1821
|
+
engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1822
|
+
// 456
|
|
1823
|
+
engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1824
|
+
// 464
|
|
1825
|
+
engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,
|
|
1826
|
+
// 504
|
|
1827
|
+
engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
1828
|
+
// 528
|
|
1829
|
+
engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
1830
|
+
// 536
|
|
1831
|
+
engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,
|
|
1832
|
+
// 544
|
|
1833
|
+
engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,
|
|
1834
|
+
// 560
|
|
1835
|
+
engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,
|
|
1836
|
+
// 576
|
|
1837
|
+
engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,
|
|
1838
|
+
// 592
|
|
1839
|
+
enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,
|
|
1840
|
+
// 608
|
|
1841
|
+
engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,
|
|
1842
|
+
// 640
|
|
1843
|
+
engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,
|
|
1844
|
+
// 642
|
|
1845
|
+
engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,
|
|
1846
|
+
// 648
|
|
1847
|
+
engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
1848
|
+
// 656
|
|
1849
|
+
engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,
|
|
1850
|
+
// 664
|
|
1851
|
+
engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,
|
|
1852
|
+
// 666
|
|
1853
|
+
engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
1854
|
+
// 672
|
|
1855
|
+
engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
1856
|
+
// 680
|
|
1857
|
+
engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,
|
|
1858
|
+
// 904
|
|
1859
|
+
engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,
|
|
1860
|
+
// 920
|
|
1861
|
+
engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,
|
|
1862
|
+
// 936
|
|
1863
|
+
engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
1864
|
+
// 952
|
|
1865
|
+
engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
1866
|
+
// 968
|
|
1867
|
+
engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
1868
|
+
// 976
|
|
1869
|
+
engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
1870
|
+
// 984
|
|
1871
|
+
engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,
|
|
1872
|
+
// 1006
|
|
1873
|
+
postBitmap: 18,
|
|
1874
|
+
acctOwnerOff: V_ADL_ACCT_OWNER_OFF,
|
|
1875
|
+
// 192
|
|
1876
|
+
hasInsuranceIsolation: true,
|
|
1877
|
+
engineInsuranceIsolatedOff: 48,
|
|
1878
|
+
engineInsuranceIsolationBpsOff: 64
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
function detectSlabLayout(dataLen, data) {
|
|
1882
|
+
const vadln = V_ADL_SIZES.get(dataLen);
|
|
1883
|
+
if (vadln !== void 0) return buildLayoutVADL(vadln);
|
|
1884
|
+
const v1mn = V1M_SIZES.get(dataLen);
|
|
1885
|
+
if (v1mn !== void 0) return buildLayoutV1M(v1mn);
|
|
1886
|
+
const v0n = V0_SIZES.get(dataLen);
|
|
1887
|
+
if (v0n !== void 0) return buildLayout(0, v0n);
|
|
1888
|
+
const v1dn = V1D_SIZES.get(dataLen);
|
|
1889
|
+
if (v1dn !== void 0) {
|
|
1890
|
+
if (data && data.length >= 12) {
|
|
1891
|
+
const version = readU32LE(data, 8);
|
|
1892
|
+
if (version === 2) return buildLayoutV2(v1dn);
|
|
1893
|
+
}
|
|
1894
|
+
return buildLayoutV1D(v1dn, 2);
|
|
1895
|
+
}
|
|
1896
|
+
const v1dln = V1D_SIZES_LEGACY.get(dataLen);
|
|
1897
|
+
if (v1dln !== void 0) return buildLayoutV1D(v1dln, 18);
|
|
1898
|
+
const v1n = V1_SIZES.get(dataLen);
|
|
1899
|
+
if (v1n !== void 0) return buildLayout(1, v1n);
|
|
1900
|
+
const v1ln = V1_SIZES_LEGACY.get(dataLen);
|
|
1901
|
+
if (v1ln !== void 0) return buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY);
|
|
1902
|
+
return null;
|
|
1903
|
+
}
|
|
1904
|
+
function detectLayout(dataLen) {
|
|
1905
|
+
const layout = detectSlabLayout(dataLen);
|
|
1906
|
+
if (!layout) return null;
|
|
1907
|
+
return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };
|
|
1908
|
+
}
|
|
1909
|
+
var PARAMS_WARMUP_PERIOD_OFF = 0;
|
|
1910
|
+
var PARAMS_MAINTENANCE_MARGIN_OFF = 8;
|
|
1911
|
+
var PARAMS_INITIAL_MARGIN_OFF = 16;
|
|
1912
|
+
var PARAMS_TRADING_FEE_OFF = 24;
|
|
1913
|
+
var PARAMS_MAX_ACCOUNTS_OFF = 32;
|
|
1914
|
+
var PARAMS_NEW_ACCOUNT_FEE_OFF = 40;
|
|
1915
|
+
var PARAMS_RISK_THRESHOLD_OFF = 56;
|
|
1916
|
+
var PARAMS_MAINTENANCE_FEE_OFF = 72;
|
|
1917
|
+
var PARAMS_MAX_CRANK_STALENESS_OFF = 88;
|
|
1918
|
+
var PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;
|
|
1919
|
+
var PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;
|
|
1920
|
+
var PARAMS_LIQUIDATION_BUFFER_OFF = 120;
|
|
1921
|
+
var PARAMS_MIN_LIQUIDATION_OFF = 128;
|
|
1922
|
+
var ACCT_ACCOUNT_ID_OFF = 0;
|
|
1923
|
+
var ACCT_CAPITAL_OFF = 8;
|
|
1924
|
+
var ACCT_KIND_OFF = 24;
|
|
1925
|
+
var ACCT_PNL_OFF = 32;
|
|
1926
|
+
var ACCT_RESERVED_PNL_OFF = 48;
|
|
1927
|
+
var ACCT_WARMUP_STARTED_OFF = 56;
|
|
1928
|
+
var ACCT_WARMUP_SLOPE_OFF = 64;
|
|
1929
|
+
var ACCT_POSITION_SIZE_OFF = 80;
|
|
1930
|
+
var ACCT_ENTRY_PRICE_OFF = 96;
|
|
1931
|
+
var ACCT_FUNDING_INDEX_OFF = 104;
|
|
1932
|
+
var ACCT_MATCHER_PROGRAM_OFF = 120;
|
|
1933
|
+
var ACCT_MATCHER_CONTEXT_OFF = 152;
|
|
1934
|
+
var ACCT_OWNER_OFF = 184;
|
|
1935
|
+
var ACCT_FEE_CREDITS_OFF = 216;
|
|
1936
|
+
var ACCT_LAST_FEE_SLOT_OFF = 232;
|
|
1937
|
+
var AccountKind = /* @__PURE__ */ ((AccountKind2) => {
|
|
1938
|
+
AccountKind2[AccountKind2["User"] = 0] = "User";
|
|
1939
|
+
AccountKind2[AccountKind2["LP"] = 1] = "LP";
|
|
1940
|
+
return AccountKind2;
|
|
1941
|
+
})(AccountKind || {});
|
|
1942
|
+
async function fetchSlab(connection, slabPubkey) {
|
|
1943
|
+
const info = await connection.getAccountInfo(slabPubkey);
|
|
1944
|
+
if (!info) {
|
|
1945
|
+
throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);
|
|
1946
|
+
}
|
|
1947
|
+
return new Uint8Array(info.data);
|
|
1948
|
+
}
|
|
1949
|
+
var RAMP_START_BPS = 1000n;
|
|
1950
|
+
var DEFAULT_OI_RAMP_SLOTS = 432000n;
|
|
1951
|
+
function computeEffectiveOiCapBps(config, currentSlot) {
|
|
1952
|
+
const target = config.oiCapMultiplierBps;
|
|
1953
|
+
if (target === 0n) return 0n;
|
|
1954
|
+
if (config.oiRampSlots === 0n) return target;
|
|
1955
|
+
if (target <= RAMP_START_BPS) return target;
|
|
1956
|
+
const elapsed = currentSlot > config.marketCreatedSlot ? currentSlot - config.marketCreatedSlot : 0n;
|
|
1957
|
+
if (elapsed >= config.oiRampSlots) return target;
|
|
1958
|
+
const range = target - RAMP_START_BPS;
|
|
1959
|
+
const rampAdd = range * elapsed / config.oiRampSlots;
|
|
1960
|
+
const result = RAMP_START_BPS + rampAdd;
|
|
1961
|
+
return result < target ? result : target;
|
|
1962
|
+
}
|
|
1963
|
+
function readNonce(data) {
|
|
1964
|
+
const layout = detectSlabLayout(data.length);
|
|
1965
|
+
if (!layout) {
|
|
1966
|
+
throw new Error(`readNonce: unrecognized slab data length ${data.length}`);
|
|
1967
|
+
}
|
|
1968
|
+
const roff = layout.reservedOff;
|
|
1969
|
+
if (data.length < roff + 8) throw new Error("Slab data too short for nonce");
|
|
1970
|
+
return readU64LE(data, roff);
|
|
1971
|
+
}
|
|
1972
|
+
function readLastThrUpdateSlot(data) {
|
|
1973
|
+
const layout = detectSlabLayout(data.length);
|
|
1974
|
+
if (!layout) {
|
|
1975
|
+
throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);
|
|
1976
|
+
}
|
|
1977
|
+
const roff = layout.reservedOff;
|
|
1978
|
+
if (data.length < roff + 16) throw new Error("Slab data too short for lastThrUpdateSlot");
|
|
1979
|
+
return readU64LE(data, roff + 8);
|
|
1980
|
+
}
|
|
1981
|
+
function parseHeader(data) {
|
|
1982
|
+
if (data.length < V0_HEADER_LEN) {
|
|
1983
|
+
throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);
|
|
1984
|
+
}
|
|
1985
|
+
const magic = readU64LE(data, 0);
|
|
1986
|
+
if (magic !== MAGIC) {
|
|
1987
|
+
throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);
|
|
1988
|
+
}
|
|
1989
|
+
const version = readU32LE(data, 8);
|
|
1990
|
+
const bump = readU8(data, 12);
|
|
1991
|
+
const flags = readU8(data, 13);
|
|
1992
|
+
const admin = new PublicKey3(data.subarray(16, 48));
|
|
1993
|
+
const layout = detectSlabLayout(data.length);
|
|
1994
|
+
const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;
|
|
1995
|
+
const nonce = readU64LE(data, roff);
|
|
1996
|
+
const lastThrUpdateSlot = readU64LE(data, roff + 8);
|
|
1997
|
+
return {
|
|
1998
|
+
magic,
|
|
1999
|
+
version,
|
|
2000
|
+
bump,
|
|
2001
|
+
flags,
|
|
2002
|
+
resolved: (flags & FLAG_RESOLVED) !== 0,
|
|
2003
|
+
paused: (flags & 2) !== 0,
|
|
2004
|
+
admin,
|
|
2005
|
+
nonce,
|
|
2006
|
+
lastThrUpdateSlot
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
function parseConfig(data, layoutHint) {
|
|
2010
|
+
const layout = layoutHint !== void 0 ? layoutHint : detectSlabLayout(data.length);
|
|
2011
|
+
const configOff = layout ? layout.configOffset : V0_HEADER_LEN;
|
|
2012
|
+
const configLen = layout ? layout.configLen : V0_CONFIG_LEN;
|
|
2013
|
+
const minLen = configOff + Math.min(configLen, 120);
|
|
2014
|
+
if (data.length < minLen) {
|
|
2015
|
+
throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);
|
|
2016
|
+
}
|
|
2017
|
+
let off = configOff;
|
|
2018
|
+
const collateralMint = new PublicKey3(data.subarray(off, off + 32));
|
|
2019
|
+
off += 32;
|
|
2020
|
+
const vaultPubkey = new PublicKey3(data.subarray(off, off + 32));
|
|
2021
|
+
off += 32;
|
|
2022
|
+
const indexFeedId = new PublicKey3(data.subarray(off, off + 32));
|
|
2023
|
+
off += 32;
|
|
2024
|
+
const maxStalenessSlots = readU64LE(data, off);
|
|
2025
|
+
off += 8;
|
|
2026
|
+
const confFilterBps = readU16LE(data, off);
|
|
2027
|
+
off += 2;
|
|
2028
|
+
const vaultAuthorityBump = readU8(data, off);
|
|
2029
|
+
off += 1;
|
|
2030
|
+
const invert = readU8(data, off);
|
|
2031
|
+
off += 1;
|
|
2032
|
+
const unitScale = readU32LE(data, off);
|
|
2033
|
+
off += 4;
|
|
2034
|
+
const fundingHorizonSlots = readU64LE(data, off);
|
|
2035
|
+
off += 8;
|
|
2036
|
+
const fundingKBps = readU64LE(data, off);
|
|
2037
|
+
off += 8;
|
|
2038
|
+
const fundingInvScaleNotionalE6 = readU128LE(data, off);
|
|
2039
|
+
off += 16;
|
|
2040
|
+
const fundingMaxPremiumBps = readI64LE(data, off);
|
|
2041
|
+
off += 8;
|
|
2042
|
+
const fundingMaxBpsPerSlot = readI64LE(data, off);
|
|
2043
|
+
off += 8;
|
|
2044
|
+
const fundingPremiumWeightBps = readU64LE(data, off);
|
|
2045
|
+
off += 8;
|
|
2046
|
+
const fundingSettlementIntervalSlots = readU64LE(data, off);
|
|
2047
|
+
off += 8;
|
|
2048
|
+
const fundingPremiumDampeningE6 = readU64LE(data, off);
|
|
2049
|
+
off += 8;
|
|
2050
|
+
const fundingPremiumMaxBpsPerSlot = readU64LE(data, off);
|
|
2051
|
+
off += 8;
|
|
2052
|
+
const threshFloor = readU128LE(data, off);
|
|
2053
|
+
off += 16;
|
|
2054
|
+
const threshRiskBps = readU64LE(data, off);
|
|
2055
|
+
off += 8;
|
|
2056
|
+
const threshUpdateIntervalSlots = readU64LE(data, off);
|
|
2057
|
+
off += 8;
|
|
2058
|
+
const threshStepBps = readU64LE(data, off);
|
|
2059
|
+
off += 8;
|
|
2060
|
+
const threshAlphaBps = readU64LE(data, off);
|
|
2061
|
+
off += 8;
|
|
2062
|
+
const threshMin = readU128LE(data, off);
|
|
2063
|
+
off += 16;
|
|
2064
|
+
const threshMax = readU128LE(data, off);
|
|
2065
|
+
off += 16;
|
|
2066
|
+
const threshMinStep = readU128LE(data, off);
|
|
2067
|
+
off += 16;
|
|
2068
|
+
const oracleAuthority = new PublicKey3(data.subarray(off, off + 32));
|
|
2069
|
+
off += 32;
|
|
2070
|
+
const authorityPriceE6 = readU64LE(data, off);
|
|
2071
|
+
off += 8;
|
|
2072
|
+
const authorityTimestamp = readI64LE(data, off);
|
|
2073
|
+
off += 8;
|
|
2074
|
+
const oraclePriceCapE2bps = readU64LE(data, off);
|
|
2075
|
+
off += 8;
|
|
2076
|
+
const lastEffectivePriceE6 = readU64LE(data, off);
|
|
2077
|
+
off += 8;
|
|
2078
|
+
const oiCapMultiplierBps = readU64LE(data, off);
|
|
2079
|
+
off += 8;
|
|
2080
|
+
const maxPnlCap = readU64LE(data, off);
|
|
2081
|
+
off += 8;
|
|
2082
|
+
const remaining = configOff + configLen - off;
|
|
2083
|
+
let adaptiveFundingEnabled = false;
|
|
2084
|
+
let adaptiveScaleBps = 0;
|
|
2085
|
+
let adaptiveMaxFundingBps = 0n;
|
|
2086
|
+
let marketCreatedSlot = 0n;
|
|
2087
|
+
let oiRampSlots = 0n;
|
|
2088
|
+
let resolvedSlot = 0n;
|
|
2089
|
+
let insuranceIsolationBps = 0;
|
|
2090
|
+
let oraclePhase = 0;
|
|
2091
|
+
let cumulativeVolumeE6 = 0n;
|
|
2092
|
+
let phase2DeltaSlots = 0;
|
|
2093
|
+
if (remaining >= 40) {
|
|
2094
|
+
marketCreatedSlot = readU64LE(data, off);
|
|
2095
|
+
off += 8;
|
|
2096
|
+
oiRampSlots = readU64LE(data, off);
|
|
2097
|
+
off += 8;
|
|
2098
|
+
adaptiveFundingEnabled = readU8(data, off) !== 0;
|
|
2099
|
+
off += 1;
|
|
2100
|
+
off += 1;
|
|
2101
|
+
adaptiveScaleBps = readU16LE(data, off);
|
|
2102
|
+
off += 2;
|
|
2103
|
+
off += 4;
|
|
2104
|
+
adaptiveMaxFundingBps = readU64LE(data, off);
|
|
2105
|
+
off += 8;
|
|
2106
|
+
if (remaining >= 42) {
|
|
2107
|
+
insuranceIsolationBps = readU16LE(data, off);
|
|
2108
|
+
if (remaining >= 56) {
|
|
2109
|
+
const padOff = off + 2;
|
|
2110
|
+
oraclePhase = Math.min(readU8(data, padOff + 2), 2);
|
|
2111
|
+
cumulativeVolumeE6 = readU64LE(data, padOff + 3);
|
|
2112
|
+
phase2DeltaSlots = data[padOff + 11] | data[padOff + 12] << 8 | data[padOff + 13] << 16;
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return {
|
|
2117
|
+
collateralMint,
|
|
2118
|
+
vaultPubkey,
|
|
2119
|
+
indexFeedId,
|
|
2120
|
+
maxStalenessSlots,
|
|
2121
|
+
confFilterBps,
|
|
2122
|
+
vaultAuthorityBump,
|
|
2123
|
+
invert,
|
|
2124
|
+
unitScale,
|
|
2125
|
+
fundingHorizonSlots,
|
|
2126
|
+
fundingKBps,
|
|
2127
|
+
fundingInvScaleNotionalE6,
|
|
2128
|
+
fundingMaxPremiumBps,
|
|
2129
|
+
fundingMaxBpsPerSlot,
|
|
2130
|
+
fundingPremiumWeightBps,
|
|
2131
|
+
fundingSettlementIntervalSlots,
|
|
2132
|
+
fundingPremiumDampeningE6,
|
|
2133
|
+
fundingPremiumMaxBpsPerSlot,
|
|
2134
|
+
threshFloor,
|
|
2135
|
+
threshRiskBps,
|
|
2136
|
+
threshUpdateIntervalSlots,
|
|
2137
|
+
threshStepBps,
|
|
2138
|
+
threshAlphaBps,
|
|
2139
|
+
threshMin,
|
|
2140
|
+
threshMax,
|
|
2141
|
+
threshMinStep,
|
|
2142
|
+
oracleAuthority,
|
|
2143
|
+
authorityPriceE6,
|
|
2144
|
+
authorityTimestamp,
|
|
2145
|
+
oraclePriceCapE2bps,
|
|
2146
|
+
lastEffectivePriceE6,
|
|
2147
|
+
oiCapMultiplierBps,
|
|
2148
|
+
maxPnlCap,
|
|
2149
|
+
adaptiveFundingEnabled,
|
|
2150
|
+
adaptiveScaleBps,
|
|
2151
|
+
adaptiveMaxFundingBps,
|
|
2152
|
+
marketCreatedSlot,
|
|
2153
|
+
oiRampSlots,
|
|
2154
|
+
resolvedSlot,
|
|
2155
|
+
insuranceIsolationBps,
|
|
2156
|
+
oraclePhase,
|
|
2157
|
+
cumulativeVolumeE6,
|
|
2158
|
+
phase2DeltaSlots
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
function parseParams(data, layoutHint) {
|
|
2162
|
+
const layout = layoutHint !== void 0 ? layoutHint : detectSlabLayout(data.length);
|
|
2163
|
+
const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;
|
|
2164
|
+
const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;
|
|
2165
|
+
const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;
|
|
2166
|
+
const base = engineOff + paramsOff;
|
|
2167
|
+
if (data.length < base + Math.min(paramsSize, 56)) {
|
|
2168
|
+
throw new Error("Slab data too short for RiskParams");
|
|
2169
|
+
}
|
|
2170
|
+
const result = {
|
|
2171
|
+
warmupPeriodSlots: readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2172
|
+
maintenanceMarginBps: readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),
|
|
2173
|
+
initialMarginBps: readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),
|
|
2174
|
+
tradingFeeBps: readU64LE(data, base + PARAMS_TRADING_FEE_OFF),
|
|
2175
|
+
maxAccounts: readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2176
|
+
newAccountFee: readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),
|
|
2177
|
+
// Extended params: only read if V1 (paramsSize >= 144)
|
|
2178
|
+
riskReductionThreshold: 0n,
|
|
2179
|
+
maintenanceFeePerSlot: 0n,
|
|
2180
|
+
maxCrankStalenessSlots: 0n,
|
|
2181
|
+
liquidationFeeBps: 0n,
|
|
2182
|
+
liquidationFeeCap: 0n,
|
|
2183
|
+
liquidationBufferBps: 0n,
|
|
2184
|
+
minLiquidationAbs: 0n
|
|
2185
|
+
};
|
|
2186
|
+
if (paramsSize >= 144) {
|
|
2187
|
+
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2188
|
+
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
2189
|
+
result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);
|
|
2190
|
+
result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);
|
|
2191
|
+
result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);
|
|
2192
|
+
result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);
|
|
2193
|
+
result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);
|
|
2194
|
+
}
|
|
2195
|
+
return result;
|
|
2196
|
+
}
|
|
2197
|
+
function parseEngine(data) {
|
|
2198
|
+
const layout = detectSlabLayout(data.length);
|
|
2199
|
+
if (!layout) {
|
|
2200
|
+
throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);
|
|
2201
|
+
}
|
|
2202
|
+
const base = layout.engineOff;
|
|
2203
|
+
return {
|
|
2204
|
+
vault: readU128LE(data, base),
|
|
2205
|
+
insuranceFund: {
|
|
2206
|
+
balance: readU128LE(data, base + layout.engineInsuranceOff),
|
|
2207
|
+
feeRevenue: readU128LE(data, base + layout.engineInsuranceOff + 16),
|
|
2208
|
+
isolatedBalance: layout.hasInsuranceIsolation ? readU128LE(data, base + layout.engineInsuranceIsolatedOff) : 0n,
|
|
2209
|
+
isolationBps: layout.hasInsuranceIsolation ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff) : 0
|
|
2210
|
+
},
|
|
2211
|
+
currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),
|
|
2212
|
+
fundingIndexQpbE6: readI128LE(data, base + layout.engineFundingIndexOff),
|
|
2213
|
+
lastFundingSlot: readU64LE(data, base + layout.engineLastFundingSlotOff),
|
|
2214
|
+
fundingRateBpsPerSlotLast: readI64LE(data, base + layout.engineFundingRateBpsOff),
|
|
2215
|
+
lastCrankSlot: readU64LE(data, base + layout.engineLastCrankSlotOff),
|
|
2216
|
+
maxCrankStalenessSlots: readU64LE(data, base + layout.engineMaxCrankStalenessOff),
|
|
2217
|
+
totalOpenInterest: readU128LE(data, base + layout.engineTotalOiOff),
|
|
2218
|
+
longOi: layout.engineLongOiOff >= 0 ? readU128LE(data, base + layout.engineLongOiOff) : 0n,
|
|
2219
|
+
shortOi: layout.engineShortOiOff >= 0 ? readU128LE(data, base + layout.engineShortOiOff) : 0n,
|
|
2220
|
+
cTot: readU128LE(data, base + layout.engineCTotOff),
|
|
2221
|
+
pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),
|
|
2222
|
+
liqCursor: readU16LE(data, base + layout.engineLiqCursorOff),
|
|
2223
|
+
gcCursor: readU16LE(data, base + layout.engineGcCursorOff),
|
|
2224
|
+
lastSweepStartSlot: readU64LE(data, base + layout.engineLastSweepStartOff),
|
|
2225
|
+
lastSweepCompleteSlot: readU64LE(data, base + layout.engineLastSweepCompleteOff),
|
|
2226
|
+
crankCursor: readU16LE(data, base + layout.engineCrankCursorOff),
|
|
2227
|
+
sweepStartIdx: readU16LE(data, base + layout.engineSweepStartIdxOff),
|
|
2228
|
+
lifetimeLiquidations: readU64LE(data, base + layout.engineLifetimeLiquidationsOff),
|
|
2229
|
+
lifetimeForceCloses: readU64LE(data, base + layout.engineLifetimeForceClosesOff),
|
|
2230
|
+
netLpPos: readI128LE(data, base + layout.engineNetLpPosOff),
|
|
2231
|
+
lpSumAbs: readU128LE(data, base + layout.engineLpSumAbsOff),
|
|
2232
|
+
lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,
|
|
2233
|
+
lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,
|
|
2234
|
+
emergencyOiMode: layout.engineEmergencyOiModeOff >= 0 ? data[base + layout.engineEmergencyOiModeOff] !== 0 : false,
|
|
2235
|
+
emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0 ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,
|
|
2236
|
+
lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0 ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,
|
|
2237
|
+
markPriceE6: layout.engineMarkPriceOff >= 0 ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,
|
|
2238
|
+
numUsedAccounts: (() => {
|
|
2239
|
+
if (layout.postBitmap < 18) return 0;
|
|
2240
|
+
const bw = layout.bitmapWords;
|
|
2241
|
+
return readU16LE(data, base + layout.engineBitmapOff + bw * 8);
|
|
2242
|
+
})(),
|
|
2243
|
+
nextAccountId: (() => {
|
|
2244
|
+
if (layout.postBitmap < 18) return 0n;
|
|
2245
|
+
const bw = layout.bitmapWords;
|
|
2246
|
+
const numUsedOff = layout.engineBitmapOff + bw * 8;
|
|
2247
|
+
return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);
|
|
2248
|
+
})()
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
function parseUsedIndices(data) {
|
|
2252
|
+
const layout = detectSlabLayout(data.length);
|
|
2253
|
+
if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);
|
|
2254
|
+
const base = layout.engineOff + layout.engineBitmapOff;
|
|
2255
|
+
if (data.length < base + layout.bitmapWords * 8) {
|
|
2256
|
+
throw new Error("Slab data too short for bitmap");
|
|
2257
|
+
}
|
|
2258
|
+
const used = [];
|
|
2259
|
+
for (let word = 0; word < layout.bitmapWords; word++) {
|
|
2260
|
+
const bits = readU64LE(data, base + word * 8);
|
|
2261
|
+
if (bits === 0n) continue;
|
|
2262
|
+
for (let bit = 0; bit < 64; bit++) {
|
|
2263
|
+
if (bits >> BigInt(bit) & 1n) {
|
|
2264
|
+
used.push(word * 64 + bit);
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
return used;
|
|
2269
|
+
}
|
|
2270
|
+
function isAccountUsed(data, idx) {
|
|
2271
|
+
const layout = detectSlabLayout(data.length);
|
|
2272
|
+
if (!layout) return false;
|
|
2273
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;
|
|
2274
|
+
const base = layout.engineOff + layout.engineBitmapOff;
|
|
2275
|
+
const word = Math.floor(idx / 64);
|
|
2276
|
+
const bit = idx % 64;
|
|
2277
|
+
const bits = readU64LE(data, base + word * 8);
|
|
2278
|
+
return (bits >> BigInt(bit) & 1n) !== 0n;
|
|
2279
|
+
}
|
|
2280
|
+
function maxAccountIndex(dataLen) {
|
|
2281
|
+
const layout = detectSlabLayout(dataLen);
|
|
2282
|
+
if (!layout) return 0;
|
|
2283
|
+
const accountsEnd = dataLen - layout.accountsOff;
|
|
2284
|
+
if (accountsEnd <= 0) return 0;
|
|
2285
|
+
return Math.floor(accountsEnd / layout.accountSize);
|
|
2286
|
+
}
|
|
2287
|
+
function parseAccount(data, idx) {
|
|
2288
|
+
const layout = detectSlabLayout(data.length);
|
|
2289
|
+
if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);
|
|
2290
|
+
const maxIdx = maxAccountIndex(data.length);
|
|
2291
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {
|
|
2292
|
+
throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);
|
|
2293
|
+
}
|
|
2294
|
+
const base = layout.accountsOff + idx * layout.accountSize;
|
|
2295
|
+
if (data.length < base + layout.accountSize) {
|
|
2296
|
+
throw new Error("Slab data too short for account");
|
|
2297
|
+
}
|
|
2298
|
+
const isAdl = layout.accountSize >= 312;
|
|
2299
|
+
const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
|
|
2300
|
+
const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;
|
|
2301
|
+
const positionSizeOff = isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2302
|
+
const entryPriceOff = isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2303
|
+
const fundingIndexOff = isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2304
|
+
const matcherProgOff = isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2305
|
+
const matcherCtxOff = isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2306
|
+
const feeCreditsOff = isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2307
|
+
const lastFeeSlotOff = isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2308
|
+
const kindByte = readU8(data, base + ACCT_KIND_OFF);
|
|
2309
|
+
const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2310
|
+
return {
|
|
2311
|
+
kind,
|
|
2312
|
+
accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),
|
|
2313
|
+
capital: readU128LE(data, base + ACCT_CAPITAL_OFF),
|
|
2314
|
+
pnl: readI128LE(data, base + ACCT_PNL_OFF),
|
|
2315
|
+
reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),
|
|
2316
|
+
warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),
|
|
2317
|
+
warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
|
|
2318
|
+
positionSize: readI128LE(data, base + positionSizeOff),
|
|
2319
|
+
entryPrice: readU64LE(data, base + entryPriceOff),
|
|
2320
|
+
fundingIndex: readI128LE(data, base + fundingIndexOff),
|
|
2321
|
+
matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
|
|
2322
|
+
matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
|
|
2323
|
+
owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
|
|
2324
|
+
feeCredits: readI128LE(data, base + feeCreditsOff),
|
|
2325
|
+
lastFeeSlot: readU64LE(data, base + lastFeeSlotOff)
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
function parseAllAccounts(data) {
|
|
2329
|
+
const indices = parseUsedIndices(data);
|
|
2330
|
+
const maxIdx = maxAccountIndex(data.length);
|
|
2331
|
+
const validIndices = indices.filter((idx) => idx < maxIdx);
|
|
2332
|
+
const droppedCount = indices.length - validIndices.length;
|
|
2333
|
+
if (droppedCount > 0) {
|
|
2334
|
+
console.warn(
|
|
2335
|
+
`[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit in the slab \u2014 ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
return validIndices.map((idx) => ({
|
|
2339
|
+
idx,
|
|
2340
|
+
account: parseAccount(data, idx)
|
|
2341
|
+
}));
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
// src/solana/pda.ts
|
|
2345
|
+
import { PublicKey as PublicKey4 } from "@solana/web3.js";
|
|
2346
|
+
var textEncoder = new TextEncoder();
|
|
2347
|
+
function deriveVaultAuthority(programId, slab) {
|
|
2348
|
+
return PublicKey4.findProgramAddressSync(
|
|
2349
|
+
[textEncoder.encode("vault"), slab.toBytes()],
|
|
2350
|
+
programId
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
function deriveInsuranceLpMint(programId, slab) {
|
|
2354
|
+
return PublicKey4.findProgramAddressSync(
|
|
2355
|
+
[textEncoder.encode("ins_lp"), slab.toBytes()],
|
|
2356
|
+
programId
|
|
2357
|
+
);
|
|
2358
|
+
}
|
|
2359
|
+
var LP_INDEX_U16_MAX = 65535;
|
|
2360
|
+
function deriveLpPda(programId, slab, lpIdx) {
|
|
2361
|
+
if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
|
|
2362
|
+
throw new Error(
|
|
2363
|
+
`deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
const idxBuf = new Uint8Array(2);
|
|
2367
|
+
new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);
|
|
2368
|
+
return PublicKey4.findProgramAddressSync(
|
|
2369
|
+
[textEncoder.encode("lp"), slab.toBytes(), idxBuf],
|
|
2370
|
+
programId
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
function deriveKeeperFund(programId, slab) {
|
|
2374
|
+
return PublicKey4.findProgramAddressSync(
|
|
2375
|
+
[textEncoder.encode("keeper_fund"), slab.toBytes()],
|
|
2376
|
+
programId
|
|
2377
|
+
);
|
|
2378
|
+
}
|
|
2379
|
+
var PUMPSWAP_PROGRAM_ID = new PublicKey4(
|
|
2380
|
+
"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
|
|
2381
|
+
);
|
|
2382
|
+
var RAYDIUM_CLMM_PROGRAM_ID = new PublicKey4(
|
|
2383
|
+
"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK"
|
|
2384
|
+
);
|
|
2385
|
+
var METEORA_DLMM_PROGRAM_ID = new PublicKey4(
|
|
2386
|
+
"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo"
|
|
2387
|
+
);
|
|
2388
|
+
var PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey4(
|
|
2389
|
+
"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT"
|
|
2390
|
+
);
|
|
2391
|
+
var CREATOR_LOCK_SEED = "creator_lock";
|
|
2392
|
+
function deriveCreatorLockPda(programId, slab) {
|
|
2393
|
+
return PublicKey4.findProgramAddressSync(
|
|
2394
|
+
[textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],
|
|
2395
|
+
programId
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
function normalizePythFeedIdHex(feedIdHex) {
|
|
2399
|
+
let s = feedIdHex.trim();
|
|
2400
|
+
if (s.startsWith("0x") || s.startsWith("0X")) {
|
|
2401
|
+
s = s.slice(2);
|
|
2402
|
+
}
|
|
2403
|
+
return s;
|
|
2404
|
+
}
|
|
2405
|
+
var FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
2406
|
+
function derivePythPushOraclePDA(feedIdHex) {
|
|
2407
|
+
const normalized = normalizePythFeedIdHex(feedIdHex);
|
|
2408
|
+
if (!FEED_HEX_RE.test(normalized)) {
|
|
2409
|
+
throw new Error(
|
|
2410
|
+
`derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? "non-hexadecimal characters" : normalized.length + " chars"}`
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
const feedId = new Uint8Array(32);
|
|
2414
|
+
for (let i = 0; i < 32; i++) {
|
|
2415
|
+
feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);
|
|
2416
|
+
}
|
|
2417
|
+
const shardBuf = new Uint8Array(2);
|
|
2418
|
+
return PublicKey4.findProgramAddressSync(
|
|
2419
|
+
[shardBuf, feedId],
|
|
2420
|
+
PYTH_PUSH_ORACLE_PROGRAM_ID
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// src/solana/ata.ts
|
|
2425
|
+
import {
|
|
2426
|
+
getAssociatedTokenAddress,
|
|
2427
|
+
getAssociatedTokenAddressSync,
|
|
2428
|
+
getAccount,
|
|
2429
|
+
TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID2
|
|
2430
|
+
} from "@solana/spl-token";
|
|
2431
|
+
async function getAta(owner, mint, allowOwnerOffCurve = false, tokenProgramId = TOKEN_PROGRAM_ID2) {
|
|
2432
|
+
return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);
|
|
2433
|
+
}
|
|
2434
|
+
function getAtaSync(owner, mint, allowOwnerOffCurve = false, tokenProgramId = TOKEN_PROGRAM_ID2) {
|
|
2435
|
+
return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);
|
|
2436
|
+
}
|
|
2437
|
+
async function fetchTokenAccount(connection, address, tokenProgramId = TOKEN_PROGRAM_ID2) {
|
|
2438
|
+
return getAccount(connection, address, void 0, tokenProgramId);
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// src/solana/discovery.ts
|
|
2442
|
+
var ENGINE_BITMAP_OFF_V0 = 320;
|
|
2443
|
+
var MAGIC_BYTES = new Uint8Array([84, 65, 76, 79, 67, 82, 69, 80]);
|
|
2444
|
+
var SLAB_TIERS = {
|
|
2445
|
+
small: { maxAccounts: 256, dataSize: 65352, label: "Small", description: "256 slots \xB7 ~0.45 SOL" },
|
|
2446
|
+
medium: { maxAccounts: 1024, dataSize: 257448, label: "Medium", description: "1,024 slots \xB7 ~1.79 SOL" },
|
|
2447
|
+
large: { maxAccounts: 4096, dataSize: 1025832, label: "Large", description: "4,096 slots \xB7 ~7.14 SOL" }
|
|
2448
|
+
};
|
|
2449
|
+
var SLAB_TIERS_V0 = {
|
|
2450
|
+
small: { maxAccounts: 256, dataSize: 62808, label: "Small", description: "256 slots \xB7 ~0.44 SOL" },
|
|
2451
|
+
medium: { maxAccounts: 1024, dataSize: 248760, label: "Medium", description: "1,024 slots \xB7 ~1.73 SOL" },
|
|
2452
|
+
large: { maxAccounts: 4096, dataSize: 992568, label: "Large", description: "4,096 slots \xB7 ~6.90 SOL" }
|
|
2453
|
+
};
|
|
2454
|
+
var SLAB_TIERS_V1D = {
|
|
2455
|
+
micro: { maxAccounts: 64, dataSize: 17064, label: "Micro", description: "64 slots (V1D devnet)" },
|
|
2456
|
+
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V1D devnet)" },
|
|
2457
|
+
medium: { maxAccounts: 1024, dataSize: 257184, label: "Medium", description: "1,024 slots (V1D devnet)" },
|
|
2458
|
+
large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V1D devnet)" }
|
|
2459
|
+
};
|
|
2460
|
+
var SLAB_TIERS_V1D_LEGACY = {
|
|
2461
|
+
micro: { maxAccounts: 64, dataSize: 17080, label: "Micro", description: "64 slots (V1D legacy, postBitmap=18)" },
|
|
2462
|
+
small: { maxAccounts: 256, dataSize: 65104, label: "Small", description: "256 slots (V1D legacy, postBitmap=18)" },
|
|
2463
|
+
medium: { maxAccounts: 1024, dataSize: 257200, label: "Medium", description: "1,024 slots (V1D legacy, postBitmap=18)" },
|
|
2464
|
+
large: { maxAccounts: 4096, dataSize: 1025584, label: "Large", description: "4,096 slots (V1D legacy, postBitmap=18)" }
|
|
2465
|
+
};
|
|
2466
|
+
var SLAB_TIERS_V1 = SLAB_TIERS;
|
|
2467
|
+
var SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;
|
|
2468
|
+
function slabDataSize(maxAccounts) {
|
|
2469
|
+
const ENGINE_OFF_V0 = 480;
|
|
2470
|
+
const ENGINE_BITMAP_OFF_V02 = 320;
|
|
2471
|
+
const ACCOUNT_SIZE_V0 = 240;
|
|
2472
|
+
const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;
|
|
2473
|
+
const postBitmap = 18;
|
|
2474
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
2475
|
+
const preAccountsLen = ENGINE_BITMAP_OFF_V02 + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2476
|
+
const accountsOff = Math.ceil(preAccountsLen / 8) * 8;
|
|
2477
|
+
return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;
|
|
2478
|
+
}
|
|
2479
|
+
function slabDataSizeV1(maxAccounts) {
|
|
2480
|
+
const ENGINE_OFF_V1 = 640;
|
|
2481
|
+
const ENGINE_BITMAP_OFF_V1 = 656;
|
|
2482
|
+
const ACCOUNT_SIZE_V1 = 248;
|
|
2483
|
+
const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;
|
|
2484
|
+
const postBitmap = 18;
|
|
2485
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
2486
|
+
const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2487
|
+
const accountsOff = Math.ceil(preAccountsLen / 8) * 8;
|
|
2488
|
+
return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;
|
|
2489
|
+
}
|
|
2490
|
+
function validateSlabTierMatch(dataSize, programSlabLen) {
|
|
2491
|
+
return dataSize === programSlabLen;
|
|
2492
|
+
}
|
|
2493
|
+
var ALL_SLAB_SIZES = [
|
|
2494
|
+
...Object.values(SLAB_TIERS).map((t) => t.dataSize),
|
|
2495
|
+
...Object.values(SLAB_TIERS_V0).map((t) => t.dataSize),
|
|
2496
|
+
...Object.values(SLAB_TIERS_V1D).map((t) => t.dataSize),
|
|
2497
|
+
...Object.values(SLAB_TIERS_V1D_LEGACY).map((t) => t.dataSize),
|
|
2498
|
+
...Object.values(SLAB_TIERS_V1M).map((t) => t.dataSize),
|
|
2499
|
+
...Object.values(SLAB_TIERS_V_ADL).map((t) => t.dataSize)
|
|
2500
|
+
];
|
|
2501
|
+
var SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;
|
|
2502
|
+
var HEADER_SLICE_LENGTH = 1940;
|
|
2503
|
+
function dv2(data) {
|
|
2504
|
+
return new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
2505
|
+
}
|
|
2506
|
+
function readU16LE2(data, off) {
|
|
2507
|
+
return dv2(data).getUint16(off, true);
|
|
2508
|
+
}
|
|
2509
|
+
function readU64LE2(data, off) {
|
|
2510
|
+
return dv2(data).getBigUint64(off, true);
|
|
2511
|
+
}
|
|
2512
|
+
function readI64LE2(data, off) {
|
|
2513
|
+
return dv2(data).getBigInt64(off, true);
|
|
2514
|
+
}
|
|
2515
|
+
function readU128LE2(buf, offset) {
|
|
2516
|
+
const lo = readU64LE2(buf, offset);
|
|
2517
|
+
const hi = readU64LE2(buf, offset + 8);
|
|
2518
|
+
return hi << 64n | lo;
|
|
2519
|
+
}
|
|
2520
|
+
function readI128LE2(buf, offset) {
|
|
2521
|
+
const lo = readU64LE2(buf, offset);
|
|
2522
|
+
const hi = readU64LE2(buf, offset + 8);
|
|
2523
|
+
const unsigned = hi << 64n | lo;
|
|
2524
|
+
const SIGN_BIT = 1n << 127n;
|
|
2525
|
+
if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);
|
|
2526
|
+
return unsigned;
|
|
2527
|
+
}
|
|
2528
|
+
function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
2529
|
+
const isV0 = !layout || layout.version === 0;
|
|
2530
|
+
const base = layout ? layout.engineOff : 480;
|
|
2531
|
+
const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;
|
|
2532
|
+
const minLen = base + bitmapOff;
|
|
2533
|
+
if (data.length < minLen) {
|
|
2534
|
+
throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);
|
|
2535
|
+
}
|
|
2536
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2537
|
+
const numUsedOff = bitmapOff + bitmapWords * 8;
|
|
2538
|
+
const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8;
|
|
2539
|
+
const canReadNumUsed = data.length >= base + numUsedOff + 2;
|
|
2540
|
+
const canReadNextId = data.length >= base + nextAccountIdOff + 8;
|
|
2541
|
+
if (isV0) {
|
|
2542
|
+
return {
|
|
2543
|
+
vault: readU128LE2(data, base + 0),
|
|
2544
|
+
insuranceFund: {
|
|
2545
|
+
balance: readU128LE2(data, base + 16),
|
|
2546
|
+
feeRevenue: readU128LE2(data, base + 32),
|
|
2547
|
+
isolatedBalance: 0n,
|
|
2548
|
+
isolationBps: 0
|
|
2549
|
+
},
|
|
2550
|
+
currentSlot: readU64LE2(data, base + 104),
|
|
2551
|
+
fundingIndexQpbE6: readI128LE2(data, base + 112),
|
|
2552
|
+
lastFundingSlot: readU64LE2(data, base + 128),
|
|
2553
|
+
fundingRateBpsPerSlotLast: readI64LE2(data, base + 136),
|
|
2554
|
+
lastCrankSlot: readU64LE2(data, base + 144),
|
|
2555
|
+
maxCrankStalenessSlots: readU64LE2(data, base + 152),
|
|
2556
|
+
totalOpenInterest: readU128LE2(data, base + 160),
|
|
2557
|
+
longOi: 0n,
|
|
2558
|
+
shortOi: 0n,
|
|
2559
|
+
cTot: readU128LE2(data, base + 176),
|
|
2560
|
+
pnlPosTot: readU128LE2(data, base + 192),
|
|
2561
|
+
liqCursor: readU16LE2(data, base + 208),
|
|
2562
|
+
gcCursor: readU16LE2(data, base + 210),
|
|
2563
|
+
lastSweepStartSlot: readU64LE2(data, base + 216),
|
|
2564
|
+
lastSweepCompleteSlot: readU64LE2(data, base + 224),
|
|
2565
|
+
crankCursor: readU16LE2(data, base + 232),
|
|
2566
|
+
sweepStartIdx: readU16LE2(data, base + 234),
|
|
2567
|
+
lifetimeLiquidations: readU64LE2(data, base + 240),
|
|
2568
|
+
lifetimeForceCloses: readU64LE2(data, base + 248),
|
|
2569
|
+
netLpPos: readI128LE2(data, base + 256),
|
|
2570
|
+
lpSumAbs: readU128LE2(data, base + 272),
|
|
2571
|
+
lpMaxAbs: readU128LE2(data, base + 288),
|
|
2572
|
+
lpMaxAbsSweep: 0n,
|
|
2573
|
+
emergencyOiMode: false,
|
|
2574
|
+
emergencyStartSlot: 0n,
|
|
2575
|
+
lastBreakerSlot: 0n,
|
|
2576
|
+
markPriceE6: 0n,
|
|
2577
|
+
// V0 engine has no mark_price field
|
|
2578
|
+
numUsedAccounts: canReadNumUsed ? readU16LE2(data, base + numUsedOff) : 0,
|
|
2579
|
+
nextAccountId: canReadNextId ? readU64LE2(data, base + nextAccountIdOff) : 0n
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
const isV2 = layout?.version === 2;
|
|
2583
|
+
if (isV2) {
|
|
2584
|
+
return {
|
|
2585
|
+
vault: readU128LE2(data, base + 0),
|
|
2586
|
+
insuranceFund: {
|
|
2587
|
+
balance: readU128LE2(data, base + 16),
|
|
2588
|
+
feeRevenue: readU128LE2(data, base + 32),
|
|
2589
|
+
isolatedBalance: readU128LE2(data, base + 48),
|
|
2590
|
+
isolationBps: readU16LE2(data, base + 64)
|
|
2591
|
+
},
|
|
2592
|
+
currentSlot: readU64LE2(data, base + 352),
|
|
2593
|
+
fundingIndexQpbE6: readI128LE2(data, base + 360),
|
|
2594
|
+
lastFundingSlot: readU64LE2(data, base + 376),
|
|
2595
|
+
fundingRateBpsPerSlotLast: readI64LE2(data, base + 384),
|
|
2596
|
+
lastCrankSlot: readU64LE2(data, base + 392),
|
|
2597
|
+
maxCrankStalenessSlots: readU64LE2(data, base + 400),
|
|
2598
|
+
totalOpenInterest: readU128LE2(data, base + 408),
|
|
2599
|
+
longOi: 0n,
|
|
2600
|
+
// V2 has no long_oi
|
|
2601
|
+
shortOi: 0n,
|
|
2602
|
+
// V2 has no short_oi
|
|
2603
|
+
cTot: readU128LE2(data, base + 424),
|
|
2604
|
+
pnlPosTot: readU128LE2(data, base + 440),
|
|
2605
|
+
liqCursor: readU16LE2(data, base + 456),
|
|
2606
|
+
gcCursor: readU16LE2(data, base + 458),
|
|
2607
|
+
lastSweepStartSlot: readU64LE2(data, base + 464),
|
|
2608
|
+
lastSweepCompleteSlot: readU64LE2(data, base + 472),
|
|
2609
|
+
crankCursor: readU16LE2(data, base + 480),
|
|
2610
|
+
sweepStartIdx: readU16LE2(data, base + 482),
|
|
2611
|
+
lifetimeLiquidations: readU64LE2(data, base + 488),
|
|
2612
|
+
lifetimeForceCloses: readU64LE2(data, base + 496),
|
|
2613
|
+
netLpPos: readI128LE2(data, base + 504),
|
|
2614
|
+
lpSumAbs: readU128LE2(data, base + 520),
|
|
2615
|
+
lpMaxAbs: readU128LE2(data, base + 536),
|
|
2616
|
+
lpMaxAbsSweep: readU128LE2(data, base + 552),
|
|
2617
|
+
emergencyOiMode: false,
|
|
2618
|
+
// V2 has no emergency OI fields
|
|
2619
|
+
emergencyStartSlot: 0n,
|
|
2620
|
+
lastBreakerSlot: 0n,
|
|
2621
|
+
markPriceE6: 0n,
|
|
2622
|
+
// V2 has no mark_price
|
|
2623
|
+
numUsedAccounts: canReadNumUsed ? readU16LE2(data, base + numUsedOff) : 0,
|
|
2624
|
+
nextAccountId: canReadNextId ? readU64LE2(data, base + nextAccountIdOff) : 0n
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
const isVAdl = layout !== null && layout.engineOff === 624 && layout.accountSize === 312;
|
|
2628
|
+
if (isVAdl) {
|
|
2629
|
+
const l = layout;
|
|
2630
|
+
return {
|
|
2631
|
+
vault: readU128LE2(data, base + 0),
|
|
2632
|
+
insuranceFund: {
|
|
2633
|
+
balance: readU128LE2(data, base + l.engineInsuranceOff),
|
|
2634
|
+
feeRevenue: readU128LE2(data, base + l.engineInsuranceOff + 16),
|
|
2635
|
+
isolatedBalance: readU128LE2(data, base + l.engineInsuranceIsolatedOff),
|
|
2636
|
+
isolationBps: readU16LE2(data, base + l.engineInsuranceIsolationBpsOff)
|
|
2637
|
+
},
|
|
2638
|
+
currentSlot: readU64LE2(data, base + l.engineCurrentSlotOff),
|
|
2639
|
+
fundingIndexQpbE6: readI128LE2(data, base + l.engineFundingIndexOff),
|
|
2640
|
+
lastFundingSlot: readU64LE2(data, base + l.engineLastFundingSlotOff),
|
|
2641
|
+
fundingRateBpsPerSlotLast: readI64LE2(data, base + l.engineFundingRateBpsOff),
|
|
2642
|
+
lastCrankSlot: readU64LE2(data, base + l.engineLastCrankSlotOff),
|
|
2643
|
+
maxCrankStalenessSlots: readU64LE2(data, base + l.engineMaxCrankStalenessOff),
|
|
2644
|
+
totalOpenInterest: readU128LE2(data, base + l.engineTotalOiOff),
|
|
2645
|
+
longOi: l.engineLongOiOff >= 0 ? readU128LE2(data, base + l.engineLongOiOff) : 0n,
|
|
2646
|
+
shortOi: l.engineShortOiOff >= 0 ? readU128LE2(data, base + l.engineShortOiOff) : 0n,
|
|
2647
|
+
cTot: readU128LE2(data, base + l.engineCTotOff),
|
|
2648
|
+
pnlPosTot: readU128LE2(data, base + l.enginePnlPosTotOff),
|
|
2649
|
+
liqCursor: readU16LE2(data, base + l.engineLiqCursorOff),
|
|
2650
|
+
gcCursor: readU16LE2(data, base + l.engineGcCursorOff),
|
|
2651
|
+
lastSweepStartSlot: readU64LE2(data, base + l.engineLastSweepStartOff),
|
|
2652
|
+
lastSweepCompleteSlot: readU64LE2(data, base + l.engineLastSweepCompleteOff),
|
|
2653
|
+
crankCursor: readU16LE2(data, base + l.engineCrankCursorOff),
|
|
2654
|
+
sweepStartIdx: readU16LE2(data, base + l.engineSweepStartIdxOff),
|
|
2655
|
+
lifetimeLiquidations: readU64LE2(data, base + l.engineLifetimeLiquidationsOff),
|
|
2656
|
+
lifetimeForceCloses: readU64LE2(data, base + l.engineLifetimeForceClosesOff),
|
|
2657
|
+
netLpPos: readI128LE2(data, base + l.engineNetLpPosOff),
|
|
2658
|
+
lpSumAbs: readU128LE2(data, base + l.engineLpSumAbsOff),
|
|
2659
|
+
lpMaxAbs: readU128LE2(data, base + l.engineLpMaxAbsOff),
|
|
2660
|
+
lpMaxAbsSweep: readU128LE2(data, base + l.engineLpMaxAbsSweepOff),
|
|
2661
|
+
emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,
|
|
2662
|
+
emergencyStartSlot: l.engineEmergencyStartSlotOff >= 0 ? readU64LE2(data, base + l.engineEmergencyStartSlotOff) : 0n,
|
|
2663
|
+
lastBreakerSlot: l.engineLastBreakerSlotOff >= 0 ? readU64LE2(data, base + l.engineLastBreakerSlotOff) : 0n,
|
|
2664
|
+
markPriceE6: l.engineMarkPriceOff >= 0 ? readU64LE2(data, base + l.engineMarkPriceOff) : 0n,
|
|
2665
|
+
numUsedAccounts: canReadNumUsed ? readU16LE2(data, base + numUsedOff) : 0,
|
|
2666
|
+
nextAccountId: canReadNextId ? readU64LE2(data, base + nextAccountIdOff) : 0n
|
|
2667
|
+
};
|
|
2668
|
+
}
|
|
2669
|
+
return {
|
|
2670
|
+
vault: readU128LE2(data, base + 0),
|
|
2671
|
+
insuranceFund: {
|
|
2672
|
+
balance: readU128LE2(data, base + 16),
|
|
2673
|
+
feeRevenue: readU128LE2(data, base + 32),
|
|
2674
|
+
isolatedBalance: readU128LE2(data, base + 48),
|
|
2675
|
+
isolationBps: readU16LE2(data, base + 64)
|
|
2676
|
+
},
|
|
2677
|
+
currentSlot: readU64LE2(data, base + 360),
|
|
2678
|
+
// PERC-1094: params end at 72+288=360 (was 352)
|
|
2679
|
+
fundingIndexQpbE6: readI128LE2(data, base + 368),
|
|
2680
|
+
lastFundingSlot: readU64LE2(data, base + 384),
|
|
2681
|
+
fundingRateBpsPerSlotLast: readI64LE2(data, base + 392),
|
|
2682
|
+
lastCrankSlot: readU64LE2(data, base + 424),
|
|
2683
|
+
maxCrankStalenessSlots: readU64LE2(data, base + 408),
|
|
2684
|
+
totalOpenInterest: readU128LE2(data, base + 416),
|
|
2685
|
+
longOi: readU128LE2(data, base + 432),
|
|
2686
|
+
shortOi: readU128LE2(data, base + 448),
|
|
2687
|
+
cTot: readU128LE2(data, base + 464),
|
|
2688
|
+
pnlPosTot: readU128LE2(data, base + 480),
|
|
2689
|
+
liqCursor: readU16LE2(data, base + 496),
|
|
2690
|
+
gcCursor: readU16LE2(data, base + 498),
|
|
2691
|
+
lastSweepStartSlot: readU64LE2(data, base + 504),
|
|
2692
|
+
lastSweepCompleteSlot: readU64LE2(data, base + 512),
|
|
2693
|
+
crankCursor: readU16LE2(data, base + 520),
|
|
2694
|
+
sweepStartIdx: readU16LE2(data, base + 522),
|
|
2695
|
+
lifetimeLiquidations: readU64LE2(data, base + 528),
|
|
2696
|
+
lifetimeForceCloses: readU64LE2(data, base + 536),
|
|
2697
|
+
netLpPos: readI128LE2(data, base + 544),
|
|
2698
|
+
lpSumAbs: readU128LE2(data, base + 560),
|
|
2699
|
+
lpMaxAbs: readU128LE2(data, base + 576),
|
|
2700
|
+
lpMaxAbsSweep: readU128LE2(data, base + 592),
|
|
2701
|
+
emergencyOiMode: data[base + 608] !== 0,
|
|
2702
|
+
emergencyStartSlot: readU64LE2(data, base + 616),
|
|
2703
|
+
lastBreakerSlot: readU64LE2(data, base + 624),
|
|
2704
|
+
markPriceE6: readU64LE2(data, base + 400),
|
|
2705
|
+
// PERC-1094: was 392
|
|
2706
|
+
numUsedAccounts: canReadNumUsed ? readU16LE2(data, base + numUsedOff) : 0,
|
|
2707
|
+
nextAccountId: canReadNextId ? readU64LE2(data, base + nextAccountIdOff) : 0n
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
function isRateLimitError(err) {
|
|
2711
|
+
if (!err) return false;
|
|
2712
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2713
|
+
return msg.includes("429") || msg.toLowerCase().includes("rate limit") || msg.toLowerCase().includes("too many requests");
|
|
2714
|
+
}
|
|
2715
|
+
function withJitter(delayMs) {
|
|
2716
|
+
return delayMs + Math.floor(Math.random() * delayMs * 0.25);
|
|
2717
|
+
}
|
|
2718
|
+
async function discoverMarkets(connection, programId, options = {}) {
|
|
2719
|
+
const {
|
|
2720
|
+
sequential = false,
|
|
2721
|
+
interTierDelayMs = 200,
|
|
2722
|
+
rateLimitBackoffMs = [1e3, 3e3, 9e3, 27e3],
|
|
2723
|
+
maxParallelTiers = 6
|
|
2724
|
+
} = options;
|
|
2725
|
+
const ALL_TIERS = [
|
|
2726
|
+
...Object.values(SLAB_TIERS),
|
|
2727
|
+
...Object.values(SLAB_TIERS_V0),
|
|
2728
|
+
...Object.values(SLAB_TIERS_V1D),
|
|
2729
|
+
...Object.values(SLAB_TIERS_V1D_LEGACY),
|
|
2730
|
+
...Object.values(SLAB_TIERS_V2),
|
|
2731
|
+
...Object.values(SLAB_TIERS_V1M),
|
|
2732
|
+
...Object.values(SLAB_TIERS_V_ADL)
|
|
2733
|
+
];
|
|
2734
|
+
let rawAccounts = [];
|
|
2735
|
+
async function fetchTierWithRetry(tier) {
|
|
2736
|
+
for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {
|
|
2737
|
+
try {
|
|
2738
|
+
const results = await connection.getProgramAccounts(programId, {
|
|
2739
|
+
filters: [{ dataSize: tier.dataSize }],
|
|
2740
|
+
dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH }
|
|
2741
|
+
});
|
|
2742
|
+
return results.map((entry) => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));
|
|
2743
|
+
} catch (err) {
|
|
2744
|
+
if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {
|
|
2745
|
+
const delay = withJitter(rateLimitBackoffMs[attempt]);
|
|
2746
|
+
console.warn(
|
|
2747
|
+
`[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`
|
|
2748
|
+
);
|
|
2749
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
2750
|
+
continue;
|
|
2751
|
+
}
|
|
2752
|
+
console.warn(
|
|
2753
|
+
`[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,
|
|
2754
|
+
err instanceof Error ? err.message : err
|
|
2755
|
+
);
|
|
2756
|
+
return [];
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
return [];
|
|
2760
|
+
}
|
|
2761
|
+
const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;
|
|
2762
|
+
const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);
|
|
2763
|
+
const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);
|
|
2764
|
+
try {
|
|
2765
|
+
if (sequential) {
|
|
2766
|
+
for (let i = 0; i < tiersToQuery.length; i++) {
|
|
2767
|
+
const tier = tiersToQuery[i];
|
|
2768
|
+
const entries = await fetchTierWithRetry(tier);
|
|
2769
|
+
rawAccounts.push(...entries);
|
|
2770
|
+
if (i < tiersToQuery.length - 1) {
|
|
2771
|
+
await new Promise((r) => setTimeout(r, interTierDelayMs));
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
} else {
|
|
2775
|
+
for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {
|
|
2776
|
+
const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);
|
|
2777
|
+
const queries = chunk.map(
|
|
2778
|
+
(tier) => connection.getProgramAccounts(programId, {
|
|
2779
|
+
filters: [{ dataSize: tier.dataSize }],
|
|
2780
|
+
dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH }
|
|
2781
|
+
}).then(
|
|
2782
|
+
(results2) => results2.map((entry) => ({
|
|
2783
|
+
...entry,
|
|
2784
|
+
maxAccounts: tier.maxAccounts,
|
|
2785
|
+
dataSize: tier.dataSize
|
|
2786
|
+
}))
|
|
2787
|
+
)
|
|
2788
|
+
);
|
|
2789
|
+
const results = await Promise.allSettled(queries);
|
|
2790
|
+
for (const result of results) {
|
|
2791
|
+
if (result.status === "fulfilled") {
|
|
2792
|
+
for (const entry of result.value) {
|
|
2793
|
+
rawAccounts.push(entry);
|
|
2794
|
+
}
|
|
2795
|
+
} else {
|
|
2796
|
+
console.warn(
|
|
2797
|
+
"[discoverMarkets] Tier query rejected:",
|
|
2798
|
+
result.reason instanceof Error ? result.reason.message : result.reason
|
|
2799
|
+
);
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
if (rawAccounts.length === 0) {
|
|
2805
|
+
console.warn("[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp");
|
|
2806
|
+
const fallback = await connection.getProgramAccounts(programId, {
|
|
2807
|
+
filters: [
|
|
2808
|
+
{
|
|
2809
|
+
memcmp: {
|
|
2810
|
+
offset: 0,
|
|
2811
|
+
bytes: "F6P2QNqpQV5"
|
|
2812
|
+
// base58 of TALOCREP (u64 LE magic)
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
],
|
|
2816
|
+
dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH }
|
|
2817
|
+
});
|
|
2818
|
+
rawAccounts = [...fallback].map((e) => ({ ...e, maxAccounts: 4096, dataSize: SLAB_TIERS.large.dataSize }));
|
|
2819
|
+
}
|
|
2820
|
+
} catch (err) {
|
|
2821
|
+
console.warn(
|
|
2822
|
+
"[discoverMarkets] dataSize filters failed, falling back to memcmp:",
|
|
2823
|
+
err instanceof Error ? err.message : err
|
|
2824
|
+
);
|
|
2825
|
+
const fallback = await connection.getProgramAccounts(programId, {
|
|
2826
|
+
filters: [
|
|
2827
|
+
{
|
|
2828
|
+
memcmp: {
|
|
2829
|
+
offset: 0,
|
|
2830
|
+
bytes: "F6P2QNqpQV5"
|
|
2831
|
+
// base58 of TALOCREP (u64 LE magic)
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
],
|
|
2835
|
+
dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH }
|
|
2836
|
+
});
|
|
2837
|
+
rawAccounts = [...fallback].map((e) => ({ ...e, maxAccounts: 4096, dataSize: SLAB_TIERS.large.dataSize }));
|
|
2838
|
+
}
|
|
2839
|
+
const accounts = rawAccounts;
|
|
2840
|
+
const markets = [];
|
|
2841
|
+
const seenPubkeys = /* @__PURE__ */ new Set();
|
|
2842
|
+
for (const { pubkey, account, maxAccounts, dataSize } of accounts) {
|
|
2843
|
+
const pkStr = pubkey.toBase58();
|
|
2844
|
+
if (seenPubkeys.has(pkStr)) continue;
|
|
2845
|
+
seenPubkeys.add(pkStr);
|
|
2846
|
+
const data = new Uint8Array(account.data);
|
|
2847
|
+
let valid = true;
|
|
2848
|
+
for (let i = 0; i < MAGIC_BYTES.length; i++) {
|
|
2849
|
+
if (data[i] !== MAGIC_BYTES[i]) {
|
|
2850
|
+
valid = false;
|
|
2851
|
+
break;
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
if (!valid) continue;
|
|
2855
|
+
const layout = detectSlabLayout(dataSize, data);
|
|
2856
|
+
if (!layout) {
|
|
2857
|
+
console.warn(
|
|
2858
|
+
`[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`
|
|
2859
|
+
);
|
|
2860
|
+
continue;
|
|
2861
|
+
}
|
|
2862
|
+
try {
|
|
2863
|
+
const header = parseHeader(data);
|
|
2864
|
+
const config = parseConfig(data, layout);
|
|
2865
|
+
const engine = parseEngineLight(data, layout, maxAccounts);
|
|
2866
|
+
const params = parseParams(data, layout);
|
|
2867
|
+
markets.push({ slabAddress: pubkey, programId, header, config, engine, params });
|
|
2868
|
+
} catch (err) {
|
|
2869
|
+
console.warn(
|
|
2870
|
+
`[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,
|
|
2871
|
+
err instanceof Error ? err.message : err
|
|
2872
|
+
);
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
return markets;
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/solana/dex-oracle.ts
|
|
2879
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
2880
|
+
function detectDexType(ownerProgramId) {
|
|
2881
|
+
if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return "pumpswap";
|
|
2882
|
+
if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return "raydium-clmm";
|
|
2883
|
+
if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return "meteora-dlmm";
|
|
2884
|
+
return null;
|
|
2885
|
+
}
|
|
2886
|
+
function parseDexPool(dexType, poolAddress, data) {
|
|
2887
|
+
switch (dexType) {
|
|
2888
|
+
case "pumpswap":
|
|
2889
|
+
return parsePumpSwapPool(poolAddress, data);
|
|
2890
|
+
case "raydium-clmm":
|
|
2891
|
+
return parseRaydiumClmmPool(poolAddress, data);
|
|
2892
|
+
case "meteora-dlmm":
|
|
2893
|
+
return parseMeteoraPool(poolAddress, data);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function computeDexSpotPriceE6(dexType, data, vaultData) {
|
|
2897
|
+
switch (dexType) {
|
|
2898
|
+
case "pumpswap":
|
|
2899
|
+
if (!vaultData) throw new Error("PumpSwap requires vaultData (base and quote vault accounts)");
|
|
2900
|
+
return computePumpSwapPriceE6(data, vaultData);
|
|
2901
|
+
case "raydium-clmm":
|
|
2902
|
+
return computeRaydiumClmmPriceE6(data);
|
|
2903
|
+
case "meteora-dlmm":
|
|
2904
|
+
return computeMeteoraDlmmPriceE6(data);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
var PUMPSWAP_MIN_LEN = 195;
|
|
2908
|
+
function parsePumpSwapPool(poolAddress, data) {
|
|
2909
|
+
if (data.length < PUMPSWAP_MIN_LEN) {
|
|
2910
|
+
throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);
|
|
2911
|
+
}
|
|
2912
|
+
return {
|
|
2913
|
+
dexType: "pumpswap",
|
|
2914
|
+
poolAddress,
|
|
2915
|
+
baseMint: new PublicKey5(data.slice(35, 67)),
|
|
2916
|
+
quoteMint: new PublicKey5(data.slice(67, 99)),
|
|
2917
|
+
baseVault: new PublicKey5(data.slice(131, 163)),
|
|
2918
|
+
quoteVault: new PublicKey5(data.slice(163, 195))
|
|
2919
|
+
};
|
|
2920
|
+
}
|
|
2921
|
+
var SPL_TOKEN_AMOUNT_MIN_LEN = 72;
|
|
2922
|
+
function computePumpSwapPriceE6(_poolData, vaultData) {
|
|
2923
|
+
if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {
|
|
2924
|
+
throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);
|
|
2925
|
+
}
|
|
2926
|
+
if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {
|
|
2927
|
+
throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);
|
|
2928
|
+
}
|
|
2929
|
+
const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);
|
|
2930
|
+
const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);
|
|
2931
|
+
const baseAmount = readU64LE3(baseDv, 64);
|
|
2932
|
+
const quoteAmount = readU64LE3(quoteDv, 64);
|
|
2933
|
+
if (baseAmount === 0n) return 0n;
|
|
2934
|
+
return quoteAmount * 1000000n / baseAmount;
|
|
2935
|
+
}
|
|
2936
|
+
var RAYDIUM_CLMM_MIN_LEN = 269;
|
|
2937
|
+
function parseRaydiumClmmPool(poolAddress, data) {
|
|
2938
|
+
if (data.length < RAYDIUM_CLMM_MIN_LEN) {
|
|
2939
|
+
throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);
|
|
2940
|
+
}
|
|
2941
|
+
return {
|
|
2942
|
+
dexType: "raydium-clmm",
|
|
2943
|
+
poolAddress,
|
|
2944
|
+
baseMint: new PublicKey5(data.slice(73, 105)),
|
|
2945
|
+
quoteMint: new PublicKey5(data.slice(105, 137))
|
|
2946
|
+
};
|
|
2947
|
+
}
|
|
2948
|
+
var MAX_TOKEN_DECIMALS = 24;
|
|
2949
|
+
function computeRaydiumClmmPriceE6(data) {
|
|
2950
|
+
if (data.length < RAYDIUM_CLMM_MIN_LEN) {
|
|
2951
|
+
throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);
|
|
2952
|
+
}
|
|
2953
|
+
const dv3 = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
2954
|
+
const decimals0 = data[233];
|
|
2955
|
+
const decimals1 = data[234];
|
|
2956
|
+
if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {
|
|
2957
|
+
throw new Error(
|
|
2958
|
+
`Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`
|
|
2959
|
+
);
|
|
2960
|
+
}
|
|
2961
|
+
const sqrtPriceX64 = readU128LE3(dv3, 253);
|
|
2962
|
+
if (sqrtPriceX64 === 0n) return 0n;
|
|
2963
|
+
const scaledSqrt = sqrtPriceX64 * 1000000n;
|
|
2964
|
+
const term = scaledSqrt >> 64n;
|
|
2965
|
+
const priceE6Raw = term * sqrtPriceX64 >> 64n;
|
|
2966
|
+
const decimalDiff = 6 + decimals0 - decimals1;
|
|
2967
|
+
const adjustedDiff = decimalDiff - 6;
|
|
2968
|
+
if (adjustedDiff >= 0) {
|
|
2969
|
+
const scale = 10n ** BigInt(adjustedDiff);
|
|
2970
|
+
return priceE6Raw * scale;
|
|
2971
|
+
} else {
|
|
2972
|
+
const scale = 10n ** BigInt(-adjustedDiff);
|
|
2973
|
+
return priceE6Raw / scale;
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
var METEORA_DLMM_MIN_LEN = 145;
|
|
2977
|
+
function parseMeteoraPool(poolAddress, data) {
|
|
2978
|
+
if (data.length < METEORA_DLMM_MIN_LEN) {
|
|
2979
|
+
throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);
|
|
2980
|
+
}
|
|
2981
|
+
return {
|
|
2982
|
+
dexType: "meteora-dlmm",
|
|
2983
|
+
poolAddress,
|
|
2984
|
+
baseMint: new PublicKey5(data.slice(81, 113)),
|
|
2985
|
+
quoteMint: new PublicKey5(data.slice(113, 145))
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
var MAX_BIN_STEP = 1e4;
|
|
2989
|
+
var MAX_ACTIVE_ID_ABS = 5e5;
|
|
2990
|
+
function computeMeteoraDlmmPriceE6(data) {
|
|
2991
|
+
if (data.length < METEORA_DLMM_MIN_LEN) {
|
|
2992
|
+
throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);
|
|
2993
|
+
}
|
|
2994
|
+
const dv3 = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
2995
|
+
const binStep = dv3.getUint16(73, true);
|
|
2996
|
+
const activeId = dv3.getInt32(76, true);
|
|
2997
|
+
if (binStep === 0) return 0n;
|
|
2998
|
+
if (binStep > MAX_BIN_STEP) {
|
|
2999
|
+
throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);
|
|
3000
|
+
}
|
|
3001
|
+
if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {
|
|
3002
|
+
throw new Error(
|
|
3003
|
+
`Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`
|
|
3004
|
+
);
|
|
3005
|
+
}
|
|
3006
|
+
const MAX_ABS_BIN_ID = 5e5;
|
|
3007
|
+
if (activeId > MAX_ABS_BIN_ID || activeId < -MAX_ABS_BIN_ID) {
|
|
3008
|
+
throw new Error(
|
|
3009
|
+
`Meteora DLMM: activeId ${activeId} exceeds safe range (\xB1${MAX_ABS_BIN_ID})`
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
const SCALE = 1000000000000000000n;
|
|
3013
|
+
const base = SCALE + BigInt(binStep) * SCALE / 10000n;
|
|
3014
|
+
const isNeg = activeId < 0;
|
|
3015
|
+
let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
|
|
3016
|
+
let result = SCALE;
|
|
3017
|
+
let b = base;
|
|
3018
|
+
while (exp > 0n) {
|
|
3019
|
+
if (exp & 1n) {
|
|
3020
|
+
result = result * b / SCALE;
|
|
3021
|
+
}
|
|
3022
|
+
exp >>= 1n;
|
|
3023
|
+
if (exp > 0n) {
|
|
3024
|
+
b = b * b / SCALE;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
if (isNeg) {
|
|
3028
|
+
if (result === 0n) return 0n;
|
|
3029
|
+
return SCALE * 1000000n / result;
|
|
3030
|
+
} else {
|
|
3031
|
+
return result / 1000000000000n;
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
function readU64LE3(dv3, offset) {
|
|
3035
|
+
const lo = BigInt(dv3.getUint32(offset, true));
|
|
3036
|
+
const hi = BigInt(dv3.getUint32(offset + 4, true));
|
|
3037
|
+
return lo | hi << 32n;
|
|
3038
|
+
}
|
|
3039
|
+
function readU128LE3(dv3, offset) {
|
|
3040
|
+
const lo = readU64LE3(dv3, offset);
|
|
3041
|
+
const hi = readU64LE3(dv3, offset + 8);
|
|
3042
|
+
return lo | hi << 64n;
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
// src/solana/oracle.ts
|
|
3046
|
+
var CHAINLINK_MIN_SIZE = 224;
|
|
3047
|
+
var MAX_DECIMALS = 18;
|
|
3048
|
+
var CHAINLINK_DECIMALS_OFFSET = 138;
|
|
3049
|
+
var CHAINLINK_ANSWER_OFFSET = 216;
|
|
3050
|
+
function readU82(data, off) {
|
|
3051
|
+
return data[off];
|
|
3052
|
+
}
|
|
3053
|
+
function readBigInt64LE(data, off) {
|
|
3054
|
+
return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
|
|
3055
|
+
}
|
|
3056
|
+
function parseChainlinkPrice(data) {
|
|
3057
|
+
if (data.length < CHAINLINK_MIN_SIZE) {
|
|
3058
|
+
throw new Error(
|
|
3059
|
+
`Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
|
|
3060
|
+
);
|
|
3061
|
+
}
|
|
3062
|
+
const decimals = readU82(data, CHAINLINK_DECIMALS_OFFSET);
|
|
3063
|
+
if (decimals > MAX_DECIMALS) {
|
|
3064
|
+
throw new Error(
|
|
3065
|
+
`Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`
|
|
3066
|
+
);
|
|
3067
|
+
}
|
|
3068
|
+
const price = readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET);
|
|
3069
|
+
if (price <= 0n) {
|
|
3070
|
+
throw new Error(
|
|
3071
|
+
`Oracle price is non-positive: ${price}`
|
|
3072
|
+
);
|
|
3073
|
+
}
|
|
3074
|
+
return { price, decimals };
|
|
3075
|
+
}
|
|
3076
|
+
function isValidChainlinkOracle(data) {
|
|
3077
|
+
try {
|
|
3078
|
+
parseChainlinkPrice(data);
|
|
3079
|
+
return true;
|
|
3080
|
+
} catch {
|
|
3081
|
+
return false;
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
// src/solana/token-program.ts
|
|
3086
|
+
import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
3087
|
+
import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID3 } from "@solana/spl-token";
|
|
3088
|
+
var TOKEN_2022_PROGRAM_ID = new PublicKey6(
|
|
3089
|
+
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
|
|
3090
|
+
);
|
|
3091
|
+
async function detectTokenProgram(connection, mint) {
|
|
3092
|
+
const info = await connection.getAccountInfo(mint);
|
|
3093
|
+
if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
3094
|
+
return info.owner;
|
|
3095
|
+
}
|
|
3096
|
+
function isToken2022(tokenProgramId) {
|
|
3097
|
+
return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
|
|
3098
|
+
}
|
|
3099
|
+
function isStandardToken(tokenProgramId) {
|
|
3100
|
+
return tokenProgramId.equals(TOKEN_PROGRAM_ID3);
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
// src/solana/stake.ts
|
|
3104
|
+
import { PublicKey as PublicKey8, SystemProgram as SystemProgram2, SYSVAR_RENT_PUBKEY as SYSVAR_RENT_PUBKEY2, SYSVAR_CLOCK_PUBKEY as SYSVAR_CLOCK_PUBKEY2 } from "@solana/web3.js";
|
|
3105
|
+
import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID4 } from "@solana/spl-token";
|
|
3106
|
+
|
|
3107
|
+
// src/config/program-ids.ts
|
|
3108
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
3109
|
+
function safeEnv(key) {
|
|
3110
|
+
try {
|
|
3111
|
+
return typeof process !== "undefined" && process?.env ? process.env[key] : void 0;
|
|
3112
|
+
} catch {
|
|
3113
|
+
return void 0;
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
var PROGRAM_IDS = {
|
|
3117
|
+
devnet: {
|
|
3118
|
+
percolator: "FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD",
|
|
3119
|
+
matcher: "GTRgyTDfrMvBubALAqtHuQwT8tbGyXid7svXZKtWfC9k"
|
|
3120
|
+
},
|
|
3121
|
+
mainnet: {
|
|
3122
|
+
percolator: "GM8zjJ8LTBMv9xEsverh6H6wLyevgMHEJXcEzyY3rY24",
|
|
3123
|
+
matcher: "DHP6DtwXP1yJsz8YzfoeigRFPB979gzmumkmCxDLSkUX"
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
function getProgramId(network) {
|
|
3127
|
+
const override = safeEnv("PROGRAM_ID");
|
|
3128
|
+
if (override) {
|
|
3129
|
+
console.warn(
|
|
3130
|
+
`[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3131
|
+
);
|
|
3132
|
+
return new PublicKey7(override);
|
|
3133
|
+
}
|
|
3134
|
+
const detectedNetwork = getCurrentNetwork();
|
|
3135
|
+
const targetNetwork = network ?? detectedNetwork;
|
|
3136
|
+
const programId = PROGRAM_IDS[targetNetwork].percolator;
|
|
3137
|
+
return new PublicKey7(programId);
|
|
3138
|
+
}
|
|
3139
|
+
function getMatcherProgramId(network) {
|
|
3140
|
+
const override = safeEnv("MATCHER_PROGRAM_ID");
|
|
3141
|
+
if (override) {
|
|
3142
|
+
console.warn(
|
|
3143
|
+
`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3144
|
+
);
|
|
3145
|
+
return new PublicKey7(override);
|
|
3146
|
+
}
|
|
3147
|
+
const detectedNetwork = getCurrentNetwork();
|
|
3148
|
+
const targetNetwork = network ?? detectedNetwork;
|
|
3149
|
+
const programId = PROGRAM_IDS[targetNetwork].matcher;
|
|
3150
|
+
if (!programId) {
|
|
3151
|
+
throw new Error(`Matcher program not deployed on ${targetNetwork}`);
|
|
3152
|
+
}
|
|
3153
|
+
return new PublicKey7(programId);
|
|
3154
|
+
}
|
|
3155
|
+
function getCurrentNetwork() {
|
|
3156
|
+
const network = safeEnv("NETWORK")?.toLowerCase();
|
|
3157
|
+
if (network === "mainnet" || network === "mainnet-beta") {
|
|
3158
|
+
return "mainnet";
|
|
3159
|
+
}
|
|
3160
|
+
return "devnet";
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
// src/solana/stake.ts
|
|
3164
|
+
var STAKE_PROGRAM_IDS = {
|
|
3165
|
+
devnet: "6aJb1F9CDCVWCNYFwj8aQsVb696YnW6J1FznteHq4Q6k",
|
|
3166
|
+
mainnet: ""
|
|
3167
|
+
// TODO: populate once DevOps deploys percolator-stake to mainnet
|
|
3168
|
+
};
|
|
3169
|
+
function getStakeProgramId(network) {
|
|
3170
|
+
const override = safeEnv("STAKE_PROGRAM_ID");
|
|
3171
|
+
if (override) {
|
|
3172
|
+
console.warn(
|
|
3173
|
+
`[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3174
|
+
);
|
|
3175
|
+
return new PublicKey8(override);
|
|
3176
|
+
}
|
|
3177
|
+
const detectedNetwork = network ?? (() => {
|
|
3178
|
+
const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? "";
|
|
3179
|
+
return n === "mainnet" || n === "mainnet-beta" ? "mainnet" : "devnet";
|
|
3180
|
+
})();
|
|
3181
|
+
const id = STAKE_PROGRAM_IDS[detectedNetwork];
|
|
3182
|
+
if (!id) {
|
|
3183
|
+
throw new Error(
|
|
3184
|
+
`Stake program not deployed on ${detectedNetwork}. Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
return new PublicKey8(id);
|
|
3188
|
+
}
|
|
3189
|
+
var STAKE_PROGRAM_ID = new PublicKey8(STAKE_PROGRAM_IDS.devnet);
|
|
3190
|
+
var STAKE_IX = {
|
|
3191
|
+
InitPool: 0,
|
|
3192
|
+
Deposit: 1,
|
|
3193
|
+
Withdraw: 2,
|
|
3194
|
+
FlushToInsurance: 3,
|
|
3195
|
+
UpdateConfig: 4,
|
|
3196
|
+
TransferAdmin: 5,
|
|
3197
|
+
AdminSetOracleAuthority: 6,
|
|
3198
|
+
AdminSetRiskThreshold: 7,
|
|
3199
|
+
AdminSetMaintenanceFee: 8,
|
|
3200
|
+
AdminResolveMarket: 9,
|
|
3201
|
+
AdminWithdrawInsurance: 10,
|
|
3202
|
+
AdminSetInsurancePolicy: 11,
|
|
3203
|
+
/** PERC-272: Accrue trading fees to LP vault */
|
|
3204
|
+
AccrueFees: 12,
|
|
3205
|
+
/** PERC-272: Init pool in trading LP mode */
|
|
3206
|
+
InitTradingPool: 13,
|
|
3207
|
+
/** PERC-313: Set HWM config (enable + floor bps) */
|
|
3208
|
+
AdminSetHwmConfig: 14,
|
|
3209
|
+
/** PERC-303: Enable/configure senior-junior LP tranches */
|
|
3210
|
+
AdminSetTrancheConfig: 15,
|
|
3211
|
+
/** PERC-303: Deposit into junior (first-loss) tranche */
|
|
3212
|
+
DepositJunior: 16
|
|
3213
|
+
};
|
|
3214
|
+
var TEXT = new TextEncoder();
|
|
3215
|
+
function deriveStakePool(slab, programId) {
|
|
3216
|
+
return PublicKey8.findProgramAddressSync(
|
|
3217
|
+
[TEXT.encode("stake_pool"), slab.toBytes()],
|
|
3218
|
+
programId ?? getStakeProgramId()
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
function deriveStakeVaultAuth(pool, programId) {
|
|
3222
|
+
return PublicKey8.findProgramAddressSync(
|
|
3223
|
+
[TEXT.encode("vault_auth"), pool.toBytes()],
|
|
3224
|
+
programId ?? getStakeProgramId()
|
|
3225
|
+
);
|
|
3226
|
+
}
|
|
3227
|
+
function deriveDepositPda(pool, user, programId) {
|
|
3228
|
+
return PublicKey8.findProgramAddressSync(
|
|
3229
|
+
[TEXT.encode("deposit"), pool.toBytes(), user.toBytes()],
|
|
3230
|
+
programId ?? getStakeProgramId()
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
3233
|
+
function readU64LE4(data, off) {
|
|
3234
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
3235
|
+
return view.getBigUint64(
|
|
3236
|
+
off,
|
|
3237
|
+
/* littleEndian= */
|
|
3238
|
+
true
|
|
3239
|
+
);
|
|
3240
|
+
}
|
|
3241
|
+
function readU16LE3(data, off) {
|
|
3242
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
3243
|
+
return view.getUint16(
|
|
3244
|
+
off,
|
|
3245
|
+
/* littleEndian= */
|
|
3246
|
+
true
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
function u64Le(v) {
|
|
3250
|
+
const big = BigInt(v);
|
|
3251
|
+
if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
|
|
3252
|
+
if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
|
|
3253
|
+
const arr = new Uint8Array(8);
|
|
3254
|
+
new DataView(arr.buffer).setBigUint64(0, big, true);
|
|
3255
|
+
return arr;
|
|
3256
|
+
}
|
|
3257
|
+
function u128Le(v) {
|
|
3258
|
+
const big = BigInt(v);
|
|
3259
|
+
if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
|
|
3260
|
+
if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
|
|
3261
|
+
const arr = new Uint8Array(16);
|
|
3262
|
+
const view = new DataView(arr.buffer);
|
|
3263
|
+
view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);
|
|
3264
|
+
view.setBigUint64(8, big >> 64n, true);
|
|
3265
|
+
return arr;
|
|
3266
|
+
}
|
|
3267
|
+
function u16Le(v) {
|
|
3268
|
+
if (v < 0 || v > 65535) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`);
|
|
3269
|
+
const arr = new Uint8Array(2);
|
|
3270
|
+
new DataView(arr.buffer).setUint16(0, v, true);
|
|
3271
|
+
return arr;
|
|
3272
|
+
}
|
|
3273
|
+
function encodeStakeInitPool(cooldownSlots, depositCap) {
|
|
3274
|
+
return concatBytes(
|
|
3275
|
+
new Uint8Array([STAKE_IX.InitPool]),
|
|
3276
|
+
u64Le(cooldownSlots),
|
|
3277
|
+
u64Le(depositCap)
|
|
3278
|
+
);
|
|
3279
|
+
}
|
|
3280
|
+
function encodeStakeDeposit(amount) {
|
|
3281
|
+
return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));
|
|
3282
|
+
}
|
|
3283
|
+
function encodeStakeWithdraw(lpAmount) {
|
|
3284
|
+
return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));
|
|
3285
|
+
}
|
|
3286
|
+
function encodeStakeFlushToInsurance(amount) {
|
|
3287
|
+
return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));
|
|
3288
|
+
}
|
|
3289
|
+
function encodeStakeUpdateConfig(newCooldownSlots, newDepositCap) {
|
|
3290
|
+
return concatBytes(
|
|
3291
|
+
new Uint8Array([STAKE_IX.UpdateConfig]),
|
|
3292
|
+
new Uint8Array([newCooldownSlots != null ? 1 : 0]),
|
|
3293
|
+
u64Le(newCooldownSlots ?? 0n),
|
|
3294
|
+
new Uint8Array([newDepositCap != null ? 1 : 0]),
|
|
3295
|
+
u64Le(newDepositCap ?? 0n)
|
|
3296
|
+
);
|
|
3297
|
+
}
|
|
3298
|
+
function encodeStakeTransferAdmin() {
|
|
3299
|
+
return new Uint8Array([STAKE_IX.TransferAdmin]);
|
|
3300
|
+
}
|
|
3301
|
+
function encodeStakeAdminSetOracleAuthority(newAuthority) {
|
|
3302
|
+
return concatBytes(
|
|
3303
|
+
new Uint8Array([STAKE_IX.AdminSetOracleAuthority]),
|
|
3304
|
+
newAuthority.toBytes()
|
|
3305
|
+
);
|
|
3306
|
+
}
|
|
3307
|
+
function encodeStakeAdminSetRiskThreshold(newThreshold) {
|
|
3308
|
+
return concatBytes(
|
|
3309
|
+
new Uint8Array([STAKE_IX.AdminSetRiskThreshold]),
|
|
3310
|
+
u128Le(newThreshold)
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
function encodeStakeAdminSetMaintenanceFee(newFee) {
|
|
3314
|
+
return concatBytes(
|
|
3315
|
+
new Uint8Array([STAKE_IX.AdminSetMaintenanceFee]),
|
|
3316
|
+
u128Le(newFee)
|
|
3317
|
+
);
|
|
3318
|
+
}
|
|
3319
|
+
function encodeStakeAdminResolveMarket() {
|
|
3320
|
+
return new Uint8Array([STAKE_IX.AdminResolveMarket]);
|
|
3321
|
+
}
|
|
3322
|
+
function encodeStakeAdminWithdrawInsurance(amount) {
|
|
3323
|
+
return concatBytes(
|
|
3324
|
+
new Uint8Array([STAKE_IX.AdminWithdrawInsurance]),
|
|
3325
|
+
u64Le(amount)
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
function encodeStakeAccrueFees() {
|
|
3329
|
+
return new Uint8Array([STAKE_IX.AccrueFees]);
|
|
3330
|
+
}
|
|
3331
|
+
function encodeStakeInitTradingPool(cooldownSlots, depositCap) {
|
|
3332
|
+
return concatBytes(
|
|
3333
|
+
new Uint8Array([STAKE_IX.InitTradingPool]),
|
|
3334
|
+
u64Le(cooldownSlots),
|
|
3335
|
+
u64Le(depositCap)
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
function encodeStakeAdminSetHwmConfig(enabled, hwmFloorBps) {
|
|
3339
|
+
return concatBytes(
|
|
3340
|
+
new Uint8Array([STAKE_IX.AdminSetHwmConfig]),
|
|
3341
|
+
new Uint8Array([enabled ? 1 : 0]),
|
|
3342
|
+
u16Le(hwmFloorBps)
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps) {
|
|
3346
|
+
return concatBytes(
|
|
3347
|
+
new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),
|
|
3348
|
+
u16Le(juniorFeeMultBps)
|
|
3349
|
+
);
|
|
3350
|
+
}
|
|
3351
|
+
function encodeStakeDepositJunior(amount) {
|
|
3352
|
+
return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));
|
|
3353
|
+
}
|
|
3354
|
+
function encodeStakeAdminSetInsurancePolicy(authority, minWithdrawBase, maxWithdrawBps, cooldownSlots) {
|
|
3355
|
+
return concatBytes(
|
|
3356
|
+
new Uint8Array([STAKE_IX.AdminSetInsurancePolicy]),
|
|
3357
|
+
authority.toBytes(),
|
|
3358
|
+
u64Le(minWithdrawBase),
|
|
3359
|
+
u16Le(maxWithdrawBps),
|
|
3360
|
+
u64Le(cooldownSlots)
|
|
3361
|
+
);
|
|
3362
|
+
}
|
|
3363
|
+
var STAKE_POOL_SIZE = 352;
|
|
3364
|
+
function decodeStakePool(data) {
|
|
3365
|
+
if (data.length < STAKE_POOL_SIZE) {
|
|
3366
|
+
throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE}`);
|
|
3367
|
+
}
|
|
3368
|
+
const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
3369
|
+
let off = 0;
|
|
3370
|
+
const isInitialized = bytes[off] === 1;
|
|
3371
|
+
off += 1;
|
|
3372
|
+
const bump = bytes[off];
|
|
3373
|
+
off += 1;
|
|
3374
|
+
const vaultAuthorityBump = bytes[off];
|
|
3375
|
+
off += 1;
|
|
3376
|
+
const adminTransferred = bytes[off] === 1;
|
|
3377
|
+
off += 1;
|
|
3378
|
+
off += 4;
|
|
3379
|
+
const slab = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3380
|
+
off += 32;
|
|
3381
|
+
const admin = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3382
|
+
off += 32;
|
|
3383
|
+
const collateralMint = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3384
|
+
off += 32;
|
|
3385
|
+
const lpMint = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3386
|
+
off += 32;
|
|
3387
|
+
const vault = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3388
|
+
off += 32;
|
|
3389
|
+
const totalDeposited = readU64LE4(bytes, off);
|
|
3390
|
+
off += 8;
|
|
3391
|
+
const totalLpSupply = readU64LE4(bytes, off);
|
|
3392
|
+
off += 8;
|
|
3393
|
+
const cooldownSlots = readU64LE4(bytes, off);
|
|
3394
|
+
off += 8;
|
|
3395
|
+
const depositCap = readU64LE4(bytes, off);
|
|
3396
|
+
off += 8;
|
|
3397
|
+
const totalFlushed = readU64LE4(bytes, off);
|
|
3398
|
+
off += 8;
|
|
3399
|
+
const totalReturned = readU64LE4(bytes, off);
|
|
3400
|
+
off += 8;
|
|
3401
|
+
const totalWithdrawn = readU64LE4(bytes, off);
|
|
3402
|
+
off += 8;
|
|
3403
|
+
const percolatorProgram = new PublicKey8(bytes.subarray(off, off + 32));
|
|
3404
|
+
off += 32;
|
|
3405
|
+
const totalFeesEarned = readU64LE4(bytes, off);
|
|
3406
|
+
off += 8;
|
|
3407
|
+
const lastFeeAccrualSlot = readU64LE4(bytes, off);
|
|
3408
|
+
off += 8;
|
|
3409
|
+
const lastVaultSnapshot = readU64LE4(bytes, off);
|
|
3410
|
+
off += 8;
|
|
3411
|
+
const poolMode = bytes[off];
|
|
3412
|
+
off += 1;
|
|
3413
|
+
off += 7;
|
|
3414
|
+
const reservedStart = off;
|
|
3415
|
+
const hwmEnabled = bytes[reservedStart + 9] === 1;
|
|
3416
|
+
const hwmTvlLow = readU64LE4(bytes, reservedStart + 10);
|
|
3417
|
+
const hwmTvlHigh = readU64LE4(bytes, reservedStart + 18);
|
|
3418
|
+
const epochHighWaterTvl = hwmTvlLow | hwmTvlHigh << 64n;
|
|
3419
|
+
const hwmFloorBps = readU16LE3(bytes, reservedStart + 26);
|
|
3420
|
+
const trancheEnabled = bytes[reservedStart + 32] === 1;
|
|
3421
|
+
const juniorBalance = readU64LE4(bytes, reservedStart + 33);
|
|
3422
|
+
const juniorTotalLp = readU64LE4(bytes, reservedStart + 41);
|
|
3423
|
+
const juniorFeeMultBps = readU16LE3(bytes, reservedStart + 49);
|
|
3424
|
+
return {
|
|
3425
|
+
isInitialized,
|
|
3426
|
+
bump,
|
|
3427
|
+
vaultAuthorityBump,
|
|
3428
|
+
adminTransferred,
|
|
3429
|
+
slab,
|
|
3430
|
+
admin,
|
|
3431
|
+
collateralMint,
|
|
3432
|
+
lpMint,
|
|
3433
|
+
vault,
|
|
3434
|
+
totalDeposited,
|
|
3435
|
+
totalLpSupply,
|
|
3436
|
+
cooldownSlots,
|
|
3437
|
+
depositCap,
|
|
3438
|
+
totalFlushed,
|
|
3439
|
+
totalReturned,
|
|
3440
|
+
totalWithdrawn,
|
|
3441
|
+
percolatorProgram,
|
|
3442
|
+
totalFeesEarned,
|
|
3443
|
+
lastFeeAccrualSlot,
|
|
3444
|
+
lastVaultSnapshot,
|
|
3445
|
+
poolMode,
|
|
3446
|
+
hwmEnabled,
|
|
3447
|
+
epochHighWaterTvl,
|
|
3448
|
+
hwmFloorBps,
|
|
3449
|
+
trancheEnabled,
|
|
3450
|
+
juniorBalance,
|
|
3451
|
+
juniorTotalLp,
|
|
3452
|
+
juniorFeeMultBps
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
function initPoolAccounts(a) {
|
|
3456
|
+
return [
|
|
3457
|
+
{ pubkey: a.admin, isSigner: true, isWritable: true },
|
|
3458
|
+
{ pubkey: a.slab, isSigner: false, isWritable: false },
|
|
3459
|
+
{ pubkey: a.pool, isSigner: false, isWritable: true },
|
|
3460
|
+
{ pubkey: a.lpMint, isSigner: false, isWritable: true },
|
|
3461
|
+
{ pubkey: a.vault, isSigner: false, isWritable: true },
|
|
3462
|
+
{ pubkey: a.vaultAuth, isSigner: false, isWritable: false },
|
|
3463
|
+
{ pubkey: a.collateralMint, isSigner: false, isWritable: false },
|
|
3464
|
+
{ pubkey: a.percolatorProgram, isSigner: false, isWritable: false },
|
|
3465
|
+
{ pubkey: TOKEN_PROGRAM_ID4, isSigner: false, isWritable: false },
|
|
3466
|
+
{ pubkey: SystemProgram2.programId, isSigner: false, isWritable: false },
|
|
3467
|
+
{ pubkey: SYSVAR_RENT_PUBKEY2, isSigner: false, isWritable: false }
|
|
3468
|
+
];
|
|
3469
|
+
}
|
|
3470
|
+
function depositAccounts(a) {
|
|
3471
|
+
return [
|
|
3472
|
+
{ pubkey: a.user, isSigner: true, isWritable: false },
|
|
3473
|
+
{ pubkey: a.pool, isSigner: false, isWritable: true },
|
|
3474
|
+
{ pubkey: a.userCollateralAta, isSigner: false, isWritable: true },
|
|
3475
|
+
{ pubkey: a.vault, isSigner: false, isWritable: true },
|
|
3476
|
+
{ pubkey: a.lpMint, isSigner: false, isWritable: true },
|
|
3477
|
+
{ pubkey: a.userLpAta, isSigner: false, isWritable: true },
|
|
3478
|
+
{ pubkey: a.vaultAuth, isSigner: false, isWritable: false },
|
|
3479
|
+
{ pubkey: a.depositPda, isSigner: false, isWritable: true },
|
|
3480
|
+
{ pubkey: TOKEN_PROGRAM_ID4, isSigner: false, isWritable: false },
|
|
3481
|
+
{ pubkey: SYSVAR_CLOCK_PUBKEY2, isSigner: false, isWritable: false },
|
|
3482
|
+
{ pubkey: SystemProgram2.programId, isSigner: false, isWritable: false }
|
|
3483
|
+
];
|
|
3484
|
+
}
|
|
3485
|
+
function withdrawAccounts(a) {
|
|
3486
|
+
return [
|
|
3487
|
+
{ pubkey: a.user, isSigner: true, isWritable: false },
|
|
3488
|
+
{ pubkey: a.pool, isSigner: false, isWritable: true },
|
|
3489
|
+
{ pubkey: a.userLpAta, isSigner: false, isWritable: true },
|
|
3490
|
+
{ pubkey: a.lpMint, isSigner: false, isWritable: true },
|
|
3491
|
+
{ pubkey: a.vault, isSigner: false, isWritable: true },
|
|
3492
|
+
{ pubkey: a.userCollateralAta, isSigner: false, isWritable: true },
|
|
3493
|
+
{ pubkey: a.vaultAuth, isSigner: false, isWritable: false },
|
|
3494
|
+
{ pubkey: a.depositPda, isSigner: false, isWritable: true },
|
|
3495
|
+
{ pubkey: TOKEN_PROGRAM_ID4, isSigner: false, isWritable: false },
|
|
3496
|
+
{ pubkey: SYSVAR_CLOCK_PUBKEY2, isSigner: false, isWritable: false }
|
|
3497
|
+
];
|
|
3498
|
+
}
|
|
3499
|
+
function flushToInsuranceAccounts(a) {
|
|
3500
|
+
return [
|
|
3501
|
+
{ pubkey: a.caller, isSigner: true, isWritable: false },
|
|
3502
|
+
{ pubkey: a.pool, isSigner: false, isWritable: true },
|
|
3503
|
+
{ pubkey: a.vault, isSigner: false, isWritable: true },
|
|
3504
|
+
{ pubkey: a.vaultAuth, isSigner: false, isWritable: false },
|
|
3505
|
+
{ pubkey: a.slab, isSigner: false, isWritable: true },
|
|
3506
|
+
{ pubkey: a.wrapperVault, isSigner: false, isWritable: true },
|
|
3507
|
+
{ pubkey: a.percolatorProgram, isSigner: false, isWritable: false },
|
|
3508
|
+
{ pubkey: TOKEN_PROGRAM_ID4, isSigner: false, isWritable: false }
|
|
3509
|
+
];
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
// src/solana/adl.ts
|
|
3513
|
+
import {
|
|
3514
|
+
TransactionInstruction,
|
|
3515
|
+
SYSVAR_CLOCK_PUBKEY as SYSVAR_CLOCK_PUBKEY3
|
|
3516
|
+
} from "@solana/web3.js";
|
|
3517
|
+
function computePnlPct(pnl, capital) {
|
|
3518
|
+
if (capital === 0n) return 0n;
|
|
3519
|
+
return pnl * 10000n / capital;
|
|
3520
|
+
}
|
|
3521
|
+
function isAdlTriggered(slabData) {
|
|
3522
|
+
const layout = detectSlabLayout(slabData.length);
|
|
3523
|
+
if (!layout) return false;
|
|
3524
|
+
try {
|
|
3525
|
+
const engine = parseEngine(slabData);
|
|
3526
|
+
if (engine.pnlPosTot === 0n) return false;
|
|
3527
|
+
const config = parseConfig(slabData, layout);
|
|
3528
|
+
if (config.maxPnlCap === 0n) return false;
|
|
3529
|
+
return engine.pnlPosTot > config.maxPnlCap;
|
|
3530
|
+
} catch {
|
|
3531
|
+
return false;
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
async function fetchAdlRankedPositions(connection, slab) {
|
|
3535
|
+
const data = await fetchSlab(connection, slab);
|
|
3536
|
+
return rankAdlPositions(data);
|
|
3537
|
+
}
|
|
3538
|
+
function rankAdlPositions(slabData) {
|
|
3539
|
+
const layout = detectSlabLayout(slabData.length);
|
|
3540
|
+
let pnlPosTot = 0n;
|
|
3541
|
+
try {
|
|
3542
|
+
const engine = parseEngine(slabData);
|
|
3543
|
+
pnlPosTot = engine.pnlPosTot;
|
|
3544
|
+
} catch (err) {
|
|
3545
|
+
console.warn(
|
|
3546
|
+
`[rankAdlPositions] parseEngine failed:`,
|
|
3547
|
+
err instanceof Error ? err.message : err
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
let maxPnlCap = 0n;
|
|
3551
|
+
let isTriggered = false;
|
|
3552
|
+
if (layout) {
|
|
3553
|
+
try {
|
|
3554
|
+
const config = parseConfig(slabData, layout);
|
|
3555
|
+
maxPnlCap = config.maxPnlCap;
|
|
3556
|
+
isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;
|
|
3557
|
+
} catch {
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
const accounts = parseAllAccounts(slabData);
|
|
3561
|
+
const positions = [];
|
|
3562
|
+
for (const { idx, account } of accounts) {
|
|
3563
|
+
if (account.kind !== 0 /* User */) continue;
|
|
3564
|
+
if (account.positionSize === 0n) continue;
|
|
3565
|
+
const side = account.positionSize > 0n ? "long" : "short";
|
|
3566
|
+
const pnlPct = computePnlPct(account.pnl, account.capital);
|
|
3567
|
+
positions.push({
|
|
3568
|
+
idx,
|
|
3569
|
+
owner: account.owner,
|
|
3570
|
+
positionSize: account.positionSize,
|
|
3571
|
+
pnl: account.pnl,
|
|
3572
|
+
capital: account.capital,
|
|
3573
|
+
pnlPct,
|
|
3574
|
+
side,
|
|
3575
|
+
adlRank: -1
|
|
3576
|
+
// assigned below
|
|
3577
|
+
});
|
|
3578
|
+
}
|
|
3579
|
+
const longs = positions.filter((p) => p.side === "long").sort((a, b) => b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0);
|
|
3580
|
+
longs.forEach((p, i) => {
|
|
3581
|
+
p.adlRank = i;
|
|
3582
|
+
});
|
|
3583
|
+
const shorts = positions.filter((p) => p.side === "short").sort((a, b) => b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0);
|
|
3584
|
+
shorts.forEach((p, i) => {
|
|
3585
|
+
p.adlRank = i;
|
|
3586
|
+
});
|
|
3587
|
+
const ranked = [...longs, ...shorts].sort(
|
|
3588
|
+
(a, b) => b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0
|
|
3589
|
+
);
|
|
3590
|
+
return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap };
|
|
3591
|
+
}
|
|
3592
|
+
function buildAdlInstruction(caller, slab, oracle, programId, targetIdx, backupOracles = []) {
|
|
3593
|
+
if (!Number.isInteger(targetIdx) || targetIdx < 0) {
|
|
3594
|
+
throw new Error(
|
|
3595
|
+
`buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`
|
|
3596
|
+
);
|
|
3597
|
+
}
|
|
3598
|
+
const dataBytes = encodeExecuteAdl({ targetIdx });
|
|
3599
|
+
const data = Buffer.from(dataBytes);
|
|
3600
|
+
const keys = [
|
|
3601
|
+
{ pubkey: caller, isSigner: true, isWritable: false },
|
|
3602
|
+
{ pubkey: slab, isSigner: false, isWritable: true },
|
|
3603
|
+
{ pubkey: SYSVAR_CLOCK_PUBKEY3, isSigner: false, isWritable: false },
|
|
3604
|
+
{ pubkey: oracle, isSigner: false, isWritable: false },
|
|
3605
|
+
...backupOracles.map((k) => ({ pubkey: k, isSigner: false, isWritable: false }))
|
|
3606
|
+
];
|
|
3607
|
+
return new TransactionInstruction({ keys, programId, data });
|
|
3608
|
+
}
|
|
3609
|
+
async function buildAdlTransaction(connection, caller, slab, oracle, programId, preferSide, backupOracles = []) {
|
|
3610
|
+
const ranking = await fetchAdlRankedPositions(connection, slab);
|
|
3611
|
+
if (!ranking.isTriggered) return null;
|
|
3612
|
+
let target;
|
|
3613
|
+
if (preferSide === "long") {
|
|
3614
|
+
target = ranking.longs[0];
|
|
3615
|
+
} else if (preferSide === "short") {
|
|
3616
|
+
target = ranking.shorts[0];
|
|
3617
|
+
} else {
|
|
3618
|
+
target = ranking.ranked[0];
|
|
3619
|
+
}
|
|
3620
|
+
if (!target) return null;
|
|
3621
|
+
return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);
|
|
3622
|
+
}
|
|
3623
|
+
var ADL_EVENT_TAG = 0xAD1E0001n;
|
|
3624
|
+
function parseAdlEvent(logs) {
|
|
3625
|
+
for (const line of logs) {
|
|
3626
|
+
if (typeof line !== "string") continue;
|
|
3627
|
+
const match = line.match(
|
|
3628
|
+
/^Program log: (\d+) (\d+) (\d+) (\d+) (\d+)$/
|
|
3629
|
+
);
|
|
3630
|
+
if (!match) continue;
|
|
3631
|
+
let tag;
|
|
3632
|
+
try {
|
|
3633
|
+
tag = BigInt(match[1]);
|
|
3634
|
+
} catch {
|
|
3635
|
+
continue;
|
|
3636
|
+
}
|
|
3637
|
+
if (tag !== ADL_EVENT_TAG) continue;
|
|
3638
|
+
try {
|
|
3639
|
+
const targetIdx = Number(BigInt(match[2]));
|
|
3640
|
+
const price = BigInt(match[3]);
|
|
3641
|
+
const closedLo = BigInt(match[4]);
|
|
3642
|
+
const closedHi = BigInt(match[5]);
|
|
3643
|
+
const closedAbs = closedHi << 64n | closedLo;
|
|
3644
|
+
return { tag, targetIdx, price, closedAbs };
|
|
3645
|
+
} catch {
|
|
3646
|
+
continue;
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
return null;
|
|
3650
|
+
}
|
|
3651
|
+
async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
|
|
3652
|
+
const slabStr = typeof slab === "string" ? slab : slab.toBase58();
|
|
3653
|
+
const base = apiBase.replace(/\/$/, "");
|
|
3654
|
+
const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;
|
|
3655
|
+
const res = await fetchFn(url);
|
|
3656
|
+
if (!res.ok) {
|
|
3657
|
+
let body = "";
|
|
3658
|
+
try {
|
|
3659
|
+
body = await res.text();
|
|
3660
|
+
} catch {
|
|
3661
|
+
}
|
|
3662
|
+
throw new Error(
|
|
3663
|
+
`fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` \u2014 ${body}` : ""}`
|
|
3664
|
+
);
|
|
3665
|
+
}
|
|
3666
|
+
const json = await res.json();
|
|
3667
|
+
return json;
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
// src/runtime/tx.ts
|
|
3671
|
+
import {
|
|
3672
|
+
TransactionInstruction as TransactionInstruction2,
|
|
3673
|
+
Transaction,
|
|
3674
|
+
ComputeBudgetProgram
|
|
3675
|
+
} from "@solana/web3.js";
|
|
3676
|
+
function buildIx(params) {
|
|
3677
|
+
return new TransactionInstruction2({
|
|
3678
|
+
programId: params.programId,
|
|
3679
|
+
keys: params.keys,
|
|
3680
|
+
// TransactionInstruction types expect Buffer, but Uint8Array works at runtime.
|
|
3681
|
+
// Cast to avoid Buffer polyfill issues in the browser.
|
|
3682
|
+
data: params.data
|
|
3683
|
+
});
|
|
3684
|
+
}
|
|
3685
|
+
var MAX_COMPUTE_UNIT_LIMIT = 14e5;
|
|
3686
|
+
async function simulateOrSend(params) {
|
|
3687
|
+
const { connection, ix, signers, simulate, commitment = "confirmed", computeUnitLimit } = params;
|
|
3688
|
+
if (!signers.length) {
|
|
3689
|
+
throw new Error("simulateOrSend: at least one signer is required");
|
|
3690
|
+
}
|
|
3691
|
+
if (computeUnitLimit !== void 0) {
|
|
3692
|
+
if (typeof computeUnitLimit !== "number" || !Number.isInteger(computeUnitLimit) || computeUnitLimit < 1 || computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT) {
|
|
3693
|
+
throw new Error(
|
|
3694
|
+
`computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`
|
|
3695
|
+
);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
const tx = new Transaction();
|
|
3699
|
+
if (computeUnitLimit !== void 0) {
|
|
3700
|
+
tx.add(
|
|
3701
|
+
ComputeBudgetProgram.setComputeUnitLimit({
|
|
3702
|
+
units: computeUnitLimit
|
|
3703
|
+
})
|
|
3704
|
+
);
|
|
3705
|
+
}
|
|
3706
|
+
tx.add(ix);
|
|
3707
|
+
const latestBlockhash = await connection.getLatestBlockhash(commitment);
|
|
3708
|
+
tx.recentBlockhash = latestBlockhash.blockhash;
|
|
3709
|
+
tx.feePayer = signers[0].publicKey;
|
|
3710
|
+
if (simulate) {
|
|
3711
|
+
try {
|
|
3712
|
+
tx.sign(...signers);
|
|
3713
|
+
const result = await connection.simulateTransaction(tx, signers);
|
|
3714
|
+
const logs = result.value.logs ?? [];
|
|
3715
|
+
let err = null;
|
|
3716
|
+
let hint;
|
|
3717
|
+
if (result.value.err) {
|
|
3718
|
+
const parsed = parseErrorFromLogs(logs);
|
|
3719
|
+
if (parsed) {
|
|
3720
|
+
err = `${parsed.name} (0x${parsed.code.toString(16)})`;
|
|
3721
|
+
hint = parsed.hint;
|
|
3722
|
+
} else {
|
|
3723
|
+
err = JSON.stringify(result.value.err);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
return {
|
|
3727
|
+
signature: "(simulated)",
|
|
3728
|
+
slot: result.context.slot,
|
|
3729
|
+
err,
|
|
3730
|
+
hint,
|
|
3731
|
+
logs,
|
|
3732
|
+
unitsConsumed: result.value.unitsConsumed ?? void 0
|
|
3733
|
+
};
|
|
3734
|
+
} catch (e) {
|
|
3735
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
3736
|
+
return {
|
|
3737
|
+
signature: "(simulated)",
|
|
3738
|
+
slot: 0,
|
|
3739
|
+
err: message,
|
|
3740
|
+
logs: []
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
const options = {
|
|
3745
|
+
skipPreflight: false,
|
|
3746
|
+
preflightCommitment: commitment
|
|
3747
|
+
};
|
|
3748
|
+
try {
|
|
3749
|
+
const signature = await connection.sendTransaction(tx, signers, options);
|
|
3750
|
+
const confirmation = await connection.confirmTransaction(
|
|
3751
|
+
{
|
|
3752
|
+
signature,
|
|
3753
|
+
blockhash: latestBlockhash.blockhash,
|
|
3754
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
|
|
3755
|
+
},
|
|
3756
|
+
commitment
|
|
3757
|
+
);
|
|
3758
|
+
const txInfo = await connection.getTransaction(signature, {
|
|
3759
|
+
commitment: "confirmed",
|
|
3760
|
+
maxSupportedTransactionVersion: 0
|
|
3761
|
+
});
|
|
3762
|
+
const logs = txInfo?.meta?.logMessages ?? [];
|
|
3763
|
+
let err = null;
|
|
3764
|
+
let hint;
|
|
3765
|
+
if (confirmation.value.err) {
|
|
3766
|
+
const parsed = parseErrorFromLogs(logs);
|
|
3767
|
+
if (parsed) {
|
|
3768
|
+
err = `${parsed.name} (0x${parsed.code.toString(16)})`;
|
|
3769
|
+
hint = parsed.hint;
|
|
3770
|
+
} else {
|
|
3771
|
+
err = JSON.stringify(confirmation.value.err);
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
return {
|
|
3775
|
+
signature,
|
|
3776
|
+
slot: txInfo?.slot ?? 0,
|
|
3777
|
+
err,
|
|
3778
|
+
hint,
|
|
3779
|
+
logs
|
|
3780
|
+
};
|
|
3781
|
+
} catch (e) {
|
|
3782
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
3783
|
+
return {
|
|
3784
|
+
signature: "",
|
|
3785
|
+
slot: 0,
|
|
3786
|
+
err: message,
|
|
3787
|
+
logs: []
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
function formatResult(result, jsonMode) {
|
|
3792
|
+
if (jsonMode) {
|
|
3793
|
+
return JSON.stringify(result, null, 2);
|
|
3794
|
+
}
|
|
3795
|
+
const lines = [];
|
|
3796
|
+
if (result.err) {
|
|
3797
|
+
lines.push(`Error: ${result.err}`);
|
|
3798
|
+
if (result.hint) {
|
|
3799
|
+
lines.push(`Hint: ${result.hint}`);
|
|
3800
|
+
}
|
|
3801
|
+
if (result.unitsConsumed !== void 0) {
|
|
3802
|
+
lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);
|
|
3803
|
+
}
|
|
3804
|
+
if (result.logs.length > 0) {
|
|
3805
|
+
lines.push("Logs:");
|
|
3806
|
+
result.logs.forEach((log) => lines.push(` ${log}`));
|
|
3807
|
+
}
|
|
3808
|
+
} else {
|
|
3809
|
+
lines.push(`Signature: ${result.signature}`);
|
|
3810
|
+
lines.push(`Slot: ${result.slot}`);
|
|
3811
|
+
if (result.unitsConsumed !== void 0) {
|
|
3812
|
+
lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);
|
|
3813
|
+
}
|
|
3814
|
+
if (result.signature !== "(simulated)") {
|
|
3815
|
+
lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
return lines.join("\n");
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
// src/math/trading.ts
|
|
3822
|
+
function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
|
|
3823
|
+
if (positionSize === 0n || oraclePrice === 0n) return 0n;
|
|
3824
|
+
const absPos = positionSize < 0n ? -positionSize : positionSize;
|
|
3825
|
+
const diff = positionSize > 0n ? oraclePrice - entryPrice : entryPrice - oraclePrice;
|
|
3826
|
+
return diff * absPos / oraclePrice;
|
|
3827
|
+
}
|
|
3828
|
+
function computeLiqPrice(entryPrice, capital, positionSize, maintenanceMarginBps) {
|
|
3829
|
+
if (positionSize === 0n || entryPrice === 0n) return 0n;
|
|
3830
|
+
const absPos = positionSize < 0n ? -positionSize : positionSize;
|
|
3831
|
+
const capitalPerUnitE6 = capital * 1000000n / absPos;
|
|
3832
|
+
if (positionSize > 0n) {
|
|
3833
|
+
const adjusted = capitalPerUnitE6 * 10000n / (10000n + maintenanceMarginBps);
|
|
3834
|
+
const liq = entryPrice - adjusted;
|
|
3835
|
+
return liq > 0n ? liq : 0n;
|
|
3836
|
+
} else {
|
|
3837
|
+
if (maintenanceMarginBps >= 10000n) return 18446744073709551615n;
|
|
3838
|
+
const adjusted = capitalPerUnitE6 * 10000n / (10000n - maintenanceMarginBps);
|
|
3839
|
+
return entryPrice + adjusted;
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
function computePreTradeLiqPrice(oracleE6, margin, posSize, maintBps, feeBps, direction) {
|
|
3843
|
+
if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;
|
|
3844
|
+
const absPos = posSize < 0n ? -posSize : posSize;
|
|
3845
|
+
const fee = absPos * feeBps / 10000n;
|
|
3846
|
+
const effectiveCapital = margin > fee ? margin - fee : 0n;
|
|
3847
|
+
const signedPos = direction === "long" ? absPos : -absPos;
|
|
3848
|
+
return computeLiqPrice(oracleE6, effectiveCapital, signedPos, maintBps);
|
|
3849
|
+
}
|
|
3850
|
+
function computeTradingFee(notional, tradingFeeBps) {
|
|
3851
|
+
return notional * tradingFeeBps / 10000n;
|
|
3852
|
+
}
|
|
3853
|
+
function computeDynamicFeeBps(notional, config) {
|
|
3854
|
+
if (config.tier2Threshold === 0n) return config.baseBps;
|
|
3855
|
+
if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;
|
|
3856
|
+
if (notional >= config.tier2Threshold) return config.tier2Bps;
|
|
3857
|
+
return config.baseBps;
|
|
3858
|
+
}
|
|
3859
|
+
function computeDynamicTradingFee(notional, config) {
|
|
3860
|
+
const feeBps = computeDynamicFeeBps(notional, config);
|
|
3861
|
+
if (notional <= 0n || feeBps <= 0n) return 0n;
|
|
3862
|
+
return (notional * feeBps + 9999n) / 10000n;
|
|
3863
|
+
}
|
|
3864
|
+
function computeFeeSplit(totalFee, config) {
|
|
3865
|
+
if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
|
|
3866
|
+
return [totalFee, 0n, 0n];
|
|
3867
|
+
}
|
|
3868
|
+
const lp = totalFee * config.lpBps / 10000n;
|
|
3869
|
+
const protocol = totalFee * config.protocolBps / 10000n;
|
|
3870
|
+
const creator = totalFee - lp - protocol;
|
|
3871
|
+
return [lp, protocol, creator];
|
|
3872
|
+
}
|
|
3873
|
+
function computePnlPercent(pnlTokens, capital) {
|
|
3874
|
+
if (capital === 0n) return 0;
|
|
3875
|
+
const scaledPct = pnlTokens * 10000n / capital;
|
|
3876
|
+
if (scaledPct > BigInt(Number.MAX_SAFE_INTEGER) || scaledPct < BigInt(-Number.MAX_SAFE_INTEGER)) {
|
|
3877
|
+
throw new Error(
|
|
3878
|
+
`computePnlPercent: scaled result ${scaledPct} exceeds Number.MAX_SAFE_INTEGER \u2014 precision loss`
|
|
3879
|
+
);
|
|
3880
|
+
}
|
|
3881
|
+
return Number(scaledPct) / 100;
|
|
3882
|
+
}
|
|
3883
|
+
function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
|
|
3884
|
+
if (oracleE6 === 0n) return 0n;
|
|
3885
|
+
const feeImpact = oracleE6 * tradingFeeBps / 10000n;
|
|
3886
|
+
return direction === "long" ? oracleE6 + feeImpact : oracleE6 - feeImpact;
|
|
3887
|
+
}
|
|
3888
|
+
var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
3889
|
+
var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
|
|
3890
|
+
function computeFundingRateAnnualized(fundingRateBpsPerSlot) {
|
|
3891
|
+
if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT || fundingRateBpsPerSlot < MIN_SAFE_BIGINT) {
|
|
3892
|
+
throw new Error(
|
|
3893
|
+
`computeFundingRateAnnualized: value ${fundingRateBpsPerSlot} exceeds safe integer range`
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
const bpsPerSlot = Number(fundingRateBpsPerSlot);
|
|
3897
|
+
const slotsPerYear = 2.5 * 60 * 60 * 24 * 365;
|
|
3898
|
+
return bpsPerSlot * slotsPerYear / 100;
|
|
3899
|
+
}
|
|
3900
|
+
function computeRequiredMargin(notional, initialMarginBps) {
|
|
3901
|
+
return notional * initialMarginBps / 10000n;
|
|
3902
|
+
}
|
|
3903
|
+
function computeMaxLeverage(initialMarginBps) {
|
|
3904
|
+
if (initialMarginBps <= 0n) {
|
|
3905
|
+
throw new Error("computeMaxLeverage: initialMarginBps must be positive");
|
|
3906
|
+
}
|
|
3907
|
+
return Number(10000n / initialMarginBps);
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
// src/math/warmup.ts
|
|
3911
|
+
function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
3912
|
+
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;
|
|
3913
|
+
if (totalCapital <= 0n) return 0n;
|
|
3914
|
+
const elapsed = currentSlot > warmupStartSlot ? currentSlot - warmupStartSlot : 0n;
|
|
3915
|
+
if (elapsed >= warmupPeriodSlots) return totalCapital;
|
|
3916
|
+
return totalCapital * elapsed / warmupPeriodSlots;
|
|
3917
|
+
}
|
|
3918
|
+
function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
3919
|
+
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
3920
|
+
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
|
|
3921
|
+
if (totalCapital <= 0n) return 1;
|
|
3922
|
+
const unlocked = computeWarmupUnlockedCapital(
|
|
3923
|
+
totalCapital,
|
|
3924
|
+
currentSlot,
|
|
3925
|
+
warmupStartSlot,
|
|
3926
|
+
warmupPeriodSlots
|
|
3927
|
+
);
|
|
3928
|
+
if (unlocked <= 0n) return 1;
|
|
3929
|
+
const effectiveLev = Number(BigInt(maxLev) * unlocked / totalCapital);
|
|
3930
|
+
return Math.max(1, effectiveLev);
|
|
3931
|
+
}
|
|
3932
|
+
function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
3933
|
+
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
3934
|
+
const unlocked = computeWarmupUnlockedCapital(
|
|
3935
|
+
totalCapital,
|
|
3936
|
+
currentSlot,
|
|
3937
|
+
warmupStartSlot,
|
|
3938
|
+
warmupPeriodSlots
|
|
3939
|
+
);
|
|
3940
|
+
return unlocked * BigInt(maxLev);
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
// src/validation.ts
|
|
3944
|
+
import { PublicKey as PublicKey11 } from "@solana/web3.js";
|
|
3945
|
+
var U16_MAX = 65535;
|
|
3946
|
+
var U64_MAX = BigInt("18446744073709551615");
|
|
3947
|
+
var I64_MIN = BigInt("-9223372036854775808");
|
|
3948
|
+
var I64_MAX = BigInt("9223372036854775807");
|
|
3949
|
+
var U128_MAX = (1n << 128n) - 1n;
|
|
3950
|
+
var I128_MIN = -(1n << 127n);
|
|
3951
|
+
var I128_MAX = (1n << 127n) - 1n;
|
|
3952
|
+
function requireDecimalUIntString(value, field) {
|
|
3953
|
+
const t = value.trim();
|
|
3954
|
+
if (t === "") {
|
|
3955
|
+
throw new ValidationError(field, `"${value}" is not a valid number`);
|
|
3956
|
+
}
|
|
3957
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
3958
|
+
throw new ValidationError(
|
|
3959
|
+
field,
|
|
3960
|
+
`"${value}" is not a valid non-negative integer (use decimal digits only, e.g. 123).`
|
|
3961
|
+
);
|
|
3962
|
+
}
|
|
3963
|
+
return t;
|
|
3964
|
+
}
|
|
3965
|
+
var ValidationError = class extends Error {
|
|
3966
|
+
constructor(field, message) {
|
|
3967
|
+
super(`Invalid ${field}: ${message}`);
|
|
3968
|
+
this.field = field;
|
|
3969
|
+
this.name = "ValidationError";
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
function validatePublicKey(value, field) {
|
|
3973
|
+
try {
|
|
3974
|
+
return new PublicKey11(value);
|
|
3975
|
+
} catch {
|
|
3976
|
+
throw new ValidationError(
|
|
3977
|
+
field,
|
|
3978
|
+
`"${value}" is not a valid base58 public key. Example: "11111111111111111111111111111111"`
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
function validateIndex(value, field) {
|
|
3983
|
+
const t = requireDecimalUIntString(value, field);
|
|
3984
|
+
const bi = BigInt(t);
|
|
3985
|
+
if (bi > BigInt(U16_MAX)) {
|
|
3986
|
+
throw new ValidationError(
|
|
3987
|
+
field,
|
|
3988
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
3989
|
+
);
|
|
3990
|
+
}
|
|
3991
|
+
return Number(bi);
|
|
3992
|
+
}
|
|
3993
|
+
function validateAmount(value, field) {
|
|
3994
|
+
let num;
|
|
3995
|
+
try {
|
|
3996
|
+
num = BigInt(value);
|
|
3997
|
+
} catch {
|
|
3998
|
+
throw new ValidationError(
|
|
3999
|
+
field,
|
|
4000
|
+
`"${value}" is not a valid number. Use decimal digits only.`
|
|
4001
|
+
);
|
|
4002
|
+
}
|
|
4003
|
+
if (num < 0n) {
|
|
4004
|
+
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4005
|
+
}
|
|
4006
|
+
if (num > U64_MAX) {
|
|
4007
|
+
throw new ValidationError(
|
|
4008
|
+
field,
|
|
4009
|
+
`must be <= ${U64_MAX} (u64 max), got ${num}`
|
|
4010
|
+
);
|
|
4011
|
+
}
|
|
4012
|
+
return num;
|
|
4013
|
+
}
|
|
4014
|
+
function validateU128(value, field) {
|
|
4015
|
+
let num;
|
|
4016
|
+
try {
|
|
4017
|
+
num = BigInt(value);
|
|
4018
|
+
} catch {
|
|
4019
|
+
throw new ValidationError(
|
|
4020
|
+
field,
|
|
4021
|
+
`"${value}" is not a valid number. Use decimal digits only.`
|
|
4022
|
+
);
|
|
4023
|
+
}
|
|
4024
|
+
if (num < 0n) {
|
|
4025
|
+
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4026
|
+
}
|
|
4027
|
+
if (num > U128_MAX) {
|
|
4028
|
+
throw new ValidationError(
|
|
4029
|
+
field,
|
|
4030
|
+
`must be <= ${U128_MAX} (u128 max), got ${num}`
|
|
4031
|
+
);
|
|
4032
|
+
}
|
|
4033
|
+
return num;
|
|
4034
|
+
}
|
|
4035
|
+
function validateI64(value, field) {
|
|
4036
|
+
let num;
|
|
4037
|
+
try {
|
|
4038
|
+
num = BigInt(value);
|
|
4039
|
+
} catch {
|
|
4040
|
+
throw new ValidationError(
|
|
4041
|
+
field,
|
|
4042
|
+
`"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
|
|
4043
|
+
);
|
|
4044
|
+
}
|
|
4045
|
+
if (num < I64_MIN) {
|
|
4046
|
+
throw new ValidationError(
|
|
4047
|
+
field,
|
|
4048
|
+
`must be >= ${I64_MIN} (i64 min), got ${num}`
|
|
4049
|
+
);
|
|
4050
|
+
}
|
|
4051
|
+
if (num > I64_MAX) {
|
|
4052
|
+
throw new ValidationError(
|
|
4053
|
+
field,
|
|
4054
|
+
`must be <= ${I64_MAX} (i64 max), got ${num}`
|
|
4055
|
+
);
|
|
4056
|
+
}
|
|
4057
|
+
return num;
|
|
4058
|
+
}
|
|
4059
|
+
function validateI128(value, field) {
|
|
4060
|
+
let num;
|
|
4061
|
+
try {
|
|
4062
|
+
num = BigInt(value);
|
|
4063
|
+
} catch {
|
|
4064
|
+
throw new ValidationError(
|
|
4065
|
+
field,
|
|
4066
|
+
`"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
|
|
4067
|
+
);
|
|
4068
|
+
}
|
|
4069
|
+
if (num < I128_MIN) {
|
|
4070
|
+
throw new ValidationError(
|
|
4071
|
+
field,
|
|
4072
|
+
`must be >= ${I128_MIN} (i128 min), got ${num}`
|
|
4073
|
+
);
|
|
4074
|
+
}
|
|
4075
|
+
if (num > I128_MAX) {
|
|
4076
|
+
throw new ValidationError(
|
|
4077
|
+
field,
|
|
4078
|
+
`must be <= ${I128_MAX} (i128 max), got ${num}`
|
|
4079
|
+
);
|
|
4080
|
+
}
|
|
4081
|
+
return num;
|
|
4082
|
+
}
|
|
4083
|
+
function validateBps(value, field) {
|
|
4084
|
+
const t = requireDecimalUIntString(value, field);
|
|
4085
|
+
const bi = BigInt(t);
|
|
4086
|
+
if (bi > 10000n) {
|
|
4087
|
+
throw new ValidationError(
|
|
4088
|
+
field,
|
|
4089
|
+
`must be <= 10000 (100%), got ${t}`
|
|
4090
|
+
);
|
|
4091
|
+
}
|
|
4092
|
+
return Number(bi);
|
|
4093
|
+
}
|
|
4094
|
+
function validateU64(value, field) {
|
|
4095
|
+
return validateAmount(value, field);
|
|
4096
|
+
}
|
|
4097
|
+
function validateU16(value, field) {
|
|
4098
|
+
const t = requireDecimalUIntString(value, field);
|
|
4099
|
+
const bi = BigInt(t);
|
|
4100
|
+
if (bi > BigInt(U16_MAX)) {
|
|
4101
|
+
throw new ValidationError(
|
|
4102
|
+
field,
|
|
4103
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4104
|
+
);
|
|
4105
|
+
}
|
|
4106
|
+
return Number(bi);
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
// src/oracle/price-router.ts
|
|
4110
|
+
var DEFAULT_RESOLVE_TIMEOUT_MS = 15e3;
|
|
4111
|
+
function isRecord(v) {
|
|
4112
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4113
|
+
}
|
|
4114
|
+
function combineAbortSignals(signals) {
|
|
4115
|
+
const already = signals.find((s) => s.aborted);
|
|
4116
|
+
if (already) {
|
|
4117
|
+
const c = new AbortController();
|
|
4118
|
+
c.abort(already.reason);
|
|
4119
|
+
return c.signal;
|
|
4120
|
+
}
|
|
4121
|
+
const active = signals.filter((s) => !s.aborted);
|
|
4122
|
+
if (active.length === 0) {
|
|
4123
|
+
const c = new AbortController();
|
|
4124
|
+
c.abort();
|
|
4125
|
+
return c.signal;
|
|
4126
|
+
}
|
|
4127
|
+
if (active.length === 1) return active[0];
|
|
4128
|
+
const ctrl = new AbortController();
|
|
4129
|
+
for (const s of active) {
|
|
4130
|
+
s.addEventListener("abort", () => ctrl.abort(s.reason), { once: true });
|
|
4131
|
+
}
|
|
4132
|
+
return ctrl.signal;
|
|
4133
|
+
}
|
|
4134
|
+
var SUPPORTED_DEX_IDS = /* @__PURE__ */ new Set(["pumpswap", "raydium", "meteora"]);
|
|
4135
|
+
function parseDexScreenerPairs(json) {
|
|
4136
|
+
if (!isRecord(json)) return [];
|
|
4137
|
+
const rawPairs = json.pairs;
|
|
4138
|
+
if (!Array.isArray(rawPairs)) return [];
|
|
4139
|
+
const sources = [];
|
|
4140
|
+
for (const pair of rawPairs) {
|
|
4141
|
+
if (!isRecord(pair)) continue;
|
|
4142
|
+
if (pair.chainId !== "solana") continue;
|
|
4143
|
+
const dexId = String(pair.dexId || "").toLowerCase();
|
|
4144
|
+
if (!SUPPORTED_DEX_IDS.has(dexId)) continue;
|
|
4145
|
+
let liquidity = 0;
|
|
4146
|
+
if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === "number") {
|
|
4147
|
+
liquidity = pair.liquidity.usd;
|
|
4148
|
+
}
|
|
4149
|
+
if (liquidity < 100) continue;
|
|
4150
|
+
let confidence = 30;
|
|
4151
|
+
if (liquidity > 1e6) confidence = 90;
|
|
4152
|
+
else if (liquidity > 1e5) confidence = 75;
|
|
4153
|
+
else if (liquidity > 1e4) confidence = 60;
|
|
4154
|
+
else if (liquidity > 1e3) confidence = 45;
|
|
4155
|
+
const priceUsd = pair.priceUsd;
|
|
4156
|
+
const price = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) || 0 : 0;
|
|
4157
|
+
let baseSym = "?";
|
|
4158
|
+
let quoteSym = "?";
|
|
4159
|
+
if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
|
|
4160
|
+
baseSym = pair.baseToken.symbol;
|
|
4161
|
+
}
|
|
4162
|
+
if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === "string") {
|
|
4163
|
+
quoteSym = pair.quoteToken.symbol;
|
|
4164
|
+
}
|
|
4165
|
+
const addr = pair.pairAddress;
|
|
4166
|
+
sources.push({
|
|
4167
|
+
type: "dex",
|
|
4168
|
+
address: typeof addr === "string" ? addr : "",
|
|
4169
|
+
dexId,
|
|
4170
|
+
pairLabel: `${baseSym} / ${quoteSym}`,
|
|
4171
|
+
liquidity,
|
|
4172
|
+
price,
|
|
4173
|
+
confidence
|
|
4174
|
+
});
|
|
4175
|
+
}
|
|
4176
|
+
sources.sort((a, b) => b.liquidity - a.liquidity);
|
|
4177
|
+
return sources.slice(0, 10);
|
|
4178
|
+
}
|
|
4179
|
+
function parseJupiterMintEntry(json, mint) {
|
|
4180
|
+
if (!isRecord(json)) return null;
|
|
4181
|
+
const data = json.data;
|
|
4182
|
+
if (!isRecord(data)) return null;
|
|
4183
|
+
const row = data[mint];
|
|
4184
|
+
if (!isRecord(row)) return null;
|
|
4185
|
+
const rawPrice = row.price;
|
|
4186
|
+
if (rawPrice === void 0 || rawPrice === null) return null;
|
|
4187
|
+
const price = parseFloat(String(rawPrice)) || 0;
|
|
4188
|
+
if (price <= 0) return null;
|
|
4189
|
+
let mintSymbol = "?";
|
|
4190
|
+
if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
|
|
4191
|
+
return { price, mintSymbol };
|
|
4192
|
+
}
|
|
4193
|
+
var PYTH_SOLANA_FEEDS = {
|
|
4194
|
+
// SOL
|
|
4195
|
+
"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d": { symbol: "SOL", mint: "So11111111111111111111111111111111111111112" },
|
|
4196
|
+
// BTC
|
|
4197
|
+
"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43": { symbol: "BTC", mint: "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E" },
|
|
4198
|
+
// ETH
|
|
4199
|
+
"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace": { symbol: "ETH", mint: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" },
|
|
4200
|
+
// USDC
|
|
4201
|
+
"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a": { symbol: "USDC", mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" },
|
|
4202
|
+
// USDT
|
|
4203
|
+
"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b": { symbol: "USDT", mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" },
|
|
4204
|
+
// BONK
|
|
4205
|
+
"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419": { symbol: "BONK", mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" },
|
|
4206
|
+
// JTO
|
|
4207
|
+
"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2": { symbol: "JTO", mint: "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL" },
|
|
4208
|
+
// JUP
|
|
4209
|
+
"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996": { symbol: "JUP", mint: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" },
|
|
4210
|
+
// PYTH
|
|
4211
|
+
"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff": { symbol: "PYTH", mint: "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3" },
|
|
4212
|
+
// RAY
|
|
4213
|
+
"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0": { symbol: "RAY", mint: "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R" },
|
|
4214
|
+
// ORCA
|
|
4215
|
+
"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95": { symbol: "ORCA", mint: "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE" },
|
|
4216
|
+
// MNGO
|
|
4217
|
+
"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90": { symbol: "MNGO", mint: "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac" },
|
|
4218
|
+
// MSOL
|
|
4219
|
+
"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4": { symbol: "MSOL", mint: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" },
|
|
4220
|
+
// JITOSOL
|
|
4221
|
+
"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb": { symbol: "JITOSOL", mint: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn" },
|
|
4222
|
+
// WIF
|
|
4223
|
+
"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03": { symbol: "WIF", mint: "EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm" },
|
|
4224
|
+
// RENDER
|
|
4225
|
+
"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6": { symbol: "RENDER", mint: "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof" },
|
|
4226
|
+
// W
|
|
4227
|
+
"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389": { symbol: "W", mint: "85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ" },
|
|
4228
|
+
// TNSR
|
|
4229
|
+
"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b": { symbol: "TNSR", mint: "TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6" },
|
|
4230
|
+
// HNT
|
|
4231
|
+
"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756": { symbol: "HNT", mint: "hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux" },
|
|
4232
|
+
// MOBILE
|
|
4233
|
+
"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0": { symbol: "MOBILE", mint: "mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6" },
|
|
4234
|
+
// IOT
|
|
4235
|
+
"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef": { symbol: "IOT", mint: "iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns" }
|
|
4236
|
+
};
|
|
4237
|
+
var MINT_TO_PYTH_FEED = /* @__PURE__ */ new Map();
|
|
4238
|
+
for (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {
|
|
4239
|
+
MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });
|
|
4240
|
+
}
|
|
4241
|
+
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
4242
|
+
function effectiveSignal(signal) {
|
|
4243
|
+
return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);
|
|
4244
|
+
}
|
|
4245
|
+
async function fetchDexSources(mint, signal) {
|
|
4246
|
+
try {
|
|
4247
|
+
const resp = await fetch(
|
|
4248
|
+
`https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,
|
|
4249
|
+
{
|
|
4250
|
+
signal: effectiveSignal(signal),
|
|
4251
|
+
headers: { "User-Agent": "percolator/1.0" }
|
|
4252
|
+
}
|
|
4253
|
+
);
|
|
4254
|
+
if (!resp.ok) return [];
|
|
4255
|
+
const json = await resp.json();
|
|
4256
|
+
return parseDexScreenerPairs(json);
|
|
4257
|
+
} catch {
|
|
4258
|
+
return [];
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
function lookupPythSource(mint) {
|
|
4262
|
+
const entry = MINT_TO_PYTH_FEED.get(mint);
|
|
4263
|
+
if (!entry) return null;
|
|
4264
|
+
return {
|
|
4265
|
+
type: "pyth",
|
|
4266
|
+
address: entry.feedId,
|
|
4267
|
+
pairLabel: `${entry.symbol} / USD (Pyth)`,
|
|
4268
|
+
liquidity: Infinity,
|
|
4269
|
+
// Pyth is considered deep liquidity
|
|
4270
|
+
price: 0,
|
|
4271
|
+
// We don't fetch live price here; caller can enrich
|
|
4272
|
+
confidence: 95
|
|
4273
|
+
// Pyth is highest reliability for supported tokens
|
|
4274
|
+
};
|
|
4275
|
+
}
|
|
4276
|
+
async function fetchJupiterSource(mint, signal) {
|
|
4277
|
+
try {
|
|
4278
|
+
const resp = await fetch(
|
|
4279
|
+
`https://api.jup.ag/price/v2?ids=${encodeURIComponent(mint)}`,
|
|
4280
|
+
{
|
|
4281
|
+
signal: effectiveSignal(signal),
|
|
4282
|
+
headers: { "User-Agent": "percolator/1.0" }
|
|
4283
|
+
}
|
|
4284
|
+
);
|
|
4285
|
+
if (!resp.ok) return null;
|
|
4286
|
+
const json = await resp.json();
|
|
4287
|
+
const row = parseJupiterMintEntry(json, mint);
|
|
4288
|
+
if (!row) return null;
|
|
4289
|
+
return {
|
|
4290
|
+
type: "jupiter",
|
|
4291
|
+
address: mint,
|
|
4292
|
+
pairLabel: `${row.mintSymbol} / USD (Jupiter)`,
|
|
4293
|
+
liquidity: 0,
|
|
4294
|
+
// Jupiter aggregator — no single pool liquidity
|
|
4295
|
+
price: row.price,
|
|
4296
|
+
confidence: 40
|
|
4297
|
+
// Fallback — lower confidence
|
|
4298
|
+
};
|
|
4299
|
+
} catch {
|
|
4300
|
+
return null;
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
async function resolvePrice(mint, signal, options) {
|
|
4304
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;
|
|
4305
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
4306
|
+
const effectiveSignal2 = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
|
|
4307
|
+
const [dexSources, jupiterSource] = await Promise.all([
|
|
4308
|
+
fetchDexSources(mint, effectiveSignal2),
|
|
4309
|
+
fetchJupiterSource(mint, effectiveSignal2)
|
|
4310
|
+
]);
|
|
4311
|
+
const pythSource = lookupPythSource(mint);
|
|
4312
|
+
const allSources = [];
|
|
4313
|
+
if (pythSource) {
|
|
4314
|
+
const refPrice = dexSources[0]?.price || jupiterSource?.price || 0;
|
|
4315
|
+
pythSource.price = refPrice;
|
|
4316
|
+
allSources.push(pythSource);
|
|
4317
|
+
}
|
|
4318
|
+
allSources.push(...dexSources);
|
|
4319
|
+
if (jupiterSource) {
|
|
4320
|
+
allSources.push(jupiterSource);
|
|
4321
|
+
}
|
|
4322
|
+
allSources.sort((a, b) => b.confidence - a.confidence);
|
|
4323
|
+
return {
|
|
4324
|
+
mint,
|
|
4325
|
+
bestSource: allSources[0] || null,
|
|
4326
|
+
allSources,
|
|
4327
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4328
|
+
};
|
|
4329
|
+
}
|
|
4330
|
+
export {
|
|
4331
|
+
ACCOUNTS_ADVANCE_ORACLE_PHASE,
|
|
4332
|
+
ACCOUNTS_AUDIT_CRANK,
|
|
4333
|
+
ACCOUNTS_BURN_POSITION_NFT,
|
|
4334
|
+
ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL,
|
|
4335
|
+
ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL,
|
|
4336
|
+
ACCOUNTS_CLEAR_PENDING_SETTLEMENT,
|
|
4337
|
+
ACCOUNTS_CLOSE_ACCOUNT,
|
|
4338
|
+
ACCOUNTS_CLOSE_SLAB,
|
|
4339
|
+
ACCOUNTS_CLOSE_STALE_SLABS,
|
|
4340
|
+
ACCOUNTS_CREATE_INSURANCE_MINT,
|
|
4341
|
+
ACCOUNTS_DEPOSIT_COLLATERAL,
|
|
4342
|
+
ACCOUNTS_DEPOSIT_INSURANCE_LP,
|
|
4343
|
+
ACCOUNTS_EXECUTE_ADL,
|
|
4344
|
+
ACCOUNTS_FUND_MARKET_INSURANCE,
|
|
4345
|
+
ACCOUNTS_INIT_LP,
|
|
4346
|
+
ACCOUNTS_INIT_MARKET,
|
|
4347
|
+
ACCOUNTS_INIT_USER,
|
|
4348
|
+
ACCOUNTS_KEEPER_CRANK,
|
|
4349
|
+
ACCOUNTS_LIQUIDATE_AT_ORACLE,
|
|
4350
|
+
ACCOUNTS_LP_VAULT_WITHDRAW,
|
|
4351
|
+
ACCOUNTS_MINT_POSITION_NFT,
|
|
4352
|
+
ACCOUNTS_PAUSE_MARKET,
|
|
4353
|
+
ACCOUNTS_PUSH_ORACLE_PRICE,
|
|
4354
|
+
ACCOUNTS_QUEUE_WITHDRAWAL,
|
|
4355
|
+
ACCOUNTS_RECLAIM_SLAB_RENT,
|
|
4356
|
+
ACCOUNTS_RESOLVE_MARKET,
|
|
4357
|
+
ACCOUNTS_SET_INSURANCE_ISOLATION,
|
|
4358
|
+
ACCOUNTS_SET_MAINTENANCE_FEE,
|
|
4359
|
+
ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK,
|
|
4360
|
+
ACCOUNTS_SET_ORACLE_AUTHORITY,
|
|
4361
|
+
ACCOUNTS_SET_ORACLE_PRICE_CAP,
|
|
4362
|
+
ACCOUNTS_SET_PENDING_SETTLEMENT,
|
|
4363
|
+
ACCOUNTS_SET_RISK_THRESHOLD,
|
|
4364
|
+
ACCOUNTS_SET_WALLET_CAP,
|
|
4365
|
+
ACCOUNTS_TOPUP_INSURANCE,
|
|
4366
|
+
ACCOUNTS_TOPUP_KEEPER_FUND,
|
|
4367
|
+
ACCOUNTS_TRADE_CPI,
|
|
4368
|
+
ACCOUNTS_TRADE_NOCPI,
|
|
4369
|
+
ACCOUNTS_TRANSFER_POSITION_OWNERSHIP,
|
|
4370
|
+
ACCOUNTS_UNPAUSE_MARKET,
|
|
4371
|
+
ACCOUNTS_UPDATE_ADMIN,
|
|
4372
|
+
ACCOUNTS_UPDATE_CONFIG,
|
|
4373
|
+
ACCOUNTS_WITHDRAW_COLLATERAL,
|
|
4374
|
+
ACCOUNTS_WITHDRAW_INSURANCE,
|
|
4375
|
+
ACCOUNTS_WITHDRAW_INSURANCE_LP,
|
|
4376
|
+
AccountKind,
|
|
4377
|
+
CHAINLINK_ANSWER_OFFSET,
|
|
4378
|
+
CHAINLINK_DECIMALS_OFFSET,
|
|
4379
|
+
CHAINLINK_MIN_SIZE,
|
|
4380
|
+
CREATOR_LOCK_SEED,
|
|
4381
|
+
CTX_VAMM_OFFSET,
|
|
4382
|
+
DEFAULT_OI_RAMP_SLOTS,
|
|
4383
|
+
ENGINE_MARK_PRICE_OFF,
|
|
4384
|
+
ENGINE_OFF,
|
|
4385
|
+
IX_TAG,
|
|
4386
|
+
MARK_PRICE_EMA_ALPHA_E6,
|
|
4387
|
+
MARK_PRICE_EMA_WINDOW_SLOTS,
|
|
4388
|
+
MAX_DECIMALS,
|
|
4389
|
+
METEORA_DLMM_PROGRAM_ID,
|
|
4390
|
+
ORACLE_PHASE_GROWING,
|
|
4391
|
+
ORACLE_PHASE_MATURE,
|
|
4392
|
+
ORACLE_PHASE_NASCENT,
|
|
4393
|
+
PERCOLATOR_ERRORS,
|
|
4394
|
+
PHASE1_MIN_SLOTS,
|
|
4395
|
+
PHASE1_VOLUME_MIN_SLOTS,
|
|
4396
|
+
PHASE2_MATURITY_SLOTS,
|
|
4397
|
+
PHASE2_VOLUME_THRESHOLD,
|
|
4398
|
+
PROGRAM_IDS,
|
|
4399
|
+
PUMPSWAP_PROGRAM_ID,
|
|
4400
|
+
PYTH_PUSH_ORACLE_PROGRAM_ID,
|
|
4401
|
+
PYTH_RECEIVER_PROGRAM_ID,
|
|
4402
|
+
PYTH_SOLANA_FEEDS,
|
|
4403
|
+
RAMP_START_BPS,
|
|
4404
|
+
RAYDIUM_CLMM_PROGRAM_ID,
|
|
4405
|
+
RENOUNCE_ADMIN_CONFIRMATION,
|
|
4406
|
+
SLAB_TIERS,
|
|
4407
|
+
SLAB_TIERS_V0,
|
|
4408
|
+
SLAB_TIERS_V1,
|
|
4409
|
+
SLAB_TIERS_V1D,
|
|
4410
|
+
SLAB_TIERS_V1D_LEGACY,
|
|
4411
|
+
SLAB_TIERS_V1M,
|
|
4412
|
+
SLAB_TIERS_V2,
|
|
4413
|
+
SLAB_TIERS_V_ADL,
|
|
4414
|
+
SLAB_TIERS_V_ADL_DISCOVERY,
|
|
4415
|
+
STAKE_IX,
|
|
4416
|
+
STAKE_POOL_SIZE,
|
|
4417
|
+
STAKE_PROGRAM_ID,
|
|
4418
|
+
STAKE_PROGRAM_IDS,
|
|
4419
|
+
TOKEN_2022_PROGRAM_ID,
|
|
4420
|
+
UNRESOLVE_CONFIRMATION,
|
|
4421
|
+
VAMM_MAGIC,
|
|
4422
|
+
ValidationError,
|
|
4423
|
+
WELL_KNOWN,
|
|
4424
|
+
buildAccountMetas,
|
|
4425
|
+
buildAdlInstruction,
|
|
4426
|
+
buildAdlTransaction,
|
|
4427
|
+
buildIx,
|
|
4428
|
+
checkPhaseTransition,
|
|
4429
|
+
computeDexSpotPriceE6,
|
|
4430
|
+
computeDynamicFeeBps,
|
|
4431
|
+
computeDynamicTradingFee,
|
|
4432
|
+
computeEffectiveOiCapBps,
|
|
4433
|
+
computeEmaMarkPrice,
|
|
4434
|
+
computeEstimatedEntryPrice,
|
|
4435
|
+
computeFeeSplit,
|
|
4436
|
+
computeFundingRateAnnualized,
|
|
4437
|
+
computeLiqPrice,
|
|
4438
|
+
computeMarkPnl,
|
|
4439
|
+
computeMaxLeverage,
|
|
4440
|
+
computePnlPercent,
|
|
4441
|
+
computePreTradeLiqPrice,
|
|
4442
|
+
computeRequiredMargin,
|
|
4443
|
+
computeTradingFee,
|
|
4444
|
+
computeVammQuote,
|
|
4445
|
+
computeWarmupLeverageCap,
|
|
4446
|
+
computeWarmupMaxPositionSize,
|
|
4447
|
+
computeWarmupUnlockedCapital,
|
|
4448
|
+
concatBytes,
|
|
4449
|
+
decodeError,
|
|
4450
|
+
decodeStakePool,
|
|
4451
|
+
depositAccounts,
|
|
4452
|
+
deriveCreatorLockPda,
|
|
4453
|
+
deriveDepositPda,
|
|
4454
|
+
deriveInsuranceLpMint,
|
|
4455
|
+
deriveKeeperFund,
|
|
4456
|
+
deriveLpPda,
|
|
4457
|
+
derivePythPriceUpdateAccount,
|
|
4458
|
+
derivePythPushOraclePDA,
|
|
4459
|
+
deriveStakePool,
|
|
4460
|
+
deriveStakeVaultAuth,
|
|
4461
|
+
deriveVaultAuthority,
|
|
4462
|
+
detectDexType,
|
|
4463
|
+
detectLayout,
|
|
4464
|
+
detectSlabLayout,
|
|
4465
|
+
detectTokenProgram,
|
|
4466
|
+
discoverMarkets,
|
|
4467
|
+
encBool,
|
|
4468
|
+
encI128,
|
|
4469
|
+
encI64,
|
|
4470
|
+
encPubkey,
|
|
4471
|
+
encU128,
|
|
4472
|
+
encU16,
|
|
4473
|
+
encU32,
|
|
4474
|
+
encU64,
|
|
4475
|
+
encU8,
|
|
4476
|
+
encodeAdminForceClose,
|
|
4477
|
+
encodeAdvanceEpoch,
|
|
4478
|
+
encodeAdvanceOraclePhase,
|
|
4479
|
+
encodeAllocateMarket,
|
|
4480
|
+
encodeAuditCrank,
|
|
4481
|
+
encodeBurnPositionNft,
|
|
4482
|
+
encodeCancelQueuedWithdrawal,
|
|
4483
|
+
encodeClaimEpochWithdrawal,
|
|
4484
|
+
encodeClaimQueuedWithdrawal,
|
|
4485
|
+
encodeClearPendingSettlement,
|
|
4486
|
+
encodeCloseAccount,
|
|
4487
|
+
encodeCloseSlab,
|
|
4488
|
+
encodeCloseStaleSlabs,
|
|
4489
|
+
encodeCreateInsuranceMint,
|
|
4490
|
+
encodeDepositCollateral,
|
|
4491
|
+
encodeDepositInsuranceLP,
|
|
4492
|
+
encodeExecuteAdl,
|
|
4493
|
+
encodeFundMarketInsurance,
|
|
4494
|
+
encodeInitLP,
|
|
4495
|
+
encodeInitMarket,
|
|
4496
|
+
encodeInitSharedVault,
|
|
4497
|
+
encodeInitUser,
|
|
4498
|
+
encodeKeeperCrank,
|
|
4499
|
+
encodeLiquidateAtOracle,
|
|
4500
|
+
encodeLpVaultWithdraw,
|
|
4501
|
+
encodeMintPositionNft,
|
|
4502
|
+
encodePauseMarket,
|
|
4503
|
+
encodePushOraclePrice,
|
|
4504
|
+
encodeQueueWithdrawal,
|
|
4505
|
+
encodeQueueWithdrawalSV,
|
|
4506
|
+
encodeReclaimSlabRent,
|
|
4507
|
+
encodeRenounceAdmin,
|
|
4508
|
+
encodeResolveMarket,
|
|
4509
|
+
encodeSetInsuranceIsolation,
|
|
4510
|
+
encodeSetMaintenanceFee,
|
|
4511
|
+
encodeSetOiImbalanceHardBlock,
|
|
4512
|
+
encodeSetOracleAuthority,
|
|
4513
|
+
encodeSetOraclePriceCap,
|
|
4514
|
+
encodeSetPendingSettlement,
|
|
4515
|
+
encodeSetPythOracle,
|
|
4516
|
+
encodeSetRiskThreshold,
|
|
4517
|
+
encodeSetWalletCap,
|
|
4518
|
+
encodeSlashCreationDeposit,
|
|
4519
|
+
encodeStakeAccrueFees,
|
|
4520
|
+
encodeStakeAdminResolveMarket,
|
|
4521
|
+
encodeStakeAdminSetHwmConfig,
|
|
4522
|
+
encodeStakeAdminSetInsurancePolicy,
|
|
4523
|
+
encodeStakeAdminSetMaintenanceFee,
|
|
4524
|
+
encodeStakeAdminSetOracleAuthority,
|
|
4525
|
+
encodeStakeAdminSetRiskThreshold,
|
|
4526
|
+
encodeStakeAdminSetTrancheConfig,
|
|
4527
|
+
encodeStakeAdminWithdrawInsurance,
|
|
4528
|
+
encodeStakeDeposit,
|
|
4529
|
+
encodeStakeDepositJunior,
|
|
4530
|
+
encodeStakeFlushToInsurance,
|
|
4531
|
+
encodeStakeInitPool,
|
|
4532
|
+
encodeStakeInitTradingPool,
|
|
4533
|
+
encodeStakeTransferAdmin,
|
|
4534
|
+
encodeStakeUpdateConfig,
|
|
4535
|
+
encodeStakeWithdraw,
|
|
4536
|
+
encodeTopUpInsurance,
|
|
4537
|
+
encodeTopUpKeeperFund,
|
|
4538
|
+
encodeTradeCpi,
|
|
4539
|
+
encodeTradeCpiV2,
|
|
4540
|
+
encodeTradeNoCpi,
|
|
4541
|
+
encodeTransferOwnershipCpi,
|
|
4542
|
+
encodeTransferPositionOwnership,
|
|
4543
|
+
encodeUnpauseMarket,
|
|
4544
|
+
encodeUpdateAdmin,
|
|
4545
|
+
encodeUpdateConfig,
|
|
4546
|
+
encodeUpdateHyperpMark,
|
|
4547
|
+
encodeUpdateMarkPrice,
|
|
4548
|
+
encodeUpdateRiskParams,
|
|
4549
|
+
encodeWithdrawCollateral,
|
|
4550
|
+
encodeWithdrawInsurance,
|
|
4551
|
+
encodeWithdrawInsuranceLP,
|
|
4552
|
+
fetchAdlRankedPositions,
|
|
4553
|
+
fetchAdlRankings,
|
|
4554
|
+
fetchSlab,
|
|
4555
|
+
fetchTokenAccount,
|
|
4556
|
+
flushToInsuranceAccounts,
|
|
4557
|
+
formatResult,
|
|
4558
|
+
getAta,
|
|
4559
|
+
getAtaSync,
|
|
4560
|
+
getCurrentNetwork,
|
|
4561
|
+
getErrorHint,
|
|
4562
|
+
getErrorName,
|
|
4563
|
+
getMatcherProgramId,
|
|
4564
|
+
getProgramId,
|
|
4565
|
+
getStakeProgramId,
|
|
4566
|
+
initPoolAccounts,
|
|
4567
|
+
isAccountUsed,
|
|
4568
|
+
isAdlTriggered,
|
|
4569
|
+
isStandardToken,
|
|
4570
|
+
isToken2022,
|
|
4571
|
+
isValidChainlinkOracle,
|
|
4572
|
+
maxAccountIndex,
|
|
4573
|
+
parseAccount,
|
|
4574
|
+
parseAdlEvent,
|
|
4575
|
+
parseAllAccounts,
|
|
4576
|
+
parseChainlinkPrice,
|
|
4577
|
+
parseConfig,
|
|
4578
|
+
parseDexPool,
|
|
4579
|
+
parseEngine,
|
|
4580
|
+
parseErrorFromLogs,
|
|
4581
|
+
parseHeader,
|
|
4582
|
+
parseParams,
|
|
4583
|
+
parseUsedIndices,
|
|
4584
|
+
rankAdlPositions,
|
|
4585
|
+
readLastThrUpdateSlot,
|
|
4586
|
+
readNonce,
|
|
4587
|
+
resolvePrice,
|
|
4588
|
+
safeEnv,
|
|
4589
|
+
simulateOrSend,
|
|
4590
|
+
slabDataSize,
|
|
4591
|
+
slabDataSizeV1,
|
|
4592
|
+
validateAmount,
|
|
4593
|
+
validateBps,
|
|
4594
|
+
validateI128,
|
|
4595
|
+
validateI64,
|
|
4596
|
+
validateIndex,
|
|
4597
|
+
validatePublicKey,
|
|
4598
|
+
validateSlabTierMatch,
|
|
4599
|
+
validateU128,
|
|
4600
|
+
validateU16,
|
|
4601
|
+
validateU64,
|
|
4602
|
+
withdrawAccounts
|
|
4603
|
+
};
|
|
4604
|
+
//# sourceMappingURL=index.js.map
|