@percolatorct/sdk 1.0.0-beta.14 → 1.0.0-beta.16
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 +754 -0
- package/dist/abi/accounts.d.ts +244 -0
- package/dist/abi/encode.d.ts +46 -0
- package/dist/abi/errors.d.ts +45 -0
- package/dist/abi/index.d.ts +4 -0
- package/dist/abi/instructions.d.ts +1102 -0
- package/dist/config/program-ids.d.ts +50 -0
- package/dist/index.d.ts +7 -3459
- package/dist/index.js +1047 -308
- package/dist/index.js.map +1 -1
- package/dist/math/index.d.ts +2 -0
- package/dist/math/trading.d.ts +222 -0
- package/dist/math/warmup.d.ts +105 -0
- package/dist/oracle/price-router.d.ts +38 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/lighthouse.d.ts +170 -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 +492 -0
- package/dist/solana/index.d.ts +11 -0
- package/dist/solana/oracle.d.ts +52 -0
- package/dist/solana/pda.d.ts +44 -0
- package/dist/solana/rpc-pool.d.ts +347 -0
- package/dist/solana/slab.d.ts +421 -0
- package/dist/solana/stake.d.ts +216 -0
- package/dist/solana/static-markets.d.ts +86 -0
- package/dist/solana/token-program.d.ts +19 -0
- package/dist/validation.d.ts +70 -0
- package/package.json +11 -5
package/dist/index.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
// src/abi/encode.ts
|
|
2
2
|
import { PublicKey } from "@solana/web3.js";
|
|
3
|
-
var U8_MAX = 255;
|
|
4
|
-
var U16_MAX = 65535;
|
|
5
|
-
var U32_MAX = 4294967295;
|
|
6
3
|
function encU8(val) {
|
|
7
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
4
|
+
if (!Number.isInteger(val) || val < 0 || val > 255) {
|
|
8
5
|
throw new Error(`encU8: value out of range (0..255), got ${val}`);
|
|
9
6
|
}
|
|
10
7
|
return new Uint8Array([val]);
|
|
11
8
|
}
|
|
12
9
|
function encU16(val) {
|
|
13
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
10
|
+
if (!Number.isInteger(val) || val < 0 || val > 65535) {
|
|
14
11
|
throw new Error(`encU16: value out of range (0..65535), got ${val}`);
|
|
15
12
|
}
|
|
16
13
|
const buf = new Uint8Array(2);
|
|
@@ -18,7 +15,7 @@ function encU16(val) {
|
|
|
18
15
|
return buf;
|
|
19
16
|
}
|
|
20
17
|
function encU32(val) {
|
|
21
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
18
|
+
if (!Number.isInteger(val) || val < 0 || val > 4294967295) {
|
|
22
19
|
throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);
|
|
23
20
|
}
|
|
24
21
|
const buf = new Uint8Array(4);
|
|
@@ -134,8 +131,13 @@ var IX_TAG = {
|
|
|
134
131
|
ReclaimEmptyAccount: 25,
|
|
135
132
|
SettleAccount: 26,
|
|
136
133
|
// Tags 27-28: on-chain = DepositFeeCredits/ConvertReleasedPnl.
|
|
134
|
+
// Legacy aliases (PauseMarket/UnpauseMarket) kept — those instructions don't exist on-chain.
|
|
137
135
|
DepositFeeCredits: 27,
|
|
136
|
+
/** @deprecated No on-chain PauseMarket instruction */
|
|
137
|
+
PauseMarket: 27,
|
|
138
138
|
ConvertReleasedPnl: 28,
|
|
139
|
+
/** @deprecated No on-chain UnpauseMarket instruction */
|
|
140
|
+
UnpauseMarket: 28,
|
|
139
141
|
// Tags 29-30: on-chain = ResolvePermissionless/ForceCloseResolved.
|
|
140
142
|
ResolvePermissionless: 29,
|
|
141
143
|
/** @deprecated Use ResolvePermissionless */
|
|
@@ -186,8 +188,7 @@ var IX_TAG = {
|
|
|
186
188
|
AttestCrossMargin: 55,
|
|
187
189
|
/** PERC-622: Advance oracle phase (permissionless crank) */
|
|
188
190
|
AdvanceOraclePhase: 56,
|
|
189
|
-
|
|
190
|
-
TopUpKeeperFund: 57,
|
|
191
|
+
// 57: removed (keeper fund)
|
|
191
192
|
/** PERC-629: Slash a market creator's deposit (permissionless) */
|
|
192
193
|
SlashCreationDeposit: 58,
|
|
193
194
|
/** PERC-628: Initialize the global shared vault (admin) */
|
|
@@ -223,13 +224,7 @@ var IX_TAG = {
|
|
|
223
224
|
/** PERC-SetDexPool: Pin admin-approved DEX pool address for a HYPERP market (admin). */
|
|
224
225
|
SetDexPool: 74,
|
|
225
226
|
/** CPI to the matcher program to initialize a matcher context account for an LP slot. Admin-only. */
|
|
226
|
-
InitMatcherCtx: 75
|
|
227
|
-
/** PauseMarket (tag 76): admin emergency pause. Blocks Trade/Deposit/Withdraw/InitUser. */
|
|
228
|
-
PauseMarket: 76,
|
|
229
|
-
/** UnpauseMarket (tag 77): admin unpause. Re-enables all operations. */
|
|
230
|
-
UnpauseMarket: 77,
|
|
231
|
-
/** CloseKeeperFund (tag 78): close keeper fund PDA and recover lamports to admin. */
|
|
232
|
-
CloseKeeperFund: 78
|
|
227
|
+
InitMatcherCtx: 75
|
|
233
228
|
};
|
|
234
229
|
Object.freeze(IX_TAG);
|
|
235
230
|
var HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
@@ -252,8 +247,10 @@ function encodeFeedId(feedId) {
|
|
|
252
247
|
}
|
|
253
248
|
return bytes;
|
|
254
249
|
}
|
|
255
|
-
var INIT_MARKET_DATA_LEN =
|
|
250
|
+
var INIT_MARKET_DATA_LEN = 360;
|
|
256
251
|
function encodeInitMarket(args) {
|
|
252
|
+
const hMin = args.hMin ?? args.warmupPeriodSlots ?? 0n;
|
|
253
|
+
const hMax = args.hMax ?? args.warmupPeriodSlots ?? 0n;
|
|
257
254
|
const data = concatBytes(
|
|
258
255
|
encU8(IX_TAG.InitMarket),
|
|
259
256
|
encPubkey(args.admin),
|
|
@@ -268,27 +265,25 @@ function encodeInitMarket(args) {
|
|
|
268
265
|
encU128(args.maxMaintenanceFeePerSlot ?? 0n),
|
|
269
266
|
encU128(args.maxInsuranceFloor ?? 0n),
|
|
270
267
|
encU64(args.minOraclePriceCap ?? 0n),
|
|
271
|
-
// RiskParams
|
|
272
|
-
|
|
273
|
-
// and liquidationBufferBps is read but discarded (kept for wire compat).
|
|
274
|
-
encU64(args.warmupPeriodSlots),
|
|
268
|
+
// RiskParams block (16 fields — h_min replaces warmup_period_slots, h_max added at end)
|
|
269
|
+
encU64(hMin),
|
|
275
270
|
encU64(args.maintenanceMarginBps),
|
|
276
271
|
encU64(args.initialMarginBps),
|
|
277
272
|
encU64(args.tradingFeeBps),
|
|
278
273
|
encU64(args.maxAccounts),
|
|
279
274
|
encU128(args.newAccountFee),
|
|
280
|
-
encU128(args.
|
|
281
|
-
// wire slot: old riskReductionThreshold → now insurance_floor
|
|
275
|
+
encU128(args.riskReductionThreshold),
|
|
282
276
|
encU128(args.maintenanceFeePerSlot),
|
|
283
277
|
encU64(args.maxCrankStalenessSlots),
|
|
284
278
|
encU64(args.liquidationFeeBps),
|
|
285
279
|
encU128(args.liquidationFeeCap),
|
|
286
|
-
encU64(args.liquidationBufferBps
|
|
287
|
-
// wire slot: read and discarded by program
|
|
280
|
+
encU64(args.liquidationBufferBps),
|
|
288
281
|
encU128(args.minLiquidationAbs),
|
|
289
282
|
encU128(args.minInitialDeposit),
|
|
290
283
|
encU128(args.minNonzeroMmReq),
|
|
291
|
-
encU128(args.minNonzeroImReq)
|
|
284
|
+
encU128(args.minNonzeroImReq),
|
|
285
|
+
encU64(hMax)
|
|
286
|
+
// h_max — new in v12.15, appended after minNonzeroImReq
|
|
292
287
|
);
|
|
293
288
|
if (data.length !== INIT_MARKET_DATA_LEN) {
|
|
294
289
|
throw new Error(
|
|
@@ -488,12 +483,12 @@ function encodeSetPythOracle(args) {
|
|
|
488
483
|
}
|
|
489
484
|
var PYTH_RECEIVER_PROGRAM_ID = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ";
|
|
490
485
|
async function derivePythPriceUpdateAccount(feedId, shardId = 0) {
|
|
491
|
-
const { PublicKey:
|
|
486
|
+
const { PublicKey: PublicKey15 } = await import("@solana/web3.js");
|
|
492
487
|
const shardBuf = new Uint8Array(2);
|
|
493
488
|
new DataView(shardBuf.buffer).setUint16(0, shardId, true);
|
|
494
|
-
const [pda] =
|
|
489
|
+
const [pda] = PublicKey15.findProgramAddressSync(
|
|
495
490
|
[shardBuf, feedId],
|
|
496
|
-
new
|
|
491
|
+
new PublicKey15(PYTH_RECEIVER_PROGRAM_ID)
|
|
497
492
|
);
|
|
498
493
|
return pda.toBase58();
|
|
499
494
|
}
|
|
@@ -604,9 +599,6 @@ function checkPhaseTransition(currentSlot, marketCreatedSlot, oraclePhase, cumul
|
|
|
604
599
|
return [ORACLE_PHASE_MATURE, false];
|
|
605
600
|
}
|
|
606
601
|
}
|
|
607
|
-
function encodeTopUpKeeperFund(args) {
|
|
608
|
-
return concatBytes(encU8(IX_TAG.TopUpKeeperFund), encU64(args.amount));
|
|
609
|
-
}
|
|
610
602
|
function encodeSlashCreationDeposit() {
|
|
611
603
|
return encU8(IX_TAG.SlashCreationDeposit);
|
|
612
604
|
}
|
|
@@ -728,18 +720,6 @@ function encodeCloseOrphanSlab() {
|
|
|
728
720
|
function encodeSetDexPool(args) {
|
|
729
721
|
return concatBytes(encU8(IX_TAG.SetDexPool), encPubkey(args.pool));
|
|
730
722
|
}
|
|
731
|
-
function encodeCloseKeeperFund() {
|
|
732
|
-
return concatBytes(encU8(IX_TAG.CloseKeeperFund));
|
|
733
|
-
}
|
|
734
|
-
function encodeCreateInsuranceMint() {
|
|
735
|
-
return encodeCreateLpVault({ feeShareBps: 0n });
|
|
736
|
-
}
|
|
737
|
-
function encodeDepositInsuranceLP(args) {
|
|
738
|
-
return encodeLpVaultDeposit({ amount: args.amount });
|
|
739
|
-
}
|
|
740
|
-
function encodeWithdrawInsuranceLP(args) {
|
|
741
|
-
return encodeLpVaultWithdraw({ lpAmount: args.lpAmount });
|
|
742
|
-
}
|
|
743
723
|
|
|
744
724
|
// src/abi/accounts.ts
|
|
745
725
|
import {
|
|
@@ -764,8 +744,7 @@ var ACCOUNTS_INIT_USER = [
|
|
|
764
744
|
{ name: "slab", signer: false, writable: true },
|
|
765
745
|
{ name: "userAta", signer: false, writable: true },
|
|
766
746
|
{ name: "vault", signer: false, writable: true },
|
|
767
|
-
{ name: "tokenProgram", signer: false, writable: false }
|
|
768
|
-
{ name: "clock", signer: false, writable: false }
|
|
747
|
+
{ name: "tokenProgram", signer: false, writable: false }
|
|
769
748
|
];
|
|
770
749
|
var ACCOUNTS_INIT_LP = [
|
|
771
750
|
{ name: "user", signer: true, writable: true },
|
|
@@ -832,7 +811,6 @@ var ACCOUNTS_TRADE_CPI = [
|
|
|
832
811
|
{ name: "lpOwner", signer: false, writable: false },
|
|
833
812
|
// LP delegated to matcher - no signature needed
|
|
834
813
|
{ name: "slab", signer: false, writable: true },
|
|
835
|
-
{ name: "clock", signer: false, writable: false },
|
|
836
814
|
{ name: "oracle", signer: false, writable: false },
|
|
837
815
|
{ name: "matcherProg", signer: false, writable: false },
|
|
838
816
|
{ name: "matcherCtx", signer: false, writable: true },
|
|
@@ -916,37 +894,6 @@ function buildAccountMetas(spec, keys) {
|
|
|
916
894
|
isWritable: s.writable
|
|
917
895
|
}));
|
|
918
896
|
}
|
|
919
|
-
var ACCOUNTS_CREATE_INSURANCE_MINT = [
|
|
920
|
-
{ name: "admin", signer: true, writable: false },
|
|
921
|
-
{ name: "slab", signer: false, writable: false },
|
|
922
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
923
|
-
{ name: "vaultAuthority", signer: false, writable: false },
|
|
924
|
-
{ name: "collateralMint", signer: false, writable: false },
|
|
925
|
-
{ name: "systemProgram", signer: false, writable: false },
|
|
926
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
927
|
-
{ name: "rent", signer: false, writable: false },
|
|
928
|
-
{ name: "payer", signer: true, writable: true }
|
|
929
|
-
];
|
|
930
|
-
var ACCOUNTS_DEPOSIT_INSURANCE_LP = [
|
|
931
|
-
{ name: "depositor", signer: true, writable: false },
|
|
932
|
-
{ name: "slab", signer: false, writable: true },
|
|
933
|
-
{ name: "depositorAta", signer: false, writable: true },
|
|
934
|
-
{ name: "vault", signer: false, writable: true },
|
|
935
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
936
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
937
|
-
{ name: "depositorLpAta", signer: false, writable: true },
|
|
938
|
-
{ name: "vaultAuthority", signer: false, writable: false }
|
|
939
|
-
];
|
|
940
|
-
var ACCOUNTS_WITHDRAW_INSURANCE_LP = [
|
|
941
|
-
{ name: "withdrawer", signer: true, writable: false },
|
|
942
|
-
{ name: "slab", signer: false, writable: true },
|
|
943
|
-
{ name: "withdrawerAta", signer: false, writable: true },
|
|
944
|
-
{ name: "vault", signer: false, writable: true },
|
|
945
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
946
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
947
|
-
{ name: "withdrawerLpAta", signer: false, writable: true },
|
|
948
|
-
{ name: "vaultAuthority", signer: false, writable: false }
|
|
949
|
-
];
|
|
950
897
|
var ACCOUNTS_LP_VAULT_WITHDRAW = [
|
|
951
898
|
{ name: "withdrawer", signer: true, writable: false },
|
|
952
899
|
{ name: "slab", signer: false, writable: true },
|
|
@@ -1014,12 +961,6 @@ var ACCOUNTS_AUDIT_CRANK = [
|
|
|
1014
961
|
var ACCOUNTS_ADVANCE_ORACLE_PHASE = [
|
|
1015
962
|
{ name: "slab", signer: false, writable: true }
|
|
1016
963
|
];
|
|
1017
|
-
var ACCOUNTS_TOPUP_KEEPER_FUND = [
|
|
1018
|
-
{ name: "funder", signer: true, writable: true },
|
|
1019
|
-
{ name: "slab", signer: false, writable: true },
|
|
1020
|
-
{ name: "keeperFund", signer: false, writable: true },
|
|
1021
|
-
{ name: "systemProgram", signer: false, writable: false }
|
|
1022
|
-
];
|
|
1023
964
|
var ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK = [
|
|
1024
965
|
{ name: "admin", signer: true, writable: false },
|
|
1025
966
|
{ name: "slab", signer: false, writable: true }
|
|
@@ -1069,11 +1010,6 @@ var ACCOUNTS_SET_WALLET_CAP = [
|
|
|
1069
1010
|
{ name: "admin", signer: true, writable: false },
|
|
1070
1011
|
{ name: "slab", signer: false, writable: true }
|
|
1071
1012
|
];
|
|
1072
|
-
var ACCOUNTS_SET_DEX_POOL = [
|
|
1073
|
-
{ name: "admin", signer: true, writable: false },
|
|
1074
|
-
{ name: "slab", signer: false, writable: true },
|
|
1075
|
-
{ name: "poolAccount", signer: false, writable: false }
|
|
1076
|
-
];
|
|
1077
1013
|
var ACCOUNTS_INIT_MATCHER_CTX = [
|
|
1078
1014
|
{ name: "admin", signer: true, writable: false },
|
|
1079
1015
|
{ name: "slab", signer: false, writable: false },
|
|
@@ -1365,11 +1301,24 @@ function getErrorName(code) {
|
|
|
1365
1301
|
function getErrorHint(code) {
|
|
1366
1302
|
return PERCOLATOR_ERRORS[code]?.hint;
|
|
1367
1303
|
}
|
|
1304
|
+
var LIGHTHOUSE_PROGRAM_ID_STR = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
1305
|
+
var ANCHOR_ERROR_RANGE_START = 6e3;
|
|
1306
|
+
var ANCHOR_ERROR_RANGE_END = 8191;
|
|
1307
|
+
var ANCHOR_ERROR_NAMES = {
|
|
1308
|
+
6032: "ConstraintMut",
|
|
1309
|
+
6036: "ConstraintOwner",
|
|
1310
|
+
6038: "ConstraintSeeds",
|
|
1311
|
+
6400: "ConstraintAddress"
|
|
1312
|
+
};
|
|
1313
|
+
function isAnchorErrorCode(code) {
|
|
1314
|
+
return code >= ANCHOR_ERROR_RANGE_START && code <= ANCHOR_ERROR_RANGE_END;
|
|
1315
|
+
}
|
|
1368
1316
|
var CUSTOM_ERROR_HEX_MAX_LEN = 8;
|
|
1369
1317
|
function parseErrorFromLogs(logs) {
|
|
1370
1318
|
if (!Array.isArray(logs)) {
|
|
1371
1319
|
return null;
|
|
1372
1320
|
}
|
|
1321
|
+
let insideLighthouse = false;
|
|
1373
1322
|
const re = new RegExp(
|
|
1374
1323
|
`custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,
|
|
1375
1324
|
"i"
|
|
@@ -1378,17 +1327,32 @@ function parseErrorFromLogs(logs) {
|
|
|
1378
1327
|
if (typeof log !== "string") {
|
|
1379
1328
|
continue;
|
|
1380
1329
|
}
|
|
1330
|
+
if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {
|
|
1331
|
+
insideLighthouse = true;
|
|
1332
|
+
} else if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {
|
|
1333
|
+
insideLighthouse = false;
|
|
1334
|
+
}
|
|
1381
1335
|
const match = log.match(re);
|
|
1382
1336
|
if (match) {
|
|
1383
1337
|
const code = parseInt(match[1], 16);
|
|
1384
1338
|
if (!Number.isFinite(code) || code < 0 || code > 4294967295) {
|
|
1385
1339
|
continue;
|
|
1386
1340
|
}
|
|
1341
|
+
if (isAnchorErrorCode(code) || insideLighthouse) {
|
|
1342
|
+
const anchorName = ANCHOR_ERROR_NAMES[code] ?? `AnchorError(0x${code.toString(16)})`;
|
|
1343
|
+
return {
|
|
1344
|
+
code,
|
|
1345
|
+
name: `Lighthouse:${anchorName}`,
|
|
1346
|
+
hint: "This error comes from the Lighthouse/Blowfish wallet guard, not from Percolator. The transaction itself is valid. Disable transaction simulation in your wallet settings, or use a wallet without Blowfish protection (e.g., Backpack, Solflare).",
|
|
1347
|
+
source: "lighthouse"
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1387
1350
|
const info = decodeError(code);
|
|
1388
1351
|
return {
|
|
1389
1352
|
code,
|
|
1390
1353
|
name: info?.name ?? `Unknown(${code})`,
|
|
1391
|
-
hint: info?.hint
|
|
1354
|
+
hint: info?.hint,
|
|
1355
|
+
source: info ? "percolator" : "unknown"
|
|
1392
1356
|
};
|
|
1393
1357
|
}
|
|
1394
1358
|
}
|
|
@@ -1619,10 +1583,6 @@ var V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;
|
|
|
1619
1583
|
var V12_1_SBF_OFF_CRANK_CURSOR = 320;
|
|
1620
1584
|
var V12_1_SBF_OFF_SWEEP_START_IDX = 322;
|
|
1621
1585
|
var V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;
|
|
1622
|
-
var V12_1_SBF_OFF_TOTAL_OI = 448;
|
|
1623
|
-
var V12_1_SBF_OFF_LONG_OI = 464;
|
|
1624
|
-
var V12_1_SBF_OFF_SHORT_OI = 480;
|
|
1625
|
-
var V12_1_SBF_OFF_MARK_PRICE_E6 = 560;
|
|
1626
1586
|
var V12_1_ENGINE_CURRENT_SLOT_OFF = 448;
|
|
1627
1587
|
var V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;
|
|
1628
1588
|
var V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;
|
|
@@ -1657,13 +1617,40 @@ var V12_1_ACCT_FEE_CREDITS_OFF = 240;
|
|
|
1657
1617
|
var V12_1_ACCT_LAST_FEE_SLOT_OFF = 256;
|
|
1658
1618
|
var V12_1_ACCT_POSITION_SIZE_OFF = 88;
|
|
1659
1619
|
var V12_1_ACCT_ENTRY_PRICE_OFF = -1;
|
|
1660
|
-
var
|
|
1661
|
-
var
|
|
1662
|
-
var
|
|
1663
|
-
var
|
|
1664
|
-
var
|
|
1665
|
-
var
|
|
1666
|
-
var
|
|
1620
|
+
var V12_1_ACCT_FUNDING_INDEX_OFF = 288;
|
|
1621
|
+
var V12_15_ENGINE_OFF = 624;
|
|
1622
|
+
var V12_15_ACCOUNT_SIZE = 4400;
|
|
1623
|
+
var V12_15_ACCT_ACCOUNT_ID_OFF = 0;
|
|
1624
|
+
var V12_15_ACCT_CAPITAL_OFF = 8;
|
|
1625
|
+
var V12_15_ACCT_KIND_OFF = 24;
|
|
1626
|
+
var V12_15_ACCT_PNL_OFF = 32;
|
|
1627
|
+
var V12_15_ACCT_RESERVED_PNL_OFF = 48;
|
|
1628
|
+
var V12_15_ACCT_POSITION_BASIS_Q_OFF = 64;
|
|
1629
|
+
var V12_15_ACCT_ENTRY_PRICE_OFF = 120;
|
|
1630
|
+
var V12_15_ACCT_MATCHER_PROGRAM_OFF = 128;
|
|
1631
|
+
var V12_15_ACCT_MATCHER_CONTEXT_OFF = 160;
|
|
1632
|
+
var V12_15_ACCT_OWNER_OFF = 192;
|
|
1633
|
+
var V12_15_ACCT_FEE_CREDITS_OFF = 224;
|
|
1634
|
+
var V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240;
|
|
1635
|
+
var V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256;
|
|
1636
|
+
var V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224;
|
|
1637
|
+
var V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240;
|
|
1638
|
+
var V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304;
|
|
1639
|
+
var V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320;
|
|
1640
|
+
var V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384;
|
|
1641
|
+
var V12_15_PARAMS_SIZE = 192;
|
|
1642
|
+
var V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24;
|
|
1643
|
+
var V12_15_PARAMS_H_MIN_OFF = 160;
|
|
1644
|
+
var V12_15_PARAMS_H_MAX_OFF = 168;
|
|
1645
|
+
var V12_15_ENGINE_PARAMS_OFF = 32;
|
|
1646
|
+
var V12_15_ENGINE_CURRENT_SLOT_OFF = 224;
|
|
1647
|
+
var V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240;
|
|
1648
|
+
var V12_15_ENGINE_MARKET_MODE_OFF = 256;
|
|
1649
|
+
var V12_15_ENGINE_C_TOT_OFF = 344;
|
|
1650
|
+
var V12_15_ENGINE_PNL_POS_TOT_OFF = 368;
|
|
1651
|
+
var V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384;
|
|
1652
|
+
var V12_15_ENGINE_BITMAP_OFF = 862;
|
|
1653
|
+
var V12_15_SIZES = /* @__PURE__ */ new Map();
|
|
1667
1654
|
var V1M_ENGINE_OFF = 640;
|
|
1668
1655
|
var V1M_CONFIG_LEN = 536;
|
|
1669
1656
|
var V1M_ACCOUNT_SIZE = 248;
|
|
@@ -1736,7 +1723,9 @@ for (const n of TIERS) {
|
|
|
1736
1723
|
V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);
|
|
1737
1724
|
V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);
|
|
1738
1725
|
V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);
|
|
1726
|
+
V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);
|
|
1739
1727
|
}
|
|
1728
|
+
V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);
|
|
1740
1729
|
var V12_1_SBF_ACCOUNT_SIZE = 280;
|
|
1741
1730
|
var V12_1_SBF_ENGINE_OFF = 616;
|
|
1742
1731
|
var V12_1_SBF_BITMAP_OFF = 584;
|
|
@@ -1747,14 +1736,6 @@ for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large",
|
|
|
1747
1736
|
const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
|
|
1748
1737
|
V12_1_SIZES.set(total, n);
|
|
1749
1738
|
}
|
|
1750
|
-
var V12_1_EP_SIZES = /* @__PURE__ */ new Map();
|
|
1751
|
-
for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
1752
|
-
const bitmapBytes = Math.ceil(n / 64) * 8;
|
|
1753
|
-
const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;
|
|
1754
|
-
const accountsOff = Math.ceil(preAccLen / 8) * 8;
|
|
1755
|
-
const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;
|
|
1756
|
-
V12_1_EP_SIZES.set(total, n);
|
|
1757
|
-
}
|
|
1758
1739
|
var SLAB_TIERS_V2 = {
|
|
1759
1740
|
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
|
|
1760
1741
|
large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V2 BPF intermediate)" }
|
|
@@ -2219,6 +2200,11 @@ for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Lar
|
|
|
2219
2200
|
const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);
|
|
2220
2201
|
SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };
|
|
2221
2202
|
}
|
|
2203
|
+
var SLAB_TIERS_V12_15 = {};
|
|
2204
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Medium2048", 2048], ["Large", 4096]]) {
|
|
2205
|
+
const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);
|
|
2206
|
+
SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };
|
|
2207
|
+
}
|
|
2222
2208
|
function buildLayoutVSetDexPool(maxAccounts) {
|
|
2223
2209
|
const engineOff = V_SETDEXPOOL_ENGINE_OFF;
|
|
2224
2210
|
const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;
|
|
@@ -2315,12 +2301,16 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2315
2301
|
engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
2316
2302
|
// not in deployed struct
|
|
2317
2303
|
engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
2318
|
-
engineMarkPriceOff: isSbf ?
|
|
2304
|
+
engineMarkPriceOff: isSbf ? -1 : V12_1_ENGINE_MARK_PRICE_OFF,
|
|
2305
|
+
// not in deployed struct
|
|
2319
2306
|
engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2320
2307
|
engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2321
|
-
engineTotalOiOff: isSbf ?
|
|
2322
|
-
|
|
2323
|
-
|
|
2308
|
+
engineTotalOiOff: isSbf ? -1 : V12_1_ENGINE_TOTAL_OI_OFF,
|
|
2309
|
+
// not in deployed struct
|
|
2310
|
+
engineLongOiOff: isSbf ? -1 : V12_1_ENGINE_LONG_OI_OFF,
|
|
2311
|
+
// not in deployed struct
|
|
2312
|
+
engineShortOiOff: isSbf ? -1 : V12_1_ENGINE_SHORT_OI_OFF,
|
|
2313
|
+
// not in deployed struct
|
|
2324
2314
|
engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,
|
|
2325
2315
|
enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,
|
|
2326
2316
|
engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,
|
|
@@ -2356,10 +2346,10 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2356
2346
|
engineInsuranceIsolationBpsOff: isSbf ? -1 : 64
|
|
2357
2347
|
};
|
|
2358
2348
|
}
|
|
2359
|
-
function
|
|
2360
|
-
const engineOff =
|
|
2361
|
-
const bitmapOff =
|
|
2362
|
-
const accountSize =
|
|
2349
|
+
function buildLayoutV12_15(maxAccounts) {
|
|
2350
|
+
const engineOff = V12_15_ENGINE_OFF;
|
|
2351
|
+
const bitmapOff = V12_15_ENGINE_BITMAP_OFF;
|
|
2352
|
+
const accountSize = V12_15_ACCOUNT_SIZE;
|
|
2363
2353
|
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2364
2354
|
const bitmapBytes = bitmapWords * 8;
|
|
2365
2355
|
const postBitmap = 18;
|
|
@@ -2367,63 +2357,94 @@ function buildLayoutV12_1EP(maxAccounts) {
|
|
|
2367
2357
|
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2368
2358
|
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2369
2359
|
return {
|
|
2370
|
-
version:
|
|
2371
|
-
headerLen:
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2360
|
+
version: 2,
|
|
2361
|
+
headerLen: V0_HEADER_LEN,
|
|
2362
|
+
// 72 (same as V12_1)
|
|
2363
|
+
configOffset: V0_HEADER_LEN,
|
|
2364
|
+
// 72
|
|
2365
|
+
configLen: 552,
|
|
2366
|
+
// SBF CONFIG_LEN for v12.15
|
|
2367
|
+
reservedOff: V1_RESERVED_OFF,
|
|
2368
|
+
// 80
|
|
2376
2369
|
engineOff,
|
|
2377
2370
|
accountSize,
|
|
2378
2371
|
maxAccounts,
|
|
2379
2372
|
bitmapWords,
|
|
2380
2373
|
accountsOff: engineOff + accountsOffRel,
|
|
2381
2374
|
engineInsuranceOff: 16,
|
|
2382
|
-
engineParamsOff:
|
|
2383
|
-
//
|
|
2384
|
-
paramsSize:
|
|
2385
|
-
//
|
|
2386
|
-
|
|
2387
|
-
|
|
2375
|
+
engineParamsOff: V12_15_ENGINE_PARAMS_OFF,
|
|
2376
|
+
// 32
|
|
2377
|
+
paramsSize: V12_15_PARAMS_SIZE,
|
|
2378
|
+
// 192
|
|
2379
|
+
engineCurrentSlotOff: V12_15_ENGINE_CURRENT_SLOT_OFF,
|
|
2380
|
+
// 224
|
|
2388
2381
|
engineFundingIndexOff: -1,
|
|
2382
|
+
// not present in v12.15 engine struct
|
|
2389
2383
|
engineLastFundingSlotOff: -1,
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2384
|
+
// not present in v12.15 engine struct
|
|
2385
|
+
// funding_rate_e9 is i128 — stored in engineFundingRateBpsOff for EngineState.fundingRateBpsPerSlotLast
|
|
2386
|
+
// callers should treat this as the i128 funding rate in e9 units
|
|
2387
|
+
engineFundingRateBpsOff: V12_15_ENGINE_FUNDING_RATE_E9_OFF,
|
|
2388
|
+
// 240
|
|
2389
|
+
engineMarkPriceOff: -1,
|
|
2390
|
+
// not present in v12.15 (removed with oracle refactor)
|
|
2391
|
+
engineLastCrankSlotOff: -1,
|
|
2392
|
+
// not yet mapped; set -1 until offset verified on-chain
|
|
2393
|
+
engineMaxCrankStalenessOff: -1,
|
|
2394
|
+
// not yet mapped
|
|
2395
|
+
engineTotalOiOff: -1,
|
|
2396
|
+
// not present in v12.15 engine
|
|
2397
|
+
engineLongOiOff: -1,
|
|
2398
|
+
// not present in v12.15 engine
|
|
2399
|
+
engineShortOiOff: -1,
|
|
2400
|
+
// not present in v12.15 engine
|
|
2401
|
+
engineCTotOff: V12_15_ENGINE_C_TOT_OFF,
|
|
2402
|
+
// 344
|
|
2403
|
+
enginePnlPosTotOff: V12_15_ENGINE_PNL_POS_TOT_OFF,
|
|
2404
|
+
// 368
|
|
2405
|
+
engineLiqCursorOff: -1,
|
|
2406
|
+
// not yet mapped
|
|
2407
|
+
engineGcCursorOff: -1,
|
|
2408
|
+
// not yet mapped
|
|
2409
|
+
engineLastSweepStartOff: -1,
|
|
2410
|
+
// not yet mapped
|
|
2411
|
+
engineLastSweepCompleteOff: -1,
|
|
2412
|
+
// not yet mapped
|
|
2413
|
+
engineCrankCursorOff: -1,
|
|
2414
|
+
// not yet mapped
|
|
2415
|
+
engineSweepStartIdxOff: -1,
|
|
2416
|
+
// not yet mapped
|
|
2417
|
+
engineLifetimeLiquidationsOff: -1,
|
|
2418
|
+
// not yet mapped
|
|
2406
2419
|
engineLifetimeForceClosesOff: -1,
|
|
2420
|
+
// not present in v12.15
|
|
2407
2421
|
engineNetLpPosOff: -1,
|
|
2422
|
+
// not present in v12.15
|
|
2408
2423
|
engineLpSumAbsOff: -1,
|
|
2424
|
+
// not present in v12.15
|
|
2409
2425
|
engineLpMaxAbsOff: -1,
|
|
2426
|
+
// not present in v12.15
|
|
2410
2427
|
engineLpMaxAbsSweepOff: -1,
|
|
2428
|
+
// not present in v12.15
|
|
2411
2429
|
engineEmergencyOiModeOff: -1,
|
|
2430
|
+
// not present in v12.15
|
|
2412
2431
|
engineEmergencyStartSlotOff: -1,
|
|
2432
|
+
// not present in v12.15
|
|
2413
2433
|
engineLastBreakerSlotOff: -1,
|
|
2434
|
+
// not present in v12.15
|
|
2414
2435
|
engineBitmapOff: bitmapOff,
|
|
2415
|
-
postBitmap
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
// 216 (was 208)
|
|
2436
|
+
postBitmap,
|
|
2437
|
+
acctOwnerOff: V12_15_ACCT_OWNER_OFF,
|
|
2438
|
+
// 192
|
|
2419
2439
|
hasInsuranceIsolation: false,
|
|
2440
|
+
// InsuranceFund = {balance: u128} = 16 bytes in v12.15
|
|
2420
2441
|
engineInsuranceIsolatedOff: -1,
|
|
2421
2442
|
engineInsuranceIsolationBpsOff: -1
|
|
2422
2443
|
};
|
|
2423
2444
|
}
|
|
2424
2445
|
function detectSlabLayout(dataLen, data) {
|
|
2425
|
-
const
|
|
2426
|
-
if (
|
|
2446
|
+
const v1215n = V12_15_SIZES.get(dataLen);
|
|
2447
|
+
if (v1215n !== void 0) return buildLayoutV12_15(v1215n);
|
|
2427
2448
|
const v121n = V12_1_SIZES.get(dataLen);
|
|
2428
2449
|
if (v121n !== void 0) return buildLayoutV12_1(v121n, dataLen);
|
|
2429
2450
|
const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);
|
|
@@ -2470,15 +2491,6 @@ var PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;
|
|
|
2470
2491
|
var PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;
|
|
2471
2492
|
var PARAMS_LIQUIDATION_BUFFER_OFF = 120;
|
|
2472
2493
|
var PARAMS_MIN_LIQUIDATION_OFF = 128;
|
|
2473
|
-
var V12_1_PARAMS_MAINT_FEE_OFF = 56;
|
|
2474
|
-
var V12_1_PARAMS_MAX_CRANK_OFF = 72;
|
|
2475
|
-
var V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80;
|
|
2476
|
-
var V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88;
|
|
2477
|
-
var V12_1_PARAMS_MIN_LIQ_OFF = 104;
|
|
2478
|
-
var V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120;
|
|
2479
|
-
var V12_1_PARAMS_MIN_NZ_MM_OFF = 136;
|
|
2480
|
-
var V12_1_PARAMS_MIN_NZ_IM_OFF = 152;
|
|
2481
|
-
var V12_1_PARAMS_INS_FLOOR_OFF = 168;
|
|
2482
2494
|
var ACCT_ACCOUNT_ID_OFF = 0;
|
|
2483
2495
|
var ACCT_CAPITAL_OFF = 8;
|
|
2484
2496
|
var ACCT_KIND_OFF = 24;
|
|
@@ -2728,15 +2740,15 @@ function parseParams(data, layoutHint) {
|
|
|
2728
2740
|
if (data.length < base + Math.min(paramsSize, 56)) {
|
|
2729
2741
|
throw new Error("Slab data too short for RiskParams");
|
|
2730
2742
|
}
|
|
2731
|
-
const
|
|
2743
|
+
const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE;
|
|
2732
2744
|
const result = {
|
|
2733
|
-
warmupPeriodSlots: readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2745
|
+
warmupPeriodSlots: isV12_15Params ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2734
2746
|
maintenanceMarginBps: readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),
|
|
2735
2747
|
initialMarginBps: readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),
|
|
2736
2748
|
tradingFeeBps: readU64LE(data, base + PARAMS_TRADING_FEE_OFF),
|
|
2737
|
-
maxAccounts: readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2749
|
+
maxAccounts: isV12_15Params ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2738
2750
|
newAccountFee: readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),
|
|
2739
|
-
// Extended params:
|
|
2751
|
+
// Extended params: only read if V1 (paramsSize >= 144)
|
|
2740
2752
|
riskReductionThreshold: 0n,
|
|
2741
2753
|
maintenanceFeePerSlot: 0n,
|
|
2742
2754
|
maxCrankStalenessSlots: 0n,
|
|
@@ -2744,21 +2756,19 @@ function parseParams(data, layoutHint) {
|
|
|
2744
2756
|
liquidationFeeCap: 0n,
|
|
2745
2757
|
liquidationBufferBps: 0n,
|
|
2746
2758
|
minLiquidationAbs: 0n,
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
minNonzeroImReq: 0n,
|
|
2750
|
-
insuranceFloor: 0n
|
|
2759
|
+
hMin: 0n,
|
|
2760
|
+
hMax: 0n
|
|
2751
2761
|
};
|
|
2752
|
-
if (
|
|
2753
|
-
result.
|
|
2754
|
-
result.
|
|
2755
|
-
result.
|
|
2756
|
-
result.
|
|
2757
|
-
result.
|
|
2758
|
-
result.
|
|
2759
|
-
result.
|
|
2760
|
-
result.
|
|
2761
|
-
result.
|
|
2762
|
+
if (isV12_15Params) {
|
|
2763
|
+
result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);
|
|
2764
|
+
result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);
|
|
2765
|
+
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2766
|
+
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
2767
|
+
result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);
|
|
2768
|
+
result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);
|
|
2769
|
+
result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);
|
|
2770
|
+
result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);
|
|
2771
|
+
result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);
|
|
2762
2772
|
} else if (paramsSize >= 144) {
|
|
2763
2773
|
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2764
2774
|
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
@@ -2767,6 +2777,8 @@ function parseParams(data, layoutHint) {
|
|
|
2767
2777
|
result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);
|
|
2768
2778
|
result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);
|
|
2769
2779
|
result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);
|
|
2780
|
+
result.hMin = result.warmupPeriodSlots;
|
|
2781
|
+
result.hMax = result.warmupPeriodSlots;
|
|
2770
2782
|
}
|
|
2771
2783
|
return result;
|
|
2772
2784
|
}
|
|
@@ -2776,6 +2788,8 @@ function parseEngine(data) {
|
|
|
2776
2788
|
throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);
|
|
2777
2789
|
}
|
|
2778
2790
|
const base = layout.engineOff;
|
|
2791
|
+
const isV12_15 = layout.accountSize === V12_15_ACCOUNT_SIZE && layout.engineOff === V12_15_ENGINE_OFF;
|
|
2792
|
+
const fundingRateBpsPerSlotLast = isV12_15 ? readI128LE(data, base + V12_15_ENGINE_FUNDING_RATE_E9_OFF) : readI64LE(data, base + layout.engineFundingRateBpsOff);
|
|
2779
2793
|
return {
|
|
2780
2794
|
vault: readU128LE(data, base),
|
|
2781
2795
|
insuranceFund: {
|
|
@@ -2788,21 +2802,24 @@ function parseEngine(data) {
|
|
|
2788
2802
|
currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),
|
|
2789
2803
|
fundingIndexQpbE6: layout.engineFundingIndexOff >= 0 ? readI128LE(data, base + layout.engineFundingIndexOff) : 0n,
|
|
2790
2804
|
lastFundingSlot: layout.engineLastFundingSlotOff >= 0 ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,
|
|
2791
|
-
fundingRateBpsPerSlotLast
|
|
2792
|
-
|
|
2793
|
-
|
|
2805
|
+
fundingRateBpsPerSlotLast,
|
|
2806
|
+
fundingRateE9: isV12_15 ? readI128LE(data, base + V12_15_ENGINE_FUNDING_RATE_E9_OFF) : 0n,
|
|
2807
|
+
marketMode: isV12_15 ? readU8(data, base + V12_15_ENGINE_MARKET_MODE_OFF) === 1 ? 1 : 0 : null,
|
|
2808
|
+
lastCrankSlot: layout.engineLastCrankSlotOff >= 0 ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,
|
|
2809
|
+
maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0 ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,
|
|
2794
2810
|
totalOpenInterest: layout.engineTotalOiOff >= 0 ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,
|
|
2795
2811
|
longOi: layout.engineLongOiOff >= 0 ? readU128LE(data, base + layout.engineLongOiOff) : 0n,
|
|
2796
2812
|
shortOi: layout.engineShortOiOff >= 0 ? readU128LE(data, base + layout.engineShortOiOff) : 0n,
|
|
2797
2813
|
cTot: readU128LE(data, base + layout.engineCTotOff),
|
|
2798
2814
|
pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2815
|
+
pnlMaturedPosTot: isV12_15 ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF) : 0n,
|
|
2816
|
+
liqCursor: layout.engineLiqCursorOff >= 0 ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,
|
|
2817
|
+
gcCursor: layout.engineGcCursorOff >= 0 ? readU16LE(data, base + layout.engineGcCursorOff) : 0,
|
|
2818
|
+
lastSweepStartSlot: layout.engineLastSweepStartOff >= 0 ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,
|
|
2819
|
+
lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0 ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,
|
|
2820
|
+
crankCursor: layout.engineCrankCursorOff >= 0 ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,
|
|
2821
|
+
sweepStartIdx: layout.engineSweepStartIdxOff >= 0 ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,
|
|
2822
|
+
lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0 ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,
|
|
2806
2823
|
lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0 ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,
|
|
2807
2824
|
netLpPos: layout.engineNetLpPosOff >= 0 ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,
|
|
2808
2825
|
lpSumAbs: layout.engineLpSumAbsOff >= 0 ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,
|
|
@@ -2872,18 +2889,58 @@ function parseAccount(data, idx) {
|
|
|
2872
2889
|
if (data.length < base + layout.accountSize) {
|
|
2873
2890
|
throw new Error("Slab data too short for account");
|
|
2874
2891
|
}
|
|
2875
|
-
const
|
|
2876
|
-
const isV12_1 = !
|
|
2877
|
-
const isAdl = layout.accountSize >= 312 || isV12_1
|
|
2892
|
+
const isV12_15 = layout.accountSize === V12_15_ACCOUNT_SIZE;
|
|
2893
|
+
const isV12_1 = !isV12_15 && (layout.engineOff === V12_1_ENGINE_OFF || layout.engineOff === V12_1_SBF_ENGINE_OFF) && (layout.accountSize === V12_1_ACCOUNT_SIZE || layout.accountSize === V12_1_ACCOUNT_SIZE_SBF);
|
|
2894
|
+
const isAdl = !isV12_15 && (layout.accountSize >= 312 || isV12_1);
|
|
2895
|
+
if (isV12_15) {
|
|
2896
|
+
const kindByte2 = readU8(data, base + V12_15_ACCT_KIND_OFF);
|
|
2897
|
+
const kind2 = kindByte2 === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2898
|
+
const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);
|
|
2899
|
+
const exactReserveCohorts = [];
|
|
2900
|
+
for (let i = 0; i < 62; i++) {
|
|
2901
|
+
const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;
|
|
2902
|
+
exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));
|
|
2903
|
+
}
|
|
2904
|
+
const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;
|
|
2905
|
+
const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;
|
|
2906
|
+
return {
|
|
2907
|
+
kind: kind2,
|
|
2908
|
+
accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),
|
|
2909
|
+
capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),
|
|
2910
|
+
pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),
|
|
2911
|
+
reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),
|
|
2912
|
+
warmupStartedAtSlot: 0n,
|
|
2913
|
+
// removed in v12.15
|
|
2914
|
+
warmupSlopePerStep: 0n,
|
|
2915
|
+
// removed in v12.15
|
|
2916
|
+
positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),
|
|
2917
|
+
entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),
|
|
2918
|
+
fundingIndex: 0n,
|
|
2919
|
+
// not present in v12.15 account struct
|
|
2920
|
+
matcherProgram: new PublicKey3(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),
|
|
2921
|
+
matcherContext: new PublicKey3(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),
|
|
2922
|
+
owner: new PublicKey3(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),
|
|
2923
|
+
feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),
|
|
2924
|
+
lastFeeSlot: 0n,
|
|
2925
|
+
// removed in v12.15
|
|
2926
|
+
feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),
|
|
2927
|
+
exactReserveCohorts,
|
|
2928
|
+
exactCohortCount: cohortCount,
|
|
2929
|
+
overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),
|
|
2930
|
+
overflowOlderPresent,
|
|
2931
|
+
overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),
|
|
2932
|
+
overflowNewestPresent
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2878
2935
|
const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
|
|
2879
2936
|
const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;
|
|
2880
|
-
const positionSizeOff = isV12_1
|
|
2881
|
-
const entryPriceOff =
|
|
2882
|
-
const fundingIndexOff = isV12_1
|
|
2883
|
-
const matcherProgOff =
|
|
2884
|
-
const matcherCtxOff =
|
|
2885
|
-
const feeCreditsOff =
|
|
2886
|
-
const lastFeeSlotOff =
|
|
2937
|
+
const positionSizeOff = isV12_1 ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2938
|
+
const entryPriceOff = isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2939
|
+
const fundingIndexOff = isV12_1 ? V12_1_ACCT_FUNDING_INDEX_OFF : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2940
|
+
const matcherProgOff = isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2941
|
+
const matcherCtxOff = isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2942
|
+
const feeCreditsOff = isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2943
|
+
const lastFeeSlotOff = isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2887
2944
|
const kindByte = readU8(data, base + ACCT_KIND_OFF);
|
|
2888
2945
|
const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2889
2946
|
return {
|
|
@@ -2896,13 +2953,23 @@ function parseAccount(data, idx) {
|
|
|
2896
2953
|
warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
|
|
2897
2954
|
positionSize: readI128LE(data, base + positionSizeOff),
|
|
2898
2955
|
entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,
|
|
2899
|
-
// V12_1
|
|
2900
|
-
|
|
2956
|
+
// V12_1: entry_price removed
|
|
2957
|
+
// V12_1 changed funding_index from i128 to i64 (legacy field moved to end of account)
|
|
2958
|
+
fundingIndex: isV12_1 ? BigInt(readI64LE(data, base + fundingIndexOff)) : readI128LE(data, base + fundingIndexOff),
|
|
2901
2959
|
matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
|
|
2902
2960
|
matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
|
|
2903
2961
|
owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
|
|
2904
2962
|
feeCredits: readI128LE(data, base + feeCreditsOff),
|
|
2905
|
-
lastFeeSlot: readU64LE(data, base + lastFeeSlotOff)
|
|
2963
|
+
lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),
|
|
2964
|
+
feesEarnedTotal: 0n,
|
|
2965
|
+
// not present in pre-v12.15 layouts
|
|
2966
|
+
exactReserveCohorts: null,
|
|
2967
|
+
// not present in pre-v12.15 layouts
|
|
2968
|
+
exactCohortCount: null,
|
|
2969
|
+
overflowOlder: null,
|
|
2970
|
+
overflowOlderPresent: null,
|
|
2971
|
+
overflowNewest: null,
|
|
2972
|
+
overflowNewestPresent: null
|
|
2906
2973
|
};
|
|
2907
2974
|
}
|
|
2908
2975
|
function parseAllAccounts(data) {
|
|
@@ -2930,12 +2997,6 @@ function deriveVaultAuthority(programId, slab) {
|
|
|
2930
2997
|
programId
|
|
2931
2998
|
);
|
|
2932
2999
|
}
|
|
2933
|
-
function deriveInsuranceLpMint(programId, slab) {
|
|
2934
|
-
return PublicKey4.findProgramAddressSync(
|
|
2935
|
-
[textEncoder.encode("ins_lp"), slab.toBytes()],
|
|
2936
|
-
programId
|
|
2937
|
-
);
|
|
2938
|
-
}
|
|
2939
3000
|
var LP_INDEX_U16_MAX = 65535;
|
|
2940
3001
|
function deriveLpPda(programId, slab, lpIdx) {
|
|
2941
3002
|
if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
|
|
@@ -2950,12 +3011,6 @@ function deriveLpPda(programId, slab, lpIdx) {
|
|
|
2950
3011
|
programId
|
|
2951
3012
|
);
|
|
2952
3013
|
}
|
|
2953
|
-
function deriveKeeperFund(programId, slab) {
|
|
2954
|
-
return PublicKey4.findProgramAddressSync(
|
|
2955
|
-
[textEncoder.encode("keeper_fund"), slab.toBytes()],
|
|
2956
|
-
programId
|
|
2957
|
-
);
|
|
2958
|
-
}
|
|
2959
3014
|
var PUMPSWAP_PROGRAM_ID = new PublicKey4(
|
|
2960
3015
|
"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
|
|
2961
3016
|
);
|
|
@@ -2992,7 +3047,14 @@ function derivePythPushOraclePDA(feedIdHex) {
|
|
|
2992
3047
|
}
|
|
2993
3048
|
const feedId = new Uint8Array(32);
|
|
2994
3049
|
for (let i = 0; i < 32; i++) {
|
|
2995
|
-
|
|
3050
|
+
const hexPair = normalized.substring(i * 2, i * 2 + 2);
|
|
3051
|
+
const byte = parseInt(hexPair, 16);
|
|
3052
|
+
if (Number.isNaN(byte)) {
|
|
3053
|
+
throw new Error(
|
|
3054
|
+
`derivePythPushOraclePDA: failed to parse hex byte at position ${i}: "${hexPair}"`
|
|
3055
|
+
);
|
|
3056
|
+
}
|
|
3057
|
+
feedId[i] = byte;
|
|
2996
3058
|
}
|
|
2997
3059
|
const shardBuf = new Uint8Array(2);
|
|
2998
3060
|
return PublicKey4.findProgramAddressSync(
|
|
@@ -3024,7 +3086,9 @@ import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
|
3024
3086
|
// src/solana/static-markets.ts
|
|
3025
3087
|
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
3026
3088
|
var MAINNET_MARKETS = [
|
|
3027
|
-
|
|
3089
|
+
// Populated at mainnet launch — currently empty.
|
|
3090
|
+
// To add entries:
|
|
3091
|
+
// { slabAddress: "ABC123...", symbol: "SOL-PERP", name: "SOL Perpetual" },
|
|
3028
3092
|
];
|
|
3029
3093
|
var DEVNET_MARKETS = [
|
|
3030
3094
|
// Populated from prior discoverMarkets() runs on devnet.
|
|
@@ -3192,6 +3256,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3192
3256
|
fundingIndexQpbE6: readI128LE2(data, base + 112),
|
|
3193
3257
|
lastFundingSlot: readU64LE2(data, base + 128),
|
|
3194
3258
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 136),
|
|
3259
|
+
fundingRateE9: 0n,
|
|
3260
|
+
marketMode: null,
|
|
3195
3261
|
lastCrankSlot: readU64LE2(data, base + 144),
|
|
3196
3262
|
maxCrankStalenessSlots: readU64LE2(data, base + 152),
|
|
3197
3263
|
totalOpenInterest: readU128LE2(data, base + 160),
|
|
@@ -3199,6 +3265,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3199
3265
|
shortOi: 0n,
|
|
3200
3266
|
cTot: readU128LE2(data, base + 176),
|
|
3201
3267
|
pnlPosTot: readU128LE2(data, base + 192),
|
|
3268
|
+
pnlMaturedPosTot: 0n,
|
|
3202
3269
|
liqCursor: readU16LE2(data, base + 208),
|
|
3203
3270
|
gcCursor: readU16LE2(data, base + 210),
|
|
3204
3271
|
lastSweepStartSlot: readU64LE2(data, base + 216),
|
|
@@ -3234,6 +3301,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3234
3301
|
fundingIndexQpbE6: readI128LE2(data, base + 360),
|
|
3235
3302
|
lastFundingSlot: readU64LE2(data, base + 376),
|
|
3236
3303
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 384),
|
|
3304
|
+
fundingRateE9: 0n,
|
|
3305
|
+
marketMode: null,
|
|
3237
3306
|
lastCrankSlot: readU64LE2(data, base + 392),
|
|
3238
3307
|
maxCrankStalenessSlots: readU64LE2(data, base + 400),
|
|
3239
3308
|
totalOpenInterest: readU128LE2(data, base + 408),
|
|
@@ -3243,6 +3312,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3243
3312
|
// V2 has no short_oi
|
|
3244
3313
|
cTot: readU128LE2(data, base + 424),
|
|
3245
3314
|
pnlPosTot: readU128LE2(data, base + 440),
|
|
3315
|
+
pnlMaturedPosTot: 0n,
|
|
3246
3316
|
liqCursor: readU16LE2(data, base + 456),
|
|
3247
3317
|
gcCursor: readU16LE2(data, base + 458),
|
|
3248
3318
|
lastSweepStartSlot: readU64LE2(data, base + 464),
|
|
@@ -3280,6 +3350,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3280
3350
|
fundingIndexQpbE6: readI128LE2(data, base + l.engineFundingIndexOff),
|
|
3281
3351
|
lastFundingSlot: readU64LE2(data, base + l.engineLastFundingSlotOff),
|
|
3282
3352
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + l.engineFundingRateBpsOff),
|
|
3353
|
+
fundingRateE9: 0n,
|
|
3354
|
+
marketMode: null,
|
|
3283
3355
|
lastCrankSlot: readU64LE2(data, base + l.engineLastCrankSlotOff),
|
|
3284
3356
|
maxCrankStalenessSlots: readU64LE2(data, base + l.engineMaxCrankStalenessOff),
|
|
3285
3357
|
totalOpenInterest: readU128LE2(data, base + l.engineTotalOiOff),
|
|
@@ -3287,6 +3359,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3287
3359
|
shortOi: l.engineShortOiOff >= 0 ? readU128LE2(data, base + l.engineShortOiOff) : 0n,
|
|
3288
3360
|
cTot: readU128LE2(data, base + l.engineCTotOff),
|
|
3289
3361
|
pnlPosTot: readU128LE2(data, base + l.enginePnlPosTotOff),
|
|
3362
|
+
pnlMaturedPosTot: 0n,
|
|
3290
3363
|
liqCursor: readU16LE2(data, base + l.engineLiqCursorOff),
|
|
3291
3364
|
gcCursor: readU16LE2(data, base + l.engineGcCursorOff),
|
|
3292
3365
|
lastSweepStartSlot: readU64LE2(data, base + l.engineLastSweepStartOff),
|
|
@@ -3320,6 +3393,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3320
3393
|
fundingIndexQpbE6: readI128LE2(data, base + 368),
|
|
3321
3394
|
lastFundingSlot: readU64LE2(data, base + 384),
|
|
3322
3395
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 392),
|
|
3396
|
+
fundingRateE9: 0n,
|
|
3397
|
+
marketMode: null,
|
|
3323
3398
|
lastCrankSlot: readU64LE2(data, base + 424),
|
|
3324
3399
|
maxCrankStalenessSlots: readU64LE2(data, base + 408),
|
|
3325
3400
|
totalOpenInterest: readU128LE2(data, base + 416),
|
|
@@ -3327,6 +3402,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3327
3402
|
shortOi: readU128LE2(data, base + 448),
|
|
3328
3403
|
cTot: readU128LE2(data, base + 464),
|
|
3329
3404
|
pnlPosTot: readU128LE2(data, base + 480),
|
|
3405
|
+
pnlMaturedPosTot: 0n,
|
|
3330
3406
|
liqCursor: readU16LE2(data, base + 496),
|
|
3331
3407
|
gcCursor: readU16LE2(data, base + 498),
|
|
3332
3408
|
lastSweepStartSlot: readU64LE2(data, base + 504),
|
|
@@ -3792,9 +3868,7 @@ function computeRaydiumClmmPriceE6(data) {
|
|
|
3792
3868
|
}
|
|
3793
3869
|
const sqrtPriceX64 = readU128LE3(dv3, 253);
|
|
3794
3870
|
if (sqrtPriceX64 === 0n) return 0n;
|
|
3795
|
-
const
|
|
3796
|
-
const term = scaledSqrt >> 64n;
|
|
3797
|
-
const priceE6Raw = term * sqrtPriceX64 >> 64n;
|
|
3871
|
+
const priceE6Raw = sqrtPriceX64 * sqrtPriceX64 * 1000000n >> 128n;
|
|
3798
3872
|
const decimalDiff = 6 + decimals0 - decimals1;
|
|
3799
3873
|
const adjustedDiff = decimalDiff - 6;
|
|
3800
3874
|
if (adjustedDiff >= 0) {
|
|
@@ -3835,13 +3909,26 @@ function computeMeteoraDlmmPriceE6(data) {
|
|
|
3835
3909
|
`Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`
|
|
3836
3910
|
);
|
|
3837
3911
|
}
|
|
3912
|
+
const MAX_ABS_BIN_ID = 5e5;
|
|
3913
|
+
if (activeId > MAX_ABS_BIN_ID || activeId < -MAX_ABS_BIN_ID) {
|
|
3914
|
+
throw new Error(
|
|
3915
|
+
`Meteora DLMM: activeId ${activeId} exceeds safe range (\xB1${MAX_ABS_BIN_ID})`
|
|
3916
|
+
);
|
|
3917
|
+
}
|
|
3838
3918
|
const SCALE = 1000000000000000000n;
|
|
3839
3919
|
const base = SCALE + BigInt(binStep) * SCALE / 10000n;
|
|
3840
3920
|
const isNeg = activeId < 0;
|
|
3841
3921
|
let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
|
|
3842
3922
|
let result = SCALE;
|
|
3843
3923
|
let b = base;
|
|
3924
|
+
let iterations = 0;
|
|
3925
|
+
const MAX_ITERATIONS = 25;
|
|
3844
3926
|
while (exp > 0n) {
|
|
3927
|
+
if (iterations++ >= MAX_ITERATIONS) {
|
|
3928
|
+
throw new Error(
|
|
3929
|
+
`Meteora DLMM: exponentiation loop exceeded ${MAX_ITERATIONS} iterations (activeId=${activeId})`
|
|
3930
|
+
);
|
|
3931
|
+
}
|
|
3845
3932
|
if (exp & 1n) {
|
|
3846
3933
|
result = result * b / SCALE;
|
|
3847
3934
|
}
|
|
@@ -3872,6 +3959,7 @@ function readU128LE3(dv3, offset) {
|
|
|
3872
3959
|
var CHAINLINK_MIN_SIZE = 224;
|
|
3873
3960
|
var MAX_DECIMALS = 18;
|
|
3874
3961
|
var CHAINLINK_DECIMALS_OFFSET = 138;
|
|
3962
|
+
var CHAINLINK_TIMESTAMP_OFFSET = 168;
|
|
3875
3963
|
var CHAINLINK_ANSWER_OFFSET = 216;
|
|
3876
3964
|
function readU82(data, off) {
|
|
3877
3965
|
return data[off];
|
|
@@ -3879,7 +3967,7 @@ function readU82(data, off) {
|
|
|
3879
3967
|
function readBigInt64LE(data, off) {
|
|
3880
3968
|
return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
|
|
3881
3969
|
}
|
|
3882
|
-
function parseChainlinkPrice(data) {
|
|
3970
|
+
function parseChainlinkPrice(data, options) {
|
|
3883
3971
|
if (data.length < CHAINLINK_MIN_SIZE) {
|
|
3884
3972
|
throw new Error(
|
|
3885
3973
|
`Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
|
|
@@ -3897,7 +3985,18 @@ function parseChainlinkPrice(data) {
|
|
|
3897
3985
|
`Oracle price is non-positive: ${price}`
|
|
3898
3986
|
);
|
|
3899
3987
|
}
|
|
3900
|
-
|
|
3988
|
+
const updatedAtBig = readBigInt64LE(data, CHAINLINK_TIMESTAMP_OFFSET);
|
|
3989
|
+
const updatedAt = Number(updatedAtBig);
|
|
3990
|
+
if (options?.maxStalenessSeconds !== void 0 && updatedAt > 0) {
|
|
3991
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3992
|
+
const age = now - updatedAt;
|
|
3993
|
+
if (age > options.maxStalenessSeconds) {
|
|
3994
|
+
throw new Error(
|
|
3995
|
+
`Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : void 0 };
|
|
3901
4000
|
}
|
|
3902
4001
|
function isValidChainlinkOracle(data) {
|
|
3903
4002
|
try {
|
|
@@ -3917,7 +4016,11 @@ var TOKEN_2022_PROGRAM_ID = new PublicKey8(
|
|
|
3917
4016
|
async function detectTokenProgram(connection, mint) {
|
|
3918
4017
|
const info = await connection.getAccountInfo(mint);
|
|
3919
4018
|
if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
3920
|
-
|
|
4019
|
+
if (info.owner.equals(TOKEN_PROGRAM_ID3)) return TOKEN_PROGRAM_ID3;
|
|
4020
|
+
if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;
|
|
4021
|
+
throw new Error(
|
|
4022
|
+
`Mint ${mint.toBase58()} is owned by ${info.owner.toBase58()}, which is neither TOKEN_PROGRAM_ID nor TOKEN_2022_PROGRAM_ID`
|
|
4023
|
+
);
|
|
3921
4024
|
}
|
|
3922
4025
|
function isToken2022(tokenProgramId) {
|
|
3923
4026
|
return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
|
|
@@ -3950,12 +4053,14 @@ var PROGRAM_IDS = {
|
|
|
3950
4053
|
}
|
|
3951
4054
|
};
|
|
3952
4055
|
function getProgramId(network) {
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
4056
|
+
if (!network) {
|
|
4057
|
+
const override = safeEnv("PROGRAM_ID");
|
|
4058
|
+
if (override) {
|
|
4059
|
+
console.warn(
|
|
4060
|
+
`[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
4061
|
+
);
|
|
4062
|
+
return new PublicKey9(override);
|
|
4063
|
+
}
|
|
3959
4064
|
}
|
|
3960
4065
|
const detectedNetwork = getCurrentNetwork();
|
|
3961
4066
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -3963,12 +4068,14 @@ function getProgramId(network) {
|
|
|
3963
4068
|
return new PublicKey9(programId);
|
|
3964
4069
|
}
|
|
3965
4070
|
function getMatcherProgramId(network) {
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
4071
|
+
if (!network) {
|
|
4072
|
+
const override = safeEnv("MATCHER_PROGRAM_ID");
|
|
4073
|
+
if (override) {
|
|
4074
|
+
console.warn(
|
|
4075
|
+
`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
4076
|
+
);
|
|
4077
|
+
return new PublicKey9(override);
|
|
4078
|
+
}
|
|
3972
4079
|
}
|
|
3973
4080
|
const detectedNetwork = getCurrentNetwork();
|
|
3974
4081
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -4001,10 +4108,7 @@ function getStakeProgramId(network) {
|
|
|
4001
4108
|
}
|
|
4002
4109
|
const detectedNetwork = network ?? (() => {
|
|
4003
4110
|
const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? "";
|
|
4004
|
-
|
|
4005
|
-
if (n === "devnet") return "devnet";
|
|
4006
|
-
if (typeof window !== "undefined") return "mainnet";
|
|
4007
|
-
return "devnet";
|
|
4111
|
+
return n === "mainnet" || n === "mainnet-beta" ? "mainnet" : "devnet";
|
|
4008
4112
|
})();
|
|
4009
4113
|
const id = STAKE_PROGRAM_IDS[detectedNetwork];
|
|
4010
4114
|
if (!id) {
|
|
@@ -4014,7 +4118,7 @@ function getStakeProgramId(network) {
|
|
|
4014
4118
|
}
|
|
4015
4119
|
return new PublicKey10(id);
|
|
4016
4120
|
}
|
|
4017
|
-
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.
|
|
4121
|
+
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.mainnet);
|
|
4018
4122
|
var STAKE_IX = {
|
|
4019
4123
|
InitPool: 0,
|
|
4020
4124
|
Deposit: 1,
|
|
@@ -4075,6 +4179,9 @@ function readU16LE3(data, off) {
|
|
|
4075
4179
|
);
|
|
4076
4180
|
}
|
|
4077
4181
|
function u64Le(v) {
|
|
4182
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
4183
|
+
throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
4184
|
+
}
|
|
4078
4185
|
const big = BigInt(v);
|
|
4079
4186
|
if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
|
|
4080
4187
|
if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
|
|
@@ -4083,6 +4190,9 @@ function u64Le(v) {
|
|
|
4083
4190
|
return arr;
|
|
4084
4191
|
}
|
|
4085
4192
|
function u128Le(v) {
|
|
4193
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
4194
|
+
throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
4195
|
+
}
|
|
4086
4196
|
const big = BigInt(v);
|
|
4087
4197
|
if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
|
|
4088
4198
|
if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
|
|
@@ -4093,7 +4203,7 @@ function u128Le(v) {
|
|
|
4093
4203
|
return arr;
|
|
4094
4204
|
}
|
|
4095
4205
|
function u16Le(v) {
|
|
4096
|
-
if (v < 0 || v > 65535) throw new Error(`u16Le: value
|
|
4206
|
+
if (!Number.isInteger(v) || v < 0 || v > 65535) throw new Error(`u16Le: value must be integer in range 0..65535, got ${v}`);
|
|
4097
4207
|
const arr = new Uint8Array(2);
|
|
4098
4208
|
new DataView(arr.buffer).setUint16(0, v, true);
|
|
4099
4209
|
return arr;
|
|
@@ -4348,7 +4458,9 @@ function computePnlPct(pnl, capital) {
|
|
|
4348
4458
|
}
|
|
4349
4459
|
function isAdlTriggered(slabData) {
|
|
4350
4460
|
const layout = detectSlabLayout(slabData.length);
|
|
4351
|
-
if (!layout)
|
|
4461
|
+
if (!layout) {
|
|
4462
|
+
return false;
|
|
4463
|
+
}
|
|
4352
4464
|
try {
|
|
4353
4465
|
const engine = parseEngine(slabData);
|
|
4354
4466
|
if (engine.pnlPosTot === 0n) return false;
|
|
@@ -4391,6 +4503,14 @@ function rankAdlPositions(slabData) {
|
|
|
4391
4503
|
if (account.kind !== 0 /* User */) continue;
|
|
4392
4504
|
if (account.positionSize === 0n) continue;
|
|
4393
4505
|
const side = account.positionSize > 0n ? "long" : "short";
|
|
4506
|
+
if (side === "long" && account.positionSize <= 0n) {
|
|
4507
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=long but positionSize=${account.positionSize}`);
|
|
4508
|
+
continue;
|
|
4509
|
+
}
|
|
4510
|
+
if (side === "short" && account.positionSize >= 0n) {
|
|
4511
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=short but positionSize=${account.positionSize}`);
|
|
4512
|
+
continue;
|
|
4513
|
+
}
|
|
4394
4514
|
const pnlPct = computePnlPct(account.pnl, account.capital);
|
|
4395
4515
|
positions.push({
|
|
4396
4516
|
idx,
|
|
@@ -4423,7 +4543,8 @@ function buildAdlInstruction(caller, slab, oracle, programId, targetIdx, backupO
|
|
|
4423
4543
|
`buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`
|
|
4424
4544
|
);
|
|
4425
4545
|
}
|
|
4426
|
-
const
|
|
4546
|
+
const dataBytes = encodeExecuteAdl({ targetIdx });
|
|
4547
|
+
const data = Buffer.from(dataBytes);
|
|
4427
4548
|
const keys = [
|
|
4428
4549
|
{ pubkey: caller, isSigner: true, isWritable: false },
|
|
4429
4550
|
{ pubkey: slab, isSigner: false, isWritable: true },
|
|
@@ -4463,7 +4584,11 @@ function parseAdlEvent(logs) {
|
|
|
4463
4584
|
}
|
|
4464
4585
|
if (tag !== ADL_EVENT_TAG) continue;
|
|
4465
4586
|
try {
|
|
4466
|
-
const
|
|
4587
|
+
const targetIdxBig = BigInt(match[2]);
|
|
4588
|
+
if (targetIdxBig < 0n || targetIdxBig > 65535n) {
|
|
4589
|
+
continue;
|
|
4590
|
+
}
|
|
4591
|
+
const targetIdx = Number(targetIdxBig);
|
|
4467
4592
|
const price = BigInt(match[3]);
|
|
4468
4593
|
const closedLo = BigInt(match[4]);
|
|
4469
4594
|
const closedHi = BigInt(match[5]);
|
|
@@ -4491,9 +4616,387 @@ async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
|
|
|
4491
4616
|
);
|
|
4492
4617
|
}
|
|
4493
4618
|
const json = await res.json();
|
|
4619
|
+
if (typeof json !== "object" || json === null) {
|
|
4620
|
+
throw new Error("fetchAdlRankings: API returned non-object response");
|
|
4621
|
+
}
|
|
4622
|
+
const obj = json;
|
|
4623
|
+
if (!Array.isArray(obj.rankings)) {
|
|
4624
|
+
throw new Error("fetchAdlRankings: API response missing rankings array");
|
|
4625
|
+
}
|
|
4626
|
+
for (const entry of obj.rankings) {
|
|
4627
|
+
if (typeof entry !== "object" || entry === null) {
|
|
4628
|
+
throw new Error("fetchAdlRankings: invalid ranking entry (not an object)");
|
|
4629
|
+
}
|
|
4630
|
+
const r = entry;
|
|
4631
|
+
if (typeof r.idx !== "number" || !Number.isInteger(r.idx) || r.idx < 0) {
|
|
4632
|
+
throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);
|
|
4633
|
+
}
|
|
4634
|
+
}
|
|
4494
4635
|
return json;
|
|
4495
4636
|
}
|
|
4496
4637
|
|
|
4638
|
+
// src/solana/rpc-pool.ts
|
|
4639
|
+
import {
|
|
4640
|
+
Connection as Connection5
|
|
4641
|
+
} from "@solana/web3.js";
|
|
4642
|
+
async function checkRpcHealth(endpoint, timeoutMs = 5e3) {
|
|
4643
|
+
const conn = new Connection5(endpoint, { commitment: "processed" });
|
|
4644
|
+
const start = performance.now();
|
|
4645
|
+
const timeout = rejectAfter(timeoutMs, `Health probe timed out after ${timeoutMs}ms`);
|
|
4646
|
+
try {
|
|
4647
|
+
const slot = await Promise.race([
|
|
4648
|
+
conn.getSlot("processed"),
|
|
4649
|
+
timeout.promise
|
|
4650
|
+
]);
|
|
4651
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4652
|
+
return { endpoint, healthy: true, latencyMs, slot };
|
|
4653
|
+
} catch (err) {
|
|
4654
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4655
|
+
return {
|
|
4656
|
+
endpoint,
|
|
4657
|
+
healthy: false,
|
|
4658
|
+
latencyMs,
|
|
4659
|
+
slot: 0,
|
|
4660
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4661
|
+
};
|
|
4662
|
+
} finally {
|
|
4663
|
+
timeout.cancel();
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
function resolveRetryConfig(cfg) {
|
|
4667
|
+
if (cfg === false) return null;
|
|
4668
|
+
const c = cfg ?? {};
|
|
4669
|
+
return {
|
|
4670
|
+
maxRetries: c.maxRetries ?? 3,
|
|
4671
|
+
baseDelayMs: c.baseDelayMs ?? 500,
|
|
4672
|
+
maxDelayMs: c.maxDelayMs ?? 1e4,
|
|
4673
|
+
jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),
|
|
4674
|
+
retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504]
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
function normalizeEndpoint(ep) {
|
|
4678
|
+
if (typeof ep === "string") return { url: ep };
|
|
4679
|
+
return ep;
|
|
4680
|
+
}
|
|
4681
|
+
function endpointLabel(ep) {
|
|
4682
|
+
if (ep.label) return ep.label;
|
|
4683
|
+
try {
|
|
4684
|
+
return new URL(ep.url).hostname;
|
|
4685
|
+
} catch {
|
|
4686
|
+
return ep.url.slice(0, 40);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
function isRetryable(err, codes) {
|
|
4690
|
+
if (!err) return false;
|
|
4691
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4692
|
+
for (const code of codes) {
|
|
4693
|
+
if (msg.includes(String(code))) return true;
|
|
4694
|
+
}
|
|
4695
|
+
if (msg.toLowerCase().includes("rate limit") || msg.toLowerCase().includes("too many requests") || msg.toLowerCase().includes("econnreset") || msg.toLowerCase().includes("econnrefused") || msg.toLowerCase().includes("socket hang up") || msg.toLowerCase().includes("network") || msg.toLowerCase().includes("timeout") || msg.toLowerCase().includes("abort")) {
|
|
4696
|
+
return true;
|
|
4697
|
+
}
|
|
4698
|
+
return false;
|
|
4699
|
+
}
|
|
4700
|
+
function computeDelay(attempt, config) {
|
|
4701
|
+
const raw = Math.min(
|
|
4702
|
+
config.baseDelayMs * Math.pow(2, attempt),
|
|
4703
|
+
config.maxDelayMs
|
|
4704
|
+
);
|
|
4705
|
+
const jitter = Math.floor(Math.random() * raw * config.jitterFactor);
|
|
4706
|
+
return raw + jitter;
|
|
4707
|
+
}
|
|
4708
|
+
function rejectAfter(ms, message) {
|
|
4709
|
+
let timer;
|
|
4710
|
+
const promise = new Promise((_, reject) => {
|
|
4711
|
+
timer = setTimeout(() => reject(new Error(message)), ms);
|
|
4712
|
+
});
|
|
4713
|
+
return { promise, cancel: () => clearTimeout(timer) };
|
|
4714
|
+
}
|
|
4715
|
+
function sleep(ms) {
|
|
4716
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4717
|
+
}
|
|
4718
|
+
function redactUrl(raw) {
|
|
4719
|
+
try {
|
|
4720
|
+
const u = new URL(raw);
|
|
4721
|
+
const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;
|
|
4722
|
+
for (const k of [...u.searchParams.keys()]) {
|
|
4723
|
+
if (sensitive.test(k)) {
|
|
4724
|
+
u.searchParams.set(k, "***");
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
return u.toString();
|
|
4728
|
+
} catch {
|
|
4729
|
+
return raw;
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
var RpcPool = class _RpcPool {
|
|
4733
|
+
endpoints;
|
|
4734
|
+
strategy;
|
|
4735
|
+
retryConfig;
|
|
4736
|
+
requestTimeoutMs;
|
|
4737
|
+
verbose;
|
|
4738
|
+
/** Round-robin index tracker. */
|
|
4739
|
+
rrIndex = 0;
|
|
4740
|
+
/** Consecutive failure threshold before marking an endpoint unhealthy. */
|
|
4741
|
+
static UNHEALTHY_THRESHOLD = 3;
|
|
4742
|
+
/** Minimum endpoints before auto-recovery is attempted. */
|
|
4743
|
+
static MIN_HEALTHY = 1;
|
|
4744
|
+
constructor(config) {
|
|
4745
|
+
if (!config.endpoints || config.endpoints.length === 0) {
|
|
4746
|
+
throw new Error("RpcPool: at least one endpoint is required");
|
|
4747
|
+
}
|
|
4748
|
+
this.strategy = config.strategy ?? "failover";
|
|
4749
|
+
this.retryConfig = resolveRetryConfig(config.retry);
|
|
4750
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? 3e4;
|
|
4751
|
+
this.verbose = config.verbose ?? true;
|
|
4752
|
+
const commitment = config.commitment ?? "confirmed";
|
|
4753
|
+
this.endpoints = config.endpoints.map((raw) => {
|
|
4754
|
+
const ep = normalizeEndpoint(raw);
|
|
4755
|
+
const connConfig = {
|
|
4756
|
+
commitment,
|
|
4757
|
+
...ep.connectionConfig
|
|
4758
|
+
};
|
|
4759
|
+
return {
|
|
4760
|
+
config: ep,
|
|
4761
|
+
connection: new Connection5(ep.url, connConfig),
|
|
4762
|
+
label: endpointLabel(ep),
|
|
4763
|
+
weight: Math.max(1, ep.weight ?? 1),
|
|
4764
|
+
failures: 0,
|
|
4765
|
+
healthy: true,
|
|
4766
|
+
lastLatencyMs: -1
|
|
4767
|
+
};
|
|
4768
|
+
});
|
|
4769
|
+
}
|
|
4770
|
+
// -----------------------------------------------------------------------
|
|
4771
|
+
// Public API
|
|
4772
|
+
// -----------------------------------------------------------------------
|
|
4773
|
+
/**
|
|
4774
|
+
* Execute a function against a pooled connection with automatic retry
|
|
4775
|
+
* and failover.
|
|
4776
|
+
*
|
|
4777
|
+
* @param fn - Async function that receives a `Connection` and returns a result.
|
|
4778
|
+
* @returns The result of `fn`.
|
|
4779
|
+
* @throws The last error if all retries and failovers are exhausted.
|
|
4780
|
+
*
|
|
4781
|
+
* @example
|
|
4782
|
+
* ```ts
|
|
4783
|
+
* const balance = await pool.call(c => c.getBalance(pubkey));
|
|
4784
|
+
* const markets = await pool.call(c => discoverMarkets(c, programId, opts));
|
|
4785
|
+
* ```
|
|
4786
|
+
*/
|
|
4787
|
+
async call(fn) {
|
|
4788
|
+
const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;
|
|
4789
|
+
let lastError;
|
|
4790
|
+
const triedEndpoints = /* @__PURE__ */ new Set();
|
|
4791
|
+
const maxTotalIterations = maxAttempts + this.endpoints.length;
|
|
4792
|
+
let totalIterations = 0;
|
|
4793
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4794
|
+
if (++totalIterations > maxTotalIterations) break;
|
|
4795
|
+
const epIdx = this.selectEndpoint(triedEndpoints);
|
|
4796
|
+
if (epIdx === -1) {
|
|
4797
|
+
break;
|
|
4798
|
+
}
|
|
4799
|
+
const ep = this.endpoints[epIdx];
|
|
4800
|
+
const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);
|
|
4801
|
+
try {
|
|
4802
|
+
const result = await Promise.race([
|
|
4803
|
+
fn(ep.connection),
|
|
4804
|
+
timeout.promise
|
|
4805
|
+
]);
|
|
4806
|
+
timeout.cancel();
|
|
4807
|
+
ep.failures = 0;
|
|
4808
|
+
ep.healthy = true;
|
|
4809
|
+
return result;
|
|
4810
|
+
} catch (err) {
|
|
4811
|
+
timeout.cancel();
|
|
4812
|
+
lastError = err;
|
|
4813
|
+
ep.failures++;
|
|
4814
|
+
if (ep.failures >= _RpcPool.UNHEALTHY_THRESHOLD) {
|
|
4815
|
+
ep.healthy = false;
|
|
4816
|
+
if (this.verbose) {
|
|
4817
|
+
console.warn(
|
|
4818
|
+
`[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`
|
|
4819
|
+
);
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
const retryable = this.retryConfig ? isRetryable(err, this.retryConfig.retryableStatusCodes) : false;
|
|
4823
|
+
if (!retryable) {
|
|
4824
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4825
|
+
triedEndpoints.add(epIdx);
|
|
4826
|
+
attempt--;
|
|
4827
|
+
if (triedEndpoints.size >= this.endpoints.length) break;
|
|
4828
|
+
continue;
|
|
4829
|
+
}
|
|
4830
|
+
throw err;
|
|
4831
|
+
}
|
|
4832
|
+
if (this.verbose) {
|
|
4833
|
+
console.warn(
|
|
4834
|
+
`[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,
|
|
4835
|
+
err instanceof Error ? err.message : err
|
|
4836
|
+
);
|
|
4837
|
+
}
|
|
4838
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4839
|
+
triedEndpoints.add(epIdx);
|
|
4840
|
+
}
|
|
4841
|
+
if (attempt < maxAttempts - 1 && this.retryConfig) {
|
|
4842
|
+
const delay = computeDelay(attempt, this.retryConfig);
|
|
4843
|
+
await sleep(delay);
|
|
4844
|
+
}
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
this.maybeRecoverEndpoints();
|
|
4848
|
+
throw lastError ?? new Error("RpcPool: all endpoints exhausted");
|
|
4849
|
+
}
|
|
4850
|
+
/**
|
|
4851
|
+
* Get a raw `Connection` from the current preferred endpoint.
|
|
4852
|
+
* Useful when you need to pass a Connection to external code.
|
|
4853
|
+
*
|
|
4854
|
+
* NOTE: This bypasses retry and failover logic. Prefer `call()`.
|
|
4855
|
+
*
|
|
4856
|
+
* @returns Solana Connection from the current preferred endpoint.
|
|
4857
|
+
*
|
|
4858
|
+
* @example
|
|
4859
|
+
* ```ts
|
|
4860
|
+
* const conn = pool.getConnection();
|
|
4861
|
+
* const balance = await conn.getBalance(pubkey);
|
|
4862
|
+
* ```
|
|
4863
|
+
*/
|
|
4864
|
+
getConnection() {
|
|
4865
|
+
const idx = this.selectEndpoint();
|
|
4866
|
+
if (idx === -1) {
|
|
4867
|
+
this.maybeRecoverEndpoints();
|
|
4868
|
+
return this.endpoints[0].connection;
|
|
4869
|
+
}
|
|
4870
|
+
return this.endpoints[idx].connection;
|
|
4871
|
+
}
|
|
4872
|
+
/**
|
|
4873
|
+
* Run a health check against all endpoints in the pool.
|
|
4874
|
+
*
|
|
4875
|
+
* @param timeoutMs - Per-endpoint probe timeout (default: 5000)
|
|
4876
|
+
* @returns Array of health results, one per endpoint.
|
|
4877
|
+
*
|
|
4878
|
+
* @example
|
|
4879
|
+
* ```ts
|
|
4880
|
+
* const results = await pool.healthCheck();
|
|
4881
|
+
* for (const r of results) {
|
|
4882
|
+
* console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);
|
|
4883
|
+
* }
|
|
4884
|
+
* ```
|
|
4885
|
+
*/
|
|
4886
|
+
async healthCheck(timeoutMs = 5e3) {
|
|
4887
|
+
const results = await Promise.all(
|
|
4888
|
+
this.endpoints.map(async (ep) => {
|
|
4889
|
+
const result = await checkRpcHealth(ep.config.url, timeoutMs);
|
|
4890
|
+
ep.lastLatencyMs = result.latencyMs;
|
|
4891
|
+
ep.healthy = result.healthy;
|
|
4892
|
+
if (result.healthy) ep.failures = 0;
|
|
4893
|
+
result.endpoint = redactUrl(result.endpoint);
|
|
4894
|
+
return result;
|
|
4895
|
+
})
|
|
4896
|
+
);
|
|
4897
|
+
return results;
|
|
4898
|
+
}
|
|
4899
|
+
/**
|
|
4900
|
+
* Get the number of endpoints in the pool.
|
|
4901
|
+
*/
|
|
4902
|
+
get size() {
|
|
4903
|
+
return this.endpoints.length;
|
|
4904
|
+
}
|
|
4905
|
+
/**
|
|
4906
|
+
* Get the number of currently healthy endpoints.
|
|
4907
|
+
*/
|
|
4908
|
+
get healthyCount() {
|
|
4909
|
+
return this.endpoints.filter((ep) => ep.healthy).length;
|
|
4910
|
+
}
|
|
4911
|
+
/**
|
|
4912
|
+
* Get endpoint labels and their current status.
|
|
4913
|
+
*
|
|
4914
|
+
* @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.
|
|
4915
|
+
*/
|
|
4916
|
+
status() {
|
|
4917
|
+
return this.endpoints.map((ep) => ({
|
|
4918
|
+
label: ep.label,
|
|
4919
|
+
url: redactUrl(ep.config.url),
|
|
4920
|
+
healthy: ep.healthy,
|
|
4921
|
+
failures: ep.failures,
|
|
4922
|
+
lastLatencyMs: ep.lastLatencyMs
|
|
4923
|
+
}));
|
|
4924
|
+
}
|
|
4925
|
+
// -----------------------------------------------------------------------
|
|
4926
|
+
// Internals
|
|
4927
|
+
// -----------------------------------------------------------------------
|
|
4928
|
+
/**
|
|
4929
|
+
* Select the next endpoint based on strategy.
|
|
4930
|
+
* Returns -1 if no endpoint is available.
|
|
4931
|
+
*/
|
|
4932
|
+
selectEndpoint(exclude) {
|
|
4933
|
+
const healthy = this.endpoints.map((ep, i) => ({ ep, i })).filter(({ ep, i }) => ep.healthy && !exclude?.has(i));
|
|
4934
|
+
if (healthy.length === 0) {
|
|
4935
|
+
const remaining = this.endpoints.map((_, i) => i).filter((i) => !exclude?.has(i));
|
|
4936
|
+
return remaining.length > 0 ? remaining[0] : -1;
|
|
4937
|
+
}
|
|
4938
|
+
if (this.strategy === "failover") {
|
|
4939
|
+
return healthy[0].i;
|
|
4940
|
+
}
|
|
4941
|
+
const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);
|
|
4942
|
+
this.rrIndex = (this.rrIndex + 1) % totalWeight;
|
|
4943
|
+
let cumulative = 0;
|
|
4944
|
+
for (const { ep, i } of healthy) {
|
|
4945
|
+
cumulative += ep.weight;
|
|
4946
|
+
if (this.rrIndex < cumulative) return i;
|
|
4947
|
+
}
|
|
4948
|
+
return healthy[healthy.length - 1].i;
|
|
4949
|
+
}
|
|
4950
|
+
/**
|
|
4951
|
+
* If all endpoints are unhealthy, reset them so we at least try again.
|
|
4952
|
+
*/
|
|
4953
|
+
maybeRecoverEndpoints() {
|
|
4954
|
+
const healthyCount = this.endpoints.filter((ep) => ep.healthy).length;
|
|
4955
|
+
if (healthyCount < _RpcPool.MIN_HEALTHY) {
|
|
4956
|
+
if (this.verbose) {
|
|
4957
|
+
console.warn("[RpcPool] All endpoints unhealthy \u2014 resetting for recovery");
|
|
4958
|
+
}
|
|
4959
|
+
for (const ep of this.endpoints) {
|
|
4960
|
+
ep.healthy = true;
|
|
4961
|
+
ep.failures = 0;
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
};
|
|
4966
|
+
async function withRetry(fn, config) {
|
|
4967
|
+
const resolved = resolveRetryConfig(config) ?? {
|
|
4968
|
+
maxRetries: 3,
|
|
4969
|
+
baseDelayMs: 500,
|
|
4970
|
+
maxDelayMs: 1e4,
|
|
4971
|
+
jitterFactor: 0.25,
|
|
4972
|
+
retryableStatusCodes: [429, 502, 503, 504]
|
|
4973
|
+
};
|
|
4974
|
+
let lastError;
|
|
4975
|
+
const maxAttempts = resolved.maxRetries + 1;
|
|
4976
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4977
|
+
try {
|
|
4978
|
+
return await fn();
|
|
4979
|
+
} catch (err) {
|
|
4980
|
+
lastError = err;
|
|
4981
|
+
if (!isRetryable(err, resolved.retryableStatusCodes)) {
|
|
4982
|
+
throw err;
|
|
4983
|
+
}
|
|
4984
|
+
if (attempt < maxAttempts - 1) {
|
|
4985
|
+
const delay = computeDelay(attempt, resolved);
|
|
4986
|
+
await sleep(delay);
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
throw lastError ?? new Error("withRetry: all attempts exhausted");
|
|
4991
|
+
}
|
|
4992
|
+
var _internal = {
|
|
4993
|
+
isRetryable,
|
|
4994
|
+
computeDelay,
|
|
4995
|
+
resolveRetryConfig,
|
|
4996
|
+
normalizeEndpoint,
|
|
4997
|
+
endpointLabel
|
|
4998
|
+
};
|
|
4999
|
+
|
|
4497
5000
|
// src/runtime/tx.ts
|
|
4498
5001
|
import {
|
|
4499
5002
|
TransactionInstruction as TransactionInstruction2,
|
|
@@ -4645,6 +5148,139 @@ function formatResult(result, jsonMode) {
|
|
|
4645
5148
|
return lines.join("\n");
|
|
4646
5149
|
}
|
|
4647
5150
|
|
|
5151
|
+
// src/runtime/lighthouse.ts
|
|
5152
|
+
import { PublicKey as PublicKey13, Transaction as Transaction2 } from "@solana/web3.js";
|
|
5153
|
+
var LIGHTHOUSE_PROGRAM_ID = new PublicKey13(
|
|
5154
|
+
"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"
|
|
5155
|
+
);
|
|
5156
|
+
var LIGHTHOUSE_PROGRAM_ID_STR2 = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
5157
|
+
var LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
|
|
5158
|
+
var LIGHTHOUSE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5159
|
+
6e3,
|
|
5160
|
+
// InstructionMissing
|
|
5161
|
+
6001,
|
|
5162
|
+
// InstructionFallbackNotFound
|
|
5163
|
+
6002,
|
|
5164
|
+
// InstructionDidNotDeserialize
|
|
5165
|
+
6003,
|
|
5166
|
+
// InstructionDidNotSerialize
|
|
5167
|
+
6016,
|
|
5168
|
+
// IdlInstructionStub
|
|
5169
|
+
6032,
|
|
5170
|
+
// ConstraintMut
|
|
5171
|
+
6033,
|
|
5172
|
+
// ConstraintHasOne
|
|
5173
|
+
6034,
|
|
5174
|
+
// ConstraintSigner
|
|
5175
|
+
6035,
|
|
5176
|
+
// ConstraintRaw
|
|
5177
|
+
6036,
|
|
5178
|
+
// ConstraintOwner
|
|
5179
|
+
6037,
|
|
5180
|
+
// ConstraintRentExempt
|
|
5181
|
+
6038,
|
|
5182
|
+
// ConstraintSeeds
|
|
5183
|
+
6039,
|
|
5184
|
+
// ConstraintExecutable
|
|
5185
|
+
6040,
|
|
5186
|
+
// ConstraintState
|
|
5187
|
+
6041,
|
|
5188
|
+
// ConstraintAssociated
|
|
5189
|
+
6042,
|
|
5190
|
+
// ConstraintAssociatedInit
|
|
5191
|
+
6043,
|
|
5192
|
+
// ConstraintClose
|
|
5193
|
+
6400
|
|
5194
|
+
// ConstraintAddress (the one we hit most often)
|
|
5195
|
+
]);
|
|
5196
|
+
function isLighthouseInstruction(ix) {
|
|
5197
|
+
return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);
|
|
5198
|
+
}
|
|
5199
|
+
function isLighthouseError(error) {
|
|
5200
|
+
const msg = extractErrorMessage(error);
|
|
5201
|
+
if (!msg) return false;
|
|
5202
|
+
if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR2)) return true;
|
|
5203
|
+
if (/custom\s+program\s+error:\s*0x1900\b/i.test(msg)) return true;
|
|
5204
|
+
if (/"Custom"\s*:\s*6400\b/.test(msg) && /InstructionError/i.test(msg)) return true;
|
|
5205
|
+
return false;
|
|
5206
|
+
}
|
|
5207
|
+
function isLighthouseFailureInLogs(logs) {
|
|
5208
|
+
if (!Array.isArray(logs)) return false;
|
|
5209
|
+
let insideLighthouse = false;
|
|
5210
|
+
for (const line of logs) {
|
|
5211
|
+
if (typeof line !== "string") continue;
|
|
5212
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} invoke`)) {
|
|
5213
|
+
insideLighthouse = true;
|
|
5214
|
+
continue;
|
|
5215
|
+
}
|
|
5216
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} success`)) {
|
|
5217
|
+
insideLighthouse = false;
|
|
5218
|
+
continue;
|
|
5219
|
+
}
|
|
5220
|
+
if (insideLighthouse && /failed/i.test(line)) {
|
|
5221
|
+
return true;
|
|
5222
|
+
}
|
|
5223
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} failed`)) {
|
|
5224
|
+
return true;
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
return false;
|
|
5228
|
+
}
|
|
5229
|
+
function stripLighthouseInstructions(instructions, percolatorProgramId) {
|
|
5230
|
+
if (percolatorProgramId) {
|
|
5231
|
+
const hasPercolatorIx = instructions.some(
|
|
5232
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5233
|
+
);
|
|
5234
|
+
if (!hasPercolatorIx) {
|
|
5235
|
+
return instructions;
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
return instructions.filter((ix) => !isLighthouseInstruction(ix));
|
|
5239
|
+
}
|
|
5240
|
+
function stripLighthouseFromTransaction(transaction, percolatorProgramId) {
|
|
5241
|
+
if (percolatorProgramId) {
|
|
5242
|
+
const hasPercolatorIx = transaction.instructions.some(
|
|
5243
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5244
|
+
);
|
|
5245
|
+
if (!hasPercolatorIx) return transaction;
|
|
5246
|
+
}
|
|
5247
|
+
const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);
|
|
5248
|
+
if (!hasLighthouse) return transaction;
|
|
5249
|
+
const clean = new Transaction2();
|
|
5250
|
+
clean.recentBlockhash = transaction.recentBlockhash;
|
|
5251
|
+
clean.feePayer = transaction.feePayer;
|
|
5252
|
+
for (const ix of transaction.instructions) {
|
|
5253
|
+
if (!isLighthouseInstruction(ix)) {
|
|
5254
|
+
clean.add(ix);
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
return clean;
|
|
5258
|
+
}
|
|
5259
|
+
function countLighthouseInstructions(ixsOrTx) {
|
|
5260
|
+
const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;
|
|
5261
|
+
return instructions.filter(isLighthouseInstruction).length;
|
|
5262
|
+
}
|
|
5263
|
+
var LIGHTHOUSE_USER_MESSAGE = "Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. This is a known compatibility issue \u2014 the transaction itself is valid. Try one of these workarounds:\n1. Disable transaction simulation in your wallet settings\n2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\n3. The SDK will automatically retry without the guard";
|
|
5264
|
+
function classifyLighthouseError(error) {
|
|
5265
|
+
if (isLighthouseError(error)) {
|
|
5266
|
+
return LIGHTHOUSE_USER_MESSAGE;
|
|
5267
|
+
}
|
|
5268
|
+
return null;
|
|
5269
|
+
}
|
|
5270
|
+
function extractErrorMessage(error) {
|
|
5271
|
+
if (!error) return null;
|
|
5272
|
+
if (typeof error === "string") return error;
|
|
5273
|
+
if (error instanceof Error) return error.message;
|
|
5274
|
+
if (typeof error === "object" && "message" in error) {
|
|
5275
|
+
return String(error.message);
|
|
5276
|
+
}
|
|
5277
|
+
try {
|
|
5278
|
+
return JSON.stringify(error);
|
|
5279
|
+
} catch {
|
|
5280
|
+
return null;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
|
|
4648
5284
|
// src/math/trading.ts
|
|
4649
5285
|
function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
|
|
4650
5286
|
if (positionSize === 0n || oraclePrice === 0n) return 0n;
|
|
@@ -4669,16 +5305,10 @@ function computeLiqPrice(entryPrice, capital, positionSize, maintenanceMarginBps
|
|
|
4669
5305
|
function computePreTradeLiqPrice(oracleE6, margin, posSize, maintBps, feeBps, direction) {
|
|
4670
5306
|
if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;
|
|
4671
5307
|
const absPos = posSize < 0n ? -posSize : posSize;
|
|
5308
|
+
const fee = absPos * feeBps / 10000n;
|
|
5309
|
+
const effectiveCapital = margin > fee ? margin - fee : 0n;
|
|
4672
5310
|
const signedPos = direction === "long" ? absPos : -absPos;
|
|
4673
|
-
|
|
4674
|
-
let adjustedEntry;
|
|
4675
|
-
if (direction === "long") {
|
|
4676
|
-
adjustedEntry = oracleE6 + feeAdjust;
|
|
4677
|
-
} else {
|
|
4678
|
-
const shortEntry = oracleE6 - feeAdjust;
|
|
4679
|
-
adjustedEntry = shortEntry > 0n ? shortEntry : 1n;
|
|
4680
|
-
}
|
|
4681
|
-
return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);
|
|
5311
|
+
return computeLiqPrice(oracleE6, effectiveCapital, signedPos, maintBps);
|
|
4682
5312
|
}
|
|
4683
5313
|
function computeTradingFee(notional, tradingFeeBps) {
|
|
4684
5314
|
return notional * tradingFeeBps / 10000n;
|
|
@@ -4698,9 +5328,20 @@ function computeFeeSplit(totalFee, config) {
|
|
|
4698
5328
|
if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
|
|
4699
5329
|
return [totalFee, 0n, 0n];
|
|
4700
5330
|
}
|
|
5331
|
+
const totalBps = config.lpBps + config.protocolBps + config.creatorBps;
|
|
5332
|
+
if (totalBps !== 10000n) {
|
|
5333
|
+
throw new Error(
|
|
5334
|
+
`Fee split must equal exactly 10000 bps (100%): lpBps=${config.lpBps} + protocolBps=${config.protocolBps} + creatorBps=${config.creatorBps} = ${totalBps}`
|
|
5335
|
+
);
|
|
5336
|
+
}
|
|
4701
5337
|
const lp = totalFee * config.lpBps / 10000n;
|
|
4702
5338
|
const protocol = totalFee * config.protocolBps / 10000n;
|
|
4703
5339
|
const creator = totalFee - lp - protocol;
|
|
5340
|
+
if (creator < 0n) {
|
|
5341
|
+
throw new Error(
|
|
5342
|
+
`Internal error: creator fee is negative (${creator}). This should not happen if lpBps + protocolBps + creatorBps === 10000.`
|
|
5343
|
+
);
|
|
5344
|
+
}
|
|
4704
5345
|
return [lp, protocol, creator];
|
|
4705
5346
|
}
|
|
4706
5347
|
function computePnlPercent(pnlTokens, capital) {
|
|
@@ -4715,10 +5356,17 @@ function computePnlPercent(pnlTokens, capital) {
|
|
|
4715
5356
|
}
|
|
4716
5357
|
function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
|
|
4717
5358
|
if (oracleE6 === 0n) return 0n;
|
|
5359
|
+
if (tradingFeeBps < 0n) {
|
|
5360
|
+
throw new Error(`computeEstimatedEntryPrice: tradingFeeBps must be non-negative, got ${tradingFeeBps}`);
|
|
5361
|
+
}
|
|
4718
5362
|
const feeImpact = oracleE6 * tradingFeeBps / 10000n;
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
5363
|
+
const result = direction === "long" ? oracleE6 + feeImpact : oracleE6 - feeImpact;
|
|
5364
|
+
if (result <= 0n) {
|
|
5365
|
+
throw new Error(
|
|
5366
|
+
`computeEstimatedEntryPrice: result ${result} is non-positive (tradingFeeBps=${tradingFeeBps} too high for oracle=${oracleE6})`
|
|
5367
|
+
);
|
|
5368
|
+
}
|
|
5369
|
+
return result;
|
|
4722
5370
|
}
|
|
4723
5371
|
var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
4724
5372
|
var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
|
|
@@ -4739,7 +5387,12 @@ function computeMaxLeverage(initialMarginBps) {
|
|
|
4739
5387
|
if (initialMarginBps <= 0n) {
|
|
4740
5388
|
throw new Error("computeMaxLeverage: initialMarginBps must be positive");
|
|
4741
5389
|
}
|
|
4742
|
-
|
|
5390
|
+
const scaledResult = 10000n * 1000000n / initialMarginBps;
|
|
5391
|
+
return Number(scaledResult) / 1e6;
|
|
5392
|
+
}
|
|
5393
|
+
function computeMaxWithdrawable(capital, pnl, reservedPnl) {
|
|
5394
|
+
const maturedPnl = pnl - reservedPnl;
|
|
5395
|
+
return capital + (maturedPnl > 0n ? maturedPnl : 0n);
|
|
4743
5396
|
}
|
|
4744
5397
|
|
|
4745
5398
|
// src/math/warmup.ts
|
|
@@ -4751,6 +5404,9 @@ function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot
|
|
|
4751
5404
|
return totalCapital * elapsed / warmupPeriodSlots;
|
|
4752
5405
|
}
|
|
4753
5406
|
function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
5407
|
+
if (initialMarginBps <= 0n) {
|
|
5408
|
+
throw new Error("computeWarmupLeverageCap: initialMarginBps must be positive");
|
|
5409
|
+
}
|
|
4754
5410
|
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
4755
5411
|
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
|
|
4756
5412
|
if (totalCapital <= 0n) return 1;
|
|
@@ -4761,7 +5417,14 @@ function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, w
|
|
|
4761
5417
|
warmupPeriodSlots
|
|
4762
5418
|
);
|
|
4763
5419
|
if (unlocked <= 0n) return 1;
|
|
4764
|
-
const
|
|
5420
|
+
const scaledResult = BigInt(maxLev) * unlocked / totalCapital;
|
|
5421
|
+
if (scaledResult > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5422
|
+
console.warn(
|
|
5423
|
+
`[computeWarmupLeverageCap] Warning: effective leverage ${scaledResult} exceeds MAX_SAFE_INTEGER, returning MAX_SAFE_INTEGER as a safety bound`
|
|
5424
|
+
);
|
|
5425
|
+
return Number.MAX_SAFE_INTEGER;
|
|
5426
|
+
}
|
|
5427
|
+
const effectiveLev = Number(scaledResult);
|
|
4765
5428
|
return Math.max(1, effectiveLev);
|
|
4766
5429
|
}
|
|
4767
5430
|
function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
@@ -4774,10 +5437,41 @@ function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlo
|
|
|
4774
5437
|
);
|
|
4775
5438
|
return unlocked * BigInt(maxLev);
|
|
4776
5439
|
}
|
|
5440
|
+
function computeWarmupProgress(currentSlot, warmupStartedAtSlot, warmupPeriodSlots, pnl, reservedPnl) {
|
|
5441
|
+
if (warmupPeriodSlots === 0n || warmupStartedAtSlot === 0n) {
|
|
5442
|
+
return {
|
|
5443
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5444
|
+
reservedPnl: 0n,
|
|
5445
|
+
progressBps: 10000n,
|
|
5446
|
+
// 100%
|
|
5447
|
+
slotsRemaining: 0n
|
|
5448
|
+
};
|
|
5449
|
+
}
|
|
5450
|
+
const elapsed = currentSlot >= warmupStartedAtSlot ? currentSlot - warmupStartedAtSlot : 0n;
|
|
5451
|
+
if (elapsed >= warmupPeriodSlots) {
|
|
5452
|
+
return {
|
|
5453
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5454
|
+
reservedPnl: 0n,
|
|
5455
|
+
progressBps: 10000n,
|
|
5456
|
+
// 100%
|
|
5457
|
+
slotsRemaining: 0n
|
|
5458
|
+
};
|
|
5459
|
+
}
|
|
5460
|
+
const progressBps = elapsed * 10000n / warmupPeriodSlots;
|
|
5461
|
+
const slotsRemaining = warmupPeriodSlots - elapsed;
|
|
5462
|
+
const maturedPnl = pnl > 0n ? pnl * progressBps / 10000n : 0n;
|
|
5463
|
+
const locked = reservedPnl > 0n ? reservedPnl : 0n;
|
|
5464
|
+
return {
|
|
5465
|
+
maturedPnl,
|
|
5466
|
+
reservedPnl: locked,
|
|
5467
|
+
progressBps,
|
|
5468
|
+
slotsRemaining
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
4777
5471
|
|
|
4778
5472
|
// src/validation.ts
|
|
4779
|
-
import { PublicKey as
|
|
4780
|
-
var
|
|
5473
|
+
import { PublicKey as PublicKey14 } from "@solana/web3.js";
|
|
5474
|
+
var U16_MAX = 65535;
|
|
4781
5475
|
var U64_MAX = BigInt("18446744073709551615");
|
|
4782
5476
|
var I64_MIN = BigInt("-9223372036854775808");
|
|
4783
5477
|
var I64_MAX = BigInt("9223372036854775807");
|
|
@@ -4806,7 +5500,7 @@ var ValidationError = class extends Error {
|
|
|
4806
5500
|
};
|
|
4807
5501
|
function validatePublicKey(value, field) {
|
|
4808
5502
|
try {
|
|
4809
|
-
return new
|
|
5503
|
+
return new PublicKey14(value);
|
|
4810
5504
|
} catch {
|
|
4811
5505
|
throw new ValidationError(
|
|
4812
5506
|
field,
|
|
@@ -4817,24 +5511,26 @@ function validatePublicKey(value, field) {
|
|
|
4817
5511
|
function validateIndex(value, field) {
|
|
4818
5512
|
const t = requireDecimalUIntString(value, field);
|
|
4819
5513
|
const bi = BigInt(t);
|
|
4820
|
-
if (bi > BigInt(
|
|
5514
|
+
if (bi > BigInt(U16_MAX)) {
|
|
4821
5515
|
throw new ValidationError(
|
|
4822
5516
|
field,
|
|
4823
|
-
`must be <= ${
|
|
5517
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4824
5518
|
);
|
|
4825
5519
|
}
|
|
5520
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5521
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5522
|
+
}
|
|
4826
5523
|
return Number(bi);
|
|
4827
5524
|
}
|
|
4828
5525
|
function validateAmount(value, field) {
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
num = BigInt(value);
|
|
4832
|
-
} catch {
|
|
5526
|
+
const t = value.trim();
|
|
5527
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4833
5528
|
throw new ValidationError(
|
|
4834
5529
|
field,
|
|
4835
|
-
`"${value}" is not a valid
|
|
5530
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4836
5531
|
);
|
|
4837
5532
|
}
|
|
5533
|
+
const num = BigInt(t);
|
|
4838
5534
|
if (num < 0n) {
|
|
4839
5535
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4840
5536
|
}
|
|
@@ -4847,15 +5543,14 @@ function validateAmount(value, field) {
|
|
|
4847
5543
|
return num;
|
|
4848
5544
|
}
|
|
4849
5545
|
function validateU128(value, field) {
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
num = BigInt(value);
|
|
4853
|
-
} catch {
|
|
5546
|
+
const t = value.trim();
|
|
5547
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4854
5548
|
throw new ValidationError(
|
|
4855
5549
|
field,
|
|
4856
|
-
`"${value}" is not a valid
|
|
5550
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4857
5551
|
);
|
|
4858
5552
|
}
|
|
5553
|
+
const num = BigInt(t);
|
|
4859
5554
|
if (num < 0n) {
|
|
4860
5555
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4861
5556
|
}
|
|
@@ -4868,15 +5563,14 @@ function validateU128(value, field) {
|
|
|
4868
5563
|
return num;
|
|
4869
5564
|
}
|
|
4870
5565
|
function validateI64(value, field) {
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
num = BigInt(value);
|
|
4874
|
-
} catch {
|
|
5566
|
+
const t = value.trim();
|
|
5567
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4875
5568
|
throw new ValidationError(
|
|
4876
5569
|
field,
|
|
4877
|
-
`"${value}" is not a valid
|
|
5570
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4878
5571
|
);
|
|
4879
5572
|
}
|
|
5573
|
+
const num = BigInt(t);
|
|
4880
5574
|
if (num < I64_MIN) {
|
|
4881
5575
|
throw new ValidationError(
|
|
4882
5576
|
field,
|
|
@@ -4892,15 +5586,14 @@ function validateI64(value, field) {
|
|
|
4892
5586
|
return num;
|
|
4893
5587
|
}
|
|
4894
5588
|
function validateI128(value, field) {
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
num = BigInt(value);
|
|
4898
|
-
} catch {
|
|
5589
|
+
const t = value.trim();
|
|
5590
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4899
5591
|
throw new ValidationError(
|
|
4900
5592
|
field,
|
|
4901
|
-
`"${value}" is not a valid
|
|
5593
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4902
5594
|
);
|
|
4903
5595
|
}
|
|
5596
|
+
const num = BigInt(t);
|
|
4904
5597
|
if (num < I128_MIN) {
|
|
4905
5598
|
throw new ValidationError(
|
|
4906
5599
|
field,
|
|
@@ -4924,6 +5617,9 @@ function validateBps(value, field) {
|
|
|
4924
5617
|
`must be <= 10000 (100%), got ${t}`
|
|
4925
5618
|
);
|
|
4926
5619
|
}
|
|
5620
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5621
|
+
throw new ValidationError(field, `internal error: bps value exceeds MAX_SAFE_INTEGER`);
|
|
5622
|
+
}
|
|
4927
5623
|
return Number(bi);
|
|
4928
5624
|
}
|
|
4929
5625
|
function validateU64(value, field) {
|
|
@@ -4932,12 +5628,15 @@ function validateU64(value, field) {
|
|
|
4932
5628
|
function validateU16(value, field) {
|
|
4933
5629
|
const t = requireDecimalUIntString(value, field);
|
|
4934
5630
|
const bi = BigInt(t);
|
|
4935
|
-
if (bi > BigInt(
|
|
5631
|
+
if (bi > BigInt(U16_MAX)) {
|
|
4936
5632
|
throw new ValidationError(
|
|
4937
5633
|
field,
|
|
4938
|
-
`must be <= ${
|
|
5634
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4939
5635
|
);
|
|
4940
5636
|
}
|
|
5637
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5638
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5639
|
+
}
|
|
4941
5640
|
return Number(bi);
|
|
4942
5641
|
}
|
|
4943
5642
|
|
|
@@ -4988,7 +5687,9 @@ function parseDexScreenerPairs(json) {
|
|
|
4988
5687
|
else if (liquidity > 1e4) confidence = 60;
|
|
4989
5688
|
else if (liquidity > 1e3) confidence = 45;
|
|
4990
5689
|
const priceUsd = pair.priceUsd;
|
|
4991
|
-
const
|
|
5690
|
+
const rawPrice = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) : NaN;
|
|
5691
|
+
if (!Number.isFinite(rawPrice) || rawPrice <= 0) continue;
|
|
5692
|
+
const price = rawPrice;
|
|
4992
5693
|
let baseSym = "?";
|
|
4993
5694
|
let quoteSym = "?";
|
|
4994
5695
|
if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
|
|
@@ -5019,8 +5720,8 @@ function parseJupiterMintEntry(json, mint) {
|
|
|
5019
5720
|
if (!isRecord(row)) return null;
|
|
5020
5721
|
const rawPrice = row.price;
|
|
5021
5722
|
if (rawPrice === void 0 || rawPrice === null) return null;
|
|
5022
|
-
const price = parseFloat(String(rawPrice))
|
|
5023
|
-
if (price <= 0) return null;
|
|
5723
|
+
const price = parseFloat(String(rawPrice));
|
|
5724
|
+
if (!Number.isFinite(price) || price <= 0) return null;
|
|
5024
5725
|
let mintSymbol = "?";
|
|
5025
5726
|
if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
|
|
5026
5727
|
return { price, mintSymbol };
|
|
@@ -5086,10 +5787,17 @@ async function fetchDexSources(mint, signal) {
|
|
|
5086
5787
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5087
5788
|
}
|
|
5088
5789
|
);
|
|
5089
|
-
if (!resp.ok)
|
|
5790
|
+
if (!resp.ok) {
|
|
5791
|
+
console.debug(`[fetchDexSources] HTTP ${resp.status} for mint ${mint}`);
|
|
5792
|
+
return [];
|
|
5793
|
+
}
|
|
5090
5794
|
const json = await resp.json();
|
|
5091
5795
|
return parseDexScreenerPairs(json);
|
|
5092
|
-
} catch {
|
|
5796
|
+
} catch (err) {
|
|
5797
|
+
console.warn(
|
|
5798
|
+
`[fetchDexSources] Error fetching DexScreener data for mint ${mint}:`,
|
|
5799
|
+
err instanceof Error ? err.message : String(err)
|
|
5800
|
+
);
|
|
5093
5801
|
return [];
|
|
5094
5802
|
}
|
|
5095
5803
|
}
|
|
@@ -5100,7 +5808,7 @@ function lookupPythSource(mint) {
|
|
|
5100
5808
|
type: "pyth",
|
|
5101
5809
|
address: entry.feedId,
|
|
5102
5810
|
pairLabel: `${entry.symbol} / USD (Pyth)`,
|
|
5103
|
-
liquidity:
|
|
5811
|
+
liquidity: Number.MAX_SAFE_INTEGER,
|
|
5104
5812
|
// Pyth is considered deep liquidity
|
|
5105
5813
|
price: 0,
|
|
5106
5814
|
// We don't fetch live price here; caller can enrich
|
|
@@ -5117,10 +5825,16 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5117
5825
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5118
5826
|
}
|
|
5119
5827
|
);
|
|
5120
|
-
if (!resp.ok)
|
|
5828
|
+
if (!resp.ok) {
|
|
5829
|
+
console.debug(`[fetchJupiterSource] HTTP ${resp.status} for mint ${mint}`);
|
|
5830
|
+
return null;
|
|
5831
|
+
}
|
|
5121
5832
|
const json = await resp.json();
|
|
5122
5833
|
const row = parseJupiterMintEntry(json, mint);
|
|
5123
|
-
if (!row)
|
|
5834
|
+
if (!row) {
|
|
5835
|
+
console.debug(`[fetchJupiterSource] No price data from Jupiter for mint ${mint}`);
|
|
5836
|
+
return null;
|
|
5837
|
+
}
|
|
5124
5838
|
return {
|
|
5125
5839
|
type: "jupiter",
|
|
5126
5840
|
address: mint,
|
|
@@ -5131,23 +5845,39 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5131
5845
|
confidence: 40
|
|
5132
5846
|
// Fallback — lower confidence
|
|
5133
5847
|
};
|
|
5134
|
-
} catch {
|
|
5848
|
+
} catch (err) {
|
|
5849
|
+
console.warn(
|
|
5850
|
+
`[fetchJupiterSource] Error fetching Jupiter data for mint ${mint}:`,
|
|
5851
|
+
err instanceof Error ? err.message : String(err)
|
|
5852
|
+
);
|
|
5135
5853
|
return null;
|
|
5136
5854
|
}
|
|
5137
5855
|
}
|
|
5138
5856
|
async function resolvePrice(mint, signal, options) {
|
|
5139
5857
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;
|
|
5140
5858
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
5141
|
-
const
|
|
5859
|
+
const effectiveSignal2 = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
|
|
5142
5860
|
const [dexSources, jupiterSource] = await Promise.all([
|
|
5143
|
-
fetchDexSources(mint,
|
|
5144
|
-
fetchJupiterSource(mint,
|
|
5861
|
+
fetchDexSources(mint, effectiveSignal2),
|
|
5862
|
+
fetchJupiterSource(mint, effectiveSignal2)
|
|
5145
5863
|
]);
|
|
5146
5864
|
const pythSource = lookupPythSource(mint);
|
|
5147
5865
|
const allSources = [];
|
|
5148
5866
|
if (pythSource) {
|
|
5149
|
-
const
|
|
5150
|
-
|
|
5867
|
+
const dexPrice = dexSources[0]?.price ?? 0;
|
|
5868
|
+
const jupPrice = jupiterSource?.price ?? 0;
|
|
5869
|
+
if (dexPrice > 0 && jupPrice > 0) {
|
|
5870
|
+
const mid = (dexPrice + jupPrice) / 2;
|
|
5871
|
+
const deviation = Math.abs(dexPrice - jupPrice) / mid;
|
|
5872
|
+
if (deviation > 0.5) {
|
|
5873
|
+
pythSource.price = 0;
|
|
5874
|
+
pythSource.confidence = 20;
|
|
5875
|
+
} else {
|
|
5876
|
+
pythSource.price = mid;
|
|
5877
|
+
}
|
|
5878
|
+
} else {
|
|
5879
|
+
pythSource.price = dexPrice || jupPrice || 0;
|
|
5880
|
+
}
|
|
5151
5881
|
allSources.push(pythSource);
|
|
5152
5882
|
}
|
|
5153
5883
|
allSources.push(...dexSources);
|
|
@@ -5172,9 +5902,7 @@ export {
|
|
|
5172
5902
|
ACCOUNTS_CLOSE_ACCOUNT,
|
|
5173
5903
|
ACCOUNTS_CLOSE_SLAB,
|
|
5174
5904
|
ACCOUNTS_CLOSE_STALE_SLABS,
|
|
5175
|
-
ACCOUNTS_CREATE_INSURANCE_MINT,
|
|
5176
5905
|
ACCOUNTS_DEPOSIT_COLLATERAL,
|
|
5177
|
-
ACCOUNTS_DEPOSIT_INSURANCE_LP,
|
|
5178
5906
|
ACCOUNTS_EXECUTE_ADL,
|
|
5179
5907
|
ACCOUNTS_FUND_MARKET_INSURANCE,
|
|
5180
5908
|
ACCOUNTS_INIT_LP,
|
|
@@ -5190,7 +5918,6 @@ export {
|
|
|
5190
5918
|
ACCOUNTS_QUEUE_WITHDRAWAL,
|
|
5191
5919
|
ACCOUNTS_RECLAIM_SLAB_RENT,
|
|
5192
5920
|
ACCOUNTS_RESOLVE_MARKET,
|
|
5193
|
-
ACCOUNTS_SET_DEX_POOL,
|
|
5194
5921
|
ACCOUNTS_SET_INSURANCE_ISOLATION,
|
|
5195
5922
|
ACCOUNTS_SET_MAINTENANCE_FEE,
|
|
5196
5923
|
ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK,
|
|
@@ -5200,7 +5927,6 @@ export {
|
|
|
5200
5927
|
ACCOUNTS_SET_RISK_THRESHOLD,
|
|
5201
5928
|
ACCOUNTS_SET_WALLET_CAP,
|
|
5202
5929
|
ACCOUNTS_TOPUP_INSURANCE,
|
|
5203
|
-
ACCOUNTS_TOPUP_KEEPER_FUND,
|
|
5204
5930
|
ACCOUNTS_TRADE_CPI,
|
|
5205
5931
|
ACCOUNTS_TRADE_NOCPI,
|
|
5206
5932
|
ACCOUNTS_TRANSFER_POSITION_OWNERSHIP,
|
|
@@ -5209,17 +5935,22 @@ export {
|
|
|
5209
5935
|
ACCOUNTS_UPDATE_CONFIG,
|
|
5210
5936
|
ACCOUNTS_WITHDRAW_COLLATERAL,
|
|
5211
5937
|
ACCOUNTS_WITHDRAW_INSURANCE,
|
|
5212
|
-
ACCOUNTS_WITHDRAW_INSURANCE_LP,
|
|
5213
5938
|
AccountKind,
|
|
5214
5939
|
CHAINLINK_ANSWER_OFFSET,
|
|
5215
5940
|
CHAINLINK_DECIMALS_OFFSET,
|
|
5216
5941
|
CHAINLINK_MIN_SIZE,
|
|
5942
|
+
CHAINLINK_TIMESTAMP_OFFSET,
|
|
5217
5943
|
CREATOR_LOCK_SEED,
|
|
5218
5944
|
CTX_VAMM_OFFSET,
|
|
5219
5945
|
DEFAULT_OI_RAMP_SLOTS,
|
|
5220
5946
|
ENGINE_MARK_PRICE_OFF,
|
|
5221
5947
|
ENGINE_OFF,
|
|
5222
5948
|
IX_TAG,
|
|
5949
|
+
LIGHTHOUSE_CONSTRAINT_ADDRESS,
|
|
5950
|
+
LIGHTHOUSE_ERROR_CODES,
|
|
5951
|
+
LIGHTHOUSE_PROGRAM_ID,
|
|
5952
|
+
LIGHTHOUSE_PROGRAM_ID_STR2 as LIGHTHOUSE_PROGRAM_ID_STR,
|
|
5953
|
+
LIGHTHOUSE_USER_MESSAGE,
|
|
5223
5954
|
MARK_PRICE_EMA_ALPHA_E6,
|
|
5224
5955
|
MARK_PRICE_EMA_WINDOW_SLOTS,
|
|
5225
5956
|
MAX_DECIMALS,
|
|
@@ -5241,10 +5972,12 @@ export {
|
|
|
5241
5972
|
RAMP_START_BPS,
|
|
5242
5973
|
RAYDIUM_CLMM_PROGRAM_ID,
|
|
5243
5974
|
RENOUNCE_ADMIN_CONFIRMATION,
|
|
5975
|
+
RpcPool,
|
|
5244
5976
|
SLAB_TIERS,
|
|
5245
5977
|
SLAB_TIERS_V0,
|
|
5246
5978
|
SLAB_TIERS_V1,
|
|
5247
5979
|
SLAB_TIERS_V12_1,
|
|
5980
|
+
SLAB_TIERS_V12_15,
|
|
5248
5981
|
SLAB_TIERS_V1D,
|
|
5249
5982
|
SLAB_TIERS_V1D_LEGACY,
|
|
5250
5983
|
SLAB_TIERS_V1M,
|
|
@@ -5262,11 +5995,14 @@ export {
|
|
|
5262
5995
|
VAMM_MAGIC,
|
|
5263
5996
|
ValidationError,
|
|
5264
5997
|
WELL_KNOWN,
|
|
5998
|
+
_internal,
|
|
5265
5999
|
buildAccountMetas,
|
|
5266
6000
|
buildAdlInstruction,
|
|
5267
6001
|
buildAdlTransaction,
|
|
5268
6002
|
buildIx,
|
|
5269
6003
|
checkPhaseTransition,
|
|
6004
|
+
checkRpcHealth,
|
|
6005
|
+
classifyLighthouseError,
|
|
5270
6006
|
clearStaticMarkets,
|
|
5271
6007
|
computeDexSpotPriceE6,
|
|
5272
6008
|
computeDynamicFeeBps,
|
|
@@ -5279,6 +6015,7 @@ export {
|
|
|
5279
6015
|
computeLiqPrice,
|
|
5280
6016
|
computeMarkPnl,
|
|
5281
6017
|
computeMaxLeverage,
|
|
6018
|
+
computeMaxWithdrawable,
|
|
5282
6019
|
computePnlPercent,
|
|
5283
6020
|
computePreTradeLiqPrice,
|
|
5284
6021
|
computeRequiredMargin,
|
|
@@ -5286,15 +6023,15 @@ export {
|
|
|
5286
6023
|
computeVammQuote,
|
|
5287
6024
|
computeWarmupLeverageCap,
|
|
5288
6025
|
computeWarmupMaxPositionSize,
|
|
6026
|
+
computeWarmupProgress,
|
|
5289
6027
|
computeWarmupUnlockedCapital,
|
|
5290
6028
|
concatBytes,
|
|
6029
|
+
countLighthouseInstructions,
|
|
5291
6030
|
decodeError,
|
|
5292
6031
|
decodeStakePool,
|
|
5293
6032
|
depositAccounts,
|
|
5294
6033
|
deriveCreatorLockPda,
|
|
5295
6034
|
deriveDepositPda,
|
|
5296
|
-
deriveInsuranceLpMint,
|
|
5297
|
-
deriveKeeperFund,
|
|
5298
6035
|
deriveLpPda,
|
|
5299
6036
|
derivePythPriceUpdateAccount,
|
|
5300
6037
|
derivePythPushOraclePDA,
|
|
@@ -5330,14 +6067,11 @@ export {
|
|
|
5330
6067
|
encodeClaimQueuedWithdrawal,
|
|
5331
6068
|
encodeClearPendingSettlement,
|
|
5332
6069
|
encodeCloseAccount,
|
|
5333
|
-
encodeCloseKeeperFund,
|
|
5334
6070
|
encodeCloseOrphanSlab,
|
|
5335
6071
|
encodeCloseSlab,
|
|
5336
6072
|
encodeCloseStaleSlabs,
|
|
5337
|
-
encodeCreateInsuranceMint,
|
|
5338
6073
|
encodeCreateLpVault,
|
|
5339
6074
|
encodeDepositCollateral,
|
|
5340
|
-
encodeDepositInsuranceLP,
|
|
5341
6075
|
encodeDepositLpCollateral,
|
|
5342
6076
|
encodeExecuteAdl,
|
|
5343
6077
|
encodeForceCloseResolved,
|
|
@@ -5394,7 +6128,6 @@ export {
|
|
|
5394
6128
|
encodeStakeUpdateConfig,
|
|
5395
6129
|
encodeStakeWithdraw,
|
|
5396
6130
|
encodeTopUpInsurance,
|
|
5397
|
-
encodeTopUpKeeperFund,
|
|
5398
6131
|
encodeTradeCpi,
|
|
5399
6132
|
encodeTradeCpiV2,
|
|
5400
6133
|
encodeTradeNoCpi,
|
|
@@ -5408,7 +6141,6 @@ export {
|
|
|
5408
6141
|
encodeUpdateRiskParams,
|
|
5409
6142
|
encodeWithdrawCollateral,
|
|
5410
6143
|
encodeWithdrawInsurance,
|
|
5411
|
-
encodeWithdrawInsuranceLP,
|
|
5412
6144
|
encodeWithdrawInsuranceLimited,
|
|
5413
6145
|
encodeWithdrawLpCollateral,
|
|
5414
6146
|
fetchAdlRankedPositions,
|
|
@@ -5430,6 +6162,10 @@ export {
|
|
|
5430
6162
|
initPoolAccounts,
|
|
5431
6163
|
isAccountUsed,
|
|
5432
6164
|
isAdlTriggered,
|
|
6165
|
+
isAnchorErrorCode,
|
|
6166
|
+
isLighthouseError,
|
|
6167
|
+
isLighthouseFailureInLogs,
|
|
6168
|
+
isLighthouseInstruction,
|
|
5433
6169
|
isStandardToken,
|
|
5434
6170
|
isToken2022,
|
|
5435
6171
|
isValidChainlinkOracle,
|
|
@@ -5454,6 +6190,8 @@ export {
|
|
|
5454
6190
|
simulateOrSend,
|
|
5455
6191
|
slabDataSize,
|
|
5456
6192
|
slabDataSizeV1,
|
|
6193
|
+
stripLighthouseFromTransaction,
|
|
6194
|
+
stripLighthouseInstructions,
|
|
5457
6195
|
validateAmount,
|
|
5458
6196
|
validateBps,
|
|
5459
6197
|
validateI128,
|
|
@@ -5464,6 +6202,7 @@ export {
|
|
|
5464
6202
|
validateU128,
|
|
5465
6203
|
validateU16,
|
|
5466
6204
|
validateU64,
|
|
6205
|
+
withRetry,
|
|
5467
6206
|
withdrawAccounts
|
|
5468
6207
|
};
|
|
5469
6208
|
//# sourceMappingURL=index.js.map
|