@percolatorct/sdk 1.0.0-beta.15 → 1.0.0-beta.17
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 -3455
- package/dist/index.js +1049 -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,41 @@ 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_ACCOUNT_SIZE_SMALL = 944;
|
|
1624
|
+
var V12_15_ACCT_ACCOUNT_ID_OFF = 0;
|
|
1625
|
+
var V12_15_ACCT_CAPITAL_OFF = 8;
|
|
1626
|
+
var V12_15_ACCT_KIND_OFF = 24;
|
|
1627
|
+
var V12_15_ACCT_PNL_OFF = 32;
|
|
1628
|
+
var V12_15_ACCT_RESERVED_PNL_OFF = 48;
|
|
1629
|
+
var V12_15_ACCT_POSITION_BASIS_Q_OFF = 64;
|
|
1630
|
+
var V12_15_ACCT_ENTRY_PRICE_OFF = 120;
|
|
1631
|
+
var V12_15_ACCT_MATCHER_PROGRAM_OFF = 128;
|
|
1632
|
+
var V12_15_ACCT_MATCHER_CONTEXT_OFF = 160;
|
|
1633
|
+
var V12_15_ACCT_OWNER_OFF = 192;
|
|
1634
|
+
var V12_15_ACCT_FEE_CREDITS_OFF = 224;
|
|
1635
|
+
var V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240;
|
|
1636
|
+
var V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256;
|
|
1637
|
+
var V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224;
|
|
1638
|
+
var V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240;
|
|
1639
|
+
var V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304;
|
|
1640
|
+
var V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320;
|
|
1641
|
+
var V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384;
|
|
1642
|
+
var V12_15_PARAMS_SIZE = 192;
|
|
1643
|
+
var V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24;
|
|
1644
|
+
var V12_15_PARAMS_H_MIN_OFF = 160;
|
|
1645
|
+
var V12_15_PARAMS_H_MAX_OFF = 168;
|
|
1646
|
+
var V12_15_ENGINE_PARAMS_OFF = 32;
|
|
1647
|
+
var V12_15_ENGINE_CURRENT_SLOT_OFF = 224;
|
|
1648
|
+
var V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240;
|
|
1649
|
+
var V12_15_ENGINE_MARKET_MODE_OFF = 256;
|
|
1650
|
+
var V12_15_ENGINE_C_TOT_OFF = 344;
|
|
1651
|
+
var V12_15_ENGINE_PNL_POS_TOT_OFF = 368;
|
|
1652
|
+
var V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384;
|
|
1653
|
+
var V12_15_ENGINE_BITMAP_OFF = 862;
|
|
1654
|
+
var V12_15_SIZES = /* @__PURE__ */ new Map();
|
|
1667
1655
|
var V1M_ENGINE_OFF = 640;
|
|
1668
1656
|
var V1M_CONFIG_LEN = 536;
|
|
1669
1657
|
var V1M_ACCOUNT_SIZE = 248;
|
|
@@ -1736,7 +1724,10 @@ for (const n of TIERS) {
|
|
|
1736
1724
|
V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);
|
|
1737
1725
|
V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);
|
|
1738
1726
|
V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);
|
|
1727
|
+
V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);
|
|
1739
1728
|
}
|
|
1729
|
+
V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);
|
|
1730
|
+
V12_15_SIZES.set(237512, 256);
|
|
1740
1731
|
var V12_1_SBF_ACCOUNT_SIZE = 280;
|
|
1741
1732
|
var V12_1_SBF_ENGINE_OFF = 616;
|
|
1742
1733
|
var V12_1_SBF_BITMAP_OFF = 584;
|
|
@@ -1747,14 +1738,6 @@ for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large",
|
|
|
1747
1738
|
const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
|
|
1748
1739
|
V12_1_SIZES.set(total, n);
|
|
1749
1740
|
}
|
|
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
1741
|
var SLAB_TIERS_V2 = {
|
|
1759
1742
|
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
|
|
1760
1743
|
large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V2 BPF intermediate)" }
|
|
@@ -2219,6 +2202,11 @@ for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Lar
|
|
|
2219
2202
|
const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);
|
|
2220
2203
|
SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };
|
|
2221
2204
|
}
|
|
2205
|
+
var SLAB_TIERS_V12_15 = {};
|
|
2206
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Medium2048", 2048], ["Large", 4096]]) {
|
|
2207
|
+
const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);
|
|
2208
|
+
SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };
|
|
2209
|
+
}
|
|
2222
2210
|
function buildLayoutVSetDexPool(maxAccounts) {
|
|
2223
2211
|
const engineOff = V_SETDEXPOOL_ENGINE_OFF;
|
|
2224
2212
|
const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;
|
|
@@ -2315,12 +2303,16 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2315
2303
|
engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
2316
2304
|
// not in deployed struct
|
|
2317
2305
|
engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
2318
|
-
engineMarkPriceOff: isSbf ?
|
|
2306
|
+
engineMarkPriceOff: isSbf ? -1 : V12_1_ENGINE_MARK_PRICE_OFF,
|
|
2307
|
+
// not in deployed struct
|
|
2319
2308
|
engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2320
2309
|
engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2321
|
-
engineTotalOiOff: isSbf ?
|
|
2322
|
-
|
|
2323
|
-
|
|
2310
|
+
engineTotalOiOff: isSbf ? -1 : V12_1_ENGINE_TOTAL_OI_OFF,
|
|
2311
|
+
// not in deployed struct
|
|
2312
|
+
engineLongOiOff: isSbf ? -1 : V12_1_ENGINE_LONG_OI_OFF,
|
|
2313
|
+
// not in deployed struct
|
|
2314
|
+
engineShortOiOff: isSbf ? -1 : V12_1_ENGINE_SHORT_OI_OFF,
|
|
2315
|
+
// not in deployed struct
|
|
2324
2316
|
engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,
|
|
2325
2317
|
enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,
|
|
2326
2318
|
engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,
|
|
@@ -2356,10 +2348,10 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2356
2348
|
engineInsuranceIsolationBpsOff: isSbf ? -1 : 64
|
|
2357
2349
|
};
|
|
2358
2350
|
}
|
|
2359
|
-
function
|
|
2360
|
-
const engineOff =
|
|
2361
|
-
const bitmapOff =
|
|
2362
|
-
const accountSize =
|
|
2351
|
+
function buildLayoutV12_15(maxAccounts) {
|
|
2352
|
+
const engineOff = V12_15_ENGINE_OFF;
|
|
2353
|
+
const bitmapOff = V12_15_ENGINE_BITMAP_OFF;
|
|
2354
|
+
const accountSize = V12_15_ACCOUNT_SIZE;
|
|
2363
2355
|
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2364
2356
|
const bitmapBytes = bitmapWords * 8;
|
|
2365
2357
|
const postBitmap = 18;
|
|
@@ -2367,63 +2359,94 @@ function buildLayoutV12_1EP(maxAccounts) {
|
|
|
2367
2359
|
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2368
2360
|
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2369
2361
|
return {
|
|
2370
|
-
version:
|
|
2371
|
-
headerLen:
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2362
|
+
version: 2,
|
|
2363
|
+
headerLen: V0_HEADER_LEN,
|
|
2364
|
+
// 72 (same as V12_1)
|
|
2365
|
+
configOffset: V0_HEADER_LEN,
|
|
2366
|
+
// 72
|
|
2367
|
+
configLen: 552,
|
|
2368
|
+
// SBF CONFIG_LEN for v12.15
|
|
2369
|
+
reservedOff: V1_RESERVED_OFF,
|
|
2370
|
+
// 80
|
|
2376
2371
|
engineOff,
|
|
2377
2372
|
accountSize,
|
|
2378
2373
|
maxAccounts,
|
|
2379
2374
|
bitmapWords,
|
|
2380
2375
|
accountsOff: engineOff + accountsOffRel,
|
|
2381
2376
|
engineInsuranceOff: 16,
|
|
2382
|
-
engineParamsOff:
|
|
2383
|
-
//
|
|
2384
|
-
paramsSize:
|
|
2385
|
-
//
|
|
2386
|
-
|
|
2387
|
-
|
|
2377
|
+
engineParamsOff: V12_15_ENGINE_PARAMS_OFF,
|
|
2378
|
+
// 32
|
|
2379
|
+
paramsSize: V12_15_PARAMS_SIZE,
|
|
2380
|
+
// 192
|
|
2381
|
+
engineCurrentSlotOff: V12_15_ENGINE_CURRENT_SLOT_OFF,
|
|
2382
|
+
// 224
|
|
2388
2383
|
engineFundingIndexOff: -1,
|
|
2384
|
+
// not present in v12.15 engine struct
|
|
2389
2385
|
engineLastFundingSlotOff: -1,
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2386
|
+
// not present in v12.15 engine struct
|
|
2387
|
+
// funding_rate_e9 is i128 — stored in engineFundingRateBpsOff for EngineState.fundingRateBpsPerSlotLast
|
|
2388
|
+
// callers should treat this as the i128 funding rate in e9 units
|
|
2389
|
+
engineFundingRateBpsOff: V12_15_ENGINE_FUNDING_RATE_E9_OFF,
|
|
2390
|
+
// 240
|
|
2391
|
+
engineMarkPriceOff: -1,
|
|
2392
|
+
// not present in v12.15 (removed with oracle refactor)
|
|
2393
|
+
engineLastCrankSlotOff: -1,
|
|
2394
|
+
// not yet mapped; set -1 until offset verified on-chain
|
|
2395
|
+
engineMaxCrankStalenessOff: -1,
|
|
2396
|
+
// not yet mapped
|
|
2397
|
+
engineTotalOiOff: -1,
|
|
2398
|
+
// not present in v12.15 engine
|
|
2399
|
+
engineLongOiOff: -1,
|
|
2400
|
+
// not present in v12.15 engine
|
|
2401
|
+
engineShortOiOff: -1,
|
|
2402
|
+
// not present in v12.15 engine
|
|
2403
|
+
engineCTotOff: V12_15_ENGINE_C_TOT_OFF,
|
|
2404
|
+
// 344
|
|
2405
|
+
enginePnlPosTotOff: V12_15_ENGINE_PNL_POS_TOT_OFF,
|
|
2406
|
+
// 368
|
|
2407
|
+
engineLiqCursorOff: -1,
|
|
2408
|
+
// not yet mapped
|
|
2409
|
+
engineGcCursorOff: -1,
|
|
2410
|
+
// not yet mapped
|
|
2411
|
+
engineLastSweepStartOff: -1,
|
|
2412
|
+
// not yet mapped
|
|
2413
|
+
engineLastSweepCompleteOff: -1,
|
|
2414
|
+
// not yet mapped
|
|
2415
|
+
engineCrankCursorOff: -1,
|
|
2416
|
+
// not yet mapped
|
|
2417
|
+
engineSweepStartIdxOff: -1,
|
|
2418
|
+
// not yet mapped
|
|
2419
|
+
engineLifetimeLiquidationsOff: -1,
|
|
2420
|
+
// not yet mapped
|
|
2406
2421
|
engineLifetimeForceClosesOff: -1,
|
|
2422
|
+
// not present in v12.15
|
|
2407
2423
|
engineNetLpPosOff: -1,
|
|
2424
|
+
// not present in v12.15
|
|
2408
2425
|
engineLpSumAbsOff: -1,
|
|
2426
|
+
// not present in v12.15
|
|
2409
2427
|
engineLpMaxAbsOff: -1,
|
|
2428
|
+
// not present in v12.15
|
|
2410
2429
|
engineLpMaxAbsSweepOff: -1,
|
|
2430
|
+
// not present in v12.15
|
|
2411
2431
|
engineEmergencyOiModeOff: -1,
|
|
2432
|
+
// not present in v12.15
|
|
2412
2433
|
engineEmergencyStartSlotOff: -1,
|
|
2434
|
+
// not present in v12.15
|
|
2413
2435
|
engineLastBreakerSlotOff: -1,
|
|
2436
|
+
// not present in v12.15
|
|
2414
2437
|
engineBitmapOff: bitmapOff,
|
|
2415
|
-
postBitmap
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
// 216 (was 208)
|
|
2438
|
+
postBitmap,
|
|
2439
|
+
acctOwnerOff: V12_15_ACCT_OWNER_OFF,
|
|
2440
|
+
// 192
|
|
2419
2441
|
hasInsuranceIsolation: false,
|
|
2442
|
+
// InsuranceFund = {balance: u128} = 16 bytes in v12.15
|
|
2420
2443
|
engineInsuranceIsolatedOff: -1,
|
|
2421
2444
|
engineInsuranceIsolationBpsOff: -1
|
|
2422
2445
|
};
|
|
2423
2446
|
}
|
|
2424
2447
|
function detectSlabLayout(dataLen, data) {
|
|
2425
|
-
const
|
|
2426
|
-
if (
|
|
2448
|
+
const v1215n = V12_15_SIZES.get(dataLen);
|
|
2449
|
+
if (v1215n !== void 0) return buildLayoutV12_15(v1215n);
|
|
2427
2450
|
const v121n = V12_1_SIZES.get(dataLen);
|
|
2428
2451
|
if (v121n !== void 0) return buildLayoutV12_1(v121n, dataLen);
|
|
2429
2452
|
const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);
|
|
@@ -2470,15 +2493,6 @@ var PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;
|
|
|
2470
2493
|
var PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;
|
|
2471
2494
|
var PARAMS_LIQUIDATION_BUFFER_OFF = 120;
|
|
2472
2495
|
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
2496
|
var ACCT_ACCOUNT_ID_OFF = 0;
|
|
2483
2497
|
var ACCT_CAPITAL_OFF = 8;
|
|
2484
2498
|
var ACCT_KIND_OFF = 24;
|
|
@@ -2728,15 +2742,15 @@ function parseParams(data, layoutHint) {
|
|
|
2728
2742
|
if (data.length < base + Math.min(paramsSize, 56)) {
|
|
2729
2743
|
throw new Error("Slab data too short for RiskParams");
|
|
2730
2744
|
}
|
|
2731
|
-
const
|
|
2745
|
+
const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE;
|
|
2732
2746
|
const result = {
|
|
2733
|
-
warmupPeriodSlots: readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2747
|
+
warmupPeriodSlots: isV12_15Params ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2734
2748
|
maintenanceMarginBps: readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),
|
|
2735
2749
|
initialMarginBps: readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),
|
|
2736
2750
|
tradingFeeBps: readU64LE(data, base + PARAMS_TRADING_FEE_OFF),
|
|
2737
|
-
maxAccounts: readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2751
|
+
maxAccounts: isV12_15Params ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2738
2752
|
newAccountFee: readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),
|
|
2739
|
-
// Extended params:
|
|
2753
|
+
// Extended params: only read if V1 (paramsSize >= 144)
|
|
2740
2754
|
riskReductionThreshold: 0n,
|
|
2741
2755
|
maintenanceFeePerSlot: 0n,
|
|
2742
2756
|
maxCrankStalenessSlots: 0n,
|
|
@@ -2744,21 +2758,19 @@ function parseParams(data, layoutHint) {
|
|
|
2744
2758
|
liquidationFeeCap: 0n,
|
|
2745
2759
|
liquidationBufferBps: 0n,
|
|
2746
2760
|
minLiquidationAbs: 0n,
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
minNonzeroImReq: 0n,
|
|
2750
|
-
insuranceFloor: 0n
|
|
2761
|
+
hMin: 0n,
|
|
2762
|
+
hMax: 0n
|
|
2751
2763
|
};
|
|
2752
|
-
if (
|
|
2753
|
-
result.
|
|
2754
|
-
result.
|
|
2755
|
-
result.
|
|
2756
|
-
result.
|
|
2757
|
-
result.
|
|
2758
|
-
result.
|
|
2759
|
-
result.
|
|
2760
|
-
result.
|
|
2761
|
-
result.
|
|
2764
|
+
if (isV12_15Params) {
|
|
2765
|
+
result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);
|
|
2766
|
+
result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);
|
|
2767
|
+
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2768
|
+
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
2769
|
+
result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);
|
|
2770
|
+
result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);
|
|
2771
|
+
result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);
|
|
2772
|
+
result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);
|
|
2773
|
+
result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);
|
|
2762
2774
|
} else if (paramsSize >= 144) {
|
|
2763
2775
|
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2764
2776
|
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
@@ -2767,6 +2779,8 @@ function parseParams(data, layoutHint) {
|
|
|
2767
2779
|
result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);
|
|
2768
2780
|
result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);
|
|
2769
2781
|
result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);
|
|
2782
|
+
result.hMin = result.warmupPeriodSlots;
|
|
2783
|
+
result.hMax = result.warmupPeriodSlots;
|
|
2770
2784
|
}
|
|
2771
2785
|
return result;
|
|
2772
2786
|
}
|
|
@@ -2776,6 +2790,8 @@ function parseEngine(data) {
|
|
|
2776
2790
|
throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);
|
|
2777
2791
|
}
|
|
2778
2792
|
const base = layout.engineOff;
|
|
2793
|
+
const isV12_15 = (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && layout.engineOff === V12_15_ENGINE_OFF;
|
|
2794
|
+
const fundingRateBpsPerSlotLast = isV12_15 ? readI128LE(data, base + V12_15_ENGINE_FUNDING_RATE_E9_OFF) : readI64LE(data, base + layout.engineFundingRateBpsOff);
|
|
2779
2795
|
return {
|
|
2780
2796
|
vault: readU128LE(data, base),
|
|
2781
2797
|
insuranceFund: {
|
|
@@ -2788,21 +2804,24 @@ function parseEngine(data) {
|
|
|
2788
2804
|
currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),
|
|
2789
2805
|
fundingIndexQpbE6: layout.engineFundingIndexOff >= 0 ? readI128LE(data, base + layout.engineFundingIndexOff) : 0n,
|
|
2790
2806
|
lastFundingSlot: layout.engineLastFundingSlotOff >= 0 ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,
|
|
2791
|
-
fundingRateBpsPerSlotLast
|
|
2792
|
-
|
|
2793
|
-
|
|
2807
|
+
fundingRateBpsPerSlotLast,
|
|
2808
|
+
fundingRateE9: isV12_15 ? readI128LE(data, base + V12_15_ENGINE_FUNDING_RATE_E9_OFF) : 0n,
|
|
2809
|
+
marketMode: isV12_15 ? readU8(data, base + V12_15_ENGINE_MARKET_MODE_OFF) === 1 ? 1 : 0 : null,
|
|
2810
|
+
lastCrankSlot: layout.engineLastCrankSlotOff >= 0 ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,
|
|
2811
|
+
maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0 ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,
|
|
2794
2812
|
totalOpenInterest: layout.engineTotalOiOff >= 0 ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,
|
|
2795
2813
|
longOi: layout.engineLongOiOff >= 0 ? readU128LE(data, base + layout.engineLongOiOff) : 0n,
|
|
2796
2814
|
shortOi: layout.engineShortOiOff >= 0 ? readU128LE(data, base + layout.engineShortOiOff) : 0n,
|
|
2797
2815
|
cTot: readU128LE(data, base + layout.engineCTotOff),
|
|
2798
2816
|
pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2817
|
+
pnlMaturedPosTot: isV12_15 ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF) : 0n,
|
|
2818
|
+
liqCursor: layout.engineLiqCursorOff >= 0 ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,
|
|
2819
|
+
gcCursor: layout.engineGcCursorOff >= 0 ? readU16LE(data, base + layout.engineGcCursorOff) : 0,
|
|
2820
|
+
lastSweepStartSlot: layout.engineLastSweepStartOff >= 0 ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,
|
|
2821
|
+
lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0 ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,
|
|
2822
|
+
crankCursor: layout.engineCrankCursorOff >= 0 ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,
|
|
2823
|
+
sweepStartIdx: layout.engineSweepStartIdxOff >= 0 ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,
|
|
2824
|
+
lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0 ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,
|
|
2806
2825
|
lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0 ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,
|
|
2807
2826
|
netLpPos: layout.engineNetLpPosOff >= 0 ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,
|
|
2808
2827
|
lpSumAbs: layout.engineLpSumAbsOff >= 0 ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,
|
|
@@ -2872,18 +2891,58 @@ function parseAccount(data, idx) {
|
|
|
2872
2891
|
if (data.length < base + layout.accountSize) {
|
|
2873
2892
|
throw new Error("Slab data too short for account");
|
|
2874
2893
|
}
|
|
2875
|
-
const
|
|
2876
|
-
const isV12_1 = !
|
|
2877
|
-
const isAdl = layout.accountSize >= 312 || isV12_1
|
|
2894
|
+
const isV12_15 = layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL;
|
|
2895
|
+
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);
|
|
2896
|
+
const isAdl = !isV12_15 && (layout.accountSize >= 312 || isV12_1);
|
|
2897
|
+
if (isV12_15) {
|
|
2898
|
+
const kindByte2 = readU8(data, base + V12_15_ACCT_KIND_OFF);
|
|
2899
|
+
const kind2 = kindByte2 === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2900
|
+
const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);
|
|
2901
|
+
const exactReserveCohorts = [];
|
|
2902
|
+
for (let i = 0; i < 62; i++) {
|
|
2903
|
+
const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;
|
|
2904
|
+
exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));
|
|
2905
|
+
}
|
|
2906
|
+
const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;
|
|
2907
|
+
const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;
|
|
2908
|
+
return {
|
|
2909
|
+
kind: kind2,
|
|
2910
|
+
accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),
|
|
2911
|
+
capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),
|
|
2912
|
+
pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),
|
|
2913
|
+
reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),
|
|
2914
|
+
warmupStartedAtSlot: 0n,
|
|
2915
|
+
// removed in v12.15
|
|
2916
|
+
warmupSlopePerStep: 0n,
|
|
2917
|
+
// removed in v12.15
|
|
2918
|
+
positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),
|
|
2919
|
+
entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),
|
|
2920
|
+
fundingIndex: 0n,
|
|
2921
|
+
// not present in v12.15 account struct
|
|
2922
|
+
matcherProgram: new PublicKey3(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),
|
|
2923
|
+
matcherContext: new PublicKey3(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),
|
|
2924
|
+
owner: new PublicKey3(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),
|
|
2925
|
+
feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),
|
|
2926
|
+
lastFeeSlot: 0n,
|
|
2927
|
+
// removed in v12.15
|
|
2928
|
+
feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),
|
|
2929
|
+
exactReserveCohorts,
|
|
2930
|
+
exactCohortCount: cohortCount,
|
|
2931
|
+
overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),
|
|
2932
|
+
overflowOlderPresent,
|
|
2933
|
+
overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),
|
|
2934
|
+
overflowNewestPresent
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2878
2937
|
const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
|
|
2879
2938
|
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 =
|
|
2939
|
+
const positionSizeOff = isV12_1 ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2940
|
+
const entryPriceOff = isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2941
|
+
const fundingIndexOff = isV12_1 ? V12_1_ACCT_FUNDING_INDEX_OFF : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2942
|
+
const matcherProgOff = isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2943
|
+
const matcherCtxOff = isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2944
|
+
const feeCreditsOff = isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2945
|
+
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
2946
|
const kindByte = readU8(data, base + ACCT_KIND_OFF);
|
|
2888
2947
|
const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2889
2948
|
return {
|
|
@@ -2896,13 +2955,23 @@ function parseAccount(data, idx) {
|
|
|
2896
2955
|
warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
|
|
2897
2956
|
positionSize: readI128LE(data, base + positionSizeOff),
|
|
2898
2957
|
entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,
|
|
2899
|
-
// V12_1
|
|
2900
|
-
|
|
2958
|
+
// V12_1: entry_price removed
|
|
2959
|
+
// V12_1 changed funding_index from i128 to i64 (legacy field moved to end of account)
|
|
2960
|
+
fundingIndex: isV12_1 ? BigInt(readI64LE(data, base + fundingIndexOff)) : readI128LE(data, base + fundingIndexOff),
|
|
2901
2961
|
matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
|
|
2902
2962
|
matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
|
|
2903
2963
|
owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
|
|
2904
2964
|
feeCredits: readI128LE(data, base + feeCreditsOff),
|
|
2905
|
-
lastFeeSlot: readU64LE(data, base + lastFeeSlotOff)
|
|
2965
|
+
lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),
|
|
2966
|
+
feesEarnedTotal: 0n,
|
|
2967
|
+
// not present in pre-v12.15 layouts
|
|
2968
|
+
exactReserveCohorts: null,
|
|
2969
|
+
// not present in pre-v12.15 layouts
|
|
2970
|
+
exactCohortCount: null,
|
|
2971
|
+
overflowOlder: null,
|
|
2972
|
+
overflowOlderPresent: null,
|
|
2973
|
+
overflowNewest: null,
|
|
2974
|
+
overflowNewestPresent: null
|
|
2906
2975
|
};
|
|
2907
2976
|
}
|
|
2908
2977
|
function parseAllAccounts(data) {
|
|
@@ -2930,12 +2999,6 @@ function deriveVaultAuthority(programId, slab) {
|
|
|
2930
2999
|
programId
|
|
2931
3000
|
);
|
|
2932
3001
|
}
|
|
2933
|
-
function deriveInsuranceLpMint(programId, slab) {
|
|
2934
|
-
return PublicKey4.findProgramAddressSync(
|
|
2935
|
-
[textEncoder.encode("ins_lp"), slab.toBytes()],
|
|
2936
|
-
programId
|
|
2937
|
-
);
|
|
2938
|
-
}
|
|
2939
3002
|
var LP_INDEX_U16_MAX = 65535;
|
|
2940
3003
|
function deriveLpPda(programId, slab, lpIdx) {
|
|
2941
3004
|
if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
|
|
@@ -2950,12 +3013,6 @@ function deriveLpPda(programId, slab, lpIdx) {
|
|
|
2950
3013
|
programId
|
|
2951
3014
|
);
|
|
2952
3015
|
}
|
|
2953
|
-
function deriveKeeperFund(programId, slab) {
|
|
2954
|
-
return PublicKey4.findProgramAddressSync(
|
|
2955
|
-
[textEncoder.encode("keeper_fund"), slab.toBytes()],
|
|
2956
|
-
programId
|
|
2957
|
-
);
|
|
2958
|
-
}
|
|
2959
3016
|
var PUMPSWAP_PROGRAM_ID = new PublicKey4(
|
|
2960
3017
|
"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
|
|
2961
3018
|
);
|
|
@@ -2992,7 +3049,14 @@ function derivePythPushOraclePDA(feedIdHex) {
|
|
|
2992
3049
|
}
|
|
2993
3050
|
const feedId = new Uint8Array(32);
|
|
2994
3051
|
for (let i = 0; i < 32; i++) {
|
|
2995
|
-
|
|
3052
|
+
const hexPair = normalized.substring(i * 2, i * 2 + 2);
|
|
3053
|
+
const byte = parseInt(hexPair, 16);
|
|
3054
|
+
if (Number.isNaN(byte)) {
|
|
3055
|
+
throw new Error(
|
|
3056
|
+
`derivePythPushOraclePDA: failed to parse hex byte at position ${i}: "${hexPair}"`
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
feedId[i] = byte;
|
|
2996
3060
|
}
|
|
2997
3061
|
const shardBuf = new Uint8Array(2);
|
|
2998
3062
|
return PublicKey4.findProgramAddressSync(
|
|
@@ -3024,7 +3088,9 @@ import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
|
3024
3088
|
// src/solana/static-markets.ts
|
|
3025
3089
|
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
3026
3090
|
var MAINNET_MARKETS = [
|
|
3027
|
-
|
|
3091
|
+
// Populated at mainnet launch — currently empty.
|
|
3092
|
+
// To add entries:
|
|
3093
|
+
// { slabAddress: "ABC123...", symbol: "SOL-PERP", name: "SOL Perpetual" },
|
|
3028
3094
|
];
|
|
3029
3095
|
var DEVNET_MARKETS = [
|
|
3030
3096
|
// Populated from prior discoverMarkets() runs on devnet.
|
|
@@ -3192,6 +3258,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3192
3258
|
fundingIndexQpbE6: readI128LE2(data, base + 112),
|
|
3193
3259
|
lastFundingSlot: readU64LE2(data, base + 128),
|
|
3194
3260
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 136),
|
|
3261
|
+
fundingRateE9: 0n,
|
|
3262
|
+
marketMode: null,
|
|
3195
3263
|
lastCrankSlot: readU64LE2(data, base + 144),
|
|
3196
3264
|
maxCrankStalenessSlots: readU64LE2(data, base + 152),
|
|
3197
3265
|
totalOpenInterest: readU128LE2(data, base + 160),
|
|
@@ -3199,6 +3267,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3199
3267
|
shortOi: 0n,
|
|
3200
3268
|
cTot: readU128LE2(data, base + 176),
|
|
3201
3269
|
pnlPosTot: readU128LE2(data, base + 192),
|
|
3270
|
+
pnlMaturedPosTot: 0n,
|
|
3202
3271
|
liqCursor: readU16LE2(data, base + 208),
|
|
3203
3272
|
gcCursor: readU16LE2(data, base + 210),
|
|
3204
3273
|
lastSweepStartSlot: readU64LE2(data, base + 216),
|
|
@@ -3234,6 +3303,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3234
3303
|
fundingIndexQpbE6: readI128LE2(data, base + 360),
|
|
3235
3304
|
lastFundingSlot: readU64LE2(data, base + 376),
|
|
3236
3305
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 384),
|
|
3306
|
+
fundingRateE9: 0n,
|
|
3307
|
+
marketMode: null,
|
|
3237
3308
|
lastCrankSlot: readU64LE2(data, base + 392),
|
|
3238
3309
|
maxCrankStalenessSlots: readU64LE2(data, base + 400),
|
|
3239
3310
|
totalOpenInterest: readU128LE2(data, base + 408),
|
|
@@ -3243,6 +3314,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3243
3314
|
// V2 has no short_oi
|
|
3244
3315
|
cTot: readU128LE2(data, base + 424),
|
|
3245
3316
|
pnlPosTot: readU128LE2(data, base + 440),
|
|
3317
|
+
pnlMaturedPosTot: 0n,
|
|
3246
3318
|
liqCursor: readU16LE2(data, base + 456),
|
|
3247
3319
|
gcCursor: readU16LE2(data, base + 458),
|
|
3248
3320
|
lastSweepStartSlot: readU64LE2(data, base + 464),
|
|
@@ -3280,6 +3352,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3280
3352
|
fundingIndexQpbE6: readI128LE2(data, base + l.engineFundingIndexOff),
|
|
3281
3353
|
lastFundingSlot: readU64LE2(data, base + l.engineLastFundingSlotOff),
|
|
3282
3354
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + l.engineFundingRateBpsOff),
|
|
3355
|
+
fundingRateE9: 0n,
|
|
3356
|
+
marketMode: null,
|
|
3283
3357
|
lastCrankSlot: readU64LE2(data, base + l.engineLastCrankSlotOff),
|
|
3284
3358
|
maxCrankStalenessSlots: readU64LE2(data, base + l.engineMaxCrankStalenessOff),
|
|
3285
3359
|
totalOpenInterest: readU128LE2(data, base + l.engineTotalOiOff),
|
|
@@ -3287,6 +3361,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3287
3361
|
shortOi: l.engineShortOiOff >= 0 ? readU128LE2(data, base + l.engineShortOiOff) : 0n,
|
|
3288
3362
|
cTot: readU128LE2(data, base + l.engineCTotOff),
|
|
3289
3363
|
pnlPosTot: readU128LE2(data, base + l.enginePnlPosTotOff),
|
|
3364
|
+
pnlMaturedPosTot: 0n,
|
|
3290
3365
|
liqCursor: readU16LE2(data, base + l.engineLiqCursorOff),
|
|
3291
3366
|
gcCursor: readU16LE2(data, base + l.engineGcCursorOff),
|
|
3292
3367
|
lastSweepStartSlot: readU64LE2(data, base + l.engineLastSweepStartOff),
|
|
@@ -3320,6 +3395,8 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3320
3395
|
fundingIndexQpbE6: readI128LE2(data, base + 368),
|
|
3321
3396
|
lastFundingSlot: readU64LE2(data, base + 384),
|
|
3322
3397
|
fundingRateBpsPerSlotLast: readI64LE2(data, base + 392),
|
|
3398
|
+
fundingRateE9: 0n,
|
|
3399
|
+
marketMode: null,
|
|
3323
3400
|
lastCrankSlot: readU64LE2(data, base + 424),
|
|
3324
3401
|
maxCrankStalenessSlots: readU64LE2(data, base + 408),
|
|
3325
3402
|
totalOpenInterest: readU128LE2(data, base + 416),
|
|
@@ -3327,6 +3404,7 @@ function parseEngineLight(data, layout, maxAccounts = 4096) {
|
|
|
3327
3404
|
shortOi: readU128LE2(data, base + 448),
|
|
3328
3405
|
cTot: readU128LE2(data, base + 464),
|
|
3329
3406
|
pnlPosTot: readU128LE2(data, base + 480),
|
|
3407
|
+
pnlMaturedPosTot: 0n,
|
|
3330
3408
|
liqCursor: readU16LE2(data, base + 496),
|
|
3331
3409
|
gcCursor: readU16LE2(data, base + 498),
|
|
3332
3410
|
lastSweepStartSlot: readU64LE2(data, base + 504),
|
|
@@ -3792,9 +3870,7 @@ function computeRaydiumClmmPriceE6(data) {
|
|
|
3792
3870
|
}
|
|
3793
3871
|
const sqrtPriceX64 = readU128LE3(dv3, 253);
|
|
3794
3872
|
if (sqrtPriceX64 === 0n) return 0n;
|
|
3795
|
-
const
|
|
3796
|
-
const term = scaledSqrt >> 64n;
|
|
3797
|
-
const priceE6Raw = term * sqrtPriceX64 >> 64n;
|
|
3873
|
+
const priceE6Raw = sqrtPriceX64 * sqrtPriceX64 * 1000000n >> 128n;
|
|
3798
3874
|
const decimalDiff = 6 + decimals0 - decimals1;
|
|
3799
3875
|
const adjustedDiff = decimalDiff - 6;
|
|
3800
3876
|
if (adjustedDiff >= 0) {
|
|
@@ -3835,13 +3911,26 @@ function computeMeteoraDlmmPriceE6(data) {
|
|
|
3835
3911
|
`Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`
|
|
3836
3912
|
);
|
|
3837
3913
|
}
|
|
3914
|
+
const MAX_ABS_BIN_ID = 5e5;
|
|
3915
|
+
if (activeId > MAX_ABS_BIN_ID || activeId < -MAX_ABS_BIN_ID) {
|
|
3916
|
+
throw new Error(
|
|
3917
|
+
`Meteora DLMM: activeId ${activeId} exceeds safe range (\xB1${MAX_ABS_BIN_ID})`
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3838
3920
|
const SCALE = 1000000000000000000n;
|
|
3839
3921
|
const base = SCALE + BigInt(binStep) * SCALE / 10000n;
|
|
3840
3922
|
const isNeg = activeId < 0;
|
|
3841
3923
|
let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
|
|
3842
3924
|
let result = SCALE;
|
|
3843
3925
|
let b = base;
|
|
3926
|
+
let iterations = 0;
|
|
3927
|
+
const MAX_ITERATIONS = 25;
|
|
3844
3928
|
while (exp > 0n) {
|
|
3929
|
+
if (iterations++ >= MAX_ITERATIONS) {
|
|
3930
|
+
throw new Error(
|
|
3931
|
+
`Meteora DLMM: exponentiation loop exceeded ${MAX_ITERATIONS} iterations (activeId=${activeId})`
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3845
3934
|
if (exp & 1n) {
|
|
3846
3935
|
result = result * b / SCALE;
|
|
3847
3936
|
}
|
|
@@ -3872,6 +3961,7 @@ function readU128LE3(dv3, offset) {
|
|
|
3872
3961
|
var CHAINLINK_MIN_SIZE = 224;
|
|
3873
3962
|
var MAX_DECIMALS = 18;
|
|
3874
3963
|
var CHAINLINK_DECIMALS_OFFSET = 138;
|
|
3964
|
+
var CHAINLINK_TIMESTAMP_OFFSET = 168;
|
|
3875
3965
|
var CHAINLINK_ANSWER_OFFSET = 216;
|
|
3876
3966
|
function readU82(data, off) {
|
|
3877
3967
|
return data[off];
|
|
@@ -3879,7 +3969,7 @@ function readU82(data, off) {
|
|
|
3879
3969
|
function readBigInt64LE(data, off) {
|
|
3880
3970
|
return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
|
|
3881
3971
|
}
|
|
3882
|
-
function parseChainlinkPrice(data) {
|
|
3972
|
+
function parseChainlinkPrice(data, options) {
|
|
3883
3973
|
if (data.length < CHAINLINK_MIN_SIZE) {
|
|
3884
3974
|
throw new Error(
|
|
3885
3975
|
`Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
|
|
@@ -3897,7 +3987,18 @@ function parseChainlinkPrice(data) {
|
|
|
3897
3987
|
`Oracle price is non-positive: ${price}`
|
|
3898
3988
|
);
|
|
3899
3989
|
}
|
|
3900
|
-
|
|
3990
|
+
const updatedAtBig = readBigInt64LE(data, CHAINLINK_TIMESTAMP_OFFSET);
|
|
3991
|
+
const updatedAt = Number(updatedAtBig);
|
|
3992
|
+
if (options?.maxStalenessSeconds !== void 0 && updatedAt > 0) {
|
|
3993
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3994
|
+
const age = now - updatedAt;
|
|
3995
|
+
if (age > options.maxStalenessSeconds) {
|
|
3996
|
+
throw new Error(
|
|
3997
|
+
`Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`
|
|
3998
|
+
);
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : void 0 };
|
|
3901
4002
|
}
|
|
3902
4003
|
function isValidChainlinkOracle(data) {
|
|
3903
4004
|
try {
|
|
@@ -3917,7 +4018,11 @@ var TOKEN_2022_PROGRAM_ID = new PublicKey8(
|
|
|
3917
4018
|
async function detectTokenProgram(connection, mint) {
|
|
3918
4019
|
const info = await connection.getAccountInfo(mint);
|
|
3919
4020
|
if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
3920
|
-
|
|
4021
|
+
if (info.owner.equals(TOKEN_PROGRAM_ID3)) return TOKEN_PROGRAM_ID3;
|
|
4022
|
+
if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;
|
|
4023
|
+
throw new Error(
|
|
4024
|
+
`Mint ${mint.toBase58()} is owned by ${info.owner.toBase58()}, which is neither TOKEN_PROGRAM_ID nor TOKEN_2022_PROGRAM_ID`
|
|
4025
|
+
);
|
|
3921
4026
|
}
|
|
3922
4027
|
function isToken2022(tokenProgramId) {
|
|
3923
4028
|
return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
|
|
@@ -3950,12 +4055,14 @@ var PROGRAM_IDS = {
|
|
|
3950
4055
|
}
|
|
3951
4056
|
};
|
|
3952
4057
|
function getProgramId(network) {
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
4058
|
+
if (!network) {
|
|
4059
|
+
const override = safeEnv("PROGRAM_ID");
|
|
4060
|
+
if (override) {
|
|
4061
|
+
console.warn(
|
|
4062
|
+
`[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
4063
|
+
);
|
|
4064
|
+
return new PublicKey9(override);
|
|
4065
|
+
}
|
|
3959
4066
|
}
|
|
3960
4067
|
const detectedNetwork = getCurrentNetwork();
|
|
3961
4068
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -3963,12 +4070,14 @@ function getProgramId(network) {
|
|
|
3963
4070
|
return new PublicKey9(programId);
|
|
3964
4071
|
}
|
|
3965
4072
|
function getMatcherProgramId(network) {
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
4073
|
+
if (!network) {
|
|
4074
|
+
const override = safeEnv("MATCHER_PROGRAM_ID");
|
|
4075
|
+
if (override) {
|
|
4076
|
+
console.warn(
|
|
4077
|
+
`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
4078
|
+
);
|
|
4079
|
+
return new PublicKey9(override);
|
|
4080
|
+
}
|
|
3972
4081
|
}
|
|
3973
4082
|
const detectedNetwork = getCurrentNetwork();
|
|
3974
4083
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -4001,10 +4110,7 @@ function getStakeProgramId(network) {
|
|
|
4001
4110
|
}
|
|
4002
4111
|
const detectedNetwork = network ?? (() => {
|
|
4003
4112
|
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";
|
|
4113
|
+
return n === "mainnet" || n === "mainnet-beta" ? "mainnet" : "devnet";
|
|
4008
4114
|
})();
|
|
4009
4115
|
const id = STAKE_PROGRAM_IDS[detectedNetwork];
|
|
4010
4116
|
if (!id) {
|
|
@@ -4014,7 +4120,7 @@ function getStakeProgramId(network) {
|
|
|
4014
4120
|
}
|
|
4015
4121
|
return new PublicKey10(id);
|
|
4016
4122
|
}
|
|
4017
|
-
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.
|
|
4123
|
+
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.mainnet);
|
|
4018
4124
|
var STAKE_IX = {
|
|
4019
4125
|
InitPool: 0,
|
|
4020
4126
|
Deposit: 1,
|
|
@@ -4075,6 +4181,9 @@ function readU16LE3(data, off) {
|
|
|
4075
4181
|
);
|
|
4076
4182
|
}
|
|
4077
4183
|
function u64Le(v) {
|
|
4184
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
4185
|
+
throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
4186
|
+
}
|
|
4078
4187
|
const big = BigInt(v);
|
|
4079
4188
|
if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
|
|
4080
4189
|
if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
|
|
@@ -4083,6 +4192,9 @@ function u64Le(v) {
|
|
|
4083
4192
|
return arr;
|
|
4084
4193
|
}
|
|
4085
4194
|
function u128Le(v) {
|
|
4195
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
4196
|
+
throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
4197
|
+
}
|
|
4086
4198
|
const big = BigInt(v);
|
|
4087
4199
|
if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
|
|
4088
4200
|
if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
|
|
@@ -4093,7 +4205,7 @@ function u128Le(v) {
|
|
|
4093
4205
|
return arr;
|
|
4094
4206
|
}
|
|
4095
4207
|
function u16Le(v) {
|
|
4096
|
-
if (v < 0 || v > 65535) throw new Error(`u16Le: value
|
|
4208
|
+
if (!Number.isInteger(v) || v < 0 || v > 65535) throw new Error(`u16Le: value must be integer in range 0..65535, got ${v}`);
|
|
4097
4209
|
const arr = new Uint8Array(2);
|
|
4098
4210
|
new DataView(arr.buffer).setUint16(0, v, true);
|
|
4099
4211
|
return arr;
|
|
@@ -4348,7 +4460,9 @@ function computePnlPct(pnl, capital) {
|
|
|
4348
4460
|
}
|
|
4349
4461
|
function isAdlTriggered(slabData) {
|
|
4350
4462
|
const layout = detectSlabLayout(slabData.length);
|
|
4351
|
-
if (!layout)
|
|
4463
|
+
if (!layout) {
|
|
4464
|
+
return false;
|
|
4465
|
+
}
|
|
4352
4466
|
try {
|
|
4353
4467
|
const engine = parseEngine(slabData);
|
|
4354
4468
|
if (engine.pnlPosTot === 0n) return false;
|
|
@@ -4391,6 +4505,14 @@ function rankAdlPositions(slabData) {
|
|
|
4391
4505
|
if (account.kind !== 0 /* User */) continue;
|
|
4392
4506
|
if (account.positionSize === 0n) continue;
|
|
4393
4507
|
const side = account.positionSize > 0n ? "long" : "short";
|
|
4508
|
+
if (side === "long" && account.positionSize <= 0n) {
|
|
4509
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=long but positionSize=${account.positionSize}`);
|
|
4510
|
+
continue;
|
|
4511
|
+
}
|
|
4512
|
+
if (side === "short" && account.positionSize >= 0n) {
|
|
4513
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=short but positionSize=${account.positionSize}`);
|
|
4514
|
+
continue;
|
|
4515
|
+
}
|
|
4394
4516
|
const pnlPct = computePnlPct(account.pnl, account.capital);
|
|
4395
4517
|
positions.push({
|
|
4396
4518
|
idx,
|
|
@@ -4423,7 +4545,8 @@ function buildAdlInstruction(caller, slab, oracle, programId, targetIdx, backupO
|
|
|
4423
4545
|
`buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`
|
|
4424
4546
|
);
|
|
4425
4547
|
}
|
|
4426
|
-
const
|
|
4548
|
+
const dataBytes = encodeExecuteAdl({ targetIdx });
|
|
4549
|
+
const data = Buffer.from(dataBytes);
|
|
4427
4550
|
const keys = [
|
|
4428
4551
|
{ pubkey: caller, isSigner: true, isWritable: false },
|
|
4429
4552
|
{ pubkey: slab, isSigner: false, isWritable: true },
|
|
@@ -4463,7 +4586,11 @@ function parseAdlEvent(logs) {
|
|
|
4463
4586
|
}
|
|
4464
4587
|
if (tag !== ADL_EVENT_TAG) continue;
|
|
4465
4588
|
try {
|
|
4466
|
-
const
|
|
4589
|
+
const targetIdxBig = BigInt(match[2]);
|
|
4590
|
+
if (targetIdxBig < 0n || targetIdxBig > 65535n) {
|
|
4591
|
+
continue;
|
|
4592
|
+
}
|
|
4593
|
+
const targetIdx = Number(targetIdxBig);
|
|
4467
4594
|
const price = BigInt(match[3]);
|
|
4468
4595
|
const closedLo = BigInt(match[4]);
|
|
4469
4596
|
const closedHi = BigInt(match[5]);
|
|
@@ -4491,9 +4618,387 @@ async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
|
|
|
4491
4618
|
);
|
|
4492
4619
|
}
|
|
4493
4620
|
const json = await res.json();
|
|
4621
|
+
if (typeof json !== "object" || json === null) {
|
|
4622
|
+
throw new Error("fetchAdlRankings: API returned non-object response");
|
|
4623
|
+
}
|
|
4624
|
+
const obj = json;
|
|
4625
|
+
if (!Array.isArray(obj.rankings)) {
|
|
4626
|
+
throw new Error("fetchAdlRankings: API response missing rankings array");
|
|
4627
|
+
}
|
|
4628
|
+
for (const entry of obj.rankings) {
|
|
4629
|
+
if (typeof entry !== "object" || entry === null) {
|
|
4630
|
+
throw new Error("fetchAdlRankings: invalid ranking entry (not an object)");
|
|
4631
|
+
}
|
|
4632
|
+
const r = entry;
|
|
4633
|
+
if (typeof r.idx !== "number" || !Number.isInteger(r.idx) || r.idx < 0) {
|
|
4634
|
+
throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4494
4637
|
return json;
|
|
4495
4638
|
}
|
|
4496
4639
|
|
|
4640
|
+
// src/solana/rpc-pool.ts
|
|
4641
|
+
import {
|
|
4642
|
+
Connection as Connection5
|
|
4643
|
+
} from "@solana/web3.js";
|
|
4644
|
+
async function checkRpcHealth(endpoint, timeoutMs = 5e3) {
|
|
4645
|
+
const conn = new Connection5(endpoint, { commitment: "processed" });
|
|
4646
|
+
const start = performance.now();
|
|
4647
|
+
const timeout = rejectAfter(timeoutMs, `Health probe timed out after ${timeoutMs}ms`);
|
|
4648
|
+
try {
|
|
4649
|
+
const slot = await Promise.race([
|
|
4650
|
+
conn.getSlot("processed"),
|
|
4651
|
+
timeout.promise
|
|
4652
|
+
]);
|
|
4653
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4654
|
+
return { endpoint, healthy: true, latencyMs, slot };
|
|
4655
|
+
} catch (err) {
|
|
4656
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4657
|
+
return {
|
|
4658
|
+
endpoint,
|
|
4659
|
+
healthy: false,
|
|
4660
|
+
latencyMs,
|
|
4661
|
+
slot: 0,
|
|
4662
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4663
|
+
};
|
|
4664
|
+
} finally {
|
|
4665
|
+
timeout.cancel();
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
function resolveRetryConfig(cfg) {
|
|
4669
|
+
if (cfg === false) return null;
|
|
4670
|
+
const c = cfg ?? {};
|
|
4671
|
+
return {
|
|
4672
|
+
maxRetries: c.maxRetries ?? 3,
|
|
4673
|
+
baseDelayMs: c.baseDelayMs ?? 500,
|
|
4674
|
+
maxDelayMs: c.maxDelayMs ?? 1e4,
|
|
4675
|
+
jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),
|
|
4676
|
+
retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504]
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
function normalizeEndpoint(ep) {
|
|
4680
|
+
if (typeof ep === "string") return { url: ep };
|
|
4681
|
+
return ep;
|
|
4682
|
+
}
|
|
4683
|
+
function endpointLabel(ep) {
|
|
4684
|
+
if (ep.label) return ep.label;
|
|
4685
|
+
try {
|
|
4686
|
+
return new URL(ep.url).hostname;
|
|
4687
|
+
} catch {
|
|
4688
|
+
return ep.url.slice(0, 40);
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
function isRetryable(err, codes) {
|
|
4692
|
+
if (!err) return false;
|
|
4693
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4694
|
+
for (const code of codes) {
|
|
4695
|
+
if (msg.includes(String(code))) return true;
|
|
4696
|
+
}
|
|
4697
|
+
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")) {
|
|
4698
|
+
return true;
|
|
4699
|
+
}
|
|
4700
|
+
return false;
|
|
4701
|
+
}
|
|
4702
|
+
function computeDelay(attempt, config) {
|
|
4703
|
+
const raw = Math.min(
|
|
4704
|
+
config.baseDelayMs * Math.pow(2, attempt),
|
|
4705
|
+
config.maxDelayMs
|
|
4706
|
+
);
|
|
4707
|
+
const jitter = Math.floor(Math.random() * raw * config.jitterFactor);
|
|
4708
|
+
return raw + jitter;
|
|
4709
|
+
}
|
|
4710
|
+
function rejectAfter(ms, message) {
|
|
4711
|
+
let timer;
|
|
4712
|
+
const promise = new Promise((_, reject) => {
|
|
4713
|
+
timer = setTimeout(() => reject(new Error(message)), ms);
|
|
4714
|
+
});
|
|
4715
|
+
return { promise, cancel: () => clearTimeout(timer) };
|
|
4716
|
+
}
|
|
4717
|
+
function sleep(ms) {
|
|
4718
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4719
|
+
}
|
|
4720
|
+
function redactUrl(raw) {
|
|
4721
|
+
try {
|
|
4722
|
+
const u = new URL(raw);
|
|
4723
|
+
const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;
|
|
4724
|
+
for (const k of [...u.searchParams.keys()]) {
|
|
4725
|
+
if (sensitive.test(k)) {
|
|
4726
|
+
u.searchParams.set(k, "***");
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
return u.toString();
|
|
4730
|
+
} catch {
|
|
4731
|
+
return raw;
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
var RpcPool = class _RpcPool {
|
|
4735
|
+
endpoints;
|
|
4736
|
+
strategy;
|
|
4737
|
+
retryConfig;
|
|
4738
|
+
requestTimeoutMs;
|
|
4739
|
+
verbose;
|
|
4740
|
+
/** Round-robin index tracker. */
|
|
4741
|
+
rrIndex = 0;
|
|
4742
|
+
/** Consecutive failure threshold before marking an endpoint unhealthy. */
|
|
4743
|
+
static UNHEALTHY_THRESHOLD = 3;
|
|
4744
|
+
/** Minimum endpoints before auto-recovery is attempted. */
|
|
4745
|
+
static MIN_HEALTHY = 1;
|
|
4746
|
+
constructor(config) {
|
|
4747
|
+
if (!config.endpoints || config.endpoints.length === 0) {
|
|
4748
|
+
throw new Error("RpcPool: at least one endpoint is required");
|
|
4749
|
+
}
|
|
4750
|
+
this.strategy = config.strategy ?? "failover";
|
|
4751
|
+
this.retryConfig = resolveRetryConfig(config.retry);
|
|
4752
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? 3e4;
|
|
4753
|
+
this.verbose = config.verbose ?? true;
|
|
4754
|
+
const commitment = config.commitment ?? "confirmed";
|
|
4755
|
+
this.endpoints = config.endpoints.map((raw) => {
|
|
4756
|
+
const ep = normalizeEndpoint(raw);
|
|
4757
|
+
const connConfig = {
|
|
4758
|
+
commitment,
|
|
4759
|
+
...ep.connectionConfig
|
|
4760
|
+
};
|
|
4761
|
+
return {
|
|
4762
|
+
config: ep,
|
|
4763
|
+
connection: new Connection5(ep.url, connConfig),
|
|
4764
|
+
label: endpointLabel(ep),
|
|
4765
|
+
weight: Math.max(1, ep.weight ?? 1),
|
|
4766
|
+
failures: 0,
|
|
4767
|
+
healthy: true,
|
|
4768
|
+
lastLatencyMs: -1
|
|
4769
|
+
};
|
|
4770
|
+
});
|
|
4771
|
+
}
|
|
4772
|
+
// -----------------------------------------------------------------------
|
|
4773
|
+
// Public API
|
|
4774
|
+
// -----------------------------------------------------------------------
|
|
4775
|
+
/**
|
|
4776
|
+
* Execute a function against a pooled connection with automatic retry
|
|
4777
|
+
* and failover.
|
|
4778
|
+
*
|
|
4779
|
+
* @param fn - Async function that receives a `Connection` and returns a result.
|
|
4780
|
+
* @returns The result of `fn`.
|
|
4781
|
+
* @throws The last error if all retries and failovers are exhausted.
|
|
4782
|
+
*
|
|
4783
|
+
* @example
|
|
4784
|
+
* ```ts
|
|
4785
|
+
* const balance = await pool.call(c => c.getBalance(pubkey));
|
|
4786
|
+
* const markets = await pool.call(c => discoverMarkets(c, programId, opts));
|
|
4787
|
+
* ```
|
|
4788
|
+
*/
|
|
4789
|
+
async call(fn) {
|
|
4790
|
+
const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;
|
|
4791
|
+
let lastError;
|
|
4792
|
+
const triedEndpoints = /* @__PURE__ */ new Set();
|
|
4793
|
+
const maxTotalIterations = maxAttempts + this.endpoints.length;
|
|
4794
|
+
let totalIterations = 0;
|
|
4795
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4796
|
+
if (++totalIterations > maxTotalIterations) break;
|
|
4797
|
+
const epIdx = this.selectEndpoint(triedEndpoints);
|
|
4798
|
+
if (epIdx === -1) {
|
|
4799
|
+
break;
|
|
4800
|
+
}
|
|
4801
|
+
const ep = this.endpoints[epIdx];
|
|
4802
|
+
const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);
|
|
4803
|
+
try {
|
|
4804
|
+
const result = await Promise.race([
|
|
4805
|
+
fn(ep.connection),
|
|
4806
|
+
timeout.promise
|
|
4807
|
+
]);
|
|
4808
|
+
timeout.cancel();
|
|
4809
|
+
ep.failures = 0;
|
|
4810
|
+
ep.healthy = true;
|
|
4811
|
+
return result;
|
|
4812
|
+
} catch (err) {
|
|
4813
|
+
timeout.cancel();
|
|
4814
|
+
lastError = err;
|
|
4815
|
+
ep.failures++;
|
|
4816
|
+
if (ep.failures >= _RpcPool.UNHEALTHY_THRESHOLD) {
|
|
4817
|
+
ep.healthy = false;
|
|
4818
|
+
if (this.verbose) {
|
|
4819
|
+
console.warn(
|
|
4820
|
+
`[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`
|
|
4821
|
+
);
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
const retryable = this.retryConfig ? isRetryable(err, this.retryConfig.retryableStatusCodes) : false;
|
|
4825
|
+
if (!retryable) {
|
|
4826
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4827
|
+
triedEndpoints.add(epIdx);
|
|
4828
|
+
attempt--;
|
|
4829
|
+
if (triedEndpoints.size >= this.endpoints.length) break;
|
|
4830
|
+
continue;
|
|
4831
|
+
}
|
|
4832
|
+
throw err;
|
|
4833
|
+
}
|
|
4834
|
+
if (this.verbose) {
|
|
4835
|
+
console.warn(
|
|
4836
|
+
`[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,
|
|
4837
|
+
err instanceof Error ? err.message : err
|
|
4838
|
+
);
|
|
4839
|
+
}
|
|
4840
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4841
|
+
triedEndpoints.add(epIdx);
|
|
4842
|
+
}
|
|
4843
|
+
if (attempt < maxAttempts - 1 && this.retryConfig) {
|
|
4844
|
+
const delay = computeDelay(attempt, this.retryConfig);
|
|
4845
|
+
await sleep(delay);
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
this.maybeRecoverEndpoints();
|
|
4850
|
+
throw lastError ?? new Error("RpcPool: all endpoints exhausted");
|
|
4851
|
+
}
|
|
4852
|
+
/**
|
|
4853
|
+
* Get a raw `Connection` from the current preferred endpoint.
|
|
4854
|
+
* Useful when you need to pass a Connection to external code.
|
|
4855
|
+
*
|
|
4856
|
+
* NOTE: This bypasses retry and failover logic. Prefer `call()`.
|
|
4857
|
+
*
|
|
4858
|
+
* @returns Solana Connection from the current preferred endpoint.
|
|
4859
|
+
*
|
|
4860
|
+
* @example
|
|
4861
|
+
* ```ts
|
|
4862
|
+
* const conn = pool.getConnection();
|
|
4863
|
+
* const balance = await conn.getBalance(pubkey);
|
|
4864
|
+
* ```
|
|
4865
|
+
*/
|
|
4866
|
+
getConnection() {
|
|
4867
|
+
const idx = this.selectEndpoint();
|
|
4868
|
+
if (idx === -1) {
|
|
4869
|
+
this.maybeRecoverEndpoints();
|
|
4870
|
+
return this.endpoints[0].connection;
|
|
4871
|
+
}
|
|
4872
|
+
return this.endpoints[idx].connection;
|
|
4873
|
+
}
|
|
4874
|
+
/**
|
|
4875
|
+
* Run a health check against all endpoints in the pool.
|
|
4876
|
+
*
|
|
4877
|
+
* @param timeoutMs - Per-endpoint probe timeout (default: 5000)
|
|
4878
|
+
* @returns Array of health results, one per endpoint.
|
|
4879
|
+
*
|
|
4880
|
+
* @example
|
|
4881
|
+
* ```ts
|
|
4882
|
+
* const results = await pool.healthCheck();
|
|
4883
|
+
* for (const r of results) {
|
|
4884
|
+
* console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);
|
|
4885
|
+
* }
|
|
4886
|
+
* ```
|
|
4887
|
+
*/
|
|
4888
|
+
async healthCheck(timeoutMs = 5e3) {
|
|
4889
|
+
const results = await Promise.all(
|
|
4890
|
+
this.endpoints.map(async (ep) => {
|
|
4891
|
+
const result = await checkRpcHealth(ep.config.url, timeoutMs);
|
|
4892
|
+
ep.lastLatencyMs = result.latencyMs;
|
|
4893
|
+
ep.healthy = result.healthy;
|
|
4894
|
+
if (result.healthy) ep.failures = 0;
|
|
4895
|
+
result.endpoint = redactUrl(result.endpoint);
|
|
4896
|
+
return result;
|
|
4897
|
+
})
|
|
4898
|
+
);
|
|
4899
|
+
return results;
|
|
4900
|
+
}
|
|
4901
|
+
/**
|
|
4902
|
+
* Get the number of endpoints in the pool.
|
|
4903
|
+
*/
|
|
4904
|
+
get size() {
|
|
4905
|
+
return this.endpoints.length;
|
|
4906
|
+
}
|
|
4907
|
+
/**
|
|
4908
|
+
* Get the number of currently healthy endpoints.
|
|
4909
|
+
*/
|
|
4910
|
+
get healthyCount() {
|
|
4911
|
+
return this.endpoints.filter((ep) => ep.healthy).length;
|
|
4912
|
+
}
|
|
4913
|
+
/**
|
|
4914
|
+
* Get endpoint labels and their current status.
|
|
4915
|
+
*
|
|
4916
|
+
* @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.
|
|
4917
|
+
*/
|
|
4918
|
+
status() {
|
|
4919
|
+
return this.endpoints.map((ep) => ({
|
|
4920
|
+
label: ep.label,
|
|
4921
|
+
url: redactUrl(ep.config.url),
|
|
4922
|
+
healthy: ep.healthy,
|
|
4923
|
+
failures: ep.failures,
|
|
4924
|
+
lastLatencyMs: ep.lastLatencyMs
|
|
4925
|
+
}));
|
|
4926
|
+
}
|
|
4927
|
+
// -----------------------------------------------------------------------
|
|
4928
|
+
// Internals
|
|
4929
|
+
// -----------------------------------------------------------------------
|
|
4930
|
+
/**
|
|
4931
|
+
* Select the next endpoint based on strategy.
|
|
4932
|
+
* Returns -1 if no endpoint is available.
|
|
4933
|
+
*/
|
|
4934
|
+
selectEndpoint(exclude) {
|
|
4935
|
+
const healthy = this.endpoints.map((ep, i) => ({ ep, i })).filter(({ ep, i }) => ep.healthy && !exclude?.has(i));
|
|
4936
|
+
if (healthy.length === 0) {
|
|
4937
|
+
const remaining = this.endpoints.map((_, i) => i).filter((i) => !exclude?.has(i));
|
|
4938
|
+
return remaining.length > 0 ? remaining[0] : -1;
|
|
4939
|
+
}
|
|
4940
|
+
if (this.strategy === "failover") {
|
|
4941
|
+
return healthy[0].i;
|
|
4942
|
+
}
|
|
4943
|
+
const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);
|
|
4944
|
+
this.rrIndex = (this.rrIndex + 1) % totalWeight;
|
|
4945
|
+
let cumulative = 0;
|
|
4946
|
+
for (const { ep, i } of healthy) {
|
|
4947
|
+
cumulative += ep.weight;
|
|
4948
|
+
if (this.rrIndex < cumulative) return i;
|
|
4949
|
+
}
|
|
4950
|
+
return healthy[healthy.length - 1].i;
|
|
4951
|
+
}
|
|
4952
|
+
/**
|
|
4953
|
+
* If all endpoints are unhealthy, reset them so we at least try again.
|
|
4954
|
+
*/
|
|
4955
|
+
maybeRecoverEndpoints() {
|
|
4956
|
+
const healthyCount = this.endpoints.filter((ep) => ep.healthy).length;
|
|
4957
|
+
if (healthyCount < _RpcPool.MIN_HEALTHY) {
|
|
4958
|
+
if (this.verbose) {
|
|
4959
|
+
console.warn("[RpcPool] All endpoints unhealthy \u2014 resetting for recovery");
|
|
4960
|
+
}
|
|
4961
|
+
for (const ep of this.endpoints) {
|
|
4962
|
+
ep.healthy = true;
|
|
4963
|
+
ep.failures = 0;
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
};
|
|
4968
|
+
async function withRetry(fn, config) {
|
|
4969
|
+
const resolved = resolveRetryConfig(config) ?? {
|
|
4970
|
+
maxRetries: 3,
|
|
4971
|
+
baseDelayMs: 500,
|
|
4972
|
+
maxDelayMs: 1e4,
|
|
4973
|
+
jitterFactor: 0.25,
|
|
4974
|
+
retryableStatusCodes: [429, 502, 503, 504]
|
|
4975
|
+
};
|
|
4976
|
+
let lastError;
|
|
4977
|
+
const maxAttempts = resolved.maxRetries + 1;
|
|
4978
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4979
|
+
try {
|
|
4980
|
+
return await fn();
|
|
4981
|
+
} catch (err) {
|
|
4982
|
+
lastError = err;
|
|
4983
|
+
if (!isRetryable(err, resolved.retryableStatusCodes)) {
|
|
4984
|
+
throw err;
|
|
4985
|
+
}
|
|
4986
|
+
if (attempt < maxAttempts - 1) {
|
|
4987
|
+
const delay = computeDelay(attempt, resolved);
|
|
4988
|
+
await sleep(delay);
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
throw lastError ?? new Error("withRetry: all attempts exhausted");
|
|
4993
|
+
}
|
|
4994
|
+
var _internal = {
|
|
4995
|
+
isRetryable,
|
|
4996
|
+
computeDelay,
|
|
4997
|
+
resolveRetryConfig,
|
|
4998
|
+
normalizeEndpoint,
|
|
4999
|
+
endpointLabel
|
|
5000
|
+
};
|
|
5001
|
+
|
|
4497
5002
|
// src/runtime/tx.ts
|
|
4498
5003
|
import {
|
|
4499
5004
|
TransactionInstruction as TransactionInstruction2,
|
|
@@ -4645,6 +5150,139 @@ function formatResult(result, jsonMode) {
|
|
|
4645
5150
|
return lines.join("\n");
|
|
4646
5151
|
}
|
|
4647
5152
|
|
|
5153
|
+
// src/runtime/lighthouse.ts
|
|
5154
|
+
import { PublicKey as PublicKey13, Transaction as Transaction2 } from "@solana/web3.js";
|
|
5155
|
+
var LIGHTHOUSE_PROGRAM_ID = new PublicKey13(
|
|
5156
|
+
"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"
|
|
5157
|
+
);
|
|
5158
|
+
var LIGHTHOUSE_PROGRAM_ID_STR2 = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
5159
|
+
var LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
|
|
5160
|
+
var LIGHTHOUSE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5161
|
+
6e3,
|
|
5162
|
+
// InstructionMissing
|
|
5163
|
+
6001,
|
|
5164
|
+
// InstructionFallbackNotFound
|
|
5165
|
+
6002,
|
|
5166
|
+
// InstructionDidNotDeserialize
|
|
5167
|
+
6003,
|
|
5168
|
+
// InstructionDidNotSerialize
|
|
5169
|
+
6016,
|
|
5170
|
+
// IdlInstructionStub
|
|
5171
|
+
6032,
|
|
5172
|
+
// ConstraintMut
|
|
5173
|
+
6033,
|
|
5174
|
+
// ConstraintHasOne
|
|
5175
|
+
6034,
|
|
5176
|
+
// ConstraintSigner
|
|
5177
|
+
6035,
|
|
5178
|
+
// ConstraintRaw
|
|
5179
|
+
6036,
|
|
5180
|
+
// ConstraintOwner
|
|
5181
|
+
6037,
|
|
5182
|
+
// ConstraintRentExempt
|
|
5183
|
+
6038,
|
|
5184
|
+
// ConstraintSeeds
|
|
5185
|
+
6039,
|
|
5186
|
+
// ConstraintExecutable
|
|
5187
|
+
6040,
|
|
5188
|
+
// ConstraintState
|
|
5189
|
+
6041,
|
|
5190
|
+
// ConstraintAssociated
|
|
5191
|
+
6042,
|
|
5192
|
+
// ConstraintAssociatedInit
|
|
5193
|
+
6043,
|
|
5194
|
+
// ConstraintClose
|
|
5195
|
+
6400
|
|
5196
|
+
// ConstraintAddress (the one we hit most often)
|
|
5197
|
+
]);
|
|
5198
|
+
function isLighthouseInstruction(ix) {
|
|
5199
|
+
return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);
|
|
5200
|
+
}
|
|
5201
|
+
function isLighthouseError(error) {
|
|
5202
|
+
const msg = extractErrorMessage(error);
|
|
5203
|
+
if (!msg) return false;
|
|
5204
|
+
if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR2)) return true;
|
|
5205
|
+
if (/custom\s+program\s+error:\s*0x1900\b/i.test(msg)) return true;
|
|
5206
|
+
if (/"Custom"\s*:\s*6400\b/.test(msg) && /InstructionError/i.test(msg)) return true;
|
|
5207
|
+
return false;
|
|
5208
|
+
}
|
|
5209
|
+
function isLighthouseFailureInLogs(logs) {
|
|
5210
|
+
if (!Array.isArray(logs)) return false;
|
|
5211
|
+
let insideLighthouse = false;
|
|
5212
|
+
for (const line of logs) {
|
|
5213
|
+
if (typeof line !== "string") continue;
|
|
5214
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} invoke`)) {
|
|
5215
|
+
insideLighthouse = true;
|
|
5216
|
+
continue;
|
|
5217
|
+
}
|
|
5218
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} success`)) {
|
|
5219
|
+
insideLighthouse = false;
|
|
5220
|
+
continue;
|
|
5221
|
+
}
|
|
5222
|
+
if (insideLighthouse && /failed/i.test(line)) {
|
|
5223
|
+
return true;
|
|
5224
|
+
}
|
|
5225
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} failed`)) {
|
|
5226
|
+
return true;
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
return false;
|
|
5230
|
+
}
|
|
5231
|
+
function stripLighthouseInstructions(instructions, percolatorProgramId) {
|
|
5232
|
+
if (percolatorProgramId) {
|
|
5233
|
+
const hasPercolatorIx = instructions.some(
|
|
5234
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5235
|
+
);
|
|
5236
|
+
if (!hasPercolatorIx) {
|
|
5237
|
+
return instructions;
|
|
5238
|
+
}
|
|
5239
|
+
}
|
|
5240
|
+
return instructions.filter((ix) => !isLighthouseInstruction(ix));
|
|
5241
|
+
}
|
|
5242
|
+
function stripLighthouseFromTransaction(transaction, percolatorProgramId) {
|
|
5243
|
+
if (percolatorProgramId) {
|
|
5244
|
+
const hasPercolatorIx = transaction.instructions.some(
|
|
5245
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5246
|
+
);
|
|
5247
|
+
if (!hasPercolatorIx) return transaction;
|
|
5248
|
+
}
|
|
5249
|
+
const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);
|
|
5250
|
+
if (!hasLighthouse) return transaction;
|
|
5251
|
+
const clean = new Transaction2();
|
|
5252
|
+
clean.recentBlockhash = transaction.recentBlockhash;
|
|
5253
|
+
clean.feePayer = transaction.feePayer;
|
|
5254
|
+
for (const ix of transaction.instructions) {
|
|
5255
|
+
if (!isLighthouseInstruction(ix)) {
|
|
5256
|
+
clean.add(ix);
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
return clean;
|
|
5260
|
+
}
|
|
5261
|
+
function countLighthouseInstructions(ixsOrTx) {
|
|
5262
|
+
const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;
|
|
5263
|
+
return instructions.filter(isLighthouseInstruction).length;
|
|
5264
|
+
}
|
|
5265
|
+
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";
|
|
5266
|
+
function classifyLighthouseError(error) {
|
|
5267
|
+
if (isLighthouseError(error)) {
|
|
5268
|
+
return LIGHTHOUSE_USER_MESSAGE;
|
|
5269
|
+
}
|
|
5270
|
+
return null;
|
|
5271
|
+
}
|
|
5272
|
+
function extractErrorMessage(error) {
|
|
5273
|
+
if (!error) return null;
|
|
5274
|
+
if (typeof error === "string") return error;
|
|
5275
|
+
if (error instanceof Error) return error.message;
|
|
5276
|
+
if (typeof error === "object" && "message" in error) {
|
|
5277
|
+
return String(error.message);
|
|
5278
|
+
}
|
|
5279
|
+
try {
|
|
5280
|
+
return JSON.stringify(error);
|
|
5281
|
+
} catch {
|
|
5282
|
+
return null;
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
|
|
4648
5286
|
// src/math/trading.ts
|
|
4649
5287
|
function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
|
|
4650
5288
|
if (positionSize === 0n || oraclePrice === 0n) return 0n;
|
|
@@ -4669,16 +5307,10 @@ function computeLiqPrice(entryPrice, capital, positionSize, maintenanceMarginBps
|
|
|
4669
5307
|
function computePreTradeLiqPrice(oracleE6, margin, posSize, maintBps, feeBps, direction) {
|
|
4670
5308
|
if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;
|
|
4671
5309
|
const absPos = posSize < 0n ? -posSize : posSize;
|
|
5310
|
+
const fee = absPos * feeBps / 10000n;
|
|
5311
|
+
const effectiveCapital = margin > fee ? margin - fee : 0n;
|
|
4672
5312
|
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);
|
|
5313
|
+
return computeLiqPrice(oracleE6, effectiveCapital, signedPos, maintBps);
|
|
4682
5314
|
}
|
|
4683
5315
|
function computeTradingFee(notional, tradingFeeBps) {
|
|
4684
5316
|
return notional * tradingFeeBps / 10000n;
|
|
@@ -4698,9 +5330,20 @@ function computeFeeSplit(totalFee, config) {
|
|
|
4698
5330
|
if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
|
|
4699
5331
|
return [totalFee, 0n, 0n];
|
|
4700
5332
|
}
|
|
5333
|
+
const totalBps = config.lpBps + config.protocolBps + config.creatorBps;
|
|
5334
|
+
if (totalBps !== 10000n) {
|
|
5335
|
+
throw new Error(
|
|
5336
|
+
`Fee split must equal exactly 10000 bps (100%): lpBps=${config.lpBps} + protocolBps=${config.protocolBps} + creatorBps=${config.creatorBps} = ${totalBps}`
|
|
5337
|
+
);
|
|
5338
|
+
}
|
|
4701
5339
|
const lp = totalFee * config.lpBps / 10000n;
|
|
4702
5340
|
const protocol = totalFee * config.protocolBps / 10000n;
|
|
4703
5341
|
const creator = totalFee - lp - protocol;
|
|
5342
|
+
if (creator < 0n) {
|
|
5343
|
+
throw new Error(
|
|
5344
|
+
`Internal error: creator fee is negative (${creator}). This should not happen if lpBps + protocolBps + creatorBps === 10000.`
|
|
5345
|
+
);
|
|
5346
|
+
}
|
|
4704
5347
|
return [lp, protocol, creator];
|
|
4705
5348
|
}
|
|
4706
5349
|
function computePnlPercent(pnlTokens, capital) {
|
|
@@ -4715,10 +5358,17 @@ function computePnlPercent(pnlTokens, capital) {
|
|
|
4715
5358
|
}
|
|
4716
5359
|
function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
|
|
4717
5360
|
if (oracleE6 === 0n) return 0n;
|
|
5361
|
+
if (tradingFeeBps < 0n) {
|
|
5362
|
+
throw new Error(`computeEstimatedEntryPrice: tradingFeeBps must be non-negative, got ${tradingFeeBps}`);
|
|
5363
|
+
}
|
|
4718
5364
|
const feeImpact = oracleE6 * tradingFeeBps / 10000n;
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
5365
|
+
const result = direction === "long" ? oracleE6 + feeImpact : oracleE6 - feeImpact;
|
|
5366
|
+
if (result <= 0n) {
|
|
5367
|
+
throw new Error(
|
|
5368
|
+
`computeEstimatedEntryPrice: result ${result} is non-positive (tradingFeeBps=${tradingFeeBps} too high for oracle=${oracleE6})`
|
|
5369
|
+
);
|
|
5370
|
+
}
|
|
5371
|
+
return result;
|
|
4722
5372
|
}
|
|
4723
5373
|
var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
4724
5374
|
var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
|
|
@@ -4739,7 +5389,12 @@ function computeMaxLeverage(initialMarginBps) {
|
|
|
4739
5389
|
if (initialMarginBps <= 0n) {
|
|
4740
5390
|
throw new Error("computeMaxLeverage: initialMarginBps must be positive");
|
|
4741
5391
|
}
|
|
4742
|
-
|
|
5392
|
+
const scaledResult = 10000n * 1000000n / initialMarginBps;
|
|
5393
|
+
return Number(scaledResult) / 1e6;
|
|
5394
|
+
}
|
|
5395
|
+
function computeMaxWithdrawable(capital, pnl, reservedPnl) {
|
|
5396
|
+
const maturedPnl = pnl - reservedPnl;
|
|
5397
|
+
return capital + (maturedPnl > 0n ? maturedPnl : 0n);
|
|
4743
5398
|
}
|
|
4744
5399
|
|
|
4745
5400
|
// src/math/warmup.ts
|
|
@@ -4751,6 +5406,9 @@ function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot
|
|
|
4751
5406
|
return totalCapital * elapsed / warmupPeriodSlots;
|
|
4752
5407
|
}
|
|
4753
5408
|
function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
5409
|
+
if (initialMarginBps <= 0n) {
|
|
5410
|
+
throw new Error("computeWarmupLeverageCap: initialMarginBps must be positive");
|
|
5411
|
+
}
|
|
4754
5412
|
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
4755
5413
|
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
|
|
4756
5414
|
if (totalCapital <= 0n) return 1;
|
|
@@ -4761,7 +5419,14 @@ function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, w
|
|
|
4761
5419
|
warmupPeriodSlots
|
|
4762
5420
|
);
|
|
4763
5421
|
if (unlocked <= 0n) return 1;
|
|
4764
|
-
const
|
|
5422
|
+
const scaledResult = BigInt(maxLev) * unlocked / totalCapital;
|
|
5423
|
+
if (scaledResult > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5424
|
+
console.warn(
|
|
5425
|
+
`[computeWarmupLeverageCap] Warning: effective leverage ${scaledResult} exceeds MAX_SAFE_INTEGER, returning MAX_SAFE_INTEGER as a safety bound`
|
|
5426
|
+
);
|
|
5427
|
+
return Number.MAX_SAFE_INTEGER;
|
|
5428
|
+
}
|
|
5429
|
+
const effectiveLev = Number(scaledResult);
|
|
4765
5430
|
return Math.max(1, effectiveLev);
|
|
4766
5431
|
}
|
|
4767
5432
|
function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
@@ -4774,10 +5439,41 @@ function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlo
|
|
|
4774
5439
|
);
|
|
4775
5440
|
return unlocked * BigInt(maxLev);
|
|
4776
5441
|
}
|
|
5442
|
+
function computeWarmupProgress(currentSlot, warmupStartedAtSlot, warmupPeriodSlots, pnl, reservedPnl) {
|
|
5443
|
+
if (warmupPeriodSlots === 0n || warmupStartedAtSlot === 0n) {
|
|
5444
|
+
return {
|
|
5445
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5446
|
+
reservedPnl: 0n,
|
|
5447
|
+
progressBps: 10000n,
|
|
5448
|
+
// 100%
|
|
5449
|
+
slotsRemaining: 0n
|
|
5450
|
+
};
|
|
5451
|
+
}
|
|
5452
|
+
const elapsed = currentSlot >= warmupStartedAtSlot ? currentSlot - warmupStartedAtSlot : 0n;
|
|
5453
|
+
if (elapsed >= warmupPeriodSlots) {
|
|
5454
|
+
return {
|
|
5455
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5456
|
+
reservedPnl: 0n,
|
|
5457
|
+
progressBps: 10000n,
|
|
5458
|
+
// 100%
|
|
5459
|
+
slotsRemaining: 0n
|
|
5460
|
+
};
|
|
5461
|
+
}
|
|
5462
|
+
const progressBps = elapsed * 10000n / warmupPeriodSlots;
|
|
5463
|
+
const slotsRemaining = warmupPeriodSlots - elapsed;
|
|
5464
|
+
const maturedPnl = pnl > 0n ? pnl * progressBps / 10000n : 0n;
|
|
5465
|
+
const locked = reservedPnl > 0n ? reservedPnl : 0n;
|
|
5466
|
+
return {
|
|
5467
|
+
maturedPnl,
|
|
5468
|
+
reservedPnl: locked,
|
|
5469
|
+
progressBps,
|
|
5470
|
+
slotsRemaining
|
|
5471
|
+
};
|
|
5472
|
+
}
|
|
4777
5473
|
|
|
4778
5474
|
// src/validation.ts
|
|
4779
|
-
import { PublicKey as
|
|
4780
|
-
var
|
|
5475
|
+
import { PublicKey as PublicKey14 } from "@solana/web3.js";
|
|
5476
|
+
var U16_MAX = 65535;
|
|
4781
5477
|
var U64_MAX = BigInt("18446744073709551615");
|
|
4782
5478
|
var I64_MIN = BigInt("-9223372036854775808");
|
|
4783
5479
|
var I64_MAX = BigInt("9223372036854775807");
|
|
@@ -4806,7 +5502,7 @@ var ValidationError = class extends Error {
|
|
|
4806
5502
|
};
|
|
4807
5503
|
function validatePublicKey(value, field) {
|
|
4808
5504
|
try {
|
|
4809
|
-
return new
|
|
5505
|
+
return new PublicKey14(value);
|
|
4810
5506
|
} catch {
|
|
4811
5507
|
throw new ValidationError(
|
|
4812
5508
|
field,
|
|
@@ -4817,24 +5513,26 @@ function validatePublicKey(value, field) {
|
|
|
4817
5513
|
function validateIndex(value, field) {
|
|
4818
5514
|
const t = requireDecimalUIntString(value, field);
|
|
4819
5515
|
const bi = BigInt(t);
|
|
4820
|
-
if (bi > BigInt(
|
|
5516
|
+
if (bi > BigInt(U16_MAX)) {
|
|
4821
5517
|
throw new ValidationError(
|
|
4822
5518
|
field,
|
|
4823
|
-
`must be <= ${
|
|
5519
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4824
5520
|
);
|
|
4825
5521
|
}
|
|
5522
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5523
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5524
|
+
}
|
|
4826
5525
|
return Number(bi);
|
|
4827
5526
|
}
|
|
4828
5527
|
function validateAmount(value, field) {
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
num = BigInt(value);
|
|
4832
|
-
} catch {
|
|
5528
|
+
const t = value.trim();
|
|
5529
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4833
5530
|
throw new ValidationError(
|
|
4834
5531
|
field,
|
|
4835
|
-
`"${value}" is not a valid
|
|
5532
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4836
5533
|
);
|
|
4837
5534
|
}
|
|
5535
|
+
const num = BigInt(t);
|
|
4838
5536
|
if (num < 0n) {
|
|
4839
5537
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4840
5538
|
}
|
|
@@ -4847,15 +5545,14 @@ function validateAmount(value, field) {
|
|
|
4847
5545
|
return num;
|
|
4848
5546
|
}
|
|
4849
5547
|
function validateU128(value, field) {
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
num = BigInt(value);
|
|
4853
|
-
} catch {
|
|
5548
|
+
const t = value.trim();
|
|
5549
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4854
5550
|
throw new ValidationError(
|
|
4855
5551
|
field,
|
|
4856
|
-
`"${value}" is not a valid
|
|
5552
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4857
5553
|
);
|
|
4858
5554
|
}
|
|
5555
|
+
const num = BigInt(t);
|
|
4859
5556
|
if (num < 0n) {
|
|
4860
5557
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4861
5558
|
}
|
|
@@ -4868,15 +5565,14 @@ function validateU128(value, field) {
|
|
|
4868
5565
|
return num;
|
|
4869
5566
|
}
|
|
4870
5567
|
function validateI64(value, field) {
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
num = BigInt(value);
|
|
4874
|
-
} catch {
|
|
5568
|
+
const t = value.trim();
|
|
5569
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4875
5570
|
throw new ValidationError(
|
|
4876
5571
|
field,
|
|
4877
|
-
`"${value}" is not a valid
|
|
5572
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4878
5573
|
);
|
|
4879
5574
|
}
|
|
5575
|
+
const num = BigInt(t);
|
|
4880
5576
|
if (num < I64_MIN) {
|
|
4881
5577
|
throw new ValidationError(
|
|
4882
5578
|
field,
|
|
@@ -4892,15 +5588,14 @@ function validateI64(value, field) {
|
|
|
4892
5588
|
return num;
|
|
4893
5589
|
}
|
|
4894
5590
|
function validateI128(value, field) {
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
num = BigInt(value);
|
|
4898
|
-
} catch {
|
|
5591
|
+
const t = value.trim();
|
|
5592
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4899
5593
|
throw new ValidationError(
|
|
4900
5594
|
field,
|
|
4901
|
-
`"${value}" is not a valid
|
|
5595
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4902
5596
|
);
|
|
4903
5597
|
}
|
|
5598
|
+
const num = BigInt(t);
|
|
4904
5599
|
if (num < I128_MIN) {
|
|
4905
5600
|
throw new ValidationError(
|
|
4906
5601
|
field,
|
|
@@ -4924,6 +5619,9 @@ function validateBps(value, field) {
|
|
|
4924
5619
|
`must be <= 10000 (100%), got ${t}`
|
|
4925
5620
|
);
|
|
4926
5621
|
}
|
|
5622
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5623
|
+
throw new ValidationError(field, `internal error: bps value exceeds MAX_SAFE_INTEGER`);
|
|
5624
|
+
}
|
|
4927
5625
|
return Number(bi);
|
|
4928
5626
|
}
|
|
4929
5627
|
function validateU64(value, field) {
|
|
@@ -4932,12 +5630,15 @@ function validateU64(value, field) {
|
|
|
4932
5630
|
function validateU16(value, field) {
|
|
4933
5631
|
const t = requireDecimalUIntString(value, field);
|
|
4934
5632
|
const bi = BigInt(t);
|
|
4935
|
-
if (bi > BigInt(
|
|
5633
|
+
if (bi > BigInt(U16_MAX)) {
|
|
4936
5634
|
throw new ValidationError(
|
|
4937
5635
|
field,
|
|
4938
|
-
`must be <= ${
|
|
5636
|
+
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4939
5637
|
);
|
|
4940
5638
|
}
|
|
5639
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5640
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5641
|
+
}
|
|
4941
5642
|
return Number(bi);
|
|
4942
5643
|
}
|
|
4943
5644
|
|
|
@@ -4988,7 +5689,9 @@ function parseDexScreenerPairs(json) {
|
|
|
4988
5689
|
else if (liquidity > 1e4) confidence = 60;
|
|
4989
5690
|
else if (liquidity > 1e3) confidence = 45;
|
|
4990
5691
|
const priceUsd = pair.priceUsd;
|
|
4991
|
-
const
|
|
5692
|
+
const rawPrice = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) : NaN;
|
|
5693
|
+
if (!Number.isFinite(rawPrice) || rawPrice <= 0) continue;
|
|
5694
|
+
const price = rawPrice;
|
|
4992
5695
|
let baseSym = "?";
|
|
4993
5696
|
let quoteSym = "?";
|
|
4994
5697
|
if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
|
|
@@ -5019,8 +5722,8 @@ function parseJupiterMintEntry(json, mint) {
|
|
|
5019
5722
|
if (!isRecord(row)) return null;
|
|
5020
5723
|
const rawPrice = row.price;
|
|
5021
5724
|
if (rawPrice === void 0 || rawPrice === null) return null;
|
|
5022
|
-
const price = parseFloat(String(rawPrice))
|
|
5023
|
-
if (price <= 0) return null;
|
|
5725
|
+
const price = parseFloat(String(rawPrice));
|
|
5726
|
+
if (!Number.isFinite(price) || price <= 0) return null;
|
|
5024
5727
|
let mintSymbol = "?";
|
|
5025
5728
|
if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
|
|
5026
5729
|
return { price, mintSymbol };
|
|
@@ -5086,10 +5789,17 @@ async function fetchDexSources(mint, signal) {
|
|
|
5086
5789
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5087
5790
|
}
|
|
5088
5791
|
);
|
|
5089
|
-
if (!resp.ok)
|
|
5792
|
+
if (!resp.ok) {
|
|
5793
|
+
console.debug(`[fetchDexSources] HTTP ${resp.status} for mint ${mint}`);
|
|
5794
|
+
return [];
|
|
5795
|
+
}
|
|
5090
5796
|
const json = await resp.json();
|
|
5091
5797
|
return parseDexScreenerPairs(json);
|
|
5092
|
-
} catch {
|
|
5798
|
+
} catch (err) {
|
|
5799
|
+
console.warn(
|
|
5800
|
+
`[fetchDexSources] Error fetching DexScreener data for mint ${mint}:`,
|
|
5801
|
+
err instanceof Error ? err.message : String(err)
|
|
5802
|
+
);
|
|
5093
5803
|
return [];
|
|
5094
5804
|
}
|
|
5095
5805
|
}
|
|
@@ -5100,7 +5810,7 @@ function lookupPythSource(mint) {
|
|
|
5100
5810
|
type: "pyth",
|
|
5101
5811
|
address: entry.feedId,
|
|
5102
5812
|
pairLabel: `${entry.symbol} / USD (Pyth)`,
|
|
5103
|
-
liquidity:
|
|
5813
|
+
liquidity: Number.MAX_SAFE_INTEGER,
|
|
5104
5814
|
// Pyth is considered deep liquidity
|
|
5105
5815
|
price: 0,
|
|
5106
5816
|
// We don't fetch live price here; caller can enrich
|
|
@@ -5117,10 +5827,16 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5117
5827
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5118
5828
|
}
|
|
5119
5829
|
);
|
|
5120
|
-
if (!resp.ok)
|
|
5830
|
+
if (!resp.ok) {
|
|
5831
|
+
console.debug(`[fetchJupiterSource] HTTP ${resp.status} for mint ${mint}`);
|
|
5832
|
+
return null;
|
|
5833
|
+
}
|
|
5121
5834
|
const json = await resp.json();
|
|
5122
5835
|
const row = parseJupiterMintEntry(json, mint);
|
|
5123
|
-
if (!row)
|
|
5836
|
+
if (!row) {
|
|
5837
|
+
console.debug(`[fetchJupiterSource] No price data from Jupiter for mint ${mint}`);
|
|
5838
|
+
return null;
|
|
5839
|
+
}
|
|
5124
5840
|
return {
|
|
5125
5841
|
type: "jupiter",
|
|
5126
5842
|
address: mint,
|
|
@@ -5131,23 +5847,39 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5131
5847
|
confidence: 40
|
|
5132
5848
|
// Fallback — lower confidence
|
|
5133
5849
|
};
|
|
5134
|
-
} catch {
|
|
5850
|
+
} catch (err) {
|
|
5851
|
+
console.warn(
|
|
5852
|
+
`[fetchJupiterSource] Error fetching Jupiter data for mint ${mint}:`,
|
|
5853
|
+
err instanceof Error ? err.message : String(err)
|
|
5854
|
+
);
|
|
5135
5855
|
return null;
|
|
5136
5856
|
}
|
|
5137
5857
|
}
|
|
5138
5858
|
async function resolvePrice(mint, signal, options) {
|
|
5139
5859
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;
|
|
5140
5860
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
5141
|
-
const
|
|
5861
|
+
const effectiveSignal2 = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
|
|
5142
5862
|
const [dexSources, jupiterSource] = await Promise.all([
|
|
5143
|
-
fetchDexSources(mint,
|
|
5144
|
-
fetchJupiterSource(mint,
|
|
5863
|
+
fetchDexSources(mint, effectiveSignal2),
|
|
5864
|
+
fetchJupiterSource(mint, effectiveSignal2)
|
|
5145
5865
|
]);
|
|
5146
5866
|
const pythSource = lookupPythSource(mint);
|
|
5147
5867
|
const allSources = [];
|
|
5148
5868
|
if (pythSource) {
|
|
5149
|
-
const
|
|
5150
|
-
|
|
5869
|
+
const dexPrice = dexSources[0]?.price ?? 0;
|
|
5870
|
+
const jupPrice = jupiterSource?.price ?? 0;
|
|
5871
|
+
if (dexPrice > 0 && jupPrice > 0) {
|
|
5872
|
+
const mid = (dexPrice + jupPrice) / 2;
|
|
5873
|
+
const deviation = Math.abs(dexPrice - jupPrice) / mid;
|
|
5874
|
+
if (deviation > 0.5) {
|
|
5875
|
+
pythSource.price = 0;
|
|
5876
|
+
pythSource.confidence = 20;
|
|
5877
|
+
} else {
|
|
5878
|
+
pythSource.price = mid;
|
|
5879
|
+
}
|
|
5880
|
+
} else {
|
|
5881
|
+
pythSource.price = dexPrice || jupPrice || 0;
|
|
5882
|
+
}
|
|
5151
5883
|
allSources.push(pythSource);
|
|
5152
5884
|
}
|
|
5153
5885
|
allSources.push(...dexSources);
|
|
@@ -5172,9 +5904,7 @@ export {
|
|
|
5172
5904
|
ACCOUNTS_CLOSE_ACCOUNT,
|
|
5173
5905
|
ACCOUNTS_CLOSE_SLAB,
|
|
5174
5906
|
ACCOUNTS_CLOSE_STALE_SLABS,
|
|
5175
|
-
ACCOUNTS_CREATE_INSURANCE_MINT,
|
|
5176
5907
|
ACCOUNTS_DEPOSIT_COLLATERAL,
|
|
5177
|
-
ACCOUNTS_DEPOSIT_INSURANCE_LP,
|
|
5178
5908
|
ACCOUNTS_EXECUTE_ADL,
|
|
5179
5909
|
ACCOUNTS_FUND_MARKET_INSURANCE,
|
|
5180
5910
|
ACCOUNTS_INIT_LP,
|
|
@@ -5190,7 +5920,6 @@ export {
|
|
|
5190
5920
|
ACCOUNTS_QUEUE_WITHDRAWAL,
|
|
5191
5921
|
ACCOUNTS_RECLAIM_SLAB_RENT,
|
|
5192
5922
|
ACCOUNTS_RESOLVE_MARKET,
|
|
5193
|
-
ACCOUNTS_SET_DEX_POOL,
|
|
5194
5923
|
ACCOUNTS_SET_INSURANCE_ISOLATION,
|
|
5195
5924
|
ACCOUNTS_SET_MAINTENANCE_FEE,
|
|
5196
5925
|
ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK,
|
|
@@ -5200,7 +5929,6 @@ export {
|
|
|
5200
5929
|
ACCOUNTS_SET_RISK_THRESHOLD,
|
|
5201
5930
|
ACCOUNTS_SET_WALLET_CAP,
|
|
5202
5931
|
ACCOUNTS_TOPUP_INSURANCE,
|
|
5203
|
-
ACCOUNTS_TOPUP_KEEPER_FUND,
|
|
5204
5932
|
ACCOUNTS_TRADE_CPI,
|
|
5205
5933
|
ACCOUNTS_TRADE_NOCPI,
|
|
5206
5934
|
ACCOUNTS_TRANSFER_POSITION_OWNERSHIP,
|
|
@@ -5209,17 +5937,22 @@ export {
|
|
|
5209
5937
|
ACCOUNTS_UPDATE_CONFIG,
|
|
5210
5938
|
ACCOUNTS_WITHDRAW_COLLATERAL,
|
|
5211
5939
|
ACCOUNTS_WITHDRAW_INSURANCE,
|
|
5212
|
-
ACCOUNTS_WITHDRAW_INSURANCE_LP,
|
|
5213
5940
|
AccountKind,
|
|
5214
5941
|
CHAINLINK_ANSWER_OFFSET,
|
|
5215
5942
|
CHAINLINK_DECIMALS_OFFSET,
|
|
5216
5943
|
CHAINLINK_MIN_SIZE,
|
|
5944
|
+
CHAINLINK_TIMESTAMP_OFFSET,
|
|
5217
5945
|
CREATOR_LOCK_SEED,
|
|
5218
5946
|
CTX_VAMM_OFFSET,
|
|
5219
5947
|
DEFAULT_OI_RAMP_SLOTS,
|
|
5220
5948
|
ENGINE_MARK_PRICE_OFF,
|
|
5221
5949
|
ENGINE_OFF,
|
|
5222
5950
|
IX_TAG,
|
|
5951
|
+
LIGHTHOUSE_CONSTRAINT_ADDRESS,
|
|
5952
|
+
LIGHTHOUSE_ERROR_CODES,
|
|
5953
|
+
LIGHTHOUSE_PROGRAM_ID,
|
|
5954
|
+
LIGHTHOUSE_PROGRAM_ID_STR2 as LIGHTHOUSE_PROGRAM_ID_STR,
|
|
5955
|
+
LIGHTHOUSE_USER_MESSAGE,
|
|
5223
5956
|
MARK_PRICE_EMA_ALPHA_E6,
|
|
5224
5957
|
MARK_PRICE_EMA_WINDOW_SLOTS,
|
|
5225
5958
|
MAX_DECIMALS,
|
|
@@ -5241,10 +5974,12 @@ export {
|
|
|
5241
5974
|
RAMP_START_BPS,
|
|
5242
5975
|
RAYDIUM_CLMM_PROGRAM_ID,
|
|
5243
5976
|
RENOUNCE_ADMIN_CONFIRMATION,
|
|
5977
|
+
RpcPool,
|
|
5244
5978
|
SLAB_TIERS,
|
|
5245
5979
|
SLAB_TIERS_V0,
|
|
5246
5980
|
SLAB_TIERS_V1,
|
|
5247
5981
|
SLAB_TIERS_V12_1,
|
|
5982
|
+
SLAB_TIERS_V12_15,
|
|
5248
5983
|
SLAB_TIERS_V1D,
|
|
5249
5984
|
SLAB_TIERS_V1D_LEGACY,
|
|
5250
5985
|
SLAB_TIERS_V1M,
|
|
@@ -5262,11 +5997,14 @@ export {
|
|
|
5262
5997
|
VAMM_MAGIC,
|
|
5263
5998
|
ValidationError,
|
|
5264
5999
|
WELL_KNOWN,
|
|
6000
|
+
_internal,
|
|
5265
6001
|
buildAccountMetas,
|
|
5266
6002
|
buildAdlInstruction,
|
|
5267
6003
|
buildAdlTransaction,
|
|
5268
6004
|
buildIx,
|
|
5269
6005
|
checkPhaseTransition,
|
|
6006
|
+
checkRpcHealth,
|
|
6007
|
+
classifyLighthouseError,
|
|
5270
6008
|
clearStaticMarkets,
|
|
5271
6009
|
computeDexSpotPriceE6,
|
|
5272
6010
|
computeDynamicFeeBps,
|
|
@@ -5279,6 +6017,7 @@ export {
|
|
|
5279
6017
|
computeLiqPrice,
|
|
5280
6018
|
computeMarkPnl,
|
|
5281
6019
|
computeMaxLeverage,
|
|
6020
|
+
computeMaxWithdrawable,
|
|
5282
6021
|
computePnlPercent,
|
|
5283
6022
|
computePreTradeLiqPrice,
|
|
5284
6023
|
computeRequiredMargin,
|
|
@@ -5286,15 +6025,15 @@ export {
|
|
|
5286
6025
|
computeVammQuote,
|
|
5287
6026
|
computeWarmupLeverageCap,
|
|
5288
6027
|
computeWarmupMaxPositionSize,
|
|
6028
|
+
computeWarmupProgress,
|
|
5289
6029
|
computeWarmupUnlockedCapital,
|
|
5290
6030
|
concatBytes,
|
|
6031
|
+
countLighthouseInstructions,
|
|
5291
6032
|
decodeError,
|
|
5292
6033
|
decodeStakePool,
|
|
5293
6034
|
depositAccounts,
|
|
5294
6035
|
deriveCreatorLockPda,
|
|
5295
6036
|
deriveDepositPda,
|
|
5296
|
-
deriveInsuranceLpMint,
|
|
5297
|
-
deriveKeeperFund,
|
|
5298
6037
|
deriveLpPda,
|
|
5299
6038
|
derivePythPriceUpdateAccount,
|
|
5300
6039
|
derivePythPushOraclePDA,
|
|
@@ -5330,14 +6069,11 @@ export {
|
|
|
5330
6069
|
encodeClaimQueuedWithdrawal,
|
|
5331
6070
|
encodeClearPendingSettlement,
|
|
5332
6071
|
encodeCloseAccount,
|
|
5333
|
-
encodeCloseKeeperFund,
|
|
5334
6072
|
encodeCloseOrphanSlab,
|
|
5335
6073
|
encodeCloseSlab,
|
|
5336
6074
|
encodeCloseStaleSlabs,
|
|
5337
|
-
encodeCreateInsuranceMint,
|
|
5338
6075
|
encodeCreateLpVault,
|
|
5339
6076
|
encodeDepositCollateral,
|
|
5340
|
-
encodeDepositInsuranceLP,
|
|
5341
6077
|
encodeDepositLpCollateral,
|
|
5342
6078
|
encodeExecuteAdl,
|
|
5343
6079
|
encodeForceCloseResolved,
|
|
@@ -5394,7 +6130,6 @@ export {
|
|
|
5394
6130
|
encodeStakeUpdateConfig,
|
|
5395
6131
|
encodeStakeWithdraw,
|
|
5396
6132
|
encodeTopUpInsurance,
|
|
5397
|
-
encodeTopUpKeeperFund,
|
|
5398
6133
|
encodeTradeCpi,
|
|
5399
6134
|
encodeTradeCpiV2,
|
|
5400
6135
|
encodeTradeNoCpi,
|
|
@@ -5408,7 +6143,6 @@ export {
|
|
|
5408
6143
|
encodeUpdateRiskParams,
|
|
5409
6144
|
encodeWithdrawCollateral,
|
|
5410
6145
|
encodeWithdrawInsurance,
|
|
5411
|
-
encodeWithdrawInsuranceLP,
|
|
5412
6146
|
encodeWithdrawInsuranceLimited,
|
|
5413
6147
|
encodeWithdrawLpCollateral,
|
|
5414
6148
|
fetchAdlRankedPositions,
|
|
@@ -5430,6 +6164,10 @@ export {
|
|
|
5430
6164
|
initPoolAccounts,
|
|
5431
6165
|
isAccountUsed,
|
|
5432
6166
|
isAdlTriggered,
|
|
6167
|
+
isAnchorErrorCode,
|
|
6168
|
+
isLighthouseError,
|
|
6169
|
+
isLighthouseFailureInLogs,
|
|
6170
|
+
isLighthouseInstruction,
|
|
5433
6171
|
isStandardToken,
|
|
5434
6172
|
isToken2022,
|
|
5435
6173
|
isValidChainlinkOracle,
|
|
@@ -5454,6 +6192,8 @@ export {
|
|
|
5454
6192
|
simulateOrSend,
|
|
5455
6193
|
slabDataSize,
|
|
5456
6194
|
slabDataSizeV1,
|
|
6195
|
+
stripLighthouseFromTransaction,
|
|
6196
|
+
stripLighthouseInstructions,
|
|
5457
6197
|
validateAmount,
|
|
5458
6198
|
validateBps,
|
|
5459
6199
|
validateI128,
|
|
@@ -5464,6 +6204,7 @@ export {
|
|
|
5464
6204
|
validateU128,
|
|
5465
6205
|
validateU16,
|
|
5466
6206
|
validateU64,
|
|
6207
|
+
withRetry,
|
|
5467
6208
|
withdrawAccounts
|
|
5468
6209
|
};
|
|
5469
6210
|
//# sourceMappingURL=index.js.map
|