@percolatorct/sdk 1.0.0-beta.12 → 1.0.0-beta.14
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/dist/index.d.ts +3459 -7
- package/dist/index.js +375 -878
- package/dist/index.js.map +1 -1
- package/package.json +5 -10
- package/LICENSE +0 -201
- package/README.md +0 -754
- package/dist/abi/accounts.d.ts +0 -249
- package/dist/abi/encode.d.ts +0 -46
- package/dist/abi/errors.d.ts +0 -45
- package/dist/abi/index.d.ts +0 -4
- package/dist/abi/instructions.d.ts +0 -1111
- package/dist/config/program-ids.d.ts +0 -50
- package/dist/math/index.d.ts +0 -2
- package/dist/math/trading.d.ts +0 -222
- package/dist/math/warmup.d.ts +0 -105
- package/dist/oracle/price-router.d.ts +0 -38
- package/dist/runtime/index.d.ts +0 -2
- package/dist/runtime/lighthouse.d.ts +0 -170
- package/dist/runtime/tx.d.ts +0 -31
- package/dist/solana/adl.d.ts +0 -305
- package/dist/solana/ata.d.ts +0 -18
- package/dist/solana/dex-oracle.d.ts +0 -49
- package/dist/solana/discovery.d.ts +0 -492
- package/dist/solana/index.d.ts +0 -11
- package/dist/solana/oracle.d.ts +0 -52
- package/dist/solana/pda.d.ts +0 -49
- package/dist/solana/rpc-pool.d.ts +0 -347
- package/dist/solana/slab.d.ts +0 -358
- package/dist/solana/stake.d.ts +0 -216
- package/dist/solana/static-markets.d.ts +0 -86
- package/dist/solana/token-program.d.ts +0 -19
- package/dist/validation.d.ts +0 -70
package/dist/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
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;
|
|
3
6
|
function encU8(val) {
|
|
4
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
7
|
+
if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {
|
|
5
8
|
throw new Error(`encU8: value out of range (0..255), got ${val}`);
|
|
6
9
|
}
|
|
7
10
|
return new Uint8Array([val]);
|
|
8
11
|
}
|
|
9
12
|
function encU16(val) {
|
|
10
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
13
|
+
if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {
|
|
11
14
|
throw new Error(`encU16: value out of range (0..65535), got ${val}`);
|
|
12
15
|
}
|
|
13
16
|
const buf = new Uint8Array(2);
|
|
@@ -15,7 +18,7 @@ function encU16(val) {
|
|
|
15
18
|
return buf;
|
|
16
19
|
}
|
|
17
20
|
function encU32(val) {
|
|
18
|
-
if (!Number.isInteger(val) || val < 0 || val >
|
|
21
|
+
if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {
|
|
19
22
|
throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);
|
|
20
23
|
}
|
|
21
24
|
const buf = new Uint8Array(4);
|
|
@@ -131,13 +134,8 @@ var IX_TAG = {
|
|
|
131
134
|
ReclaimEmptyAccount: 25,
|
|
132
135
|
SettleAccount: 26,
|
|
133
136
|
// Tags 27-28: on-chain = DepositFeeCredits/ConvertReleasedPnl.
|
|
134
|
-
// Legacy aliases (PauseMarket/UnpauseMarket) kept — those instructions don't exist on-chain.
|
|
135
137
|
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,
|
|
141
139
|
// Tags 29-30: on-chain = ResolvePermissionless/ForceCloseResolved.
|
|
142
140
|
ResolvePermissionless: 29,
|
|
143
141
|
/** @deprecated Use ResolvePermissionless */
|
|
@@ -225,7 +223,13 @@ var IX_TAG = {
|
|
|
225
223
|
/** PERC-SetDexPool: Pin admin-approved DEX pool address for a HYPERP market (admin). */
|
|
226
224
|
SetDexPool: 74,
|
|
227
225
|
/** CPI to the matcher program to initialize a matcher context account for an LP slot. Admin-only. */
|
|
228
|
-
InitMatcherCtx: 75
|
|
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
|
|
229
233
|
};
|
|
230
234
|
Object.freeze(IX_TAG);
|
|
231
235
|
var HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
@@ -264,19 +268,23 @@ function encodeInitMarket(args) {
|
|
|
264
268
|
encU128(args.maxMaintenanceFeePerSlot ?? 0n),
|
|
265
269
|
encU128(args.maxInsuranceFloor ?? 0n),
|
|
266
270
|
encU64(args.minOraclePriceCap ?? 0n),
|
|
267
|
-
// RiskParams
|
|
271
|
+
// RiskParams wire format — must match read_risk_params() in percolator.rs
|
|
272
|
+
// Note: insurance_floor occupies the old riskReductionThreshold slot,
|
|
273
|
+
// and liquidationBufferBps is read but discarded (kept for wire compat).
|
|
268
274
|
encU64(args.warmupPeriodSlots),
|
|
269
275
|
encU64(args.maintenanceMarginBps),
|
|
270
276
|
encU64(args.initialMarginBps),
|
|
271
277
|
encU64(args.tradingFeeBps),
|
|
272
278
|
encU64(args.maxAccounts),
|
|
273
279
|
encU128(args.newAccountFee),
|
|
274
|
-
encU128(args.
|
|
280
|
+
encU128(args.insuranceFloor ?? 0n),
|
|
281
|
+
// wire slot: old riskReductionThreshold → now insurance_floor
|
|
275
282
|
encU128(args.maintenanceFeePerSlot),
|
|
276
283
|
encU64(args.maxCrankStalenessSlots),
|
|
277
284
|
encU64(args.liquidationFeeBps),
|
|
278
285
|
encU128(args.liquidationFeeCap),
|
|
279
|
-
encU64(args.liquidationBufferBps),
|
|
286
|
+
encU64(args.liquidationBufferBps ?? 0n),
|
|
287
|
+
// wire slot: read and discarded by program
|
|
280
288
|
encU128(args.minLiquidationAbs),
|
|
281
289
|
encU128(args.minInitialDeposit),
|
|
282
290
|
encU128(args.minNonzeroMmReq),
|
|
@@ -480,12 +488,12 @@ function encodeSetPythOracle(args) {
|
|
|
480
488
|
}
|
|
481
489
|
var PYTH_RECEIVER_PROGRAM_ID = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ";
|
|
482
490
|
async function derivePythPriceUpdateAccount(feedId, shardId = 0) {
|
|
483
|
-
const { PublicKey:
|
|
491
|
+
const { PublicKey: PublicKey14 } = await import("@solana/web3.js");
|
|
484
492
|
const shardBuf = new Uint8Array(2);
|
|
485
493
|
new DataView(shardBuf.buffer).setUint16(0, shardId, true);
|
|
486
|
-
const [pda] =
|
|
494
|
+
const [pda] = PublicKey14.findProgramAddressSync(
|
|
487
495
|
[shardBuf, feedId],
|
|
488
|
-
new
|
|
496
|
+
new PublicKey14(PYTH_RECEIVER_PROGRAM_ID)
|
|
489
497
|
);
|
|
490
498
|
return pda.toBase58();
|
|
491
499
|
}
|
|
@@ -720,6 +728,18 @@ function encodeCloseOrphanSlab() {
|
|
|
720
728
|
function encodeSetDexPool(args) {
|
|
721
729
|
return concatBytes(encU8(IX_TAG.SetDexPool), encPubkey(args.pool));
|
|
722
730
|
}
|
|
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
|
+
}
|
|
723
743
|
|
|
724
744
|
// src/abi/accounts.ts
|
|
725
745
|
import {
|
|
@@ -744,7 +764,8 @@ var ACCOUNTS_INIT_USER = [
|
|
|
744
764
|
{ name: "slab", signer: false, writable: true },
|
|
745
765
|
{ name: "userAta", signer: false, writable: true },
|
|
746
766
|
{ name: "vault", signer: false, writable: true },
|
|
747
|
-
{ name: "tokenProgram", signer: false, writable: false }
|
|
767
|
+
{ name: "tokenProgram", signer: false, writable: false },
|
|
768
|
+
{ name: "clock", signer: false, writable: false }
|
|
748
769
|
];
|
|
749
770
|
var ACCOUNTS_INIT_LP = [
|
|
750
771
|
{ name: "user", signer: true, writable: true },
|
|
@@ -811,6 +832,7 @@ var ACCOUNTS_TRADE_CPI = [
|
|
|
811
832
|
{ name: "lpOwner", signer: false, writable: false },
|
|
812
833
|
// LP delegated to matcher - no signature needed
|
|
813
834
|
{ name: "slab", signer: false, writable: true },
|
|
835
|
+
{ name: "clock", signer: false, writable: false },
|
|
814
836
|
{ name: "oracle", signer: false, writable: false },
|
|
815
837
|
{ name: "matcherProg", signer: false, writable: false },
|
|
816
838
|
{ name: "matcherCtx", signer: false, writable: true },
|
|
@@ -894,6 +916,37 @@ function buildAccountMetas(spec, keys) {
|
|
|
894
916
|
isWritable: s.writable
|
|
895
917
|
}));
|
|
896
918
|
}
|
|
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
|
+
];
|
|
897
950
|
var ACCOUNTS_LP_VAULT_WITHDRAW = [
|
|
898
951
|
{ name: "withdrawer", signer: true, writable: false },
|
|
899
952
|
{ name: "slab", signer: false, writable: true },
|
|
@@ -964,7 +1017,8 @@ var ACCOUNTS_ADVANCE_ORACLE_PHASE = [
|
|
|
964
1017
|
var ACCOUNTS_TOPUP_KEEPER_FUND = [
|
|
965
1018
|
{ name: "funder", signer: true, writable: true },
|
|
966
1019
|
{ name: "slab", signer: false, writable: true },
|
|
967
|
-
{ name: "keeperFund", signer: false, writable: true }
|
|
1020
|
+
{ name: "keeperFund", signer: false, writable: true },
|
|
1021
|
+
{ name: "systemProgram", signer: false, writable: false }
|
|
968
1022
|
];
|
|
969
1023
|
var ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK = [
|
|
970
1024
|
{ name: "admin", signer: true, writable: false },
|
|
@@ -1015,6 +1069,11 @@ var ACCOUNTS_SET_WALLET_CAP = [
|
|
|
1015
1069
|
{ name: "admin", signer: true, writable: false },
|
|
1016
1070
|
{ name: "slab", signer: false, writable: true }
|
|
1017
1071
|
];
|
|
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
|
+
];
|
|
1018
1077
|
var ACCOUNTS_INIT_MATCHER_CTX = [
|
|
1019
1078
|
{ name: "admin", signer: true, writable: false },
|
|
1020
1079
|
{ name: "slab", signer: false, writable: false },
|
|
@@ -1306,24 +1365,11 @@ function getErrorName(code) {
|
|
|
1306
1365
|
function getErrorHint(code) {
|
|
1307
1366
|
return PERCOLATOR_ERRORS[code]?.hint;
|
|
1308
1367
|
}
|
|
1309
|
-
var LIGHTHOUSE_PROGRAM_ID_STR = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
1310
|
-
var ANCHOR_ERROR_RANGE_START = 6e3;
|
|
1311
|
-
var ANCHOR_ERROR_RANGE_END = 8191;
|
|
1312
|
-
var ANCHOR_ERROR_NAMES = {
|
|
1313
|
-
6032: "ConstraintMut",
|
|
1314
|
-
6036: "ConstraintOwner",
|
|
1315
|
-
6038: "ConstraintSeeds",
|
|
1316
|
-
6400: "ConstraintAddress"
|
|
1317
|
-
};
|
|
1318
|
-
function isAnchorErrorCode(code) {
|
|
1319
|
-
return code >= ANCHOR_ERROR_RANGE_START && code <= ANCHOR_ERROR_RANGE_END;
|
|
1320
|
-
}
|
|
1321
1368
|
var CUSTOM_ERROR_HEX_MAX_LEN = 8;
|
|
1322
1369
|
function parseErrorFromLogs(logs) {
|
|
1323
1370
|
if (!Array.isArray(logs)) {
|
|
1324
1371
|
return null;
|
|
1325
1372
|
}
|
|
1326
|
-
let insideLighthouse = false;
|
|
1327
1373
|
const re = new RegExp(
|
|
1328
1374
|
`custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,
|
|
1329
1375
|
"i"
|
|
@@ -1332,32 +1378,17 @@ function parseErrorFromLogs(logs) {
|
|
|
1332
1378
|
if (typeof log !== "string") {
|
|
1333
1379
|
continue;
|
|
1334
1380
|
}
|
|
1335
|
-
if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {
|
|
1336
|
-
insideLighthouse = true;
|
|
1337
|
-
} else if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {
|
|
1338
|
-
insideLighthouse = false;
|
|
1339
|
-
}
|
|
1340
1381
|
const match = log.match(re);
|
|
1341
1382
|
if (match) {
|
|
1342
1383
|
const code = parseInt(match[1], 16);
|
|
1343
1384
|
if (!Number.isFinite(code) || code < 0 || code > 4294967295) {
|
|
1344
1385
|
continue;
|
|
1345
1386
|
}
|
|
1346
|
-
if (isAnchorErrorCode(code) || insideLighthouse) {
|
|
1347
|
-
const anchorName = ANCHOR_ERROR_NAMES[code] ?? `AnchorError(0x${code.toString(16)})`;
|
|
1348
|
-
return {
|
|
1349
|
-
code,
|
|
1350
|
-
name: `Lighthouse:${anchorName}`,
|
|
1351
|
-
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).",
|
|
1352
|
-
source: "lighthouse"
|
|
1353
|
-
};
|
|
1354
|
-
}
|
|
1355
1387
|
const info = decodeError(code);
|
|
1356
1388
|
return {
|
|
1357
1389
|
code,
|
|
1358
1390
|
name: info?.name ?? `Unknown(${code})`,
|
|
1359
|
-
hint: info?.hint
|
|
1360
|
-
source: info ? "percolator" : "unknown"
|
|
1391
|
+
hint: info?.hint
|
|
1361
1392
|
};
|
|
1362
1393
|
}
|
|
1363
1394
|
}
|
|
@@ -1573,7 +1604,25 @@ var V12_1_ACCOUNT_SIZE_SBF = 280;
|
|
|
1573
1604
|
var V12_1_ENGINE_BITMAP_OFF = 1016;
|
|
1574
1605
|
var V12_1_ENGINE_PARAMS_OFF_SBF = 32;
|
|
1575
1606
|
var V12_1_ENGINE_PARAMS_OFF_HOST = 96;
|
|
1607
|
+
var V12_1_PARAMS_SIZE_SBF = 184;
|
|
1576
1608
|
var V12_1_PARAMS_SIZE = 352;
|
|
1609
|
+
var V12_1_SBF_OFF_CURRENT_SLOT = 216;
|
|
1610
|
+
var V12_1_SBF_OFF_FUNDING_RATE = 224;
|
|
1611
|
+
var V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;
|
|
1612
|
+
var V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;
|
|
1613
|
+
var V12_1_SBF_OFF_C_TOT = 248;
|
|
1614
|
+
var V12_1_SBF_OFF_PNL_POS_TOT = 264;
|
|
1615
|
+
var V12_1_SBF_OFF_LIQ_CURSOR = 296;
|
|
1616
|
+
var V12_1_SBF_OFF_GC_CURSOR = 298;
|
|
1617
|
+
var V12_1_SBF_OFF_LAST_SWEEP_START = 304;
|
|
1618
|
+
var V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;
|
|
1619
|
+
var V12_1_SBF_OFF_CRANK_CURSOR = 320;
|
|
1620
|
+
var V12_1_SBF_OFF_SWEEP_START_IDX = 322;
|
|
1621
|
+
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;
|
|
1577
1626
|
var V12_1_ENGINE_CURRENT_SLOT_OFF = 448;
|
|
1578
1627
|
var V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;
|
|
1579
1628
|
var V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;
|
|
@@ -1608,7 +1657,13 @@ var V12_1_ACCT_FEE_CREDITS_OFF = 240;
|
|
|
1608
1657
|
var V12_1_ACCT_LAST_FEE_SLOT_OFF = 256;
|
|
1609
1658
|
var V12_1_ACCT_POSITION_SIZE_OFF = 88;
|
|
1610
1659
|
var V12_1_ACCT_ENTRY_PRICE_OFF = -1;
|
|
1611
|
-
var
|
|
1660
|
+
var V12_1_EP_SBF_ACCOUNT_SIZE = 288;
|
|
1661
|
+
var V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;
|
|
1662
|
+
var V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;
|
|
1663
|
+
var V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;
|
|
1664
|
+
var V12_1_EP_ACCT_OWNER_OFF = 216;
|
|
1665
|
+
var V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;
|
|
1666
|
+
var V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;
|
|
1612
1667
|
var V1M_ENGINE_OFF = 640;
|
|
1613
1668
|
var V1M_CONFIG_LEN = 536;
|
|
1614
1669
|
var V1M_ACCOUNT_SIZE = 248;
|
|
@@ -1683,14 +1738,23 @@ for (const n of TIERS) {
|
|
|
1683
1738
|
V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);
|
|
1684
1739
|
}
|
|
1685
1740
|
var V12_1_SBF_ACCOUNT_SIZE = 280;
|
|
1686
|
-
var
|
|
1741
|
+
var V12_1_SBF_ENGINE_OFF = 616;
|
|
1742
|
+
var V12_1_SBF_BITMAP_OFF = 584;
|
|
1687
1743
|
for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
1688
1744
|
const bitmapBytes = Math.ceil(n / 64) * 8;
|
|
1689
|
-
const preAccLen =
|
|
1745
|
+
const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;
|
|
1690
1746
|
const accountsOff = Math.ceil(preAccLen / 8) * 8;
|
|
1691
|
-
const total =
|
|
1747
|
+
const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
|
|
1692
1748
|
V12_1_SIZES.set(total, n);
|
|
1693
1749
|
}
|
|
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
|
+
}
|
|
1694
1758
|
var SLAB_TIERS_V2 = {
|
|
1695
1759
|
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
|
|
1696
1760
|
large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V2 BPF intermediate)" }
|
|
@@ -2218,8 +2282,8 @@ function buildLayoutVSetDexPool(maxAccounts) {
|
|
|
2218
2282
|
function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
2219
2283
|
const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);
|
|
2220
2284
|
const isSbf = dataLen !== void 0 && dataLen !== hostSize;
|
|
2221
|
-
const engineOff = isSbf ?
|
|
2222
|
-
const bitmapOff = isSbf ?
|
|
2285
|
+
const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;
|
|
2286
|
+
const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF - V12_1_ENGINE_OFF;
|
|
2223
2287
|
const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;
|
|
2224
2288
|
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2225
2289
|
const bitmapBytes = bitmapWords * 8;
|
|
@@ -2229,14 +2293,11 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2229
2293
|
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2230
2294
|
return {
|
|
2231
2295
|
version: 1,
|
|
2232
|
-
// V12_1 upstream rebase uses 72-byte header (SlabHeader only, no V1 extension).
|
|
2233
|
-
// Empirically verified: USDC mint found at offset 72 on mainnet slab BVjPc6rd.
|
|
2234
2296
|
headerLen: V0_HEADER_LEN,
|
|
2235
|
-
// 72
|
|
2297
|
+
// 72
|
|
2236
2298
|
configOffset: V0_HEADER_LEN,
|
|
2237
2299
|
// 72
|
|
2238
2300
|
configLen: isSbf ? 544 : 576,
|
|
2239
|
-
// SBF=544, host=576 (alignment diff)
|
|
2240
2301
|
reservedOff: V1_RESERVED_OFF,
|
|
2241
2302
|
engineOff,
|
|
2242
2303
|
accountSize,
|
|
@@ -2245,45 +2306,124 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
|
2245
2306
|
accountsOff: engineOff + accountsOffRel,
|
|
2246
2307
|
engineInsuranceOff: 16,
|
|
2247
2308
|
engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,
|
|
2248
|
-
paramsSize: V12_1_PARAMS_SIZE,
|
|
2249
|
-
// SBF
|
|
2250
|
-
//
|
|
2251
|
-
engineCurrentSlotOff: isSbf ?
|
|
2252
|
-
engineFundingIndexOff: isSbf ?
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2309
|
+
paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,
|
|
2310
|
+
// SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.
|
|
2311
|
+
// Fields that don't exist in the deployed program are set to -1 on SBF.
|
|
2312
|
+
engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,
|
|
2313
|
+
engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF,
|
|
2314
|
+
// not in deployed struct
|
|
2315
|
+
engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
2316
|
+
// not in deployed struct
|
|
2317
|
+
engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
2318
|
+
engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,
|
|
2319
|
+
engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2320
|
+
engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2321
|
+
engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,
|
|
2322
|
+
engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,
|
|
2323
|
+
engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,
|
|
2324
|
+
engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,
|
|
2325
|
+
enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,
|
|
2326
|
+
engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,
|
|
2327
|
+
engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,
|
|
2328
|
+
engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,
|
|
2329
|
+
engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
2330
|
+
engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,
|
|
2331
|
+
engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,
|
|
2332
|
+
engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
2333
|
+
engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
2334
|
+
// not in deployed struct
|
|
2335
|
+
engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF,
|
|
2336
|
+
// not in deployed struct
|
|
2337
|
+
engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF,
|
|
2338
|
+
// not in deployed struct
|
|
2339
|
+
engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF,
|
|
2340
|
+
// not in deployed struct
|
|
2341
|
+
engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
2342
|
+
// not in deployed struct
|
|
2343
|
+
engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
2344
|
+
// not in deployed struct
|
|
2345
|
+
engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
2346
|
+
// not in deployed struct
|
|
2347
|
+
engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
2348
|
+
// not in deployed struct
|
|
2278
2349
|
engineBitmapOff: bitmapOff,
|
|
2279
2350
|
postBitmap: 18,
|
|
2280
2351
|
acctOwnerOff: V12_1_ACCT_OWNER_OFF,
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2352
|
+
// InsuranceFund on deployed program is just {balance: U128} = 16 bytes.
|
|
2353
|
+
// No isolated_balance or insurance_isolation_bps fields.
|
|
2354
|
+
hasInsuranceIsolation: !isSbf,
|
|
2355
|
+
engineInsuranceIsolatedOff: isSbf ? -1 : 48,
|
|
2356
|
+
engineInsuranceIsolationBpsOff: isSbf ? -1 : 64
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
function buildLayoutV12_1EP(maxAccounts) {
|
|
2360
|
+
const engineOff = V12_1_SBF_ENGINE_OFF;
|
|
2361
|
+
const bitmapOff = V12_1_SBF_BITMAP_OFF;
|
|
2362
|
+
const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE;
|
|
2363
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2364
|
+
const bitmapBytes = bitmapWords * 8;
|
|
2365
|
+
const postBitmap = 18;
|
|
2366
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
2367
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2368
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2369
|
+
return {
|
|
2370
|
+
version: 1,
|
|
2371
|
+
headerLen: 72,
|
|
2372
|
+
configOffset: 72,
|
|
2373
|
+
configLen: 544,
|
|
2374
|
+
reservedOff: 80,
|
|
2375
|
+
// V1_RESERVED_OFF
|
|
2376
|
+
engineOff,
|
|
2377
|
+
accountSize,
|
|
2378
|
+
maxAccounts,
|
|
2379
|
+
bitmapWords,
|
|
2380
|
+
accountsOff: engineOff + accountsOffRel,
|
|
2381
|
+
engineInsuranceOff: 16,
|
|
2382
|
+
engineParamsOff: 32,
|
|
2383
|
+
// V12_1_ENGINE_PARAMS_OFF_SBF
|
|
2384
|
+
paramsSize: 184,
|
|
2385
|
+
// V12_1_PARAMS_SIZE_SBF
|
|
2386
|
+
// Engine offsets identical to V12_1 SBF
|
|
2387
|
+
engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,
|
|
2388
|
+
engineFundingIndexOff: -1,
|
|
2389
|
+
engineLastFundingSlotOff: -1,
|
|
2390
|
+
engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,
|
|
2391
|
+
engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,
|
|
2392
|
+
engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,
|
|
2393
|
+
engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,
|
|
2394
|
+
engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,
|
|
2395
|
+
engineLongOiOff: V12_1_SBF_OFF_LONG_OI,
|
|
2396
|
+
engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,
|
|
2397
|
+
engineCTotOff: V12_1_SBF_OFF_C_TOT,
|
|
2398
|
+
enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,
|
|
2399
|
+
engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,
|
|
2400
|
+
engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,
|
|
2401
|
+
engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,
|
|
2402
|
+
engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,
|
|
2403
|
+
engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,
|
|
2404
|
+
engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,
|
|
2405
|
+
engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,
|
|
2406
|
+
engineLifetimeForceClosesOff: -1,
|
|
2407
|
+
engineNetLpPosOff: -1,
|
|
2408
|
+
engineLpSumAbsOff: -1,
|
|
2409
|
+
engineLpMaxAbsOff: -1,
|
|
2410
|
+
engineLpMaxAbsSweepOff: -1,
|
|
2411
|
+
engineEmergencyOiModeOff: -1,
|
|
2412
|
+
engineEmergencyStartSlotOff: -1,
|
|
2413
|
+
engineLastBreakerSlotOff: -1,
|
|
2414
|
+
engineBitmapOff: bitmapOff,
|
|
2415
|
+
postBitmap: 18,
|
|
2416
|
+
// Account offsets — shifted +8 from V12_1 due to entry_price insertion
|
|
2417
|
+
acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF,
|
|
2418
|
+
// 216 (was 208)
|
|
2419
|
+
hasInsuranceIsolation: false,
|
|
2420
|
+
engineInsuranceIsolatedOff: -1,
|
|
2421
|
+
engineInsuranceIsolationBpsOff: -1
|
|
2284
2422
|
};
|
|
2285
2423
|
}
|
|
2286
2424
|
function detectSlabLayout(dataLen, data) {
|
|
2425
|
+
const v121epn = V12_1_EP_SIZES.get(dataLen);
|
|
2426
|
+
if (v121epn !== void 0) return buildLayoutV12_1EP(v121epn);
|
|
2287
2427
|
const v121n = V12_1_SIZES.get(dataLen);
|
|
2288
2428
|
if (v121n !== void 0) return buildLayoutV12_1(v121n, dataLen);
|
|
2289
2429
|
const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);
|
|
@@ -2330,6 +2470,15 @@ var PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;
|
|
|
2330
2470
|
var PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;
|
|
2331
2471
|
var PARAMS_LIQUIDATION_BUFFER_OFF = 120;
|
|
2332
2472
|
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;
|
|
2333
2482
|
var ACCT_ACCOUNT_ID_OFF = 0;
|
|
2334
2483
|
var ACCT_CAPITAL_OFF = 8;
|
|
2335
2484
|
var ACCT_KIND_OFF = 24;
|
|
@@ -2579,6 +2728,7 @@ function parseParams(data, layoutHint) {
|
|
|
2579
2728
|
if (data.length < base + Math.min(paramsSize, 56)) {
|
|
2580
2729
|
throw new Error("Slab data too short for RiskParams");
|
|
2581
2730
|
}
|
|
2731
|
+
const isV12_1Sbf = layout !== null && layout !== void 0 && layout.engineOff === V12_1_SBF_ENGINE_OFF && paramsSize === 184;
|
|
2582
2732
|
const result = {
|
|
2583
2733
|
warmupPeriodSlots: readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
|
|
2584
2734
|
maintenanceMarginBps: readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),
|
|
@@ -2586,16 +2736,30 @@ function parseParams(data, layoutHint) {
|
|
|
2586
2736
|
tradingFeeBps: readU64LE(data, base + PARAMS_TRADING_FEE_OFF),
|
|
2587
2737
|
maxAccounts: readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
|
|
2588
2738
|
newAccountFee: readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),
|
|
2589
|
-
// Extended params:
|
|
2739
|
+
// Extended params: defaults; overwritten below if layout supports them
|
|
2590
2740
|
riskReductionThreshold: 0n,
|
|
2591
2741
|
maintenanceFeePerSlot: 0n,
|
|
2592
2742
|
maxCrankStalenessSlots: 0n,
|
|
2593
2743
|
liquidationFeeBps: 0n,
|
|
2594
2744
|
liquidationFeeCap: 0n,
|
|
2595
2745
|
liquidationBufferBps: 0n,
|
|
2596
|
-
minLiquidationAbs: 0n
|
|
2746
|
+
minLiquidationAbs: 0n,
|
|
2747
|
+
minInitialDeposit: 0n,
|
|
2748
|
+
minNonzeroMmReq: 0n,
|
|
2749
|
+
minNonzeroImReq: 0n,
|
|
2750
|
+
insuranceFloor: 0n
|
|
2597
2751
|
};
|
|
2598
|
-
if (
|
|
2752
|
+
if (isV12_1Sbf) {
|
|
2753
|
+
result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);
|
|
2754
|
+
result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);
|
|
2755
|
+
result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);
|
|
2756
|
+
result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);
|
|
2757
|
+
result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);
|
|
2758
|
+
result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);
|
|
2759
|
+
result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);
|
|
2760
|
+
result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);
|
|
2761
|
+
result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);
|
|
2762
|
+
} else if (paramsSize >= 144) {
|
|
2599
2763
|
result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
|
|
2600
2764
|
result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
|
|
2601
2765
|
result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);
|
|
@@ -2616,17 +2780,18 @@ function parseEngine(data) {
|
|
|
2616
2780
|
vault: readU128LE(data, base),
|
|
2617
2781
|
insuranceFund: {
|
|
2618
2782
|
balance: readU128LE(data, base + layout.engineInsuranceOff),
|
|
2619
|
-
feeRevenue:
|
|
2783
|
+
// feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)
|
|
2784
|
+
feeRevenue: layout.hasInsuranceIsolation ? readU128LE(data, base + layout.engineInsuranceOff + 16) : 0n,
|
|
2620
2785
|
isolatedBalance: layout.hasInsuranceIsolation ? readU128LE(data, base + layout.engineInsuranceIsolatedOff) : 0n,
|
|
2621
2786
|
isolationBps: layout.hasInsuranceIsolation ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff) : 0
|
|
2622
2787
|
},
|
|
2623
2788
|
currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),
|
|
2624
|
-
fundingIndexQpbE6: readI128LE(data, base + layout.engineFundingIndexOff),
|
|
2625
|
-
lastFundingSlot: readU64LE(data, base + layout.engineLastFundingSlotOff),
|
|
2789
|
+
fundingIndexQpbE6: layout.engineFundingIndexOff >= 0 ? readI128LE(data, base + layout.engineFundingIndexOff) : 0n,
|
|
2790
|
+
lastFundingSlot: layout.engineLastFundingSlotOff >= 0 ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,
|
|
2626
2791
|
fundingRateBpsPerSlotLast: readI64LE(data, base + layout.engineFundingRateBpsOff),
|
|
2627
2792
|
lastCrankSlot: readU64LE(data, base + layout.engineLastCrankSlotOff),
|
|
2628
2793
|
maxCrankStalenessSlots: readU64LE(data, base + layout.engineMaxCrankStalenessOff),
|
|
2629
|
-
totalOpenInterest: readU128LE(data, base + layout.engineTotalOiOff),
|
|
2794
|
+
totalOpenInterest: layout.engineTotalOiOff >= 0 ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,
|
|
2630
2795
|
longOi: layout.engineLongOiOff >= 0 ? readU128LE(data, base + layout.engineLongOiOff) : 0n,
|
|
2631
2796
|
shortOi: layout.engineShortOiOff >= 0 ? readU128LE(data, base + layout.engineShortOiOff) : 0n,
|
|
2632
2797
|
cTot: readU128LE(data, base + layout.engineCTotOff),
|
|
@@ -2638,9 +2803,9 @@ function parseEngine(data) {
|
|
|
2638
2803
|
crankCursor: readU16LE(data, base + layout.engineCrankCursorOff),
|
|
2639
2804
|
sweepStartIdx: readU16LE(data, base + layout.engineSweepStartIdxOff),
|
|
2640
2805
|
lifetimeLiquidations: readU64LE(data, base + layout.engineLifetimeLiquidationsOff),
|
|
2641
|
-
lifetimeForceCloses: readU64LE(data, base + layout.engineLifetimeForceClosesOff),
|
|
2642
|
-
netLpPos: readI128LE(data, base + layout.engineNetLpPosOff),
|
|
2643
|
-
lpSumAbs: readU128LE(data, base + layout.engineLpSumAbsOff),
|
|
2806
|
+
lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0 ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,
|
|
2807
|
+
netLpPos: layout.engineNetLpPosOff >= 0 ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,
|
|
2808
|
+
lpSumAbs: layout.engineLpSumAbsOff >= 0 ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,
|
|
2644
2809
|
lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,
|
|
2645
2810
|
lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,
|
|
2646
2811
|
emergencyOiMode: layout.engineEmergencyOiModeOff >= 0 ? data[base + layout.engineEmergencyOiModeOff] !== 0 : false,
|
|
@@ -2707,17 +2872,18 @@ function parseAccount(data, idx) {
|
|
|
2707
2872
|
if (data.length < base + layout.accountSize) {
|
|
2708
2873
|
throw new Error("Slab data too short for account");
|
|
2709
2874
|
}
|
|
2710
|
-
const
|
|
2711
|
-
const
|
|
2875
|
+
const isV12_1EP = layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;
|
|
2876
|
+
const isV12_1 = !isV12_1EP && (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);
|
|
2877
|
+
const isAdl = layout.accountSize >= 312 || isV12_1 || isV12_1EP;
|
|
2712
2878
|
const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
|
|
2713
2879
|
const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;
|
|
2714
|
-
const positionSizeOff = isV12_1 ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2715
|
-
const entryPriceOff = isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2716
|
-
const fundingIndexOff = isV12_1 ?
|
|
2717
|
-
const matcherProgOff = isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2718
|
-
const matcherCtxOff = isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2719
|
-
const feeCreditsOff = isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2720
|
-
const lastFeeSlotOff = isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2880
|
+
const positionSizeOff = isV12_1 || isV12_1EP ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2881
|
+
const entryPriceOff = isV12_1EP ? V12_1_EP_ACCT_ENTRY_PRICE_OFF : isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2882
|
+
const fundingIndexOff = isV12_1 || isV12_1EP ? -1 : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2883
|
+
const matcherProgOff = isV12_1EP ? V12_1_EP_ACCT_MATCHER_PROGRAM_OFF : isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2884
|
+
const matcherCtxOff = isV12_1EP ? V12_1_EP_ACCT_MATCHER_CONTEXT_OFF : isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2885
|
+
const feeCreditsOff = isV12_1EP ? V12_1_EP_ACCT_FEE_CREDITS_OFF : isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2886
|
+
const lastFeeSlotOff = isV12_1EP ? V12_1_EP_ACCT_LAST_FEE_SLOT_OFF : isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2721
2887
|
const kindByte = readU8(data, base + ACCT_KIND_OFF);
|
|
2722
2888
|
const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2723
2889
|
return {
|
|
@@ -2730,9 +2896,8 @@ function parseAccount(data, idx) {
|
|
|
2730
2896
|
warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
|
|
2731
2897
|
positionSize: readI128LE(data, base + positionSizeOff),
|
|
2732
2898
|
entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,
|
|
2733
|
-
// V12_1:
|
|
2734
|
-
|
|
2735
|
-
fundingIndex: isV12_1 ? BigInt(readI64LE(data, base + fundingIndexOff)) : readI128LE(data, base + fundingIndexOff),
|
|
2899
|
+
// V12_1/V12_1_EP: funding_index not present in SBF layout
|
|
2900
|
+
fundingIndex: isV12_1 || isV12_1EP ? fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n : readI128LE(data, base + fundingIndexOff),
|
|
2736
2901
|
matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
|
|
2737
2902
|
matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
|
|
2738
2903
|
owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
|
|
@@ -2765,6 +2930,12 @@ function deriveVaultAuthority(programId, slab) {
|
|
|
2765
2930
|
programId
|
|
2766
2931
|
);
|
|
2767
2932
|
}
|
|
2933
|
+
function deriveInsuranceLpMint(programId, slab) {
|
|
2934
|
+
return PublicKey4.findProgramAddressSync(
|
|
2935
|
+
[textEncoder.encode("ins_lp"), slab.toBytes()],
|
|
2936
|
+
programId
|
|
2937
|
+
);
|
|
2938
|
+
}
|
|
2768
2939
|
var LP_INDEX_U16_MAX = 65535;
|
|
2769
2940
|
function deriveLpPda(programId, slab, lpIdx) {
|
|
2770
2941
|
if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
|
|
@@ -2821,14 +2992,7 @@ function derivePythPushOraclePDA(feedIdHex) {
|
|
|
2821
2992
|
}
|
|
2822
2993
|
const feedId = new Uint8Array(32);
|
|
2823
2994
|
for (let i = 0; i < 32; i++) {
|
|
2824
|
-
|
|
2825
|
-
const byte = parseInt(hexPair, 16);
|
|
2826
|
-
if (Number.isNaN(byte)) {
|
|
2827
|
-
throw new Error(
|
|
2828
|
-
`derivePythPushOraclePDA: failed to parse hex byte at position ${i}: "${hexPair}"`
|
|
2829
|
-
);
|
|
2830
|
-
}
|
|
2831
|
-
feedId[i] = byte;
|
|
2995
|
+
feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);
|
|
2832
2996
|
}
|
|
2833
2997
|
const shardBuf = new Uint8Array(2);
|
|
2834
2998
|
return PublicKey4.findProgramAddressSync(
|
|
@@ -2860,9 +3024,7 @@ import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
|
2860
3024
|
// src/solana/static-markets.ts
|
|
2861
3025
|
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
2862
3026
|
var MAINNET_MARKETS = [
|
|
2863
|
-
|
|
2864
|
-
// To add entries:
|
|
2865
|
-
// { slabAddress: "ABC123...", symbol: "SOL-PERP", name: "SOL Perpetual" },
|
|
3027
|
+
{ slabAddress: "9TGSmPLTLMii4UqstL629twGeVJ9Ndr8VD3pexnvQTsV", symbol: "SOL-PERP", name: "SOL/USDC Perpetual" }
|
|
2866
3028
|
];
|
|
2867
3029
|
var DEVNET_MARKETS = [
|
|
2868
3030
|
// Populated from prior discoverMarkets() runs on devnet.
|
|
@@ -3630,7 +3792,9 @@ function computeRaydiumClmmPriceE6(data) {
|
|
|
3630
3792
|
}
|
|
3631
3793
|
const sqrtPriceX64 = readU128LE3(dv3, 253);
|
|
3632
3794
|
if (sqrtPriceX64 === 0n) return 0n;
|
|
3633
|
-
const
|
|
3795
|
+
const scaledSqrt = sqrtPriceX64 * 1000000n;
|
|
3796
|
+
const term = scaledSqrt >> 64n;
|
|
3797
|
+
const priceE6Raw = term * sqrtPriceX64 >> 64n;
|
|
3634
3798
|
const decimalDiff = 6 + decimals0 - decimals1;
|
|
3635
3799
|
const adjustedDiff = decimalDiff - 6;
|
|
3636
3800
|
if (adjustedDiff >= 0) {
|
|
@@ -3671,26 +3835,13 @@ function computeMeteoraDlmmPriceE6(data) {
|
|
|
3671
3835
|
`Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`
|
|
3672
3836
|
);
|
|
3673
3837
|
}
|
|
3674
|
-
const MAX_ABS_BIN_ID = 5e5;
|
|
3675
|
-
if (activeId > MAX_ABS_BIN_ID || activeId < -MAX_ABS_BIN_ID) {
|
|
3676
|
-
throw new Error(
|
|
3677
|
-
`Meteora DLMM: activeId ${activeId} exceeds safe range (\xB1${MAX_ABS_BIN_ID})`
|
|
3678
|
-
);
|
|
3679
|
-
}
|
|
3680
3838
|
const SCALE = 1000000000000000000n;
|
|
3681
3839
|
const base = SCALE + BigInt(binStep) * SCALE / 10000n;
|
|
3682
3840
|
const isNeg = activeId < 0;
|
|
3683
3841
|
let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
|
|
3684
3842
|
let result = SCALE;
|
|
3685
3843
|
let b = base;
|
|
3686
|
-
let iterations = 0;
|
|
3687
|
-
const MAX_ITERATIONS = 25;
|
|
3688
3844
|
while (exp > 0n) {
|
|
3689
|
-
if (iterations++ >= MAX_ITERATIONS) {
|
|
3690
|
-
throw new Error(
|
|
3691
|
-
`Meteora DLMM: exponentiation loop exceeded ${MAX_ITERATIONS} iterations (activeId=${activeId})`
|
|
3692
|
-
);
|
|
3693
|
-
}
|
|
3694
3845
|
if (exp & 1n) {
|
|
3695
3846
|
result = result * b / SCALE;
|
|
3696
3847
|
}
|
|
@@ -3721,7 +3872,6 @@ function readU128LE3(dv3, offset) {
|
|
|
3721
3872
|
var CHAINLINK_MIN_SIZE = 224;
|
|
3722
3873
|
var MAX_DECIMALS = 18;
|
|
3723
3874
|
var CHAINLINK_DECIMALS_OFFSET = 138;
|
|
3724
|
-
var CHAINLINK_TIMESTAMP_OFFSET = 168;
|
|
3725
3875
|
var CHAINLINK_ANSWER_OFFSET = 216;
|
|
3726
3876
|
function readU82(data, off) {
|
|
3727
3877
|
return data[off];
|
|
@@ -3729,7 +3879,7 @@ function readU82(data, off) {
|
|
|
3729
3879
|
function readBigInt64LE(data, off) {
|
|
3730
3880
|
return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
|
|
3731
3881
|
}
|
|
3732
|
-
function parseChainlinkPrice(data
|
|
3882
|
+
function parseChainlinkPrice(data) {
|
|
3733
3883
|
if (data.length < CHAINLINK_MIN_SIZE) {
|
|
3734
3884
|
throw new Error(
|
|
3735
3885
|
`Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
|
|
@@ -3747,18 +3897,7 @@ function parseChainlinkPrice(data, options) {
|
|
|
3747
3897
|
`Oracle price is non-positive: ${price}`
|
|
3748
3898
|
);
|
|
3749
3899
|
}
|
|
3750
|
-
|
|
3751
|
-
const updatedAt = Number(updatedAtBig);
|
|
3752
|
-
if (options?.maxStalenessSeconds !== void 0 && updatedAt > 0) {
|
|
3753
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
3754
|
-
const age = now - updatedAt;
|
|
3755
|
-
if (age > options.maxStalenessSeconds) {
|
|
3756
|
-
throw new Error(
|
|
3757
|
-
`Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`
|
|
3758
|
-
);
|
|
3759
|
-
}
|
|
3760
|
-
}
|
|
3761
|
-
return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : void 0 };
|
|
3900
|
+
return { price, decimals };
|
|
3762
3901
|
}
|
|
3763
3902
|
function isValidChainlinkOracle(data) {
|
|
3764
3903
|
try {
|
|
@@ -3778,11 +3917,7 @@ var TOKEN_2022_PROGRAM_ID = new PublicKey8(
|
|
|
3778
3917
|
async function detectTokenProgram(connection, mint) {
|
|
3779
3918
|
const info = await connection.getAccountInfo(mint);
|
|
3780
3919
|
if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
3781
|
-
|
|
3782
|
-
if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;
|
|
3783
|
-
throw new Error(
|
|
3784
|
-
`Mint ${mint.toBase58()} is owned by ${info.owner.toBase58()}, which is neither TOKEN_PROGRAM_ID nor TOKEN_2022_PROGRAM_ID`
|
|
3785
|
-
);
|
|
3920
|
+
return info.owner;
|
|
3786
3921
|
}
|
|
3787
3922
|
function isToken2022(tokenProgramId) {
|
|
3788
3923
|
return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
|
|
@@ -3815,14 +3950,12 @@ var PROGRAM_IDS = {
|
|
|
3815
3950
|
}
|
|
3816
3951
|
};
|
|
3817
3952
|
function getProgramId(network) {
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
return new PublicKey9(override);
|
|
3825
|
-
}
|
|
3953
|
+
const override = safeEnv("PROGRAM_ID");
|
|
3954
|
+
if (override) {
|
|
3955
|
+
console.warn(
|
|
3956
|
+
`[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3957
|
+
);
|
|
3958
|
+
return new PublicKey9(override);
|
|
3826
3959
|
}
|
|
3827
3960
|
const detectedNetwork = getCurrentNetwork();
|
|
3828
3961
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -3830,14 +3963,12 @@ function getProgramId(network) {
|
|
|
3830
3963
|
return new PublicKey9(programId);
|
|
3831
3964
|
}
|
|
3832
3965
|
function getMatcherProgramId(network) {
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
return new PublicKey9(override);
|
|
3840
|
-
}
|
|
3966
|
+
const override = safeEnv("MATCHER_PROGRAM_ID");
|
|
3967
|
+
if (override) {
|
|
3968
|
+
console.warn(
|
|
3969
|
+
`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3970
|
+
);
|
|
3971
|
+
return new PublicKey9(override);
|
|
3841
3972
|
}
|
|
3842
3973
|
const detectedNetwork = getCurrentNetwork();
|
|
3843
3974
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -3870,7 +4001,10 @@ function getStakeProgramId(network) {
|
|
|
3870
4001
|
}
|
|
3871
4002
|
const detectedNetwork = network ?? (() => {
|
|
3872
4003
|
const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? "";
|
|
3873
|
-
|
|
4004
|
+
if (n === "mainnet" || n === "mainnet-beta") return "mainnet";
|
|
4005
|
+
if (n === "devnet") return "devnet";
|
|
4006
|
+
if (typeof window !== "undefined") return "mainnet";
|
|
4007
|
+
return "devnet";
|
|
3874
4008
|
})();
|
|
3875
4009
|
const id = STAKE_PROGRAM_IDS[detectedNetwork];
|
|
3876
4010
|
if (!id) {
|
|
@@ -3880,7 +4014,7 @@ function getStakeProgramId(network) {
|
|
|
3880
4014
|
}
|
|
3881
4015
|
return new PublicKey10(id);
|
|
3882
4016
|
}
|
|
3883
|
-
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.
|
|
4017
|
+
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.devnet);
|
|
3884
4018
|
var STAKE_IX = {
|
|
3885
4019
|
InitPool: 0,
|
|
3886
4020
|
Deposit: 1,
|
|
@@ -3941,9 +4075,6 @@ function readU16LE3(data, off) {
|
|
|
3941
4075
|
);
|
|
3942
4076
|
}
|
|
3943
4077
|
function u64Le(v) {
|
|
3944
|
-
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
3945
|
-
throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
3946
|
-
}
|
|
3947
4078
|
const big = BigInt(v);
|
|
3948
4079
|
if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
|
|
3949
4080
|
if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
|
|
@@ -3952,9 +4083,6 @@ function u64Le(v) {
|
|
|
3952
4083
|
return arr;
|
|
3953
4084
|
}
|
|
3954
4085
|
function u128Le(v) {
|
|
3955
|
-
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
3956
|
-
throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
3957
|
-
}
|
|
3958
4086
|
const big = BigInt(v);
|
|
3959
4087
|
if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
|
|
3960
4088
|
if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
|
|
@@ -3965,7 +4093,7 @@ function u128Le(v) {
|
|
|
3965
4093
|
return arr;
|
|
3966
4094
|
}
|
|
3967
4095
|
function u16Le(v) {
|
|
3968
|
-
if (
|
|
4096
|
+
if (v < 0 || v > 65535) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`);
|
|
3969
4097
|
const arr = new Uint8Array(2);
|
|
3970
4098
|
new DataView(arr.buffer).setUint16(0, v, true);
|
|
3971
4099
|
return arr;
|
|
@@ -4220,9 +4348,7 @@ function computePnlPct(pnl, capital) {
|
|
|
4220
4348
|
}
|
|
4221
4349
|
function isAdlTriggered(slabData) {
|
|
4222
4350
|
const layout = detectSlabLayout(slabData.length);
|
|
4223
|
-
if (!layout)
|
|
4224
|
-
return false;
|
|
4225
|
-
}
|
|
4351
|
+
if (!layout) return false;
|
|
4226
4352
|
try {
|
|
4227
4353
|
const engine = parseEngine(slabData);
|
|
4228
4354
|
if (engine.pnlPosTot === 0n) return false;
|
|
@@ -4265,14 +4391,6 @@ function rankAdlPositions(slabData) {
|
|
|
4265
4391
|
if (account.kind !== 0 /* User */) continue;
|
|
4266
4392
|
if (account.positionSize === 0n) continue;
|
|
4267
4393
|
const side = account.positionSize > 0n ? "long" : "short";
|
|
4268
|
-
if (side === "long" && account.positionSize <= 0n) {
|
|
4269
|
-
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=long but positionSize=${account.positionSize}`);
|
|
4270
|
-
continue;
|
|
4271
|
-
}
|
|
4272
|
-
if (side === "short" && account.positionSize >= 0n) {
|
|
4273
|
-
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=short but positionSize=${account.positionSize}`);
|
|
4274
|
-
continue;
|
|
4275
|
-
}
|
|
4276
4394
|
const pnlPct = computePnlPct(account.pnl, account.capital);
|
|
4277
4395
|
positions.push({
|
|
4278
4396
|
idx,
|
|
@@ -4305,8 +4423,7 @@ function buildAdlInstruction(caller, slab, oracle, programId, targetIdx, backupO
|
|
|
4305
4423
|
`buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`
|
|
4306
4424
|
);
|
|
4307
4425
|
}
|
|
4308
|
-
const
|
|
4309
|
-
const data = Buffer.from(dataBytes);
|
|
4426
|
+
const data = Buffer.from(encodeExecuteAdl({ targetIdx }));
|
|
4310
4427
|
const keys = [
|
|
4311
4428
|
{ pubkey: caller, isSigner: true, isWritable: false },
|
|
4312
4429
|
{ pubkey: slab, isSigner: false, isWritable: true },
|
|
@@ -4346,11 +4463,7 @@ function parseAdlEvent(logs) {
|
|
|
4346
4463
|
}
|
|
4347
4464
|
if (tag !== ADL_EVENT_TAG) continue;
|
|
4348
4465
|
try {
|
|
4349
|
-
const
|
|
4350
|
-
if (targetIdxBig < 0n || targetIdxBig > 65535n) {
|
|
4351
|
-
continue;
|
|
4352
|
-
}
|
|
4353
|
-
const targetIdx = Number(targetIdxBig);
|
|
4466
|
+
const targetIdx = Number(BigInt(match[2]));
|
|
4354
4467
|
const price = BigInt(match[3]);
|
|
4355
4468
|
const closedLo = BigInt(match[4]);
|
|
4356
4469
|
const closedHi = BigInt(match[5]);
|
|
@@ -4378,387 +4491,9 @@ async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
|
|
|
4378
4491
|
);
|
|
4379
4492
|
}
|
|
4380
4493
|
const json = await res.json();
|
|
4381
|
-
if (typeof json !== "object" || json === null) {
|
|
4382
|
-
throw new Error("fetchAdlRankings: API returned non-object response");
|
|
4383
|
-
}
|
|
4384
|
-
const obj = json;
|
|
4385
|
-
if (!Array.isArray(obj.rankings)) {
|
|
4386
|
-
throw new Error("fetchAdlRankings: API response missing rankings array");
|
|
4387
|
-
}
|
|
4388
|
-
for (const entry of obj.rankings) {
|
|
4389
|
-
if (typeof entry !== "object" || entry === null) {
|
|
4390
|
-
throw new Error("fetchAdlRankings: invalid ranking entry (not an object)");
|
|
4391
|
-
}
|
|
4392
|
-
const r = entry;
|
|
4393
|
-
if (typeof r.idx !== "number" || !Number.isInteger(r.idx) || r.idx < 0) {
|
|
4394
|
-
throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);
|
|
4395
|
-
}
|
|
4396
|
-
}
|
|
4397
4494
|
return json;
|
|
4398
4495
|
}
|
|
4399
4496
|
|
|
4400
|
-
// src/solana/rpc-pool.ts
|
|
4401
|
-
import {
|
|
4402
|
-
Connection as Connection5
|
|
4403
|
-
} from "@solana/web3.js";
|
|
4404
|
-
async function checkRpcHealth(endpoint, timeoutMs = 5e3) {
|
|
4405
|
-
const conn = new Connection5(endpoint, { commitment: "processed" });
|
|
4406
|
-
const start = performance.now();
|
|
4407
|
-
const timeout = rejectAfter(timeoutMs, `Health probe timed out after ${timeoutMs}ms`);
|
|
4408
|
-
try {
|
|
4409
|
-
const slot = await Promise.race([
|
|
4410
|
-
conn.getSlot("processed"),
|
|
4411
|
-
timeout.promise
|
|
4412
|
-
]);
|
|
4413
|
-
const latencyMs = Math.round(performance.now() - start);
|
|
4414
|
-
return { endpoint, healthy: true, latencyMs, slot };
|
|
4415
|
-
} catch (err) {
|
|
4416
|
-
const latencyMs = Math.round(performance.now() - start);
|
|
4417
|
-
return {
|
|
4418
|
-
endpoint,
|
|
4419
|
-
healthy: false,
|
|
4420
|
-
latencyMs,
|
|
4421
|
-
slot: 0,
|
|
4422
|
-
error: err instanceof Error ? err.message : String(err)
|
|
4423
|
-
};
|
|
4424
|
-
} finally {
|
|
4425
|
-
timeout.cancel();
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
function resolveRetryConfig(cfg) {
|
|
4429
|
-
if (cfg === false) return null;
|
|
4430
|
-
const c = cfg ?? {};
|
|
4431
|
-
return {
|
|
4432
|
-
maxRetries: c.maxRetries ?? 3,
|
|
4433
|
-
baseDelayMs: c.baseDelayMs ?? 500,
|
|
4434
|
-
maxDelayMs: c.maxDelayMs ?? 1e4,
|
|
4435
|
-
jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),
|
|
4436
|
-
retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504]
|
|
4437
|
-
};
|
|
4438
|
-
}
|
|
4439
|
-
function normalizeEndpoint(ep) {
|
|
4440
|
-
if (typeof ep === "string") return { url: ep };
|
|
4441
|
-
return ep;
|
|
4442
|
-
}
|
|
4443
|
-
function endpointLabel(ep) {
|
|
4444
|
-
if (ep.label) return ep.label;
|
|
4445
|
-
try {
|
|
4446
|
-
return new URL(ep.url).hostname;
|
|
4447
|
-
} catch {
|
|
4448
|
-
return ep.url.slice(0, 40);
|
|
4449
|
-
}
|
|
4450
|
-
}
|
|
4451
|
-
function isRetryable(err, codes) {
|
|
4452
|
-
if (!err) return false;
|
|
4453
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
4454
|
-
for (const code of codes) {
|
|
4455
|
-
if (msg.includes(String(code))) return true;
|
|
4456
|
-
}
|
|
4457
|
-
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")) {
|
|
4458
|
-
return true;
|
|
4459
|
-
}
|
|
4460
|
-
return false;
|
|
4461
|
-
}
|
|
4462
|
-
function computeDelay(attempt, config) {
|
|
4463
|
-
const raw = Math.min(
|
|
4464
|
-
config.baseDelayMs * Math.pow(2, attempt),
|
|
4465
|
-
config.maxDelayMs
|
|
4466
|
-
);
|
|
4467
|
-
const jitter = Math.floor(Math.random() * raw * config.jitterFactor);
|
|
4468
|
-
return raw + jitter;
|
|
4469
|
-
}
|
|
4470
|
-
function rejectAfter(ms, message) {
|
|
4471
|
-
let timer;
|
|
4472
|
-
const promise = new Promise((_, reject) => {
|
|
4473
|
-
timer = setTimeout(() => reject(new Error(message)), ms);
|
|
4474
|
-
});
|
|
4475
|
-
return { promise, cancel: () => clearTimeout(timer) };
|
|
4476
|
-
}
|
|
4477
|
-
function sleep(ms) {
|
|
4478
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4479
|
-
}
|
|
4480
|
-
function redactUrl(raw) {
|
|
4481
|
-
try {
|
|
4482
|
-
const u = new URL(raw);
|
|
4483
|
-
const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;
|
|
4484
|
-
for (const k of [...u.searchParams.keys()]) {
|
|
4485
|
-
if (sensitive.test(k)) {
|
|
4486
|
-
u.searchParams.set(k, "***");
|
|
4487
|
-
}
|
|
4488
|
-
}
|
|
4489
|
-
return u.toString();
|
|
4490
|
-
} catch {
|
|
4491
|
-
return raw;
|
|
4492
|
-
}
|
|
4493
|
-
}
|
|
4494
|
-
var RpcPool = class _RpcPool {
|
|
4495
|
-
endpoints;
|
|
4496
|
-
strategy;
|
|
4497
|
-
retryConfig;
|
|
4498
|
-
requestTimeoutMs;
|
|
4499
|
-
verbose;
|
|
4500
|
-
/** Round-robin index tracker. */
|
|
4501
|
-
rrIndex = 0;
|
|
4502
|
-
/** Consecutive failure threshold before marking an endpoint unhealthy. */
|
|
4503
|
-
static UNHEALTHY_THRESHOLD = 3;
|
|
4504
|
-
/** Minimum endpoints before auto-recovery is attempted. */
|
|
4505
|
-
static MIN_HEALTHY = 1;
|
|
4506
|
-
constructor(config) {
|
|
4507
|
-
if (!config.endpoints || config.endpoints.length === 0) {
|
|
4508
|
-
throw new Error("RpcPool: at least one endpoint is required");
|
|
4509
|
-
}
|
|
4510
|
-
this.strategy = config.strategy ?? "failover";
|
|
4511
|
-
this.retryConfig = resolveRetryConfig(config.retry);
|
|
4512
|
-
this.requestTimeoutMs = config.requestTimeoutMs ?? 3e4;
|
|
4513
|
-
this.verbose = config.verbose ?? true;
|
|
4514
|
-
const commitment = config.commitment ?? "confirmed";
|
|
4515
|
-
this.endpoints = config.endpoints.map((raw) => {
|
|
4516
|
-
const ep = normalizeEndpoint(raw);
|
|
4517
|
-
const connConfig = {
|
|
4518
|
-
commitment,
|
|
4519
|
-
...ep.connectionConfig
|
|
4520
|
-
};
|
|
4521
|
-
return {
|
|
4522
|
-
config: ep,
|
|
4523
|
-
connection: new Connection5(ep.url, connConfig),
|
|
4524
|
-
label: endpointLabel(ep),
|
|
4525
|
-
weight: Math.max(1, ep.weight ?? 1),
|
|
4526
|
-
failures: 0,
|
|
4527
|
-
healthy: true,
|
|
4528
|
-
lastLatencyMs: -1
|
|
4529
|
-
};
|
|
4530
|
-
});
|
|
4531
|
-
}
|
|
4532
|
-
// -----------------------------------------------------------------------
|
|
4533
|
-
// Public API
|
|
4534
|
-
// -----------------------------------------------------------------------
|
|
4535
|
-
/**
|
|
4536
|
-
* Execute a function against a pooled connection with automatic retry
|
|
4537
|
-
* and failover.
|
|
4538
|
-
*
|
|
4539
|
-
* @param fn - Async function that receives a `Connection` and returns a result.
|
|
4540
|
-
* @returns The result of `fn`.
|
|
4541
|
-
* @throws The last error if all retries and failovers are exhausted.
|
|
4542
|
-
*
|
|
4543
|
-
* @example
|
|
4544
|
-
* ```ts
|
|
4545
|
-
* const balance = await pool.call(c => c.getBalance(pubkey));
|
|
4546
|
-
* const markets = await pool.call(c => discoverMarkets(c, programId, opts));
|
|
4547
|
-
* ```
|
|
4548
|
-
*/
|
|
4549
|
-
async call(fn) {
|
|
4550
|
-
const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;
|
|
4551
|
-
let lastError;
|
|
4552
|
-
const triedEndpoints = /* @__PURE__ */ new Set();
|
|
4553
|
-
const maxTotalIterations = maxAttempts + this.endpoints.length;
|
|
4554
|
-
let totalIterations = 0;
|
|
4555
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4556
|
-
if (++totalIterations > maxTotalIterations) break;
|
|
4557
|
-
const epIdx = this.selectEndpoint(triedEndpoints);
|
|
4558
|
-
if (epIdx === -1) {
|
|
4559
|
-
break;
|
|
4560
|
-
}
|
|
4561
|
-
const ep = this.endpoints[epIdx];
|
|
4562
|
-
const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);
|
|
4563
|
-
try {
|
|
4564
|
-
const result = await Promise.race([
|
|
4565
|
-
fn(ep.connection),
|
|
4566
|
-
timeout.promise
|
|
4567
|
-
]);
|
|
4568
|
-
timeout.cancel();
|
|
4569
|
-
ep.failures = 0;
|
|
4570
|
-
ep.healthy = true;
|
|
4571
|
-
return result;
|
|
4572
|
-
} catch (err) {
|
|
4573
|
-
timeout.cancel();
|
|
4574
|
-
lastError = err;
|
|
4575
|
-
ep.failures++;
|
|
4576
|
-
if (ep.failures >= _RpcPool.UNHEALTHY_THRESHOLD) {
|
|
4577
|
-
ep.healthy = false;
|
|
4578
|
-
if (this.verbose) {
|
|
4579
|
-
console.warn(
|
|
4580
|
-
`[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`
|
|
4581
|
-
);
|
|
4582
|
-
}
|
|
4583
|
-
}
|
|
4584
|
-
const retryable = this.retryConfig ? isRetryable(err, this.retryConfig.retryableStatusCodes) : false;
|
|
4585
|
-
if (!retryable) {
|
|
4586
|
-
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4587
|
-
triedEndpoints.add(epIdx);
|
|
4588
|
-
attempt--;
|
|
4589
|
-
if (triedEndpoints.size >= this.endpoints.length) break;
|
|
4590
|
-
continue;
|
|
4591
|
-
}
|
|
4592
|
-
throw err;
|
|
4593
|
-
}
|
|
4594
|
-
if (this.verbose) {
|
|
4595
|
-
console.warn(
|
|
4596
|
-
`[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,
|
|
4597
|
-
err instanceof Error ? err.message : err
|
|
4598
|
-
);
|
|
4599
|
-
}
|
|
4600
|
-
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4601
|
-
triedEndpoints.add(epIdx);
|
|
4602
|
-
}
|
|
4603
|
-
if (attempt < maxAttempts - 1 && this.retryConfig) {
|
|
4604
|
-
const delay = computeDelay(attempt, this.retryConfig);
|
|
4605
|
-
await sleep(delay);
|
|
4606
|
-
}
|
|
4607
|
-
}
|
|
4608
|
-
}
|
|
4609
|
-
this.maybeRecoverEndpoints();
|
|
4610
|
-
throw lastError ?? new Error("RpcPool: all endpoints exhausted");
|
|
4611
|
-
}
|
|
4612
|
-
/**
|
|
4613
|
-
* Get a raw `Connection` from the current preferred endpoint.
|
|
4614
|
-
* Useful when you need to pass a Connection to external code.
|
|
4615
|
-
*
|
|
4616
|
-
* NOTE: This bypasses retry and failover logic. Prefer `call()`.
|
|
4617
|
-
*
|
|
4618
|
-
* @returns Solana Connection from the current preferred endpoint.
|
|
4619
|
-
*
|
|
4620
|
-
* @example
|
|
4621
|
-
* ```ts
|
|
4622
|
-
* const conn = pool.getConnection();
|
|
4623
|
-
* const balance = await conn.getBalance(pubkey);
|
|
4624
|
-
* ```
|
|
4625
|
-
*/
|
|
4626
|
-
getConnection() {
|
|
4627
|
-
const idx = this.selectEndpoint();
|
|
4628
|
-
if (idx === -1) {
|
|
4629
|
-
this.maybeRecoverEndpoints();
|
|
4630
|
-
return this.endpoints[0].connection;
|
|
4631
|
-
}
|
|
4632
|
-
return this.endpoints[idx].connection;
|
|
4633
|
-
}
|
|
4634
|
-
/**
|
|
4635
|
-
* Run a health check against all endpoints in the pool.
|
|
4636
|
-
*
|
|
4637
|
-
* @param timeoutMs - Per-endpoint probe timeout (default: 5000)
|
|
4638
|
-
* @returns Array of health results, one per endpoint.
|
|
4639
|
-
*
|
|
4640
|
-
* @example
|
|
4641
|
-
* ```ts
|
|
4642
|
-
* const results = await pool.healthCheck();
|
|
4643
|
-
* for (const r of results) {
|
|
4644
|
-
* console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);
|
|
4645
|
-
* }
|
|
4646
|
-
* ```
|
|
4647
|
-
*/
|
|
4648
|
-
async healthCheck(timeoutMs = 5e3) {
|
|
4649
|
-
const results = await Promise.all(
|
|
4650
|
-
this.endpoints.map(async (ep) => {
|
|
4651
|
-
const result = await checkRpcHealth(ep.config.url, timeoutMs);
|
|
4652
|
-
ep.lastLatencyMs = result.latencyMs;
|
|
4653
|
-
ep.healthy = result.healthy;
|
|
4654
|
-
if (result.healthy) ep.failures = 0;
|
|
4655
|
-
result.endpoint = redactUrl(result.endpoint);
|
|
4656
|
-
return result;
|
|
4657
|
-
})
|
|
4658
|
-
);
|
|
4659
|
-
return results;
|
|
4660
|
-
}
|
|
4661
|
-
/**
|
|
4662
|
-
* Get the number of endpoints in the pool.
|
|
4663
|
-
*/
|
|
4664
|
-
get size() {
|
|
4665
|
-
return this.endpoints.length;
|
|
4666
|
-
}
|
|
4667
|
-
/**
|
|
4668
|
-
* Get the number of currently healthy endpoints.
|
|
4669
|
-
*/
|
|
4670
|
-
get healthyCount() {
|
|
4671
|
-
return this.endpoints.filter((ep) => ep.healthy).length;
|
|
4672
|
-
}
|
|
4673
|
-
/**
|
|
4674
|
-
* Get endpoint labels and their current status.
|
|
4675
|
-
*
|
|
4676
|
-
* @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.
|
|
4677
|
-
*/
|
|
4678
|
-
status() {
|
|
4679
|
-
return this.endpoints.map((ep) => ({
|
|
4680
|
-
label: ep.label,
|
|
4681
|
-
url: redactUrl(ep.config.url),
|
|
4682
|
-
healthy: ep.healthy,
|
|
4683
|
-
failures: ep.failures,
|
|
4684
|
-
lastLatencyMs: ep.lastLatencyMs
|
|
4685
|
-
}));
|
|
4686
|
-
}
|
|
4687
|
-
// -----------------------------------------------------------------------
|
|
4688
|
-
// Internals
|
|
4689
|
-
// -----------------------------------------------------------------------
|
|
4690
|
-
/**
|
|
4691
|
-
* Select the next endpoint based on strategy.
|
|
4692
|
-
* Returns -1 if no endpoint is available.
|
|
4693
|
-
*/
|
|
4694
|
-
selectEndpoint(exclude) {
|
|
4695
|
-
const healthy = this.endpoints.map((ep, i) => ({ ep, i })).filter(({ ep, i }) => ep.healthy && !exclude?.has(i));
|
|
4696
|
-
if (healthy.length === 0) {
|
|
4697
|
-
const remaining = this.endpoints.map((_, i) => i).filter((i) => !exclude?.has(i));
|
|
4698
|
-
return remaining.length > 0 ? remaining[0] : -1;
|
|
4699
|
-
}
|
|
4700
|
-
if (this.strategy === "failover") {
|
|
4701
|
-
return healthy[0].i;
|
|
4702
|
-
}
|
|
4703
|
-
const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);
|
|
4704
|
-
this.rrIndex = (this.rrIndex + 1) % totalWeight;
|
|
4705
|
-
let cumulative = 0;
|
|
4706
|
-
for (const { ep, i } of healthy) {
|
|
4707
|
-
cumulative += ep.weight;
|
|
4708
|
-
if (this.rrIndex < cumulative) return i;
|
|
4709
|
-
}
|
|
4710
|
-
return healthy[healthy.length - 1].i;
|
|
4711
|
-
}
|
|
4712
|
-
/**
|
|
4713
|
-
* If all endpoints are unhealthy, reset them so we at least try again.
|
|
4714
|
-
*/
|
|
4715
|
-
maybeRecoverEndpoints() {
|
|
4716
|
-
const healthyCount = this.endpoints.filter((ep) => ep.healthy).length;
|
|
4717
|
-
if (healthyCount < _RpcPool.MIN_HEALTHY) {
|
|
4718
|
-
if (this.verbose) {
|
|
4719
|
-
console.warn("[RpcPool] All endpoints unhealthy \u2014 resetting for recovery");
|
|
4720
|
-
}
|
|
4721
|
-
for (const ep of this.endpoints) {
|
|
4722
|
-
ep.healthy = true;
|
|
4723
|
-
ep.failures = 0;
|
|
4724
|
-
}
|
|
4725
|
-
}
|
|
4726
|
-
}
|
|
4727
|
-
};
|
|
4728
|
-
async function withRetry(fn, config) {
|
|
4729
|
-
const resolved = resolveRetryConfig(config) ?? {
|
|
4730
|
-
maxRetries: 3,
|
|
4731
|
-
baseDelayMs: 500,
|
|
4732
|
-
maxDelayMs: 1e4,
|
|
4733
|
-
jitterFactor: 0.25,
|
|
4734
|
-
retryableStatusCodes: [429, 502, 503, 504]
|
|
4735
|
-
};
|
|
4736
|
-
let lastError;
|
|
4737
|
-
const maxAttempts = resolved.maxRetries + 1;
|
|
4738
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4739
|
-
try {
|
|
4740
|
-
return await fn();
|
|
4741
|
-
} catch (err) {
|
|
4742
|
-
lastError = err;
|
|
4743
|
-
if (!isRetryable(err, resolved.retryableStatusCodes)) {
|
|
4744
|
-
throw err;
|
|
4745
|
-
}
|
|
4746
|
-
if (attempt < maxAttempts - 1) {
|
|
4747
|
-
const delay = computeDelay(attempt, resolved);
|
|
4748
|
-
await sleep(delay);
|
|
4749
|
-
}
|
|
4750
|
-
}
|
|
4751
|
-
}
|
|
4752
|
-
throw lastError ?? new Error("withRetry: all attempts exhausted");
|
|
4753
|
-
}
|
|
4754
|
-
var _internal = {
|
|
4755
|
-
isRetryable,
|
|
4756
|
-
computeDelay,
|
|
4757
|
-
resolveRetryConfig,
|
|
4758
|
-
normalizeEndpoint,
|
|
4759
|
-
endpointLabel
|
|
4760
|
-
};
|
|
4761
|
-
|
|
4762
4497
|
// src/runtime/tx.ts
|
|
4763
4498
|
import {
|
|
4764
4499
|
TransactionInstruction as TransactionInstruction2,
|
|
@@ -4910,139 +4645,6 @@ function formatResult(result, jsonMode) {
|
|
|
4910
4645
|
return lines.join("\n");
|
|
4911
4646
|
}
|
|
4912
4647
|
|
|
4913
|
-
// src/runtime/lighthouse.ts
|
|
4914
|
-
import { PublicKey as PublicKey13, Transaction as Transaction2 } from "@solana/web3.js";
|
|
4915
|
-
var LIGHTHOUSE_PROGRAM_ID = new PublicKey13(
|
|
4916
|
-
"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"
|
|
4917
|
-
);
|
|
4918
|
-
var LIGHTHOUSE_PROGRAM_ID_STR2 = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
4919
|
-
var LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
|
|
4920
|
-
var LIGHTHOUSE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
4921
|
-
6e3,
|
|
4922
|
-
// InstructionMissing
|
|
4923
|
-
6001,
|
|
4924
|
-
// InstructionFallbackNotFound
|
|
4925
|
-
6002,
|
|
4926
|
-
// InstructionDidNotDeserialize
|
|
4927
|
-
6003,
|
|
4928
|
-
// InstructionDidNotSerialize
|
|
4929
|
-
6016,
|
|
4930
|
-
// IdlInstructionStub
|
|
4931
|
-
6032,
|
|
4932
|
-
// ConstraintMut
|
|
4933
|
-
6033,
|
|
4934
|
-
// ConstraintHasOne
|
|
4935
|
-
6034,
|
|
4936
|
-
// ConstraintSigner
|
|
4937
|
-
6035,
|
|
4938
|
-
// ConstraintRaw
|
|
4939
|
-
6036,
|
|
4940
|
-
// ConstraintOwner
|
|
4941
|
-
6037,
|
|
4942
|
-
// ConstraintRentExempt
|
|
4943
|
-
6038,
|
|
4944
|
-
// ConstraintSeeds
|
|
4945
|
-
6039,
|
|
4946
|
-
// ConstraintExecutable
|
|
4947
|
-
6040,
|
|
4948
|
-
// ConstraintState
|
|
4949
|
-
6041,
|
|
4950
|
-
// ConstraintAssociated
|
|
4951
|
-
6042,
|
|
4952
|
-
// ConstraintAssociatedInit
|
|
4953
|
-
6043,
|
|
4954
|
-
// ConstraintClose
|
|
4955
|
-
6400
|
|
4956
|
-
// ConstraintAddress (the one we hit most often)
|
|
4957
|
-
]);
|
|
4958
|
-
function isLighthouseInstruction(ix) {
|
|
4959
|
-
return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);
|
|
4960
|
-
}
|
|
4961
|
-
function isLighthouseError(error) {
|
|
4962
|
-
const msg = extractErrorMessage(error);
|
|
4963
|
-
if (!msg) return false;
|
|
4964
|
-
if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR2)) return true;
|
|
4965
|
-
if (/custom\s+program\s+error:\s*0x1900\b/i.test(msg)) return true;
|
|
4966
|
-
if (/"Custom"\s*:\s*6400\b/.test(msg) && /InstructionError/i.test(msg)) return true;
|
|
4967
|
-
return false;
|
|
4968
|
-
}
|
|
4969
|
-
function isLighthouseFailureInLogs(logs) {
|
|
4970
|
-
if (!Array.isArray(logs)) return false;
|
|
4971
|
-
let insideLighthouse = false;
|
|
4972
|
-
for (const line of logs) {
|
|
4973
|
-
if (typeof line !== "string") continue;
|
|
4974
|
-
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} invoke`)) {
|
|
4975
|
-
insideLighthouse = true;
|
|
4976
|
-
continue;
|
|
4977
|
-
}
|
|
4978
|
-
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} success`)) {
|
|
4979
|
-
insideLighthouse = false;
|
|
4980
|
-
continue;
|
|
4981
|
-
}
|
|
4982
|
-
if (insideLighthouse && /failed/i.test(line)) {
|
|
4983
|
-
return true;
|
|
4984
|
-
}
|
|
4985
|
-
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} failed`)) {
|
|
4986
|
-
return true;
|
|
4987
|
-
}
|
|
4988
|
-
}
|
|
4989
|
-
return false;
|
|
4990
|
-
}
|
|
4991
|
-
function stripLighthouseInstructions(instructions, percolatorProgramId) {
|
|
4992
|
-
if (percolatorProgramId) {
|
|
4993
|
-
const hasPercolatorIx = instructions.some(
|
|
4994
|
-
(ix) => ix.programId.equals(percolatorProgramId)
|
|
4995
|
-
);
|
|
4996
|
-
if (!hasPercolatorIx) {
|
|
4997
|
-
return instructions;
|
|
4998
|
-
}
|
|
4999
|
-
}
|
|
5000
|
-
return instructions.filter((ix) => !isLighthouseInstruction(ix));
|
|
5001
|
-
}
|
|
5002
|
-
function stripLighthouseFromTransaction(transaction, percolatorProgramId) {
|
|
5003
|
-
if (percolatorProgramId) {
|
|
5004
|
-
const hasPercolatorIx = transaction.instructions.some(
|
|
5005
|
-
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5006
|
-
);
|
|
5007
|
-
if (!hasPercolatorIx) return transaction;
|
|
5008
|
-
}
|
|
5009
|
-
const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);
|
|
5010
|
-
if (!hasLighthouse) return transaction;
|
|
5011
|
-
const clean = new Transaction2();
|
|
5012
|
-
clean.recentBlockhash = transaction.recentBlockhash;
|
|
5013
|
-
clean.feePayer = transaction.feePayer;
|
|
5014
|
-
for (const ix of transaction.instructions) {
|
|
5015
|
-
if (!isLighthouseInstruction(ix)) {
|
|
5016
|
-
clean.add(ix);
|
|
5017
|
-
}
|
|
5018
|
-
}
|
|
5019
|
-
return clean;
|
|
5020
|
-
}
|
|
5021
|
-
function countLighthouseInstructions(ixsOrTx) {
|
|
5022
|
-
const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;
|
|
5023
|
-
return instructions.filter(isLighthouseInstruction).length;
|
|
5024
|
-
}
|
|
5025
|
-
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";
|
|
5026
|
-
function classifyLighthouseError(error) {
|
|
5027
|
-
if (isLighthouseError(error)) {
|
|
5028
|
-
return LIGHTHOUSE_USER_MESSAGE;
|
|
5029
|
-
}
|
|
5030
|
-
return null;
|
|
5031
|
-
}
|
|
5032
|
-
function extractErrorMessage(error) {
|
|
5033
|
-
if (!error) return null;
|
|
5034
|
-
if (typeof error === "string") return error;
|
|
5035
|
-
if (error instanceof Error) return error.message;
|
|
5036
|
-
if (typeof error === "object" && "message" in error) {
|
|
5037
|
-
return String(error.message);
|
|
5038
|
-
}
|
|
5039
|
-
try {
|
|
5040
|
-
return JSON.stringify(error);
|
|
5041
|
-
} catch {
|
|
5042
|
-
return null;
|
|
5043
|
-
}
|
|
5044
|
-
}
|
|
5045
|
-
|
|
5046
4648
|
// src/math/trading.ts
|
|
5047
4649
|
function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
|
|
5048
4650
|
if (positionSize === 0n || oraclePrice === 0n) return 0n;
|
|
@@ -5067,10 +4669,16 @@ function computeLiqPrice(entryPrice, capital, positionSize, maintenanceMarginBps
|
|
|
5067
4669
|
function computePreTradeLiqPrice(oracleE6, margin, posSize, maintBps, feeBps, direction) {
|
|
5068
4670
|
if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;
|
|
5069
4671
|
const absPos = posSize < 0n ? -posSize : posSize;
|
|
5070
|
-
const fee = absPos * feeBps / 10000n;
|
|
5071
|
-
const effectiveCapital = margin > fee ? margin - fee : 0n;
|
|
5072
4672
|
const signedPos = direction === "long" ? absPos : -absPos;
|
|
5073
|
-
|
|
4673
|
+
const feeAdjust = oracleE6 * feeBps / 10000n;
|
|
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);
|
|
5074
4682
|
}
|
|
5075
4683
|
function computeTradingFee(notional, tradingFeeBps) {
|
|
5076
4684
|
return notional * tradingFeeBps / 10000n;
|
|
@@ -5090,20 +4698,9 @@ function computeFeeSplit(totalFee, config) {
|
|
|
5090
4698
|
if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
|
|
5091
4699
|
return [totalFee, 0n, 0n];
|
|
5092
4700
|
}
|
|
5093
|
-
const totalBps = config.lpBps + config.protocolBps + config.creatorBps;
|
|
5094
|
-
if (totalBps !== 10000n) {
|
|
5095
|
-
throw new Error(
|
|
5096
|
-
`Fee split must equal exactly 10000 bps (100%): lpBps=${config.lpBps} + protocolBps=${config.protocolBps} + creatorBps=${config.creatorBps} = ${totalBps}`
|
|
5097
|
-
);
|
|
5098
|
-
}
|
|
5099
4701
|
const lp = totalFee * config.lpBps / 10000n;
|
|
5100
4702
|
const protocol = totalFee * config.protocolBps / 10000n;
|
|
5101
4703
|
const creator = totalFee - lp - protocol;
|
|
5102
|
-
if (creator < 0n) {
|
|
5103
|
-
throw new Error(
|
|
5104
|
-
`Internal error: creator fee is negative (${creator}). This should not happen if lpBps + protocolBps + creatorBps === 10000.`
|
|
5105
|
-
);
|
|
5106
|
-
}
|
|
5107
4704
|
return [lp, protocol, creator];
|
|
5108
4705
|
}
|
|
5109
4706
|
function computePnlPercent(pnlTokens, capital) {
|
|
@@ -5118,17 +4715,10 @@ function computePnlPercent(pnlTokens, capital) {
|
|
|
5118
4715
|
}
|
|
5119
4716
|
function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
|
|
5120
4717
|
if (oracleE6 === 0n) return 0n;
|
|
5121
|
-
if (tradingFeeBps < 0n) {
|
|
5122
|
-
throw new Error(`computeEstimatedEntryPrice: tradingFeeBps must be non-negative, got ${tradingFeeBps}`);
|
|
5123
|
-
}
|
|
5124
4718
|
const feeImpact = oracleE6 * tradingFeeBps / 10000n;
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
`computeEstimatedEntryPrice: result ${result} is non-positive (tradingFeeBps=${tradingFeeBps} too high for oracle=${oracleE6})`
|
|
5129
|
-
);
|
|
5130
|
-
}
|
|
5131
|
-
return result;
|
|
4719
|
+
if (direction === "long") return oracleE6 + feeImpact;
|
|
4720
|
+
const shortEntry = oracleE6 - feeImpact;
|
|
4721
|
+
return shortEntry > 0n ? shortEntry : 1n;
|
|
5132
4722
|
}
|
|
5133
4723
|
var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
5134
4724
|
var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
|
|
@@ -5149,12 +4739,7 @@ function computeMaxLeverage(initialMarginBps) {
|
|
|
5149
4739
|
if (initialMarginBps <= 0n) {
|
|
5150
4740
|
throw new Error("computeMaxLeverage: initialMarginBps must be positive");
|
|
5151
4741
|
}
|
|
5152
|
-
|
|
5153
|
-
return Number(scaledResult) / 1e6;
|
|
5154
|
-
}
|
|
5155
|
-
function computeMaxWithdrawable(capital, pnl, reservedPnl) {
|
|
5156
|
-
const maturedPnl = pnl - reservedPnl;
|
|
5157
|
-
return capital + (maturedPnl > 0n ? maturedPnl : 0n);
|
|
4742
|
+
return Number(10000n / initialMarginBps);
|
|
5158
4743
|
}
|
|
5159
4744
|
|
|
5160
4745
|
// src/math/warmup.ts
|
|
@@ -5166,9 +4751,6 @@ function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot
|
|
|
5166
4751
|
return totalCapital * elapsed / warmupPeriodSlots;
|
|
5167
4752
|
}
|
|
5168
4753
|
function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
5169
|
-
if (initialMarginBps <= 0n) {
|
|
5170
|
-
throw new Error("computeWarmupLeverageCap: initialMarginBps must be positive");
|
|
5171
|
-
}
|
|
5172
4754
|
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
5173
4755
|
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
|
|
5174
4756
|
if (totalCapital <= 0n) return 1;
|
|
@@ -5179,14 +4761,7 @@ function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, w
|
|
|
5179
4761
|
warmupPeriodSlots
|
|
5180
4762
|
);
|
|
5181
4763
|
if (unlocked <= 0n) return 1;
|
|
5182
|
-
const
|
|
5183
|
-
if (scaledResult > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5184
|
-
console.warn(
|
|
5185
|
-
`[computeWarmupLeverageCap] Warning: effective leverage ${scaledResult} exceeds MAX_SAFE_INTEGER, returning MAX_SAFE_INTEGER as a safety bound`
|
|
5186
|
-
);
|
|
5187
|
-
return Number.MAX_SAFE_INTEGER;
|
|
5188
|
-
}
|
|
5189
|
-
const effectiveLev = Number(scaledResult);
|
|
4764
|
+
const effectiveLev = Number(BigInt(maxLev) * unlocked / totalCapital);
|
|
5190
4765
|
return Math.max(1, effectiveLev);
|
|
5191
4766
|
}
|
|
5192
4767
|
function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
@@ -5199,41 +4774,10 @@ function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlo
|
|
|
5199
4774
|
);
|
|
5200
4775
|
return unlocked * BigInt(maxLev);
|
|
5201
4776
|
}
|
|
5202
|
-
function computeWarmupProgress(currentSlot, warmupStartedAtSlot, warmupPeriodSlots, pnl, reservedPnl) {
|
|
5203
|
-
if (warmupPeriodSlots === 0n || warmupStartedAtSlot === 0n) {
|
|
5204
|
-
return {
|
|
5205
|
-
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5206
|
-
reservedPnl: 0n,
|
|
5207
|
-
progressBps: 10000n,
|
|
5208
|
-
// 100%
|
|
5209
|
-
slotsRemaining: 0n
|
|
5210
|
-
};
|
|
5211
|
-
}
|
|
5212
|
-
const elapsed = currentSlot >= warmupStartedAtSlot ? currentSlot - warmupStartedAtSlot : 0n;
|
|
5213
|
-
if (elapsed >= warmupPeriodSlots) {
|
|
5214
|
-
return {
|
|
5215
|
-
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5216
|
-
reservedPnl: 0n,
|
|
5217
|
-
progressBps: 10000n,
|
|
5218
|
-
// 100%
|
|
5219
|
-
slotsRemaining: 0n
|
|
5220
|
-
};
|
|
5221
|
-
}
|
|
5222
|
-
const progressBps = elapsed * 10000n / warmupPeriodSlots;
|
|
5223
|
-
const slotsRemaining = warmupPeriodSlots - elapsed;
|
|
5224
|
-
const maturedPnl = pnl > 0n ? pnl * progressBps / 10000n : 0n;
|
|
5225
|
-
const locked = reservedPnl > 0n ? reservedPnl : 0n;
|
|
5226
|
-
return {
|
|
5227
|
-
maturedPnl,
|
|
5228
|
-
reservedPnl: locked,
|
|
5229
|
-
progressBps,
|
|
5230
|
-
slotsRemaining
|
|
5231
|
-
};
|
|
5232
|
-
}
|
|
5233
4777
|
|
|
5234
4778
|
// src/validation.ts
|
|
5235
|
-
import { PublicKey as
|
|
5236
|
-
var
|
|
4779
|
+
import { PublicKey as PublicKey13 } from "@solana/web3.js";
|
|
4780
|
+
var U16_MAX2 = 65535;
|
|
5237
4781
|
var U64_MAX = BigInt("18446744073709551615");
|
|
5238
4782
|
var I64_MIN = BigInt("-9223372036854775808");
|
|
5239
4783
|
var I64_MAX = BigInt("9223372036854775807");
|
|
@@ -5262,7 +4806,7 @@ var ValidationError = class extends Error {
|
|
|
5262
4806
|
};
|
|
5263
4807
|
function validatePublicKey(value, field) {
|
|
5264
4808
|
try {
|
|
5265
|
-
return new
|
|
4809
|
+
return new PublicKey13(value);
|
|
5266
4810
|
} catch {
|
|
5267
4811
|
throw new ValidationError(
|
|
5268
4812
|
field,
|
|
@@ -5273,26 +4817,24 @@ function validatePublicKey(value, field) {
|
|
|
5273
4817
|
function validateIndex(value, field) {
|
|
5274
4818
|
const t = requireDecimalUIntString(value, field);
|
|
5275
4819
|
const bi = BigInt(t);
|
|
5276
|
-
if (bi > BigInt(
|
|
4820
|
+
if (bi > BigInt(U16_MAX2)) {
|
|
5277
4821
|
throw new ValidationError(
|
|
5278
4822
|
field,
|
|
5279
|
-
`must be <= ${
|
|
4823
|
+
`must be <= ${U16_MAX2} (u16 max), got ${t}`
|
|
5280
4824
|
);
|
|
5281
4825
|
}
|
|
5282
|
-
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5283
|
-
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5284
|
-
}
|
|
5285
4826
|
return Number(bi);
|
|
5286
4827
|
}
|
|
5287
4828
|
function validateAmount(value, field) {
|
|
5288
|
-
|
|
5289
|
-
|
|
4829
|
+
let num;
|
|
4830
|
+
try {
|
|
4831
|
+
num = BigInt(value);
|
|
4832
|
+
} catch {
|
|
5290
4833
|
throw new ValidationError(
|
|
5291
4834
|
field,
|
|
5292
|
-
`"${value}" is not a valid
|
|
4835
|
+
`"${value}" is not a valid number. Use decimal digits only.`
|
|
5293
4836
|
);
|
|
5294
4837
|
}
|
|
5295
|
-
const num = BigInt(t);
|
|
5296
4838
|
if (num < 0n) {
|
|
5297
4839
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
5298
4840
|
}
|
|
@@ -5305,14 +4847,15 @@ function validateAmount(value, field) {
|
|
|
5305
4847
|
return num;
|
|
5306
4848
|
}
|
|
5307
4849
|
function validateU128(value, field) {
|
|
5308
|
-
|
|
5309
|
-
|
|
4850
|
+
let num;
|
|
4851
|
+
try {
|
|
4852
|
+
num = BigInt(value);
|
|
4853
|
+
} catch {
|
|
5310
4854
|
throw new ValidationError(
|
|
5311
4855
|
field,
|
|
5312
|
-
`"${value}" is not a valid
|
|
4856
|
+
`"${value}" is not a valid number. Use decimal digits only.`
|
|
5313
4857
|
);
|
|
5314
4858
|
}
|
|
5315
|
-
const num = BigInt(t);
|
|
5316
4859
|
if (num < 0n) {
|
|
5317
4860
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
5318
4861
|
}
|
|
@@ -5325,14 +4868,15 @@ function validateU128(value, field) {
|
|
|
5325
4868
|
return num;
|
|
5326
4869
|
}
|
|
5327
4870
|
function validateI64(value, field) {
|
|
5328
|
-
|
|
5329
|
-
|
|
4871
|
+
let num;
|
|
4872
|
+
try {
|
|
4873
|
+
num = BigInt(value);
|
|
4874
|
+
} catch {
|
|
5330
4875
|
throw new ValidationError(
|
|
5331
4876
|
field,
|
|
5332
|
-
`"${value}" is not a valid
|
|
4877
|
+
`"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
|
|
5333
4878
|
);
|
|
5334
4879
|
}
|
|
5335
|
-
const num = BigInt(t);
|
|
5336
4880
|
if (num < I64_MIN) {
|
|
5337
4881
|
throw new ValidationError(
|
|
5338
4882
|
field,
|
|
@@ -5348,14 +4892,15 @@ function validateI64(value, field) {
|
|
|
5348
4892
|
return num;
|
|
5349
4893
|
}
|
|
5350
4894
|
function validateI128(value, field) {
|
|
5351
|
-
|
|
5352
|
-
|
|
4895
|
+
let num;
|
|
4896
|
+
try {
|
|
4897
|
+
num = BigInt(value);
|
|
4898
|
+
} catch {
|
|
5353
4899
|
throw new ValidationError(
|
|
5354
4900
|
field,
|
|
5355
|
-
`"${value}" is not a valid
|
|
4901
|
+
`"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
|
|
5356
4902
|
);
|
|
5357
4903
|
}
|
|
5358
|
-
const num = BigInt(t);
|
|
5359
4904
|
if (num < I128_MIN) {
|
|
5360
4905
|
throw new ValidationError(
|
|
5361
4906
|
field,
|
|
@@ -5379,9 +4924,6 @@ function validateBps(value, field) {
|
|
|
5379
4924
|
`must be <= 10000 (100%), got ${t}`
|
|
5380
4925
|
);
|
|
5381
4926
|
}
|
|
5382
|
-
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5383
|
-
throw new ValidationError(field, `internal error: bps value exceeds MAX_SAFE_INTEGER`);
|
|
5384
|
-
}
|
|
5385
4927
|
return Number(bi);
|
|
5386
4928
|
}
|
|
5387
4929
|
function validateU64(value, field) {
|
|
@@ -5390,15 +4932,12 @@ function validateU64(value, field) {
|
|
|
5390
4932
|
function validateU16(value, field) {
|
|
5391
4933
|
const t = requireDecimalUIntString(value, field);
|
|
5392
4934
|
const bi = BigInt(t);
|
|
5393
|
-
if (bi > BigInt(
|
|
4935
|
+
if (bi > BigInt(U16_MAX2)) {
|
|
5394
4936
|
throw new ValidationError(
|
|
5395
4937
|
field,
|
|
5396
|
-
`must be <= ${
|
|
4938
|
+
`must be <= ${U16_MAX2} (u16 max), got ${t}`
|
|
5397
4939
|
);
|
|
5398
4940
|
}
|
|
5399
|
-
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5400
|
-
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5401
|
-
}
|
|
5402
4941
|
return Number(bi);
|
|
5403
4942
|
}
|
|
5404
4943
|
|
|
@@ -5449,9 +4988,7 @@ function parseDexScreenerPairs(json) {
|
|
|
5449
4988
|
else if (liquidity > 1e4) confidence = 60;
|
|
5450
4989
|
else if (liquidity > 1e3) confidence = 45;
|
|
5451
4990
|
const priceUsd = pair.priceUsd;
|
|
5452
|
-
const
|
|
5453
|
-
if (!Number.isFinite(rawPrice) || rawPrice <= 0) continue;
|
|
5454
|
-
const price = rawPrice;
|
|
4991
|
+
const price = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) || 0 : 0;
|
|
5455
4992
|
let baseSym = "?";
|
|
5456
4993
|
let quoteSym = "?";
|
|
5457
4994
|
if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
|
|
@@ -5482,8 +5019,8 @@ function parseJupiterMintEntry(json, mint) {
|
|
|
5482
5019
|
if (!isRecord(row)) return null;
|
|
5483
5020
|
const rawPrice = row.price;
|
|
5484
5021
|
if (rawPrice === void 0 || rawPrice === null) return null;
|
|
5485
|
-
const price = parseFloat(String(rawPrice));
|
|
5486
|
-
if (
|
|
5022
|
+
const price = parseFloat(String(rawPrice)) || 0;
|
|
5023
|
+
if (price <= 0) return null;
|
|
5487
5024
|
let mintSymbol = "?";
|
|
5488
5025
|
if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
|
|
5489
5026
|
return { price, mintSymbol };
|
|
@@ -5549,17 +5086,10 @@ async function fetchDexSources(mint, signal) {
|
|
|
5549
5086
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5550
5087
|
}
|
|
5551
5088
|
);
|
|
5552
|
-
if (!resp.ok)
|
|
5553
|
-
console.debug(`[fetchDexSources] HTTP ${resp.status} for mint ${mint}`);
|
|
5554
|
-
return [];
|
|
5555
|
-
}
|
|
5089
|
+
if (!resp.ok) return [];
|
|
5556
5090
|
const json = await resp.json();
|
|
5557
5091
|
return parseDexScreenerPairs(json);
|
|
5558
|
-
} catch
|
|
5559
|
-
console.warn(
|
|
5560
|
-
`[fetchDexSources] Error fetching DexScreener data for mint ${mint}:`,
|
|
5561
|
-
err instanceof Error ? err.message : String(err)
|
|
5562
|
-
);
|
|
5092
|
+
} catch {
|
|
5563
5093
|
return [];
|
|
5564
5094
|
}
|
|
5565
5095
|
}
|
|
@@ -5570,7 +5100,7 @@ function lookupPythSource(mint) {
|
|
|
5570
5100
|
type: "pyth",
|
|
5571
5101
|
address: entry.feedId,
|
|
5572
5102
|
pairLabel: `${entry.symbol} / USD (Pyth)`,
|
|
5573
|
-
liquidity:
|
|
5103
|
+
liquidity: Infinity,
|
|
5574
5104
|
// Pyth is considered deep liquidity
|
|
5575
5105
|
price: 0,
|
|
5576
5106
|
// We don't fetch live price here; caller can enrich
|
|
@@ -5587,16 +5117,10 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5587
5117
|
headers: { "User-Agent": "percolator/1.0" }
|
|
5588
5118
|
}
|
|
5589
5119
|
);
|
|
5590
|
-
if (!resp.ok)
|
|
5591
|
-
console.debug(`[fetchJupiterSource] HTTP ${resp.status} for mint ${mint}`);
|
|
5592
|
-
return null;
|
|
5593
|
-
}
|
|
5120
|
+
if (!resp.ok) return null;
|
|
5594
5121
|
const json = await resp.json();
|
|
5595
5122
|
const row = parseJupiterMintEntry(json, mint);
|
|
5596
|
-
if (!row)
|
|
5597
|
-
console.debug(`[fetchJupiterSource] No price data from Jupiter for mint ${mint}`);
|
|
5598
|
-
return null;
|
|
5599
|
-
}
|
|
5123
|
+
if (!row) return null;
|
|
5600
5124
|
return {
|
|
5601
5125
|
type: "jupiter",
|
|
5602
5126
|
address: mint,
|
|
@@ -5607,39 +5131,23 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
5607
5131
|
confidence: 40
|
|
5608
5132
|
// Fallback — lower confidence
|
|
5609
5133
|
};
|
|
5610
|
-
} catch
|
|
5611
|
-
console.warn(
|
|
5612
|
-
`[fetchJupiterSource] Error fetching Jupiter data for mint ${mint}:`,
|
|
5613
|
-
err instanceof Error ? err.message : String(err)
|
|
5614
|
-
);
|
|
5134
|
+
} catch {
|
|
5615
5135
|
return null;
|
|
5616
5136
|
}
|
|
5617
5137
|
}
|
|
5618
5138
|
async function resolvePrice(mint, signal, options) {
|
|
5619
5139
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;
|
|
5620
5140
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
5621
|
-
const
|
|
5141
|
+
const combinedSignal = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
|
|
5622
5142
|
const [dexSources, jupiterSource] = await Promise.all([
|
|
5623
|
-
fetchDexSources(mint,
|
|
5624
|
-
fetchJupiterSource(mint,
|
|
5143
|
+
fetchDexSources(mint, combinedSignal),
|
|
5144
|
+
fetchJupiterSource(mint, combinedSignal)
|
|
5625
5145
|
]);
|
|
5626
5146
|
const pythSource = lookupPythSource(mint);
|
|
5627
5147
|
const allSources = [];
|
|
5628
5148
|
if (pythSource) {
|
|
5629
|
-
const
|
|
5630
|
-
|
|
5631
|
-
if (dexPrice > 0 && jupPrice > 0) {
|
|
5632
|
-
const mid = (dexPrice + jupPrice) / 2;
|
|
5633
|
-
const deviation = Math.abs(dexPrice - jupPrice) / mid;
|
|
5634
|
-
if (deviation > 0.5) {
|
|
5635
|
-
pythSource.price = 0;
|
|
5636
|
-
pythSource.confidence = 20;
|
|
5637
|
-
} else {
|
|
5638
|
-
pythSource.price = mid;
|
|
5639
|
-
}
|
|
5640
|
-
} else {
|
|
5641
|
-
pythSource.price = dexPrice || jupPrice || 0;
|
|
5642
|
-
}
|
|
5149
|
+
const refPrice = dexSources[0]?.price || jupiterSource?.price || 0;
|
|
5150
|
+
pythSource.price = refPrice;
|
|
5643
5151
|
allSources.push(pythSource);
|
|
5644
5152
|
}
|
|
5645
5153
|
allSources.push(...dexSources);
|
|
@@ -5664,7 +5172,9 @@ export {
|
|
|
5664
5172
|
ACCOUNTS_CLOSE_ACCOUNT,
|
|
5665
5173
|
ACCOUNTS_CLOSE_SLAB,
|
|
5666
5174
|
ACCOUNTS_CLOSE_STALE_SLABS,
|
|
5175
|
+
ACCOUNTS_CREATE_INSURANCE_MINT,
|
|
5667
5176
|
ACCOUNTS_DEPOSIT_COLLATERAL,
|
|
5177
|
+
ACCOUNTS_DEPOSIT_INSURANCE_LP,
|
|
5668
5178
|
ACCOUNTS_EXECUTE_ADL,
|
|
5669
5179
|
ACCOUNTS_FUND_MARKET_INSURANCE,
|
|
5670
5180
|
ACCOUNTS_INIT_LP,
|
|
@@ -5680,6 +5190,7 @@ export {
|
|
|
5680
5190
|
ACCOUNTS_QUEUE_WITHDRAWAL,
|
|
5681
5191
|
ACCOUNTS_RECLAIM_SLAB_RENT,
|
|
5682
5192
|
ACCOUNTS_RESOLVE_MARKET,
|
|
5193
|
+
ACCOUNTS_SET_DEX_POOL,
|
|
5683
5194
|
ACCOUNTS_SET_INSURANCE_ISOLATION,
|
|
5684
5195
|
ACCOUNTS_SET_MAINTENANCE_FEE,
|
|
5685
5196
|
ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK,
|
|
@@ -5698,22 +5209,17 @@ export {
|
|
|
5698
5209
|
ACCOUNTS_UPDATE_CONFIG,
|
|
5699
5210
|
ACCOUNTS_WITHDRAW_COLLATERAL,
|
|
5700
5211
|
ACCOUNTS_WITHDRAW_INSURANCE,
|
|
5212
|
+
ACCOUNTS_WITHDRAW_INSURANCE_LP,
|
|
5701
5213
|
AccountKind,
|
|
5702
5214
|
CHAINLINK_ANSWER_OFFSET,
|
|
5703
5215
|
CHAINLINK_DECIMALS_OFFSET,
|
|
5704
5216
|
CHAINLINK_MIN_SIZE,
|
|
5705
|
-
CHAINLINK_TIMESTAMP_OFFSET,
|
|
5706
5217
|
CREATOR_LOCK_SEED,
|
|
5707
5218
|
CTX_VAMM_OFFSET,
|
|
5708
5219
|
DEFAULT_OI_RAMP_SLOTS,
|
|
5709
5220
|
ENGINE_MARK_PRICE_OFF,
|
|
5710
5221
|
ENGINE_OFF,
|
|
5711
5222
|
IX_TAG,
|
|
5712
|
-
LIGHTHOUSE_CONSTRAINT_ADDRESS,
|
|
5713
|
-
LIGHTHOUSE_ERROR_CODES,
|
|
5714
|
-
LIGHTHOUSE_PROGRAM_ID,
|
|
5715
|
-
LIGHTHOUSE_PROGRAM_ID_STR2 as LIGHTHOUSE_PROGRAM_ID_STR,
|
|
5716
|
-
LIGHTHOUSE_USER_MESSAGE,
|
|
5717
5223
|
MARK_PRICE_EMA_ALPHA_E6,
|
|
5718
5224
|
MARK_PRICE_EMA_WINDOW_SLOTS,
|
|
5719
5225
|
MAX_DECIMALS,
|
|
@@ -5735,7 +5241,6 @@ export {
|
|
|
5735
5241
|
RAMP_START_BPS,
|
|
5736
5242
|
RAYDIUM_CLMM_PROGRAM_ID,
|
|
5737
5243
|
RENOUNCE_ADMIN_CONFIRMATION,
|
|
5738
|
-
RpcPool,
|
|
5739
5244
|
SLAB_TIERS,
|
|
5740
5245
|
SLAB_TIERS_V0,
|
|
5741
5246
|
SLAB_TIERS_V1,
|
|
@@ -5757,14 +5262,11 @@ export {
|
|
|
5757
5262
|
VAMM_MAGIC,
|
|
5758
5263
|
ValidationError,
|
|
5759
5264
|
WELL_KNOWN,
|
|
5760
|
-
_internal,
|
|
5761
5265
|
buildAccountMetas,
|
|
5762
5266
|
buildAdlInstruction,
|
|
5763
5267
|
buildAdlTransaction,
|
|
5764
5268
|
buildIx,
|
|
5765
5269
|
checkPhaseTransition,
|
|
5766
|
-
checkRpcHealth,
|
|
5767
|
-
classifyLighthouseError,
|
|
5768
5270
|
clearStaticMarkets,
|
|
5769
5271
|
computeDexSpotPriceE6,
|
|
5770
5272
|
computeDynamicFeeBps,
|
|
@@ -5777,7 +5279,6 @@ export {
|
|
|
5777
5279
|
computeLiqPrice,
|
|
5778
5280
|
computeMarkPnl,
|
|
5779
5281
|
computeMaxLeverage,
|
|
5780
|
-
computeMaxWithdrawable,
|
|
5781
5282
|
computePnlPercent,
|
|
5782
5283
|
computePreTradeLiqPrice,
|
|
5783
5284
|
computeRequiredMargin,
|
|
@@ -5785,15 +5286,14 @@ export {
|
|
|
5785
5286
|
computeVammQuote,
|
|
5786
5287
|
computeWarmupLeverageCap,
|
|
5787
5288
|
computeWarmupMaxPositionSize,
|
|
5788
|
-
computeWarmupProgress,
|
|
5789
5289
|
computeWarmupUnlockedCapital,
|
|
5790
5290
|
concatBytes,
|
|
5791
|
-
countLighthouseInstructions,
|
|
5792
5291
|
decodeError,
|
|
5793
5292
|
decodeStakePool,
|
|
5794
5293
|
depositAccounts,
|
|
5795
5294
|
deriveCreatorLockPda,
|
|
5796
5295
|
deriveDepositPda,
|
|
5296
|
+
deriveInsuranceLpMint,
|
|
5797
5297
|
deriveKeeperFund,
|
|
5798
5298
|
deriveLpPda,
|
|
5799
5299
|
derivePythPriceUpdateAccount,
|
|
@@ -5830,11 +5330,14 @@ export {
|
|
|
5830
5330
|
encodeClaimQueuedWithdrawal,
|
|
5831
5331
|
encodeClearPendingSettlement,
|
|
5832
5332
|
encodeCloseAccount,
|
|
5333
|
+
encodeCloseKeeperFund,
|
|
5833
5334
|
encodeCloseOrphanSlab,
|
|
5834
5335
|
encodeCloseSlab,
|
|
5835
5336
|
encodeCloseStaleSlabs,
|
|
5337
|
+
encodeCreateInsuranceMint,
|
|
5836
5338
|
encodeCreateLpVault,
|
|
5837
5339
|
encodeDepositCollateral,
|
|
5340
|
+
encodeDepositInsuranceLP,
|
|
5838
5341
|
encodeDepositLpCollateral,
|
|
5839
5342
|
encodeExecuteAdl,
|
|
5840
5343
|
encodeForceCloseResolved,
|
|
@@ -5905,6 +5408,7 @@ export {
|
|
|
5905
5408
|
encodeUpdateRiskParams,
|
|
5906
5409
|
encodeWithdrawCollateral,
|
|
5907
5410
|
encodeWithdrawInsurance,
|
|
5411
|
+
encodeWithdrawInsuranceLP,
|
|
5908
5412
|
encodeWithdrawInsuranceLimited,
|
|
5909
5413
|
encodeWithdrawLpCollateral,
|
|
5910
5414
|
fetchAdlRankedPositions,
|
|
@@ -5926,10 +5430,6 @@ export {
|
|
|
5926
5430
|
initPoolAccounts,
|
|
5927
5431
|
isAccountUsed,
|
|
5928
5432
|
isAdlTriggered,
|
|
5929
|
-
isAnchorErrorCode,
|
|
5930
|
-
isLighthouseError,
|
|
5931
|
-
isLighthouseFailureInLogs,
|
|
5932
|
-
isLighthouseInstruction,
|
|
5933
5433
|
isStandardToken,
|
|
5934
5434
|
isToken2022,
|
|
5935
5435
|
isValidChainlinkOracle,
|
|
@@ -5954,8 +5454,6 @@ export {
|
|
|
5954
5454
|
simulateOrSend,
|
|
5955
5455
|
slabDataSize,
|
|
5956
5456
|
slabDataSizeV1,
|
|
5957
|
-
stripLighthouseFromTransaction,
|
|
5958
|
-
stripLighthouseInstructions,
|
|
5959
5457
|
validateAmount,
|
|
5960
5458
|
validateBps,
|
|
5961
5459
|
validateI128,
|
|
@@ -5966,7 +5464,6 @@ export {
|
|
|
5966
5464
|
validateU128,
|
|
5967
5465
|
validateU16,
|
|
5968
5466
|
validateU64,
|
|
5969
|
-
withRetry,
|
|
5970
5467
|
withdrawAccounts
|
|
5971
5468
|
};
|
|
5972
5469
|
//# sourceMappingURL=index.js.map
|